Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / lib / locking / file_locking.c
blobda44ef91d397f8aa9a29bdbefd8329b1a0aba5d8
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "lib.h"
19 #include "locking.h"
20 #include "locking_types.h"
21 #include "activate.h"
22 #include "config.h"
23 #include "defaults.h"
24 #include "lvm-file.h"
25 #include "lvm-string.h"
26 #include "lvmcache.h"
28 #include <limits.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <sys/file.h>
32 #include <fcntl.h>
33 #include <signal.h>
35 struct lock_list {
36 struct dm_list list;
37 int lf;
38 char *res;
41 static struct dm_list _lock_list;
42 static char _lock_dir[NAME_LEN];
43 static int _prioritise_write_locks;
45 static sig_t _oldhandler;
46 static sigset_t _fullsigset, _intsigset;
47 static volatile sig_atomic_t _handler_installed;
49 static void _undo_flock(const char *file, int fd)
51 struct stat buf1, buf2;
53 log_debug("_undo_flock %s", file);
54 if (!flock(fd, LOCK_NB | LOCK_EX) &&
55 !stat(file, &buf1) &&
56 !fstat(fd, &buf2) &&
57 is_same_inode(buf1, buf2))
58 if (unlink(file))
59 log_sys_error("unlink", file);
61 if (close(fd) < 0)
62 log_sys_error("close", file);
65 static int _release_lock(const char *file, int unlock)
67 struct lock_list *ll;
68 struct dm_list *llh, *llt;
70 dm_list_iterate_safe(llh, llt, &_lock_list) {
71 ll = dm_list_item(llh, struct lock_list);
73 if (!file || !strcmp(ll->res, file)) {
74 dm_list_del(llh);
75 if (unlock) {
76 log_very_verbose("Unlocking %s", ll->res);
77 if (flock(ll->lf, LOCK_NB | LOCK_UN))
78 log_sys_error("flock", ll->res);
81 _undo_flock(ll->res, ll->lf);
83 dm_free(ll->res);
84 dm_free(llh);
86 if (file)
87 return 1;
91 return 0;
94 static void _fin_file_locking(void)
96 _release_lock(NULL, 1);
99 static void _reset_file_locking(void)
101 _release_lock(NULL, 0);
104 static void _remove_ctrl_c_handler(void)
106 siginterrupt(SIGINT, 0);
107 if (!_handler_installed)
108 return;
110 _handler_installed = 0;
112 sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
113 if (signal(SIGINT, _oldhandler) == SIG_ERR)
114 log_sys_error("signal", "_remove_ctrl_c_handler");
117 static void _trap_ctrl_c(int sig __attribute((unused)))
119 _remove_ctrl_c_handler();
120 log_error("CTRL-c detected: giving up waiting for lock");
123 static void _install_ctrl_c_handler()
125 _handler_installed = 1;
127 if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
128 _handler_installed = 0;
129 return;
132 sigprocmask(SIG_SETMASK, &_intsigset, NULL);
133 siginterrupt(SIGINT, 1);
136 static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
138 int r = 1;
139 int old_errno;
140 struct stat buf1, buf2;
142 log_debug("_do_flock %s %c%c",
143 file, operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B');
144 do {
145 if ((*fd > -1) && close(*fd))
146 log_sys_error("close", file);
148 if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
149 log_sys_error("open", file);
150 return 0;
153 if (nonblock)
154 operation |= LOCK_NB;
155 else
156 _install_ctrl_c_handler();
158 r = flock(*fd, operation);
159 old_errno = errno;
160 if (!nonblock)
161 _remove_ctrl_c_handler();
163 if (r) {
164 errno = old_errno;
165 log_sys_error("flock", file);
166 close(*fd);
167 return 0;
170 if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
171 is_same_inode(buf1, buf2))
172 return 1;
173 } while (!nonblock);
175 return_0;
178 #define AUX_LOCK_SUFFIX ":aux"
180 static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
182 int r, fd_aux = -1;
183 char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX));
185 strcpy(file_aux, file);
186 strcat(file_aux, AUX_LOCK_SUFFIX);
188 if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
189 if (operation == LOCK_EX) {
190 r = _do_flock(file, fd, operation, nonblock);
191 _undo_flock(file_aux, fd_aux);
192 } else {
193 _undo_flock(file_aux, fd_aux);
194 r = _do_flock(file, fd, operation, nonblock);
198 return r;
201 static int _lock_file(const char *file, uint32_t flags)
203 int operation;
204 uint32_t nonblock = flags & LCK_NONBLOCK;
205 int r;
207 struct lock_list *ll;
208 char state;
210 switch (flags & LCK_TYPE_MASK) {
211 case LCK_READ:
212 operation = LOCK_SH;
213 state = 'R';
214 break;
215 case LCK_WRITE:
216 operation = LOCK_EX;
217 state = 'W';
218 break;
219 case LCK_UNLOCK:
220 return _release_lock(file, 1);
221 default:
222 log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
223 return 0;
226 if (!(ll = dm_malloc(sizeof(struct lock_list))))
227 return_0;
229 if (!(ll->res = dm_strdup(file))) {
230 dm_free(ll);
231 return_0;
234 ll->lf = -1;
236 log_very_verbose("Locking %s %c%c", ll->res, state,
237 nonblock ? ' ' : 'B');
239 if (_prioritise_write_locks)
240 r = _do_write_priority_flock(file, &ll->lf, operation, nonblock);
241 else
242 r = _do_flock(file, &ll->lf, operation, nonblock);
244 if (r)
245 dm_list_add(&_lock_list, &ll->list);
246 else {
247 dm_free(ll->res);
248 dm_free(ll);
249 stack;
252 return r;
255 static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
256 uint32_t flags)
258 char lockfile[PATH_MAX];
260 switch (flags & LCK_SCOPE_MASK) {
261 case LCK_VG:
262 /* Skip cache refresh for VG_GLOBAL - the caller handles it */
263 if (strcmp(resource, VG_GLOBAL))
264 lvmcache_drop_metadata(resource);
266 /* LCK_CACHE does not require a real lock */
267 if (flags & LCK_CACHE)
268 break;
270 if (*resource == '#')
271 dm_snprintf(lockfile, sizeof(lockfile),
272 "%s/P_%s", _lock_dir, resource + 1);
273 else
274 dm_snprintf(lockfile, sizeof(lockfile),
275 "%s/V_%s", _lock_dir, resource);
277 if (!_lock_file(lockfile, flags))
278 return_0;
279 break;
280 case LCK_LV:
281 switch (flags & LCK_TYPE_MASK) {
282 case LCK_UNLOCK:
283 log_very_verbose("Unlocking LV %s", resource);
284 if (!lv_resume_if_active(cmd, resource))
285 return 0;
286 break;
287 case LCK_NULL:
288 log_very_verbose("Locking LV %s (NL)", resource);
289 if (!lv_deactivate(cmd, resource))
290 return 0;
291 break;
292 case LCK_READ:
293 log_very_verbose("Locking LV %s (R)", resource);
294 if (!lv_activate_with_filter(cmd, resource, 0))
295 return 0;
296 break;
297 case LCK_PREAD:
298 log_very_verbose("Locking LV %s (PR) - ignored", resource);
299 break;
300 case LCK_WRITE:
301 log_very_verbose("Locking LV %s (W)", resource);
302 if (!lv_suspend_if_active(cmd, resource))
303 return 0;
304 break;
305 case LCK_EXCL:
306 log_very_verbose("Locking LV %s (EX)", resource);
307 if (!lv_activate_with_filter(cmd, resource, 1))
308 return 0;
309 break;
310 default:
311 break;
313 break;
314 default:
315 log_error("Unrecognised lock scope: %d",
316 flags & LCK_SCOPE_MASK);
317 return 0;
320 return 1;
323 int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
325 locking->lock_resource = _file_lock_resource;
326 locking->reset_locking = _reset_file_locking;
327 locking->fin_locking = _fin_file_locking;
328 locking->flags = 0;
330 /* Get lockfile directory from config file */
331 strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
332 DEFAULT_LOCK_DIR),
333 sizeof(_lock_dir));
335 _prioritise_write_locks =
336 find_config_tree_bool(cmd, "global/prioritise_write_locks",
337 DEFAULT_PRIORITISE_WRITE_LOCKS);
339 if (!dm_create_dir(_lock_dir))
340 return 0;
342 /* Trap a read-only file system */
343 if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
344 return 0;
346 dm_list_init(&_lock_list);
348 if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
349 log_sys_error("sigfillset", "init_file_locking");
350 return 0;
353 if (sigdelset(&_intsigset, SIGINT)) {
354 log_sys_error("sigdelset", "init_file_locking");
355 return 0;
358 return 1;