1.1 --- a/librazor/error.c Tue Jun 05 11:07:53 2018 +0100
1.2 +++ b/librazor/error.c Thu Jun 07 18:36:20 2018 +0100
1.3 @@ -42,6 +42,30 @@
1.4 return error->code;
1.5 }
1.6
1.7 +void
1.8 +razor_error_set_object(struct razor_error *error, const char *object)
1.9 +{
1.10 + if (!error)
1.11 + return;
1.12 +
1.13 + free(error->object);
1.14 +
1.15 + if (object)
1.16 + error->object = strdup(object);
1.17 + else
1.18 + error->object = NULL;
1.19 +
1.20 + if (error->obj_str) {
1.21 + free(error->obj_str);
1.22 + error->obj_str = NULL;
1.23 + }
1.24 +
1.25 + if (error->msg) {
1.26 + free(error->msg);
1.27 + error->msg = NULL;
1.28 + }
1.29 +}
1.30 +
1.31 RAZOR_EXPORT const char *
1.32 razor_error_get_object(struct razor_error *error)
1.33 {
2.1 --- a/librazor/razor-internal.h Tue Jun 05 11:07:53 2018 +0100
2.2 +++ b/librazor/razor-internal.h Thu Jun 07 18:36:20 2018 +0100
2.3 @@ -125,7 +125,7 @@
2.4 struct array file_string_pool;
2.5 struct array details_string_pool;
2.6 struct razor_mapped_file *mapped_files;
2.7 - int lock_fd, ref_count;
2.8 + int lock, ref_count;
2.9 enum razor_set_flags flags;
2.10 };
2.11
2.12 @@ -184,7 +184,8 @@
2.13 };
2.14
2.15 int
2.16 -razor_set_acquire_lock(struct razor_set *set, const char *path, int exclusive);
2.17 +razor_set_acquire_lock(struct razor_set *set, const char *path, int exclusive,
2.18 + struct razor_error **error);
2.19
2.20 struct razor_entry *
2.21 razor_set_find_entry(struct razor_set *set,
2.22 @@ -315,6 +316,7 @@
2.23 if (error) \
2.24 *(error) = razor_error_new_str(domain, code, object, str); \
2.25 else
2.26 +void razor_error_set_object(struct razor_error *error, const char *object);
2.27
2.28 #ifdef MSWIN_API
2.29 struct razor_error *razor_error_new_mswin(const wchar_t *object, DWORD error);
3.1 --- a/librazor/razor.c Tue Jun 05 11:07:53 2018 +0100
3.2 +++ b/librazor/razor.c Thu Jun 07 18:36:20 2018 +0100
3.3 @@ -1,7 +1,7 @@
3.4 /*
3.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3.6 * Copyright (C) 2008 Red Hat, Inc
3.7 - * Copyright (C) 2009-2012, 2016 J. Ali Harlow <ali@juiblex.co.uk>
3.8 + * Copyright (C) 2009-2012, 2016, 2018 J. Ali Harlow <ali@juiblex.co.uk>
3.9 *
3.10 * This program is free software; you can redistribute it and/or modify
3.11 * it under the terms of the GNU General Public License as published by
3.12 @@ -39,8 +39,9 @@
3.13 #include <windows.h>
3.14 #endif
3.15
3.16 +#include "razor.h"
3.17 +#include "types/types.h"
3.18 #include "razor-internal.h"
3.19 -#include "razor.h"
3.20
3.21 #ifndef O_BINARY
3.22 #define O_BINARY 0
3.23 @@ -84,7 +85,7 @@
3.24 empty = array_add(&set->string_pool, 1);
3.25 *empty = '\0';
3.26
3.27 - set->lock_fd = -1;
3.28 + set->lock = -1;
3.29
3.30 set->ref_count = 1;
3.31
3.32 @@ -229,7 +230,7 @@
3.33 return NULL;
3.34 }
3.35
3.36 - set->lock_fd = -1;
3.37 + set->lock = -1;
3.38 set->ref_count = 1;
3.39 if (razor_set_bind_sections(set, uri, flags, error)) {
3.40 free(set);
3.41 @@ -238,56 +239,189 @@
3.42 return set;
3.43 }
3.44
3.45 -int
3.46 -razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive)
3.47 +struct razor_uri_lock {
3.48 + char *uri;
3.49 + int fd;
3.50 + int exclusive;
3.51 +};
3.52 +
3.53 +static struct array razor_uri_locks = { 0, };
3.54 +
3.55 +/*
3.56 + * The underlying locks on MS-Windows and POSIX are different. Posix locks
3.57 + * created with fcntl(F_SETLK) only affect other processes whereas MS-Windows
3.58 + * locks affect the locking process as well. Partly because the latter is
3.59 + * preferable and partly because it makes testing easier if platforms behave
3.60 + * in the same way, we implement platform independent locks which follow the
3.61 + * MS-Windows pattern.
3.62 + *
3.63 + * Note that razor_set_aquire_lock() currently assumes that this is a private
3.64 + * helper function. Should we ever want to make this a library-wide API then
3.65 + * we should probably add a 'void *owner' parameter and add a new error code
3.66 + * (RAZOR_GENERAL_ERROR_LOCALLY_LOCKED?) if a lock is present with a different
3.67 + * owner so that razor_set_aquire_lock() can generate a different error message.
3.68 + */
3.69 +
3.70 +static int
3.71 +razor_uri_lock(const char *uri, int flags, mode_t mode, int exclusive,
3.72 + struct razor_error **error)
3.73 {
3.74 - int fd;
3.75 - assert(set != NULL);
3.76 + int fd, i;
3.77 + struct razor_uri_lock *ulock;
3.78 +#ifdef MSWIN_API
3.79 + DWORD lflags = LOCKFILE_FAIL_IMMEDIATELY, err;
3.80 + OVERLAPPED lock = {0};
3.81 +#else
3.82 + struct flock lock = {0};
3.83 +#endif
3.84
3.85 - if (uri) {
3.86 - fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
3.87 - 0666, NULL);
3.88 - if (fd < 0)
3.89 + fd = razor_uri_open(uri, flags, mode, error);
3.90 + if (fd < 0)
3.91 + return -1;
3.92 +
3.93 + for (i = ptr_array_len(&razor_uri_locks) - 1; i >= 0; i--) {
3.94 + ulock = ptr_array_index(&razor_uri_locks, i);
3.95 + if (ulock && !strcmp(ulock->uri, uri)) {
3.96 + if (!ulock->exclusive && !exclusive)
3.97 + break;
3.98 + razor_set_error(error, RAZOR_GENERAL_ERROR,
3.99 + RAZOR_GENERAL_ERROR_ALREADY_LOCKED,
3.100 + uri,
3.101 + "An existing lock is already held on this file");
3.102 + close(fd);
3.103 return -1;
3.104 - } else
3.105 - fd = -1;
3.106 + }
3.107 + }
3.108
3.109 #ifdef MSWIN_API
3.110 - DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
3.111 - OVERLAPPED lock = {0};
3.112 -
3.113 if (exclusive)
3.114 - flags |= LOCKFILE_EXCLUSIVE_LOCK;
3.115 - if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0,
3.116 - &lock)) {
3.117 + lflags |= LOCKFILE_EXCLUSIVE_LOCK;
3.118 + if (!LockFileEx((HANDLE)_get_osfhandle(fd), lflags, 0, 1, 0, &lock)) {
3.119 + err = GetLastError();
3.120 + if (err == ERROR_IO_PENDING)
3.121 + razor_set_error(error, RAZOR_GENERAL_ERROR,
3.122 + RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
3.123 + uri,
3.124 + "An existing lock is already held on this file");
3.125 + else
3.126 + razor_set_error_mswin(error, uri, err);
3.127 close(fd);
3.128 return -1;
3.129 }
3.130 - if (set->lock_fd >= 0)
3.131 - (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1,
3.132 - 0);
3.133 #else
3.134 - struct flock lock = {0};
3.135 -
3.136 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
3.137 lock.l_whence = SEEK_SET;
3.138 lock.l_start = 0;
3.139 lock.l_len = 0;
3.140 - if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
3.141 + if (fcntl(fd, F_SETLK, &lock) < 0) {
3.142 + if (errno == EAGAIN || errno == EACCES)
3.143 + razor_set_error(error, RAZOR_GENERAL_ERROR,
3.144 + RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
3.145 + uri,
3.146 + "An existing lock is already held on this file");
3.147 + else
3.148 + razor_set_error_posix(error, uri);
3.149 close(fd);
3.150 return -1;
3.151 }
3.152 - if (set->lock_fd >= 0) {
3.153 - lock.l_type = F_UNLCK;
3.154 - (void)fcntl(set->lock_fd, F_SETLK, &lock);
3.155 - }
3.156 #endif
3.157
3.158 - if (set->lock_fd >= 0)
3.159 - close(set->lock_fd);
3.160 - set->lock_fd = fd;
3.161 + ulock = zalloc(sizeof *ulock);
3.162 + ulock->uri = strdup(uri);
3.163 + ulock->fd = fd;
3.164 + ulock->exclusive = exclusive;
3.165 + return ptr_array_add(&razor_uri_locks, ulock);
3.166 +}
3.167
3.168 - return 0;
3.169 +static void
3.170 +razor_uri_unlock(int id)
3.171 +{
3.172 + struct razor_uri_lock *ulock;
3.173 +#ifndef MSWIN_API
3.174 + struct flock lock = {0};
3.175 +#endif
3.176 +
3.177 + if (id < 0 || id >= ptr_array_len(&razor_uri_locks))
3.178 + return;
3.179 +
3.180 + ulock = ptr_array_index(&razor_uri_locks, id);
3.181 +
3.182 + if (!ulock)
3.183 + return;
3.184 +
3.185 +#ifdef MSWIN_API
3.186 + (void)UnlockFile((HANDLE)_get_osfhandle(ulock->fd), 0, 0, 1, 0);
3.187 +#else
3.188 + lock.l_type = F_UNLCK;
3.189 + lock.l_whence = SEEK_SET;
3.190 + lock.l_start = 0;
3.191 + lock.l_len = 0;
3.192 + (void)fcntl(ulock->fd, F_SETLK, &lock);
3.193 +#endif
3.194 +
3.195 + ptr_array_remove_index(&razor_uri_locks, id);
3.196 + free(ulock->uri);
3.197 + close(ulock->fd);
3.198 + free(ulock);
3.199 +}
3.200 +
3.201 +int
3.202 +razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive,
3.203 + struct razor_error **error)
3.204 +{
3.205 + int lock;
3.206 + const char *errstr = NULL;
3.207 + assert(set != NULL);
3.208 +
3.209 + if (!uri) {
3.210 + razor_uri_unlock(set->lock);
3.211 + set->lock = -1;
3.212 + return 0;
3.213 + }
3.214 +
3.215 + lock = razor_uri_lock(uri,
3.216 + O_CREAT | O_RDWR | O_TRUNC | O_BINARY,
3.217 + 0666, exclusive, error);
3.218 +
3.219 + if (lock >= 0) {
3.220 + set->lock = lock;
3.221 + return 0;
3.222 + }
3.223 +
3.224 + if (!error)
3.225 + return -1;
3.226 +
3.227 + if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
3.228 + RAZOR_GENERAL_ERROR_ALREADY_LOCKED)) {
3.229 + /*
3.230 + * This represents a design flaw in the caller.
3.231 + */
3.232 + if (exclusive)
3.233 + errstr = "Database is in use and cannot be locked";
3.234 + else
3.235 + errstr = "Database is being updated and cannot be locked";
3.236 + } else if (razor_error_matches(*error, RAZOR_GENERAL_ERROR,
3.237 + RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED)) {
3.238 + /*
3.239 + * This is probably caused by another application holding
3.240 + * the lock, but under MS-Windows the file could in theory
3.241 + * be locked by this application outside of razor_set.
3.242 + */
3.243 + if (exclusive)
3.244 + errstr = "Database is in use. Please try again later";
3.245 + else
3.246 + errstr = "Database is being updated. Please try again later";
3.247 + }
3.248 +
3.249 + if (errstr) {
3.250 + razor_error_free(*error);
3.251 + razor_set_error(error,
3.252 + RAZOR_GENERAL_ERROR,
3.253 + RAZOR_GENERAL_ERROR_DATABASE_LOCKED,
3.254 + uri, errstr);
3.255 + }
3.256 +
3.257 + return -1;
3.258 }
3.259
3.260 static void
3.261 @@ -312,7 +446,7 @@
3.262 }
3.263 }
3.264
3.265 - razor_set_acquire_lock(set, NULL, 0);
3.266 + razor_set_acquire_lock(set, NULL, 0, NULL);
3.267 free(set);
3.268 }
3.269
4.1 --- a/librazor/razor.h.in Tue Jun 05 11:07:53 2018 +0100
4.2 +++ b/librazor/razor.h.in Thu Jun 07 18:36:20 2018 +0100
4.3 @@ -1,7 +1,8 @@
4.4 /*
4.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
4.6 * Copyright (C) 2008 Red Hat, Inc
4.7 - * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow <ali@juiblex.co.uk>
4.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016, 2018
4.9 + * J. Ali Harlow <ali@juiblex.co.uk>
4.10 *
4.11 * This program is free software; you can redistribute it and/or modify
4.12 * it under the terms of the GNU General Public License as published by
4.13 @@ -152,6 +153,8 @@
4.14 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
4.15 RAZOR_GENERAL_ERROR_BAD_URI,
4.16 RAZOR_GENERAL_ERROR_UNSUPPORTED_ARCHIVE,
4.17 + RAZOR_GENERAL_ERROR_ALREADY_LOCKED,
4.18 + RAZOR_GENERAL_ERROR_EXTERNALLY_LOCKED,
4.19 };
4.20
4.21 int razor_error_get_domain(struct razor_error *error);
5.1 --- a/librazor/root.c Tue Jun 05 11:07:53 2018 +0100
5.2 +++ b/librazor/root.c Thu Jun 07 18:36:20 2018 +0100
5.3 @@ -1,7 +1,7 @@
5.4 /*
5.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
5.6 * Copyright (C) 2008 Red Hat, Inc
5.7 - * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow <ali@juiblex.co.uk>
5.8 + * Copyright (C) 2009, 2011, 2012, 2014, 2016, 2018 J. Ali Harlow <ali@juiblex.co.uk>
5.9 *
5.10 * This program is free software; you can redistribute it and/or modify
5.11 * it under the terms of the GNU General Public License as published by
5.12 @@ -67,6 +67,7 @@
5.13 #endif
5.14 static char *razor_database_uri = RAZOR_DATABASE_URI;
5.15 static int razor_database_uri_alloced = FALSE;
5.16 +static int razor_database_uri_default = TRUE;
5.17
5.18 struct razor_root {
5.19 struct razor_set *system;
5.20 @@ -107,9 +108,11 @@
5.21 if (database_uri) {
5.22 razor_database_uri = strdup(database_uri);
5.23 razor_database_uri_alloced = TRUE;
5.24 + razor_database_uri_default = FALSE;
5.25 } else {
5.26 razor_database_uri = RAZOR_DATABASE_URI;
5.27 razor_database_uri_alloced = FALSE;
5.28 + razor_database_uri_default = TRUE;
5.29 }
5.30 }
5.31
5.32 @@ -223,14 +226,13 @@
5.33 return NULL;
5.34 }
5.35
5.36 - r = razor_set_acquire_lock(image->system, lock_uri, 1);
5.37 + r = razor_set_acquire_lock(image->system, lock_uri, 1, error);
5.38
5.39 free(lock_uri);
5.40
5.41 if (r < 0) {
5.42 - razor_set_error(error, RAZOR_GENERAL_ERROR,
5.43 - RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
5.44 - "Failed to acquire exclusive system lock");
5.45 + if (error && razor_database_uri_default)
5.46 + razor_error_set_object(*error, root_uri);
5.47 razor_set_unref(image->system);
5.48 free(image);
5.49 return NULL;
5.50 @@ -277,14 +279,13 @@
5.51 return NULL;
5.52 }
5.53
5.54 - r = razor_set_acquire_lock(set, uri, 0);
5.55 + r = razor_set_acquire_lock(set, uri, 0, error);
5.56
5.57 free(uri);
5.58
5.59 if (r < 0) {
5.60 - razor_set_error(error, RAZOR_GENERAL_ERROR,
5.61 - RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
5.62 - "Failed to acquire non-exclusive system lock");
5.63 + if (error && razor_database_uri_default)
5.64 + razor_error_set_object(*error, root_uri);
5.65 razor_set_unref(set);
5.66 return NULL;
5.67 }
6.1 --- a/librazor/types/array.c Tue Jun 05 11:07:53 2018 +0100
6.2 +++ b/librazor/types/array.c Thu Jun 07 18:36:20 2018 +0100
6.3 @@ -1,7 +1,7 @@
6.4 /*
6.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
6.6 * Copyright (C) 2008 Red Hat, Inc
6.7 - * Copyright (C) 2016 J. Ali Harlow <ali@juiblex.co.uk>
6.8 + * Copyright (C) 2016, 2018 J. Ali Harlow <ali@juiblex.co.uk>
6.9 *
6.10 * This program is free software; you can redistribute it and/or modify
6.11 * it under the terms of the GNU General Public License as published by
6.12 @@ -74,7 +74,16 @@
6.13 return array->data + array->size - size;
6.14 }
6.15
6.16 -void ptr_array_add(struct array *ptr_array, void *data)
6.17 +int ptr_array_len(struct array *ptr_array)
6.18 +{
6.19 + void **ptrend;
6.20 +
6.21 + ptrend = ptr_array->data + ptr_array->size;
6.22 +
6.23 + return ptrend - (void **)ptr_array->data;
6.24 +}
6.25 +
6.26 +int ptr_array_add(struct array *ptr_array, void *data)
6.27 {
6.28 void **ptr, **ptrend;
6.29
6.30 @@ -87,6 +96,21 @@
6.31 ptr = array_add(ptr_array, sizeof *ptr);
6.32
6.33 *ptr = data;
6.34 +
6.35 + return ptr - (void **)ptr_array->data;
6.36 +}
6.37 +
6.38 +void *ptr_array_index(struct array *ptr_array, int indx)
6.39 +{
6.40 + void **ptr, **ptrend;
6.41 +
6.42 + ptrend = ptr_array->data + ptr_array->size;
6.43 +
6.44 + ptr = (void **)ptr_array->data + indx;
6.45 + if (ptr < ptr_array->data || ptr >= ptrend)
6.46 + return NULL;
6.47 +
6.48 + return *ptr;
6.49 }
6.50
6.51 int ptr_array_find(struct array *ptr_array, void *data)
6.52 @@ -108,7 +132,7 @@
6.53 ptrend = ptr_array->data + ptr_array->size;
6.54
6.55 ptr = (void **)ptr_array->data + indx;
6.56 - if (ptr >= ptrend)
6.57 + if (ptr < ptr_array->data || ptr >= ptrend)
6.58 return;
6.59 *ptr = NULL;
6.60
7.1 --- a/librazor/types/types.h Tue Jun 05 11:07:53 2018 +0100
7.2 +++ b/librazor/types/types.h Thu Jun 07 18:36:20 2018 +0100
7.3 @@ -1,7 +1,7 @@
7.4 /*
7.5 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
7.6 * Copyright (C) 2008 Red Hat, Inc
7.7 - * Copyright (C) 2009 J. Ali Harlow <ali@juiblex.co.uk>
7.8 + * Copyright (C) 2009, 2018 J. Ali Harlow <ali@juiblex.co.uk>
7.9 *
7.10 * This program is free software; you can redistribute it and/or modify
7.11 * it under the terms of the GNU General Public License as published by
7.12 @@ -37,7 +37,9 @@
7.13 void array_release(struct array *array);
7.14 int array_set_size(struct array *array, int size);
7.15 void *array_add(struct array *array, int size);
7.16 -void ptr_array_add(struct array *ptr_array, void *data);
7.17 +int ptr_array_len(struct array *ptr_array);
7.18 +int ptr_array_add(struct array *ptr_array, void *data);
7.19 +void *ptr_array_index(struct array *ptr_array, int indx);
7.20 int ptr_array_find(struct array *ptr_array, void *data);
7.21 void ptr_array_remove_index(struct array *ptr_array, int indx);
7.22