Rewrite
Showing
2 changed files
with
437 additions
and
320 deletions
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2000, 2001, 2005 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2000, 2001, 2005, 2007 Free Software Foundation, Inc. |
3 | 3 | ||
4 | This library is free software; you can redistribute it and/or | 4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public | 5 | modify it under the terms of the GNU Lesser General Public |
... | @@ -47,34 +47,53 @@ enum mu_locker_set_mode | ... | @@ -47,34 +47,53 @@ enum mu_locker_set_mode |
47 | 47 | ||
48 | /* mu_locker_create() flags */ | 48 | /* mu_locker_create() flags */ |
49 | 49 | ||
50 | #define MU_LOCKER_SIMPLE 0x00 | 50 | /* Locker types */ |
51 | |||
52 | #define MU_LOCKER_TYPE_DOTLOCK 0 | ||
53 | #define MU_LOCKER_TYPE_EXTERNAL 1 | ||
54 | /* Use an external program to lock the file. This is necessary | ||
55 | for programs having permission to access a file, but do not | ||
56 | have write permission on the directory that contains that file. */ | ||
57 | #define MU_LOCKER_TYPE_KERNEL 2 | ||
58 | /* Use kernel locking (flock, lockf or ioctl) */ | ||
59 | #define MU_LOCKER_TYPE_NULL 3 | ||
60 | /* Special locker type: means no lock. This is to be used with | ||
61 | temporary mailboxes stored in memory. */ | ||
62 | |||
63 | #define MU_LOCKER_TYPE_TO_FLAG(t) ((t) << 8) | ||
64 | #define MU_LOCKER_FLAG_TO_TYPE(f) ((f) >> 8) | ||
65 | #define MU_LOCKER_IS_TYPE(f,t) (MU_LOCKER_FLAG_TO_TYPE(f) == (t)) | ||
66 | #define MU_LOCKER_SET_TYPE(f,t) ((f) = MU_LOCKER_TYPE_TO_FLAG(t) | MU_LOCKER_OPTIONS(f)) | ||
67 | #define MU_LOCKER_TYPE_MASK 0xff00 | ||
68 | #define MU_LOCKER_OPTION_MASK 0x00ff | ||
69 | #define MU_LOCKER_OPTIONS(f) ((f) & MU_LOCKER_OPTION_MASK) | ||
70 | |||
71 | #define MU_LOCKER_NULL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_NULL) | ||
72 | #define MU_LOCKER_DOTLOCK MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_DOTLOCK) | ||
73 | #define MU_LOCKER_EXTERNAL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_EXTERNAL) | ||
74 | #define MU_LOCKER_KERNEL MU_LOCKER_TYPE_TO_FLAG(MU_LOCKER_TYPE_KERNEL) | ||
75 | |||
76 | /* Options */ | ||
77 | |||
78 | #define MU_LOCKER_SIMPLE 0x0000 | ||
51 | /* Just try and dotlock the file, not the default because its usually | 79 | /* Just try and dotlock the file, not the default because its usually |
52 | better to retry. */ | 80 | better to retry. */ |
53 | #define MU_LOCKER_RETRY 0x01 | 81 | #define MU_LOCKER_RETRY 0x0001 |
54 | /* This requests that we loop retries times, sleeping retry_sleep | 82 | /* This requests that we loop retries times, sleeping retry_sleep |
55 | seconds in between trying to obtain the lock before failing with | 83 | seconds in between trying to obtain the lock before failing with |
56 | MU_LOCK_CONFLICT. */ | 84 | MU_LOCK_CONFLICT. */ |
57 | #define MU_LOCKER_TIME 0x02 | 85 | #define MU_LOCKER_TIME 0x0002 |
58 | /* This mode checks the last update time of the lock, then removes | 86 | /* This mode checks the last update time of the lock, then removes |
59 | it if older than MU_LOCKER_EXPIRE_TIME. If a client uses this, | 87 | it if older than MU_LOCKER_EXPIRE_TIME. If a client uses this, |
60 | then the servers better periodically update the lock on the | 88 | then the servers better periodically update the lock on the |
61 | file... do they? */ | 89 | file... do they? */ |
62 | #define MU_LOCKER_PID 0x04 | 90 | #define MU_LOCKER_PID 0x0004 |
63 | /* PID locking is only useful for programs that aren't using | 91 | /* PID locking is only useful for programs that aren't using |
64 | an external dotlocker, non-setgid programs will use a dotlocker, | 92 | an external dotlocker, non-setgid programs will use a dotlocker, |
65 | which locks and exits imediately. This is a protection against | 93 | which locks and exits imediately. This is a protection against |
66 | a server crashing, it's not generally useful. */ | 94 | a server crashing, it's not generally useful. */ |
67 | #define MU_LOCKER_EXTERNAL 0x08 | ||
68 | /* Use an external program to lock the file. This is necessary | ||
69 | for programs having permission to access a file, but do not | ||
70 | have write permission on the directory that contains that file. */ | ||
71 | #define MU_LOCKER_NULL 0x10 | ||
72 | /* Special locker type: means no lock. This is to be used with | ||
73 | temporary mailboxes stored in memory. */ | ||
74 | #define MU_LOCKER_KERNEL 0x20 | ||
75 | /* Use kernel locking (flock, lockf or ioctl) */ | ||
76 | 95 | ||
77 | #define MU_LOCKER_DEFAULT (MU_LOCKER_RETRY) | 96 | #define MU_LOCKER_DEFAULT (MU_LOCKER_DOTLOCK | MU_LOCKER_RETRY) |
78 | 97 | ||
79 | /* Use these flags for as the default locker flags (the default defaults | 98 | /* Use these flags for as the default locker flags (the default defaults |
80 | * to MU_LOCKER_DEFAULT). A flags of 0 resets the flags back to the | 99 | * to MU_LOCKER_DEFAULT). A flags of 0 resets the flags back to the |
... | @@ -104,6 +123,14 @@ extern int mu_locker_get_retries (mu_locker_t, int*); | ... | @@ -104,6 +123,14 @@ extern int mu_locker_get_retries (mu_locker_t, int*); |
104 | extern int mu_locker_get_retry_sleep (mu_locker_t, int*); | 123 | extern int mu_locker_get_retry_sleep (mu_locker_t, int*); |
105 | extern int mu_locker_get_external (mu_locker_t, char**); | 124 | extern int mu_locker_get_external (mu_locker_t, char**); |
106 | 125 | ||
126 | enum mu_locker_mode | ||
127 | { | ||
128 | mu_lck_shr, /* Shared (advisory) lock */ | ||
129 | mu_lck_exc, /* Exclusive lock */ | ||
130 | mu_lck_opt /* Optional lock = shared, if the locker supports it, no | ||
131 | locking otherwise */ | ||
132 | }; | ||
133 | |||
107 | extern int mu_locker_lock (mu_locker_t); | 134 | extern int mu_locker_lock (mu_locker_t); |
108 | extern int mu_locker_touchlock (mu_locker_t); | 135 | extern int mu_locker_touchlock (mu_locker_t); |
109 | extern int mu_locker_unlock (mu_locker_t); | 136 | extern int mu_locker_unlock (mu_locker_t); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2000, 2001, 2005, 2006 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2000, 2001, 2005, 2006, |
3 | 2007 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
... | @@ -49,7 +50,8 @@ | ... | @@ -49,7 +50,8 @@ |
49 | 50 | ||
50 | struct _mu_locker | 51 | struct _mu_locker |
51 | { | 52 | { |
52 | int refcnt; | 53 | unsigned refcnt; /* Number of times mu_locker_lock was called */ |
54 | enum mu_locker_mode mode; /* Current locking mode (if refcnt > 0) */ | ||
53 | 55 | ||
54 | char *file; | 56 | char *file; |
55 | int flags; | 57 | int flags; |
... | @@ -73,20 +75,121 @@ struct _mu_locker | ... | @@ -73,20 +75,121 @@ struct _mu_locker |
73 | } data; | 75 | } data; |
74 | }; | 76 | }; |
75 | 77 | ||
76 | /* Assert that we're managing the refcnt and fd correctly, either | 78 | #define MU_LOCKER_TYPE(l) MU_LOCKER_FLAG_TO_TYPE((l)->flags) |
77 | * we have a lock, and the fd is valid, or refcnt is 0 and fd is -1. | 79 | |
78 | * And refcnt can never be less than 0. | 80 | struct locker_tab |
79 | */ | 81 | { |
80 | #define INVARIANT(l) assert((l)->refcnt >= 0); | 82 | int (*init) (mu_locker_t); |
81 | 83 | void (*destroy) (mu_locker_t); | |
82 | static void expire_stale_lock (mu_locker_t lock); | 84 | int (*prelock) (mu_locker_t); |
83 | static int stat_check (const char *file, int fd, int links); | 85 | int (*lock) (mu_locker_t, enum mu_locker_mode); |
84 | static int check_file_permissions (const char *file); | 86 | int (*unlock) (mu_locker_t); |
85 | static int lock_external (mu_locker_t l, int lock); | 87 | }; |
86 | static int _locker_lock_dotlock (mu_locker_t lock); | 88 | |
87 | static int _locker_unlock_dotlock (mu_locker_t lock); | 89 | static int init_dotlock (mu_locker_t); |
88 | static int _locker_lock_kernel (mu_locker_t lock); | 90 | static void destroy_dotlock (mu_locker_t); |
89 | static int _locker_unlock_kernel (mu_locker_t lock); | 91 | static int lock_dotlock (mu_locker_t, enum mu_locker_mode); |
92 | static int unlock_dotlock (mu_locker_t); | ||
93 | |||
94 | static int init_external (mu_locker_t); | ||
95 | static void destroy_external (mu_locker_t); | ||
96 | static int lock_external (mu_locker_t, enum mu_locker_mode); | ||
97 | static int unlock_external (mu_locker_t); | ||
98 | |||
99 | static int init_kernel (mu_locker_t); | ||
100 | static int lock_kernel (mu_locker_t, enum mu_locker_mode); | ||
101 | static int unlock_kernel (mu_locker_t); | ||
102 | |||
103 | static int prelock_common (mu_locker_t); | ||
104 | |||
105 | static struct locker_tab locker_tab[] = { | ||
106 | { init_dotlock, destroy_dotlock, prelock_common, | ||
107 | lock_dotlock, unlock_dotlock }, | ||
108 | { init_external, destroy_external, prelock_common, | ||
109 | lock_external, unlock_external }, | ||
110 | { init_kernel, NULL, NULL, lock_kernel, unlock_kernel }, | ||
111 | { NULL, NULL, NULL, NULL, NULL } | ||
112 | }; | ||
113 | |||
114 | #define MU_LOCKER_NTYPES (sizeof (locker_tab) / sizeof (locker_tab[0])) | ||
115 | |||
116 | |||
117 | static int | ||
118 | stat_check (const char *file, int fd, int links) | ||
119 | { | ||
120 | struct stat fn_stat; | ||
121 | struct stat fd_stat; | ||
122 | int err = 0; | ||
123 | int localfd = -1; | ||
124 | |||
125 | if (fd == -1) | ||
126 | { | ||
127 | localfd = open (file, O_RDONLY); | ||
128 | |||
129 | if (localfd == -1) | ||
130 | return errno; | ||
131 | fd = localfd; | ||
132 | } | ||
133 | |||
134 | /* We should always be able to stat a valid fd, so this | ||
135 | is an error condition. */ | ||
136 | if (lstat (file, &fn_stat) || fstat (fd, &fd_stat)) | ||
137 | err = errno; | ||
138 | else | ||
139 | { | ||
140 | /* If the link and stat don't report the same info, or the | ||
141 | file is a symlink, fail the locking. */ | ||
142 | #define CHK(X) if(X) err = EINVAL | ||
143 | |||
144 | CHK (!S_ISREG (fn_stat.st_mode)); | ||
145 | CHK (!S_ISREG (fd_stat.st_mode)); | ||
146 | CHK (fn_stat.st_nlink != links); | ||
147 | CHK (fn_stat.st_dev != fd_stat.st_dev); | ||
148 | CHK (fn_stat.st_ino != fd_stat.st_ino); | ||
149 | CHK (fn_stat.st_mode != fd_stat.st_mode); | ||
150 | CHK (fn_stat.st_nlink != fd_stat.st_nlink); | ||
151 | CHK (fn_stat.st_uid != fd_stat.st_uid); | ||
152 | CHK (fn_stat.st_gid != fd_stat.st_gid); | ||
153 | CHK (fn_stat.st_rdev != fd_stat.st_rdev); | ||
154 | |||
155 | #undef CHK | ||
156 | } | ||
157 | if (localfd != -1) | ||
158 | close (localfd); | ||
159 | |||
160 | return err; | ||
161 | } | ||
162 | |||
163 | static int | ||
164 | check_file_permissions (const char *file) | ||
165 | { | ||
166 | int fd = -1; | ||
167 | int err = 0; | ||
168 | |||
169 | if ((fd = open (file, O_RDONLY)) == -1) | ||
170 | return errno == ENOENT ? 0 : errno; | ||
171 | |||
172 | err = stat_check (file, fd, 1); | ||
173 | close (fd); | ||
174 | fd = -1; | ||
175 | if (err) | ||
176 | { | ||
177 | if (err == EINVAL) | ||
178 | err = MU_ERR_LOCK_BAD_FILE; | ||
179 | return err; | ||
180 | } | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int | ||
186 | prelock_common (mu_locker_t locker) | ||
187 | { | ||
188 | /* Check if we are trying to lock a regular file, with a link count | ||
189 | of 1, that we have permission to read, etc., or don't lock it. */ | ||
190 | return check_file_permissions (locker->file); | ||
191 | } | ||
192 | |||
90 | 193 | ||
91 | static int mu_locker_default_flags = MU_LOCKER_DEFAULT; | 194 | static int mu_locker_default_flags = MU_LOCKER_DEFAULT; |
92 | static time_t mu_locker_retry_timeout = MU_LOCKER_RETRY_SLEEP; | 195 | static time_t mu_locker_retry_timeout = MU_LOCKER_RETRY_SLEEP; |
... | @@ -143,115 +246,36 @@ mu_locker_set_default_external_program (char *path) | ... | @@ -143,115 +246,36 @@ mu_locker_set_default_external_program (char *path) |
143 | } | 246 | } |
144 | 247 | ||
145 | int | 248 | int |
146 | mu_locker_create (mu_locker_t *plocker, const char *filename_, int flags) | 249 | mu_locker_set_flags (mu_locker_t locker, int flags) |
147 | { | 250 | { |
148 | mu_locker_t l; | 251 | unsigned otype, ntype; |
149 | char filename[_POSIX_PATH_MAX]; | ||
150 | int err = 0; | ||
151 | 252 | ||
152 | if (plocker == NULL) | 253 | if (!locker) |
153 | return MU_ERR_OUT_PTR_NULL; | 254 | return MU_ERR_LOCKER_NULL; |
154 | 255 | ||
155 | if (filename_ == NULL) | 256 | otype = MU_LOCKER_TYPE (locker); |
257 | if (otype >= MU_LOCKER_NTYPES) | ||
258 | return EINVAL; | ||
259 | ntype = MU_LOCKER_FLAG_TO_TYPE (flags); | ||
260 | if (ntype >= MU_LOCKER_NTYPES) | ||
156 | return EINVAL; | 261 | return EINVAL; |
157 | 262 | ||
158 | if((err = mu_unroll_symlink(filename, sizeof(filename), filename_))) | 263 | if (ntype != otype) |
159 | return err; | ||
160 | |||
161 | l = calloc (1, sizeof (*l)); | ||
162 | |||
163 | if (l == NULL) | ||
164 | return ENOMEM; | ||
165 | |||
166 | l->file = strdup(filename); | ||
167 | |||
168 | if (l->file == NULL) | ||
169 | { | ||
170 | free (l); | ||
171 | return ENOMEM; | ||
172 | } | ||
173 | |||
174 | if (strcmp (filename, "/dev/null") == 0) | ||
175 | l->flags = MU_LOCKER_NULL; | ||
176 | else if (flags) | ||
177 | l->flags = flags; | ||
178 | else | ||
179 | l->flags = mu_locker_default_flags; | ||
180 | |||
181 | l->expire_time = mu_locker_expire_timeout; | ||
182 | l->retries = mu_locker_retry_count; | ||
183 | l->retry_sleep = mu_locker_retry_timeout; | ||
184 | |||
185 | /* Initialize locker-type-specific data */ | ||
186 | if (l->flags & MU_LOCKER_EXTERNAL) | ||
187 | { | ||
188 | if (!(l->data.external.name = strdup (mu_locker_external_program ? | ||
189 | mu_locker_external_program : | ||
190 | MU_LOCKER_EXTERNAL_PROGRAM))) | ||
191 | { | 264 | { |
192 | mu_locker_destroy (&l); | 265 | int rc; |
193 | return ENOMEM; | ||
194 | } | ||
195 | } | ||
196 | else if (!(l->flags & MU_LOCKER_KERNEL)) | ||
197 | { | ||
198 | l->data.dot.dotlock = malloc (strlen (l->file) | ||
199 | + 5 /*strlen(".lock")*/ + 1); | ||
200 | 266 | ||
201 | if (!l->data.dot.dotlock) | 267 | if (locker_tab[otype].destroy) |
268 | locker_tab[otype].destroy (locker); | ||
269 | locker->flags = flags; | ||
270 | if (locker_tab[otype].init) | ||
202 | { | 271 | { |
203 | free (l->file); | 272 | rc = locker_tab[otype].init (locker); |
204 | free (l); | 273 | if (rc) |
205 | return ENOMEM; | 274 | locker->flags = MU_LOCKER_NULL; |
275 | return rc; | ||
206 | } | 276 | } |
207 | |||
208 | sprintf (l->data.dot.dotlock, "%s.lock", l->file); | ||
209 | } | 277 | } |
210 | |||
211 | INVARIANT(l); | ||
212 | |||
213 | *plocker = l; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | void | ||
219 | _locker_destroy_private (mu_locker_t locker) | ||
220 | { | ||
221 | if (locker) | ||
222 | { | ||
223 | if (locker->flags & MU_LOCKER_EXTERNAL) | ||
224 | free (locker->data.external.name); | ||
225 | else if (locker->flags & MU_LOCKER_KERNEL) | ||
226 | /* nothing */; | ||
227 | else | 278 | else |
228 | { | ||
229 | free (locker->data.dot.dotlock); | ||
230 | locker->data.dot.dotlock = NULL; | ||
231 | free (locker->data.dot.nfslock); | ||
232 | locker->data.dot.nfslock = NULL; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | void | ||
238 | mu_locker_destroy (mu_locker_t *plocker) | ||
239 | { | ||
240 | if (plocker && *plocker) | ||
241 | { | ||
242 | _locker_destroy_private (*plocker); | ||
243 | free ((*plocker)->file); | ||
244 | free (*plocker); | ||
245 | *plocker = NULL; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | int | ||
250 | mu_locker_set_flags (mu_locker_t locker, int flags) | ||
251 | { | ||
252 | if (!locker) | ||
253 | return MU_ERR_LOCKER_NULL; | ||
254 | |||
255 | locker->flags = flags; | 279 | locker->flags = flags; |
256 | 280 | ||
257 | return 0; | 281 | return 0; |
... | @@ -306,7 +330,7 @@ mu_locker_set_external (mu_locker_t locker, const char* program) | ... | @@ -306,7 +330,7 @@ mu_locker_set_external (mu_locker_t locker, const char* program) |
306 | 330 | ||
307 | if (!locker) | 331 | if (!locker) |
308 | return MU_ERR_LOCKER_NULL; | 332 | return MU_ERR_LOCKER_NULL; |
309 | if (!(locker->flags & MU_LOCKER_EXTERNAL)) | 333 | if (MU_LOCKER_TYPE (locker) != MU_LOCKER_TYPE_EXTERNAL) |
310 | return EINVAL; | 334 | return EINVAL; |
311 | 335 | ||
312 | /* program can be NULL */ | 336 | /* program can be NULL */ |
... | @@ -329,7 +353,7 @@ mu_locker_get_flags (mu_locker_t locker, int *flags) | ... | @@ -329,7 +353,7 @@ mu_locker_get_flags (mu_locker_t locker, int *flags) |
329 | if (!locker) | 353 | if (!locker) |
330 | return MU_ERR_LOCKER_NULL; | 354 | return MU_ERR_LOCKER_NULL; |
331 | 355 | ||
332 | if(!flags) | 356 | if (!flags) |
333 | return EINVAL; | 357 | return EINVAL; |
334 | 358 | ||
335 | *flags = locker->flags; | 359 | *flags = locker->flags; |
... | @@ -380,144 +404,162 @@ mu_locker_get_retry_sleep (mu_locker_t locker, int *retry_sleep) | ... | @@ -380,144 +404,162 @@ mu_locker_get_retry_sleep (mu_locker_t locker, int *retry_sleep) |
380 | } | 404 | } |
381 | 405 | ||
382 | int | 406 | int |
383 | mu_locker_lock (mu_locker_t lock) | 407 | mu_locker_create (mu_locker_t *plocker, const char *fname, int flags) |
384 | { | 408 | { |
385 | int rc; | 409 | unsigned type; |
386 | int retries = 1; | 410 | mu_locker_t l; |
411 | char filename[_POSIX_PATH_MAX]; | ||
412 | int err = 0; | ||
387 | 413 | ||
388 | if (lock == NULL) | 414 | if (plocker == NULL) |
415 | return MU_ERR_OUT_PTR_NULL; | ||
416 | |||
417 | if (fname == NULL) | ||
389 | return EINVAL; | 418 | return EINVAL; |
390 | 419 | ||
391 | if (lock->flags == MU_LOCKER_NULL) | 420 | if ((err = mu_unroll_symlink (filename, sizeof (filename), fname))) |
392 | return 0; | 421 | return err; |
393 | 422 | ||
394 | INVARIANT (lock) | 423 | l = calloc (1, sizeof (*l)); |
395 | /* Is the lock already applied? */ | 424 | |
396 | if (lock->refcnt > 0) | 425 | if (l == NULL) |
426 | return ENOMEM; | ||
427 | |||
428 | l->file = strdup (filename); | ||
429 | |||
430 | if (l->file == NULL) | ||
397 | { | 431 | { |
398 | lock->refcnt++; | 432 | free (l); |
399 | return 0; | 433 | return ENOMEM; |
400 | } | 434 | } |
401 | 435 | ||
402 | if (access (lock->file, W_OK)) | 436 | if (strcmp (filename, "/dev/null") == 0) |
437 | l->flags = MU_LOCKER_NULL; | ||
438 | else if (flags) | ||
439 | l->flags = flags; | ||
440 | else | ||
441 | l->flags = mu_locker_default_flags; | ||
442 | |||
443 | l->expire_time = mu_locker_expire_timeout; | ||
444 | l->retries = mu_locker_retry_count; | ||
445 | l->retry_sleep = mu_locker_retry_timeout; | ||
446 | |||
447 | type = MU_LOCKER_TYPE (l); | ||
448 | |||
449 | if (type >= MU_LOCKER_NTYPES) | ||
403 | { | 450 | { |
404 | /* There is no use trying to lock the file if we are not | 451 | free (l->file); |
405 | allowed to write to it */ | 452 | return EINVAL; |
406 | _locker_destroy_private (lock); | ||
407 | lock->flags |= MU_LOCKER_NULL; | ||
408 | return 0; | ||
409 | } | 453 | } |
410 | 454 | ||
411 | /* Check we are trying to lock a regular file, with a link count | 455 | /* Initialize locker-type-specific data */ |
412 | of 1, that we have permission to read, etc., or don't lock it. */ | 456 | err = locker_tab[type].init ? locker_tab[type].init (l) : 0; |
413 | if ((rc = check_file_permissions(lock->file))) | 457 | if (err) |
414 | return rc; | ||
415 | |||
416 | /* Do the lock with an external program, if requested. */ | ||
417 | if (lock->flags & MU_LOCKER_EXTERNAL) | ||
418 | return lock_external (lock, 1); | ||
419 | else if (!(lock->flags & MU_LOCKER_KERNEL)) | ||
420 | { | 458 | { |
421 | char *tmp, *p; | 459 | mu_locker_destroy (&l); |
460 | return err; | ||
461 | } | ||
422 | 462 | ||
423 | tmp = strdup (lock->file); | 463 | *plocker = l; |
424 | if (!tmp) | ||
425 | return ENOMEM; | ||
426 | 464 | ||
427 | strcpy (tmp, lock->file); | 465 | return 0; |
428 | p = strrchr (tmp, '/'); | 466 | } |
429 | if (!p) | 467 | |
468 | void | ||
469 | mu_locker_destroy (mu_locker_t *plocker) | ||
470 | { | ||
471 | if (plocker && *plocker) | ||
430 | { | 472 | { |
431 | free (tmp); | 473 | unsigned type = MU_LOCKER_TYPE (*plocker); |
432 | tmp = strdup ("."); | 474 | if (type < MU_LOCKER_NTYPES) |
433 | if (!tmp) | 475 | { |
434 | return ENOMEM; | 476 | if (locker_tab[type].destroy) |
477 | locker_tab[type].destroy (*plocker); | ||
478 | free ((*plocker)->file); | ||
479 | free (*plocker); | ||
480 | *plocker = NULL; | ||
435 | } | 481 | } |
436 | else | 482 | } |
437 | *p = 0; | 483 | } |
438 | 484 | ||
439 | if (access (tmp, W_OK)) | 485 | int |
486 | _mu_locker_lock (mu_locker_t lock, enum mu_locker_mode mode) | ||
487 | { | ||
488 | int rc; | ||
489 | unsigned type; | ||
490 | unsigned retries = 1; | ||
491 | |||
492 | if (lock == NULL || (type = MU_LOCKER_TYPE (lock)) >= MU_LOCKER_NTYPES) | ||
493 | return EINVAL; | ||
494 | |||
495 | if (locker_tab[type].prelock && (rc = locker_tab[type].prelock (lock))) | ||
496 | return rc; | ||
497 | |||
498 | /* Is the lock already applied? */ | ||
499 | if (lock->refcnt > 0) | ||
440 | { | 500 | { |
441 | /* Fallback to kernel locking */ | 501 | lock->refcnt++; |
442 | _locker_destroy_private (lock); | 502 | if (mode == lock->mode) |
443 | lock->flags |= MU_LOCKER_KERNEL; | 503 | return 0; |
444 | } | ||
445 | free (tmp); | ||
446 | } | 504 | } |
447 | 505 | ||
506 | lock->mode = mode; | ||
507 | |||
448 | if (lock->flags & MU_LOCKER_RETRY) | 508 | if (lock->flags & MU_LOCKER_RETRY) |
449 | { | ||
450 | retries = lock->retries; | 509 | retries = lock->retries; |
451 | } | ||
452 | 510 | ||
511 | if (locker_tab[type].lock) | ||
512 | { | ||
453 | while (retries--) | 513 | while (retries--) |
454 | { | 514 | { |
455 | if (lock->flags & MU_LOCKER_KERNEL) | 515 | rc = locker_tab[type].lock (lock, mode); |
456 | rc = _locker_lock_kernel (lock); | ||
457 | else | ||
458 | rc = _locker_lock_dotlock (lock); | ||
459 | if (rc == EAGAIN && retries) | 516 | if (rc == EAGAIN && retries) |
517 | { | ||
460 | sleep (lock->retry_sleep); | 518 | sleep (lock->retry_sleep); |
461 | else if (rc) | 519 | continue; |
462 | return rc; | ||
463 | else /* rc == 0 */ | ||
464 | break; | ||
465 | } | 520 | } |
466 | 521 | ||
467 | lock->refcnt = 1; | 522 | if (rc == 0) |
523 | lock->refcnt++; | ||
468 | 524 | ||
469 | return 0; | 525 | break; |
526 | } | ||
527 | } | ||
528 | else | ||
529 | rc = 0; | ||
530 | |||
531 | return rc; | ||
470 | } | 532 | } |
471 | 533 | ||
472 | int | 534 | int |
473 | mu_locker_touchlock (mu_locker_t lock) | 535 | mu_locker_lock (mu_locker_t lock) |
474 | { | 536 | { |
475 | if (!lock) | 537 | return _mu_locker_lock (lock, mu_lck_exc); |
476 | return MU_ERR_LOCKER_NULL; | ||
477 | |||
478 | if (lock->flags == MU_LOCKER_NULL) | ||
479 | return 0; | ||
480 | |||
481 | if (lock->refcnt > 0) | ||
482 | return utime (lock->data.dot.dotlock, NULL); | ||
483 | |||
484 | return MU_ERR_LOCK_NOT_HELD; | ||
485 | } | 538 | } |
486 | 539 | ||
487 | int | 540 | int |
488 | mu_locker_unlock (mu_locker_t lock) | 541 | mu_locker_unlock (mu_locker_t lock) |
489 | { | 542 | { |
490 | int rc = 0; | 543 | int rc = 0; |
544 | unsigned type; | ||
491 | 545 | ||
492 | if (!lock) | 546 | if (!lock) |
493 | return MU_ERR_LOCKER_NULL; | 547 | return MU_ERR_LOCKER_NULL; |
494 | 548 | ||
495 | if (lock->flags == MU_LOCKER_NULL) | ||
496 | return 0; | ||
497 | |||
498 | if (lock->refcnt == 0) | 549 | if (lock->refcnt == 0) |
499 | return MU_ERR_LOCK_NOT_HELD; | 550 | return MU_ERR_LOCK_NOT_HELD; |
500 | 551 | ||
501 | /* Do the lock with an external program, if requested. */ | ||
502 | if (lock->flags & MU_LOCKER_EXTERNAL) | ||
503 | return lock_external (lock, 0); | ||
504 | |||
505 | if (lock->refcnt > 1) | ||
506 | { | ||
507 | lock->refcnt--; | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | if ((rc = check_file_permissions (lock->file))) | 552 | if ((rc = check_file_permissions (lock->file))) |
512 | return rc; | 553 | return rc; |
513 | 554 | ||
514 | if (lock->flags & MU_LOCKER_KERNEL) | 555 | if (--lock->refcnt > 0) |
515 | rc = _locker_unlock_kernel (lock); | 556 | return 0; |
516 | else | ||
517 | rc = _locker_unlock_dotlock (lock); | ||
518 | 557 | ||
519 | if (rc == 0) | 558 | type = MU_LOCKER_TYPE (lock); |
520 | lock->refcnt = 0; | 559 | if (locker_tab[type].unlock) |
560 | rc = locker_tab[type].unlock (lock); | ||
561 | else | ||
562 | rc = 0; | ||
521 | 563 | ||
522 | return rc; | 564 | return rc; |
523 | } | 565 | } |
... | @@ -525,21 +567,17 @@ mu_locker_unlock (mu_locker_t lock) | ... | @@ -525,21 +567,17 @@ mu_locker_unlock (mu_locker_t lock) |
525 | int | 567 | int |
526 | mu_locker_remove_lock (mu_locker_t lock) | 568 | mu_locker_remove_lock (mu_locker_t lock) |
527 | { | 569 | { |
528 | int err; | ||
529 | |||
530 | if (!lock) | 570 | if (!lock) |
531 | return MU_ERR_LOCKER_NULL; | 571 | return MU_ERR_LOCKER_NULL; |
532 | 572 | ||
533 | if (lock->flags == MU_LOCKER_NULL) | ||
534 | return 0; | ||
535 | |||
536 | /* Force the reference count to 1 to unlock the file. */ | 573 | /* Force the reference count to 1 to unlock the file. */ |
537 | lock->refcnt = 1; | 574 | lock->refcnt = 1; |
538 | err = mu_locker_unlock (lock); | 575 | return mu_locker_unlock (lock); |
539 | |||
540 | return err; | ||
541 | } | 576 | } |
542 | 577 | ||
578 | |||
579 | #define DOTLOCK_SUFFIX ".lock" | ||
580 | |||
543 | /* expire a stale lock (if MU_LOCKER_PID or MU_LOCKER_TIME) */ | 581 | /* expire a stale lock (if MU_LOCKER_PID or MU_LOCKER_TIME) */ |
544 | static void | 582 | static void |
545 | expire_stale_lock (mu_locker_t lock) | 583 | expire_stale_lock (mu_locker_t lock) |
... | @@ -587,80 +625,60 @@ expire_stale_lock (mu_locker_t lock) | ... | @@ -587,80 +625,60 @@ expire_stale_lock (mu_locker_t lock) |
587 | } | 625 | } |
588 | 626 | ||
589 | static int | 627 | static int |
590 | stat_check (const char *file, int fd, int links) | 628 | init_dotlock (mu_locker_t locker) |
591 | { | 629 | { |
592 | struct stat fn_stat; | 630 | char *tmp, *p; |
593 | struct stat fd_stat; | ||
594 | int err = 0; | ||
595 | int localfd = -1; | ||
596 | 631 | ||
597 | if (fd == -1) | 632 | /* Make sure the spool directory is writable */ |
598 | { | 633 | tmp = strdup (locker->file); |
599 | localfd = open(file, O_RDONLY); | 634 | if (!tmp) |
635 | return ENOMEM; | ||
600 | 636 | ||
601 | if (localfd == -1) | 637 | strcpy (tmp, locker->file); |
602 | return errno; | 638 | p = strrchr (tmp, '/'); |
603 | fd = localfd; | 639 | if (!p) |
640 | { | ||
641 | free (tmp); | ||
642 | tmp = strdup ("."); | ||
643 | if (!tmp) | ||
644 | return ENOMEM; | ||
604 | } | 645 | } |
605 | |||
606 | /* We should always be able to stat a valid fd, so this | ||
607 | is an error condition. */ | ||
608 | if (lstat (file, &fn_stat) || fstat (fd, &fd_stat)) | ||
609 | err = errno; | ||
610 | else | 646 | else |
611 | { | 647 | *p = 0; |
612 | /* If the link and stat don't report the same info, or the | ||
613 | file is a symlink, fail the locking. */ | ||
614 | #define CHK(X) if(X) err = EINVAL | ||
615 | |||
616 | CHK (!S_ISREG (fn_stat.st_mode)); | ||
617 | CHK (!S_ISREG (fd_stat.st_mode)); | ||
618 | CHK (fn_stat.st_nlink != links); | ||
619 | CHK (fn_stat.st_dev != fd_stat.st_dev); | ||
620 | CHK (fn_stat.st_ino != fd_stat.st_ino); | ||
621 | CHK (fn_stat.st_mode != fd_stat.st_mode); | ||
622 | CHK (fn_stat.st_nlink != fd_stat.st_nlink); | ||
623 | CHK (fn_stat.st_uid != fd_stat.st_uid); | ||
624 | CHK (fn_stat.st_gid != fd_stat.st_gid); | ||
625 | CHK (fn_stat.st_rdev != fd_stat.st_rdev); | ||
626 | 648 | ||
627 | #undef CHK | 649 | if (access (tmp, W_OK)) |
650 | { | ||
651 | /* Fallback to kernel locking */ | ||
652 | free (tmp); | ||
653 | return mu_locker_set_flags (locker, | ||
654 | MU_LOCKER_KERNEL|MU_LOCKER_OPTIONS(locker->flags)); | ||
628 | } | 655 | } |
629 | if (localfd != -1) | ||
630 | close (localfd); | ||
631 | 656 | ||
632 | return err; | 657 | free (tmp); |
633 | } | ||
634 | |||
635 | static int | ||
636 | check_file_permissions (const char *file) | ||
637 | { | ||
638 | int fd = -1; | ||
639 | int err = 0; | ||
640 | 658 | ||
641 | if ((fd = open (file, O_RDONLY)) == -1) | 659 | locker->data.dot.dotlock = malloc (strlen (locker->file) |
642 | return errno == ENOENT ? 0 : errno; | 660 | + sizeof (DOTLOCK_SUFFIX)); |
643 | 661 | ||
644 | err = stat_check (file, fd, 1); | 662 | if (!locker->data.dot.dotlock) |
645 | close (fd); | 663 | return ENOMEM; |
646 | fd = -1; | 664 | strcpy (locker->data.dot.dotlock, locker->file); |
647 | if (err) | 665 | strcat (locker->data.dot.dotlock, DOTLOCK_SUFFIX); |
648 | { | ||
649 | if (err == EINVAL) | ||
650 | err = MU_ERR_LOCK_BAD_FILE; | ||
651 | return err; | ||
652 | } | ||
653 | 666 | ||
654 | return 0; | 667 | return 0; |
655 | } | 668 | } |
656 | 669 | ||
670 | static void | ||
671 | destroy_dotlock (mu_locker_t locker) | ||
672 | { | ||
673 | free (locker->data.dot.dotlock); | ||
674 | } | ||
675 | |||
657 | #ifndef MAXHOSTNAMELEN | 676 | #ifndef MAXHOSTNAMELEN |
658 | # define MAXHOSTNAMELEN 256 | 677 | # define MAXHOSTNAMELEN 256 |
659 | #endif | 678 | #endif |
660 | 679 | ||
661 | /* Locker-specific lock/unlock functions */ | 680 | static int |
662 | int | 681 | lock_dotlock (mu_locker_t locker, enum mu_locker_mode mode) |
663 | _locker_lock_dotlock (mu_locker_t lock) | ||
664 | { | 682 | { |
665 | char host[MAXHOSTNAMELEN + 1] = "localhost"; | 683 | char host[MAXHOSTNAMELEN + 1] = "localhost"; |
666 | char pid[11]; /* 10 is strlen(2^32 = 4294967296) */ | 684 | char pid[11]; /* 10 is strlen(2^32 = 4294967296) */ |
... | @@ -669,14 +687,14 @@ _locker_lock_dotlock (mu_locker_t lock) | ... | @@ -669,14 +687,14 @@ _locker_lock_dotlock (mu_locker_t lock) |
669 | int err = 0; | 687 | int err = 0; |
670 | int fd; | 688 | int fd; |
671 | 689 | ||
672 | if (lock->data.dot.nfslock) | 690 | if (locker->data.dot.nfslock) |
673 | { | 691 | { |
674 | unlink (lock->data.dot.nfslock); | 692 | unlink (locker->data.dot.nfslock); |
675 | free (lock->data.dot.nfslock); | 693 | free (locker->data.dot.nfslock); |
676 | lock->data.dot.nfslock = 0; | 694 | locker->data.dot.nfslock = 0; |
677 | } | 695 | } |
678 | 696 | ||
679 | expire_stale_lock (lock); | 697 | expire_stale_lock (locker); |
680 | 698 | ||
681 | /* build the NFS hitching-post to the lock file */ | 699 | /* build the NFS hitching-post to the lock file */ |
682 | 700 | ||
... | @@ -689,20 +707,20 @@ _locker_lock_dotlock (mu_locker_t lock) | ... | @@ -689,20 +707,20 @@ _locker_lock_dotlock (mu_locker_t lock) |
689 | snprintf (pid, sizeof (pid), "%lu", (unsigned long) getpid ()); | 707 | snprintf (pid, sizeof (pid), "%lu", (unsigned long) getpid ()); |
690 | pid[sizeof (pid) - 1] = 0; | 708 | pid[sizeof (pid) - 1] = 0; |
691 | 709 | ||
692 | sz = strlen (lock->file) + 1 /* "." */ | 710 | sz = strlen (locker->file) + 1 /* "." */ |
693 | + strlen (pid) + 1 /* "." */ | 711 | + strlen (pid) + 1 /* "." */ |
694 | + strlen (now) + 1 /* "." */ | 712 | + strlen (now) + 1 /* "." */ |
695 | + strlen (host) + 1; | 713 | + strlen (host) + 1; |
696 | 714 | ||
697 | lock->data.dot.nfslock = malloc (sz); | 715 | locker->data.dot.nfslock = malloc (sz); |
698 | 716 | ||
699 | if (!lock->data.dot.nfslock) | 717 | if (!locker->data.dot.nfslock) |
700 | return ENOMEM; | 718 | return ENOMEM; |
701 | 719 | ||
702 | snprintf (lock->data.dot.nfslock, sz, "%s.%s.%s.%s", lock->file, pid, now, | 720 | snprintf (locker->data.dot.nfslock, sz, "%s.%s.%s.%s", |
703 | host); | 721 | locker->file, pid, now, host); |
704 | 722 | ||
705 | fd = open (lock->data.dot.nfslock, | 723 | fd = open (locker->data.dot.nfslock, |
706 | O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_ATTR); | 724 | O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_ATTR); |
707 | if (fd == -1) | 725 | if (fd == -1) |
708 | { | 726 | { |
... | @@ -714,53 +732,53 @@ _locker_lock_dotlock (mu_locker_t lock) | ... | @@ -714,53 +732,53 @@ _locker_lock_dotlock (mu_locker_t lock) |
714 | close (fd); | 732 | close (fd); |
715 | 733 | ||
716 | /* Try to link to the lockfile. */ | 734 | /* Try to link to the lockfile. */ |
717 | if (link (lock->data.dot.nfslock, lock->data.dot.dotlock) == -1) | 735 | if (link (locker->data.dot.nfslock, locker->data.dot.dotlock) == -1) |
718 | { | 736 | { |
719 | unlink (lock->data.dot.nfslock); | 737 | unlink (locker->data.dot.nfslock); |
720 | if (errno == EEXIST) | 738 | if (errno == EEXIST) |
721 | return MU_ERR_LOCK_CONFLICT; | 739 | return MU_ERR_LOCK_CONFLICT; |
722 | return errno; | 740 | return errno; |
723 | } | 741 | } |
724 | 742 | ||
725 | if ((fd = open (lock->data.dot.dotlock, O_RDWR)) == -1) | 743 | if ((fd = open (locker->data.dot.dotlock, O_RDWR)) == -1) |
726 | { | 744 | { |
727 | unlink (lock->data.dot.nfslock); | 745 | unlink (locker->data.dot.nfslock); |
728 | return errno; | 746 | return errno; |
729 | } | 747 | } |
730 | 748 | ||
731 | err = stat_check (lock->data.dot.nfslock, fd, 2); | 749 | err = stat_check (locker->data.dot.nfslock, fd, 2); |
732 | if (err) | 750 | if (err) |
733 | { | 751 | { |
734 | unlink (lock->data.dot.nfslock); | 752 | unlink (locker->data.dot.nfslock); |
735 | if (err == EINVAL) | 753 | if (err == EINVAL) |
736 | return MU_ERR_LOCK_BAD_LOCK; | 754 | return MU_ERR_LOCK_BAD_LOCK; |
737 | return errno; | 755 | return errno; |
738 | } | 756 | } |
739 | 757 | ||
740 | unlink (lock->data.dot.nfslock); | 758 | unlink (locker->data.dot.nfslock); |
741 | 759 | ||
742 | /* If no errors, we have the lock. */ | 760 | /* FIXME: If no errors, we have the lock. */ |
743 | assert (lock->refcnt == 0); | 761 | assert (locker->refcnt == 0); |
744 | 762 | ||
745 | if (lock->flags & MU_LOCKER_PID) | 763 | if (locker->flags & MU_LOCKER_PID) |
746 | { | 764 | { |
747 | char buf[16]; | 765 | char buf[16]; |
748 | sprintf (buf, "%ld", (long) getpid ()); | 766 | sprintf (buf, "%ld", (long) getpid ()); |
749 | write (fd, buf, strlen (buf)); | 767 | write (fd, buf, strlen (buf)); |
750 | } | 768 | } |
751 | close(fd); | 769 | close (fd); |
752 | return 0; | 770 | return 0; |
753 | } | 771 | } |
754 | 772 | ||
755 | int | 773 | static int |
756 | _locker_unlock_dotlock (mu_locker_t lock) | 774 | unlock_dotlock (mu_locker_t locker) |
757 | { | 775 | { |
758 | if (unlink (lock->data.dot.dotlock) == -1) | 776 | if (unlink (locker->data.dot.dotlock) == -1) |
759 | { | 777 | { |
760 | int err = errno; | 778 | int err = errno; |
761 | if (err == ENOENT) | 779 | if (err == ENOENT) |
762 | { | 780 | { |
763 | lock->refcnt = 0; | 781 | locker->refcnt = 0; /*FIXME?*/ |
764 | err = MU_ERR_LOCK_NOT_HELD; | 782 | err = MU_ERR_LOCK_NOT_HELD; |
765 | return err; | 783 | return err; |
766 | } | 784 | } |
... | @@ -770,16 +788,56 @@ _locker_unlock_dotlock (mu_locker_t lock) | ... | @@ -770,16 +788,56 @@ _locker_unlock_dotlock (mu_locker_t lock) |
770 | } | 788 | } |
771 | 789 | ||
772 | int | 790 | int |
773 | _locker_lock_kernel (mu_locker_t lock) | 791 | mu_locker_touchlock (mu_locker_t lock) |
792 | { | ||
793 | if (!lock) | ||
794 | return MU_ERR_LOCKER_NULL; | ||
795 | |||
796 | if (MU_LOCKER_TYPE (lock) != MU_LOCKER_TYPE_DOTLOCK) | ||
797 | return 0; | ||
798 | |||
799 | if (lock->refcnt > 0) | ||
800 | return utime (lock->data.dot.dotlock, NULL); | ||
801 | |||
802 | return MU_ERR_LOCK_NOT_HELD; | ||
803 | } | ||
804 | |||
805 | |||
806 | /* Kernel locking */ | ||
807 | static int | ||
808 | init_kernel (mu_locker_t locker) | ||
809 | { | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int | ||
814 | lock_kernel (mu_locker_t locker, enum mu_locker_mode mode) | ||
774 | { | 815 | { |
775 | int fd; | 816 | int fd; |
776 | struct flock fl; | 817 | struct flock fl; |
777 | 818 | ||
778 | fd = open (lock->file, O_RDWR); | 819 | switch (mode) |
820 | { | ||
821 | case mu_lck_shr: | ||
822 | case mu_lck_opt: | ||
823 | mode = O_RDONLY; | ||
824 | fl.l_type = F_RDLCK; | ||
825 | break; | ||
826 | |||
827 | case mu_lck_exc: | ||
828 | mode = O_RDWR; | ||
829 | fl.l_type = F_WRLCK; | ||
830 | break; | ||
831 | |||
832 | default: | ||
833 | return EINVAL; | ||
834 | } | ||
835 | |||
836 | fd = open (locker->file, O_RDWR); | ||
779 | if (fd == -1) | 837 | if (fd == -1) |
780 | return errno; | 838 | return errno; |
781 | lock->data.kernel.fd = fd; | 839 | locker->data.kernel.fd = fd; |
782 | fl.l_type = F_WRLCK; | 840 | |
783 | fl.l_whence = SEEK_SET; | 841 | fl.l_whence = SEEK_SET; |
784 | fl.l_start = 0; | 842 | fl.l_start = 0; |
785 | fl.l_len = 0; /* Lock entire file */ | 843 | fl.l_len = 0; /* Lock entire file */ |
... | @@ -796,8 +854,8 @@ _locker_lock_kernel (mu_locker_t lock) | ... | @@ -796,8 +854,8 @@ _locker_lock_kernel (mu_locker_t lock) |
796 | return 0; | 854 | return 0; |
797 | } | 855 | } |
798 | 856 | ||
799 | int | 857 | static int |
800 | _locker_unlock_kernel (mu_locker_t lock) | 858 | unlock_kernel (mu_locker_t locker) |
801 | { | 859 | { |
802 | struct flock fl; | 860 | struct flock fl; |
803 | 861 | ||
... | @@ -805,7 +863,7 @@ _locker_unlock_kernel (mu_locker_t lock) | ... | @@ -805,7 +863,7 @@ _locker_unlock_kernel (mu_locker_t lock) |
805 | fl.l_whence = SEEK_SET; | 863 | fl.l_whence = SEEK_SET; |
806 | fl.l_start = 0; | 864 | fl.l_start = 0; |
807 | fl.l_len = 0; /* Unlock entire file */ | 865 | fl.l_len = 0; /* Unlock entire file */ |
808 | if (fcntl (lock->data.kernel.fd, F_SETLK, &fl)) | 866 | if (fcntl (locker->data.kernel.fd, F_SETLK, &fl)) |
809 | { | 867 | { |
810 | #ifdef EACCESS | 868 | #ifdef EACCESS |
811 | if (errno == EACCESS) | 869 | if (errno == EACCESS) |
... | @@ -815,17 +873,33 @@ _locker_unlock_kernel (mu_locker_t lock) | ... | @@ -815,17 +873,33 @@ _locker_unlock_kernel (mu_locker_t lock) |
815 | return EAGAIN; | 873 | return EAGAIN; |
816 | return errno; | 874 | return errno; |
817 | } | 875 | } |
818 | close (lock->data.kernel.fd); | 876 | close (locker->data.kernel.fd); |
819 | return 0; | 877 | return 0; |
820 | } | 878 | } |
821 | 879 | ||
880 | static int | ||
881 | init_external (mu_locker_t locker) | ||
882 | { | ||
883 | if (!(locker->data.external.name = strdup (mu_locker_external_program ? | ||
884 | mu_locker_external_program : | ||
885 | MU_LOCKER_EXTERNAL_PROGRAM))) | ||
886 | return ENOMEM; | ||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static void | ||
891 | destroy_external (mu_locker_t locker) | ||
892 | { | ||
893 | free (locker->data.external.name); | ||
894 | } | ||
895 | |||
822 | /* | 896 | /* |
823 | Estimate 1 decimal digit per 3 bits, + 1 for round off. | 897 | Estimate 1 decimal digit per 3 bits, + 1 for round off. |
824 | */ | 898 | */ |
825 | #define DEC_DIGS_PER_INT (sizeof(int) * 8 / 3 + 1) | 899 | #define DEC_DIGS_PER_INT (sizeof(int) * 8 / 3 + 1) |
826 | 900 | ||
827 | static int | 901 | static int |
828 | lock_external (mu_locker_t l, int lock) | 902 | external_locker (mu_locker_t l, int lock) |
829 | { | 903 | { |
830 | int err = 0; | 904 | int err = 0; |
831 | char *av[6]; | 905 | char *av[6]; |
... | @@ -836,6 +910,7 @@ lock_external (mu_locker_t l, int lock) | ... | @@ -836,6 +910,7 @@ lock_external (mu_locker_t l, int lock) |
836 | 910 | ||
837 | assert (l); | 911 | assert (l); |
838 | assert (l->flags & MU_LOCKER_EXTERNAL); | 912 | assert (l->flags & MU_LOCKER_EXTERNAL); |
913 | /* FIXME */ | ||
839 | assert (lock == !l->refcnt); | 914 | assert (lock == !l->refcnt); |
840 | /* lock is true, refcnt is 0 or lock is false and refcnt is 1 */ | 915 | /* lock is true, refcnt is 0 or lock is false and refcnt is 1 */ |
841 | 916 | ||
... | @@ -856,10 +931,8 @@ lock_external (mu_locker_t l, int lock) | ... | @@ -856,10 +931,8 @@ lock_external (mu_locker_t l, int lock) |
856 | av[ac++] = aretry; | 931 | av[ac++] = aretry; |
857 | } | 932 | } |
858 | 933 | ||
859 | if (lock == 0) | 934 | if (!lock) |
860 | { | ||
861 | av[ac++] = "-u"; | 935 | av[ac++] = "-u"; |
862 | } | ||
863 | 936 | ||
864 | av[ac++] = l->file; | 937 | av[ac++] = l->file; |
865 | 938 | ||
... | @@ -879,19 +952,24 @@ lock_external (mu_locker_t l, int lock) | ... | @@ -879,19 +952,24 @@ lock_external (mu_locker_t l, int lock) |
879 | case 127: | 952 | case 127: |
880 | err = MU_ERR_LOCK_EXT_FAIL; | 953 | err = MU_ERR_LOCK_EXT_FAIL; |
881 | break; | 954 | break; |
955 | |||
882 | case MU_DL_EX_OK: | 956 | case MU_DL_EX_OK: |
883 | err = 0; | 957 | err = 0; |
884 | l->refcnt = lock; | 958 | l->refcnt = lock; |
885 | break; | 959 | break; |
960 | |||
886 | case MU_DL_EX_NEXIST: | 961 | case MU_DL_EX_NEXIST: |
887 | err = MU_ERR_LOCK_NOT_HELD; | 962 | err = MU_ERR_LOCK_NOT_HELD; |
888 | break; | 963 | break; |
964 | |||
889 | case MU_DL_EX_EXIST: | 965 | case MU_DL_EX_EXIST: |
890 | err = MU_ERR_LOCK_CONFLICT; | 966 | err = MU_ERR_LOCK_CONFLICT; |
891 | break; | 967 | break; |
968 | |||
892 | case MU_DL_EX_PERM: | 969 | case MU_DL_EX_PERM: |
893 | err = EPERM; | 970 | err = EPERM; |
894 | break; | 971 | break; |
972 | |||
895 | default: | 973 | default: |
896 | case MU_DL_EX_ERROR: | 974 | case MU_DL_EX_ERROR: |
897 | err = MU_ERR_LOCK_EXT_ERR; | 975 | err = MU_ERR_LOCK_EXT_ERR; |
... | @@ -902,3 +980,15 @@ lock_external (mu_locker_t l, int lock) | ... | @@ -902,3 +980,15 @@ lock_external (mu_locker_t l, int lock) |
902 | return err; | 980 | return err; |
903 | } | 981 | } |
904 | 982 | ||
983 | static int | ||
984 | lock_external (mu_locker_t locker, enum mu_locker_mode mode) | ||
985 | { | ||
986 | return external_locker (locker, 1); | ||
987 | } | ||
988 | |||
989 | static int | ||
990 | unlock_external (mu_locker_t locker) | ||
991 | { | ||
992 | return external_locker (locker, 0); | ||
993 | } | ||
994 | ... | ... |
-
Please register or sign in to post a comment