Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of the device-mapper userspace tools.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "dmlib.h"
17 : : #include "libdm-targets.h"
18 : : #include "libdm-common.h"
19 : : #include "kdev_t.h"
20 : : #include "dm-ioctl.h"
21 : :
22 : : #include <stdarg.h>
23 : : #include <sys/param.h>
24 : : #include <sys/ioctl.h>
25 : : #include <fcntl.h>
26 : : #include <dirent.h>
27 : :
28 : : #ifdef UDEV_SYNC_SUPPORT
29 : : # include <sys/types.h>
30 : : # include <sys/ipc.h>
31 : : # include <sys/sem.h>
32 : : # define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
33 : : # include <libudev.h>
34 : : #endif
35 : :
36 : : #ifdef linux
37 : : # include <linux/fs.h>
38 : : #endif
39 : :
40 : : #ifdef HAVE_SELINUX
41 : : # include <selinux/selinux.h>
42 : : #endif
43 : :
44 : : #define DEV_DIR "/dev/"
45 : :
46 : : static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
47 : :
48 : : static int _verbose = 0;
49 : :
50 : : #ifdef UDEV_SYNC_SUPPORT
51 : : static int _udev_running = -1;
52 : : static int _sync_with_udev = 1;
53 : : static int _udev_checking = 1;
54 : : #endif
55 : :
56 : : /*
57 : : * Library users can provide their own logging
58 : : * function.
59 : : */
60 : :
61 : 0 : static void _default_log_line(int level,
62 : : const char *file __attribute((unused)),
63 : : int line __attribute((unused)), int dm_errno,
64 : : const char *f, va_list ap)
65 : : {
66 : 0 : int use_stderr = level & _LOG_STDERR;
67 : :
68 : 0 : level &= ~_LOG_STDERR;
69 : :
70 [ # # ][ # # ]: 0 : if (level > _LOG_WARN && !_verbose)
71 : 0 : return;
72 : :
73 [ # # ]: 0 : if (level < _LOG_WARN)
74 : 0 : vfprintf(stderr, f, ap);
75 : : else
76 [ # # ]: 0 : vfprintf(use_stderr ? stderr : stdout, f, ap);
77 : :
78 [ # # ]: 0 : if (level < _LOG_WARN)
79 : 0 : fprintf(stderr, "\n");
80 : : else
81 [ # # ]: 0 : fprintf(use_stderr ? stderr : stdout, "\n");
82 : : }
83 : :
84 : 0 : static void _default_log_with_errno(int level,
85 : : const char *file __attribute((unused)),
86 : : int line __attribute((unused)), int dm_errno,
87 : : const char *f, ...)
88 : : {
89 : : va_list ap;
90 : :
91 : 0 : va_start(ap, f);
92 : 0 : _default_log_line(level, file, line, dm_errno, f, ap);
93 : 0 : va_end(ap);
94 : 0 : }
95 : :
96 : 0 : static void _default_log(int level, const char *file,
97 : : int line, const char *f, ...)
98 : : {
99 : : va_list ap;
100 : :
101 : 0 : va_start(ap, f);
102 : 0 : _default_log_line(level, file, line, 0, f, ap);
103 : 0 : va_end(ap);
104 : 0 : }
105 : :
106 : : dm_log_fn dm_log = _default_log;
107 : : dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno;
108 : :
109 : 0 : void dm_log_init(dm_log_fn fn)
110 : : {
111 [ # # ]: 0 : if (fn)
112 : 0 : dm_log = fn;
113 : : else
114 : 0 : dm_log = _default_log;
115 : :
116 : 0 : dm_log_with_errno = _default_log_with_errno;
117 : 0 : }
118 : :
119 : 3 : int dm_log_is_non_default(void)
120 : : {
121 : 3 : return (dm_log == _default_log) ? 0 : 1;
122 : : }
123 : :
124 : 3 : void dm_log_with_errno_init(dm_log_with_errno_fn fn)
125 : : {
126 [ + - ]: 3 : if (fn)
127 : 3 : dm_log_with_errno = fn;
128 : : else
129 : 0 : dm_log_with_errno = _default_log_with_errno;
130 : :
131 : 3 : dm_log = _default_log;
132 : 3 : }
133 : :
134 : 0 : void dm_log_init_verbose(int level)
135 : : {
136 : 0 : _verbose = level;
137 : 0 : }
138 : :
139 : 0 : static void _build_dev_path(char *buffer, size_t len, const char *dev_name)
140 : : {
141 : : /* If there's a /, assume caller knows what they're doing */
142 [ # # ]: 0 : if (strchr(dev_name, '/'))
143 : 0 : snprintf(buffer, len, "%s", dev_name);
144 : : else
145 : 0 : snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
146 : 0 : }
147 : :
148 : 0 : int dm_get_library_version(char *version, size_t size)
149 : : {
150 : 0 : strncpy(version, DM_LIB_VERSION, size);
151 : 0 : return 1;
152 : : }
153 : :
154 : 0 : struct dm_task *dm_task_create(int type)
155 : : {
156 : 0 : struct dm_task *dmt = dm_malloc(sizeof(*dmt));
157 : :
158 [ # # ]: 0 : if (!dmt) {
159 [ # # ]: 0 : log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
160 : : sizeof(*dmt));
161 : 0 : return NULL;
162 : : }
163 : :
164 [ # # ]: 0 : if (!dm_check_version()) {
165 : 0 : dm_free(dmt);
166 : 0 : return NULL;
167 : : }
168 : :
169 : 0 : memset(dmt, 0, sizeof(*dmt));
170 : :
171 : 0 : dmt->type = type;
172 : 0 : dmt->minor = -1;
173 : 0 : dmt->major = -1;
174 : 0 : dmt->allow_default_major_fallback = 1;
175 : 0 : dmt->uid = DM_DEVICE_UID;
176 : 0 : dmt->gid = DM_DEVICE_GID;
177 : 0 : dmt->mode = DM_DEVICE_MODE;
178 : 0 : dmt->no_open_count = 0;
179 : 0 : dmt->read_ahead = DM_READ_AHEAD_AUTO;
180 : 0 : dmt->read_ahead_flags = 0;
181 : 0 : dmt->event_nr = 0;
182 : 0 : dmt->cookie_set = 0;
183 : 0 : dmt->query_inactive_table = 0;
184 : :
185 : 0 : return dmt;
186 : : }
187 : :
188 : : /*
189 : : * Find the name associated with a given device number by scanning _dm_dir.
190 : : */
191 : 0 : static char *_find_dm_name_of_device(dev_t st_rdev)
192 : : {
193 : : const char *name;
194 : : char path[PATH_MAX];
195 : : struct dirent *dirent;
196 : : DIR *d;
197 : : struct stat buf;
198 : 0 : char *new_name = NULL;
199 : :
200 [ # # ]: 0 : if (!(d = opendir(_dm_dir))) {
201 [ # # ]: 0 : log_sys_error("opendir", _dm_dir);
202 : 0 : return NULL;
203 : : }
204 : :
205 [ # # ]: 0 : while ((dirent = readdir(d))) {
206 : 0 : name = dirent->d_name;
207 : :
208 [ # # ][ # # ]: 0 : if (!strcmp(name, ".") || !strcmp(name, ".."))
209 : 0 : continue;
210 : :
211 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s", _dm_dir,
212 : : name) == -1) {
213 [ # # ]: 0 : log_error("Couldn't create path for %s", name);
214 : 0 : continue;
215 : : }
216 : :
217 [ # # ]: 0 : if (stat(path, &buf))
218 : 0 : continue;
219 : :
220 [ # # ]: 0 : if (buf.st_rdev == st_rdev) {
221 [ # # ]: 0 : if (!(new_name = dm_strdup(name)))
222 [ # # ]: 0 : log_error("dm_task_set_name: strdup(%s) failed",
223 : : name);
224 : 0 : break;
225 : : }
226 : : }
227 : :
228 [ # # ]: 0 : if (closedir(d))
229 [ # # ]: 0 : log_sys_error("closedir", _dm_dir);
230 : :
231 : 0 : return new_name;
232 : : }
233 : :
234 : 0 : int dm_task_set_name(struct dm_task *dmt, const char *name)
235 : : {
236 : : char *pos;
237 : 0 : char *new_name = NULL;
238 : : char path[PATH_MAX];
239 : : struct stat st1, st2;
240 : :
241 [ # # ]: 0 : if (dmt->dev_name) {
242 : 0 : dm_free(dmt->dev_name);
243 : 0 : dmt->dev_name = NULL;
244 : : }
245 : :
246 : : /*
247 : : * Path supplied for existing device?
248 : : */
249 [ # # ]: 0 : if ((pos = strrchr(name, '/'))) {
250 [ # # ]: 0 : if (dmt->type == DM_DEVICE_CREATE) {
251 [ # # ]: 0 : log_error("Name \"%s\" invalid. It contains \"/\".", name);
252 : 0 : return 0;
253 : : }
254 : :
255 [ # # ]: 0 : if (stat(name, &st1)) {
256 [ # # ]: 0 : log_error("Device %s not found", name);
257 : 0 : return 0;
258 : : }
259 : :
260 : : /*
261 : : * If supplied path points to same device as last component
262 : : * under /dev/mapper, use that name directly. Otherwise call
263 : : * _find_dm_name_of_device() to scan _dm_dir for a match.
264 : : */
265 [ # # ]: 0 : if (dm_snprintf(path, sizeof(path), "%s/%s", _dm_dir,
266 : : pos + 1) == -1) {
267 [ # # ]: 0 : log_error("Couldn't create path for %s", pos + 1);
268 : 0 : return 0;
269 : : }
270 : :
271 [ # # ][ # # ]: 0 : if (!stat(path, &st2) && (st1.st_rdev == st2.st_rdev))
272 : 0 : name = pos + 1;
273 [ # # ]: 0 : else if ((new_name = _find_dm_name_of_device(st1.st_rdev)))
274 : 0 : name = new_name;
275 : : else {
276 [ # # ]: 0 : log_error("Device %s not found", name);
277 : 0 : return 0;
278 : : }
279 : : }
280 : :
281 [ # # ]: 0 : if (strlen(name) >= DM_NAME_LEN) {
282 [ # # ]: 0 : log_error("Name \"%s\" too long", name);
283 [ # # ]: 0 : if (new_name)
284 : 0 : dm_free(new_name);
285 : 0 : return 0;
286 : : }
287 : :
288 [ # # ]: 0 : if (new_name)
289 : 0 : dmt->dev_name = new_name;
290 [ # # ]: 0 : else if (!(dmt->dev_name = dm_strdup(name))) {
291 [ # # ]: 0 : log_error("dm_task_set_name: strdup(%s) failed", name);
292 : 0 : return 0;
293 : : }
294 : :
295 : 0 : return 1;
296 : : }
297 : :
298 : 0 : int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
299 : : {
300 [ # # ]: 0 : if (dmt->uuid) {
301 : 0 : dm_free(dmt->uuid);
302 : 0 : dmt->uuid = NULL;
303 : : }
304 : :
305 [ # # ]: 0 : if (!(dmt->uuid = dm_strdup(uuid))) {
306 [ # # ]: 0 : log_error("dm_task_set_uuid: strdup(%s) failed", uuid);
307 : 0 : return 0;
308 : : }
309 : :
310 : 0 : return 1;
311 : : }
312 : :
313 : 0 : int dm_task_set_major(struct dm_task *dmt, int major)
314 : : {
315 : 0 : dmt->major = major;
316 : 0 : dmt->allow_default_major_fallback = 0;
317 : :
318 : 0 : return 1;
319 : : }
320 : :
321 : 0 : int dm_task_set_minor(struct dm_task *dmt, int minor)
322 : : {
323 : 0 : dmt->minor = minor;
324 : :
325 : 0 : return 1;
326 : : }
327 : :
328 : 0 : int dm_task_set_major_minor(struct dm_task *dmt, int major, int minor,
329 : : int allow_default_major_fallback)
330 : : {
331 : 0 : dmt->major = major;
332 : 0 : dmt->minor = minor;
333 : 0 : dmt->allow_default_major_fallback = allow_default_major_fallback;
334 : :
335 : 0 : return 1;
336 : : }
337 : :
338 : 0 : int dm_task_set_uid(struct dm_task *dmt, uid_t uid)
339 : : {
340 : 0 : dmt->uid = uid;
341 : :
342 : 0 : return 1;
343 : : }
344 : :
345 : 0 : int dm_task_set_gid(struct dm_task *dmt, gid_t gid)
346 : : {
347 : 0 : dmt->gid = gid;
348 : :
349 : 0 : return 1;
350 : : }
351 : :
352 : 0 : int dm_task_set_mode(struct dm_task *dmt, mode_t mode)
353 : : {
354 : 0 : dmt->mode = mode;
355 : :
356 : 0 : return 1;
357 : : }
358 : :
359 : 0 : int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
360 : : const char *ttype, const char *params)
361 : : {
362 : 0 : struct target *t = create_target(start, size, ttype, params);
363 : :
364 [ # # ]: 0 : if (!t)
365 : 0 : return 0;
366 : :
367 [ # # ]: 0 : if (!dmt->head)
368 : 0 : dmt->head = dmt->tail = t;
369 : : else {
370 : 0 : dmt->tail->next = t;
371 : 0 : dmt->tail = t;
372 : : }
373 : :
374 : 0 : return 1;
375 : : }
376 : :
377 : 0 : int dm_set_selinux_context(const char *path, mode_t mode)
378 : : {
379 : : #ifdef HAVE_SELINUX
380 : : security_context_t scontext;
381 : :
382 : : if (is_selinux_enabled() <= 0)
383 : : return 1;
384 : :
385 : : if (matchpathcon(path, mode, &scontext) < 0) {
386 : : log_error("%s: matchpathcon %07o failed: %s", path, mode,
387 : : strerror(errno));
388 : : return 0;
389 : : }
390 : :
391 : : log_debug("Setting SELinux context for %s to %s.", path, scontext);
392 : :
393 : : if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) {
394 : : log_sys_error("lsetfilecon", path);
395 : : freecon(scontext);
396 : : return 0;
397 : : }
398 : :
399 : : freecon(scontext);
400 : : #endif
401 : 0 : return 1;
402 : : }
403 : :
404 : 0 : static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
405 : : uid_t uid, gid_t gid, mode_t mode, int check_udev)
406 : : {
407 : : char path[PATH_MAX];
408 : : struct stat info;
409 : 0 : dev_t dev = MKDEV(major, minor);
410 : : mode_t old_mask;
411 : :
412 : 0 : _build_dev_path(path, sizeof(path), dev_name);
413 : :
414 [ # # ]: 0 : if (stat(path, &info) >= 0) {
415 [ # # ]: 0 : if (!S_ISBLK(info.st_mode)) {
416 [ # # ]: 0 : log_error("A non-block device file at '%s' "
417 : : "is already present", path);
418 : 0 : return 0;
419 : : }
420 : :
421 : : /* If right inode already exists we don't touch uid etc. */
422 [ # # ]: 0 : if (info.st_rdev == dev)
423 : 0 : return 1;
424 : :
425 [ # # ]: 0 : if (unlink(path) < 0) {
426 [ # # ]: 0 : log_error("Unable to unlink device node for '%s'",
427 : : dev_name);
428 : 0 : return 0;
429 : : }
430 [ # # ][ # # ]: 0 : } else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
[ # # ]
431 : : check_udev)
432 [ # # ]: 0 : log_warn("%s not set up by udev: Falling back to direct "
433 : : "node creation.", path);
434 : :
435 : 0 : old_mask = umask(0);
436 [ # # ]: 0 : if (mknod(path, S_IFBLK | mode, dev) < 0) {
437 : 0 : umask(old_mask);
438 [ # # ]: 0 : log_error("Unable to make device node for '%s'", dev_name);
439 : 0 : return 0;
440 : : }
441 : 0 : umask(old_mask);
442 : :
443 [ # # ]: 0 : if (chown(path, uid, gid) < 0) {
444 [ # # ]: 0 : log_sys_error("chown", path);
445 : 0 : return 0;
446 : : }
447 : :
448 [ # # ]: 0 : log_debug("Created %s", path);
449 : :
450 [ # # ]: 0 : if (!dm_set_selinux_context(path, S_IFBLK))
451 : 0 : return 0;
452 : :
453 : 0 : return 1;
454 : : }
455 : :
456 : 0 : static int _rm_dev_node(const char *dev_name, int check_udev)
457 : : {
458 : : char path[PATH_MAX];
459 : : struct stat info;
460 : :
461 : 0 : _build_dev_path(path, sizeof(path), dev_name);
462 : :
463 [ # # ]: 0 : if (stat(path, &info) < 0)
464 : 0 : return 1;
465 [ # # ][ # # ]: 0 : else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
[ # # ]
466 : : check_udev)
467 [ # # ]: 0 : log_warn("Node %s was not removed by udev. "
468 : : "Falling back to direct node removal.", path);
469 : :
470 [ # # ]: 0 : if (unlink(path) < 0) {
471 [ # # ]: 0 : log_error("Unable to unlink device node for '%s'", dev_name);
472 : 0 : return 0;
473 : : }
474 : :
475 [ # # ]: 0 : log_debug("Removed %s", path);
476 : :
477 : 0 : return 1;
478 : : }
479 : :
480 : 0 : static int _rename_dev_node(const char *old_name, const char *new_name,
481 : : int check_udev)
482 : : {
483 : : char oldpath[PATH_MAX];
484 : : char newpath[PATH_MAX];
485 : : struct stat info;
486 : :
487 : 0 : _build_dev_path(oldpath, sizeof(oldpath), old_name);
488 : 0 : _build_dev_path(newpath, sizeof(newpath), new_name);
489 : :
490 [ # # ]: 0 : if (stat(newpath, &info) == 0) {
491 [ # # ]: 0 : if (!S_ISBLK(info.st_mode)) {
492 [ # # ]: 0 : log_error("A non-block device file at '%s' "
493 : : "is already present", newpath);
494 : 0 : return 0;
495 : : }
496 [ # # ][ # # ]: 0 : else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
[ # # ]
497 : : check_udev) {
498 [ # # # # ]: 0 : if (stat(oldpath, &info) < 0 &&
499 : 0 : errno == ENOENT)
500 : : /* assume udev already deleted this */
501 : 0 : return 1;
502 : : else {
503 [ # # ]: 0 : log_warn("The node %s should have been renamed to %s "
504 : : "by udev but old node is still present. "
505 : : "Falling back to direct old node removal.",
506 : : oldpath, newpath);
507 : 0 : return _rm_dev_node(old_name, 0);
508 : : }
509 : : }
510 : :
511 [ # # ]: 0 : if (unlink(newpath) < 0) {
512 [ # # ]: 0 : if (errno == EPERM) {
513 : : /* devfs, entry has already been renamed */
514 : 0 : return 1;
515 : : }
516 [ # # ]: 0 : log_error("Unable to unlink device node for '%s'",
517 : : new_name);
518 : 0 : return 0;
519 : : }
520 : : }
521 [ # # ][ # # ]: 0 : else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
[ # # ]
522 : : check_udev)
523 [ # # ]: 0 : log_warn("The node %s should have been renamed to %s "
524 : : "by udev but new node is not present. "
525 : : "Falling back to direct node rename.",
526 : : oldpath, newpath);
527 : :
528 [ # # ]: 0 : if (rename(oldpath, newpath) < 0) {
529 [ # # ]: 0 : log_error("Unable to rename device node from '%s' to '%s'",
530 : : old_name, new_name);
531 : 0 : return 0;
532 : : }
533 : :
534 [ # # ]: 0 : log_debug("Renamed %s to %s", oldpath, newpath);
535 : :
536 : 0 : return 1;
537 : : }
538 : :
539 : : #ifdef linux
540 : 0 : static int _open_dev_node(const char *dev_name)
541 : : {
542 : 0 : int fd = -1;
543 : : char path[PATH_MAX];
544 : :
545 : 0 : _build_dev_path(path, sizeof(path), dev_name);
546 : :
547 [ # # ]: 0 : if ((fd = open(path, O_RDONLY, 0)) < 0)
548 [ # # ]: 0 : log_sys_error("open", path);
549 : :
550 : 0 : return fd;
551 : : }
552 : :
553 : 0 : int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
554 : : {
555 : 0 : int r = 1;
556 : : int fd;
557 : : long read_ahead_long;
558 : :
559 [ # # ]: 0 : if (!*dev_name) {
560 [ # # ]: 0 : log_error("Empty device name passed to BLKRAGET");
561 : 0 : return 0;
562 : : }
563 : :
564 [ # # ]: 0 : if ((fd = _open_dev_node(dev_name)) < 0)
565 [ # # ]: 0 : return_0;
566 : :
567 [ # # ]: 0 : if (ioctl(fd, BLKRAGET, &read_ahead_long)) {
568 [ # # ]: 0 : log_sys_error("BLKRAGET", dev_name);
569 : 0 : *read_ahead = 0;
570 : 0 : r = 0;
571 : : } else {
572 : 0 : *read_ahead = (uint32_t) read_ahead_long;
573 [ # # ]: 0 : log_debug("%s: read ahead is %" PRIu32, dev_name, *read_ahead);
574 : : }
575 : :
576 [ # # ]: 0 : if (close(fd))
577 [ # # ]: 0 : stack;
578 : :
579 : 0 : return r;
580 : : }
581 : :
582 : 0 : static int _set_read_ahead(const char *dev_name, uint32_t read_ahead)
583 : : {
584 : 0 : int r = 1;
585 : : int fd;
586 : 0 : long read_ahead_long = (long) read_ahead;
587 : :
588 [ # # ]: 0 : if (!*dev_name) {
589 [ # # ]: 0 : log_error("Empty device name passed to BLKRAGET");
590 : 0 : return 0;
591 : : }
592 : :
593 [ # # ]: 0 : if ((fd = _open_dev_node(dev_name)) < 0)
594 [ # # ]: 0 : return_0;
595 : :
596 [ # # ]: 0 : log_debug("%s: Setting read ahead to %" PRIu32, dev_name, read_ahead);
597 : :
598 [ # # ]: 0 : if (ioctl(fd, BLKRASET, read_ahead_long)) {
599 [ # # ]: 0 : log_sys_error("BLKRASET", dev_name);
600 : 0 : r = 0;
601 : : }
602 : :
603 [ # # ]: 0 : if (close(fd))
604 [ # # ]: 0 : stack;
605 : :
606 : 0 : return r;
607 : : }
608 : :
609 : 0 : static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
610 : : uint32_t read_ahead_flags)
611 : : {
612 : : uint32_t current_read_ahead;
613 : :
614 [ # # ]: 0 : if (read_ahead == DM_READ_AHEAD_AUTO)
615 : 0 : return 1;
616 : :
617 [ # # ]: 0 : if (read_ahead == DM_READ_AHEAD_NONE)
618 : 0 : read_ahead = 0;
619 : :
620 [ # # ]: 0 : if (read_ahead_flags & DM_READ_AHEAD_MINIMUM_FLAG) {
621 [ # # ]: 0 : if (!get_dev_node_read_ahead(dev_name, ¤t_read_ahead))
622 [ # # ]: 0 : return_0;
623 : :
624 [ # # ]: 0 : if (current_read_ahead > read_ahead) {
625 [ # # ]: 0 : log_debug("%s: retaining kernel read ahead of %" PRIu32
626 : : " (requested %" PRIu32 ")",
627 : : dev_name, current_read_ahead, read_ahead);
628 : 0 : return 1;
629 : : }
630 : : }
631 : :
632 : 0 : return _set_read_ahead(dev_name, read_ahead);
633 : : }
634 : :
635 : : #else
636 : :
637 : : int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
638 : : {
639 : : *read_ahead = 0;
640 : :
641 : : return 1;
642 : : }
643 : :
644 : : static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
645 : : uint32_t read_ahead_flags)
646 : : {
647 : : return 1;
648 : : }
649 : : #endif
650 : :
651 : : typedef enum {
652 : : NODE_ADD,
653 : : NODE_DEL,
654 : : NODE_RENAME,
655 : : NODE_READ_AHEAD
656 : : } node_op_t;
657 : :
658 : 0 : static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
659 : : uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
660 : : const char *old_name, uint32_t read_ahead,
661 : : uint32_t read_ahead_flags, int check_udev)
662 : : {
663 [ # # # # : 0 : switch (type) {
# ]
664 : : case NODE_ADD:
665 : 0 : return _add_dev_node(dev_name, major, minor, uid, gid,
666 : : mode, check_udev);
667 : : case NODE_DEL:
668 : 0 : return _rm_dev_node(dev_name, check_udev);
669 : : case NODE_RENAME:
670 : 0 : return _rename_dev_node(old_name, dev_name, check_udev);
671 : : case NODE_READ_AHEAD:
672 : 0 : return _set_dev_node_read_ahead(dev_name, read_ahead,
673 : : read_ahead_flags);
674 : : }
675 : :
676 : 0 : return 1;
677 : : }
678 : :
679 : : static DM_LIST_INIT(_node_ops);
680 : :
681 : : struct node_op_parms {
682 : : struct dm_list list;
683 : : node_op_t type;
684 : : char *dev_name;
685 : : uint32_t major;
686 : : uint32_t minor;
687 : : uid_t uid;
688 : : gid_t gid;
689 : : mode_t mode;
690 : : uint32_t read_ahead;
691 : : uint32_t read_ahead_flags;
692 : : char *old_name;
693 : : int check_udev;
694 : : char names[0];
695 : : };
696 : :
697 : 0 : static void _store_str(char **pos, char **ptr, const char *str)
698 : : {
699 : 0 : strcpy(*pos, str);
700 : 0 : *ptr = *pos;
701 : 0 : *pos += strlen(*ptr) + 1;
702 : 0 : }
703 : :
704 : 0 : static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
705 : : uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
706 : : const char *old_name, uint32_t read_ahead,
707 : : uint32_t read_ahead_flags, int check_udev)
708 : : {
709 : : struct node_op_parms *nop;
710 : : struct dm_list *noph, *nopht;
711 : 0 : size_t len = strlen(dev_name) + strlen(old_name) + 2;
712 : : char *pos;
713 : :
714 : : /*
715 : : * Ignore any outstanding operations on the node if deleting it
716 : : */
717 [ # # ]: 0 : if (type == NODE_DEL) {
718 [ # # ]: 0 : dm_list_iterate_safe(noph, nopht, &_node_ops) {
719 : 0 : nop = dm_list_item(noph, struct node_op_parms);
720 [ # # ]: 0 : if (!strcmp(dev_name, nop->dev_name)) {
721 : 0 : dm_list_del(&nop->list);
722 : 0 : dm_free(nop);
723 : : }
724 : : }
725 : : }
726 : :
727 [ # # ]: 0 : if (!(nop = dm_malloc(sizeof(*nop) + len))) {
728 [ # # ]: 0 : log_error("Insufficient memory to stack mknod operation");
729 : 0 : return 0;
730 : : }
731 : :
732 : 0 : pos = nop->names;
733 : 0 : nop->type = type;
734 : 0 : nop->major = major;
735 : 0 : nop->minor = minor;
736 : 0 : nop->uid = uid;
737 : 0 : nop->gid = gid;
738 : 0 : nop->mode = mode;
739 : 0 : nop->read_ahead = read_ahead;
740 : 0 : nop->read_ahead_flags = read_ahead_flags;
741 : 0 : nop->check_udev = check_udev;
742 : :
743 : 0 : _store_str(&pos, &nop->dev_name, dev_name);
744 : 0 : _store_str(&pos, &nop->old_name, old_name);
745 : :
746 : 0 : dm_list_add(&_node_ops, &nop->list);
747 : :
748 : 0 : return 1;
749 : : }
750 : :
751 : 3 : static void _pop_node_ops(void)
752 : : {
753 : : struct dm_list *noph, *nopht;
754 : : struct node_op_parms *nop;
755 : :
756 [ - + ]: 3 : dm_list_iterate_safe(noph, nopht, &_node_ops) {
757 : 0 : nop = dm_list_item(noph, struct node_op_parms);
758 : 0 : _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
759 : 0 : nop->uid, nop->gid, nop->mode, nop->old_name,
760 : : nop->read_ahead, nop->read_ahead_flags,
761 : : nop->check_udev);
762 : 0 : dm_list_del(&nop->list);
763 : 0 : dm_free(nop);
764 : : }
765 : 3 : }
766 : :
767 : 0 : int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
768 : : uid_t uid, gid_t gid, mode_t mode, int check_udev)
769 : : {
770 [ # # ]: 0 : log_debug("%s: Stacking NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o",
771 : : dev_name, major, minor, uid, gid, mode);
772 : :
773 : 0 : return _stack_node_op(NODE_ADD, dev_name, major, minor, uid,
774 : : gid, mode, "", 0, 0, check_udev);
775 : : }
776 : :
777 : 0 : int rename_dev_node(const char *old_name, const char *new_name, int check_udev)
778 : : {
779 [ # # ]: 0 : log_debug("%s: Stacking NODE_RENAME to %s", old_name, new_name);
780 : :
781 : 0 : return _stack_node_op(NODE_RENAME, new_name, 0, 0, 0,
782 : : 0, 0, old_name, 0, 0, check_udev);
783 : : }
784 : :
785 : 0 : int rm_dev_node(const char *dev_name, int check_udev)
786 : : {
787 [ # # ]: 0 : log_debug("%s: Stacking NODE_DEL (replaces other stacked ops)", dev_name);
788 : :
789 : 0 : return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0,
790 : : 0, 0, "", 0, 0, check_udev);
791 : : }
792 : :
793 : 0 : int set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
794 : : uint32_t read_ahead_flags)
795 : : {
796 [ # # ]: 0 : if (read_ahead == DM_READ_AHEAD_AUTO)
797 : 0 : return 1;
798 : :
799 [ # # ]: 0 : log_debug("%s: Stacking NODE_READ_AHEAD %" PRIu32 " (flags=%" PRIu32
800 : : ")", dev_name, read_ahead, read_ahead_flags);
801 : :
802 : 0 : return _stack_node_op(NODE_READ_AHEAD, dev_name, 0, 0, 0, 0,
803 : : 0, "", read_ahead, read_ahead_flags, 0);
804 : : }
805 : :
806 : 3 : void update_devs(void)
807 : : {
808 : 3 : _pop_node_ops();
809 : 3 : }
810 : :
811 : 3 : int dm_set_dev_dir(const char *dev_dir)
812 : : {
813 : : size_t len;
814 : : const char *slash;
815 [ - + ]: 3 : if (*dev_dir != '/') {
816 [ # # ]: 0 : log_debug("Invalid dev_dir value, %s: "
817 : : "not an absolute name.", dev_dir);
818 : 0 : return 0;
819 : : }
820 : :
821 : 3 : len = strlen(dev_dir);
822 [ + - ]: 3 : slash = dev_dir[len-1] == '/' ? "" : "/";
823 : :
824 [ - + ]: 3 : if (snprintf(_dm_dir, sizeof _dm_dir, "%s%s%s", dev_dir, slash, DM_DIR)
825 : : >= sizeof _dm_dir) {
826 [ # # ]: 0 : log_debug("Invalid dev_dir value, %s: name too long.", dev_dir);
827 : 0 : return 0;
828 : : }
829 : :
830 : 3 : return 1;
831 : : }
832 : :
833 : 0 : const char *dm_dir(void)
834 : : {
835 : 0 : return _dm_dir;
836 : : }
837 : :
838 : 0 : int dm_mknodes(const char *name)
839 : : {
840 : : struct dm_task *dmt;
841 : 0 : int r = 0;
842 : :
843 [ # # ]: 0 : if (!(dmt = dm_task_create(DM_DEVICE_MKNODES)))
844 : 0 : return 0;
845 : :
846 [ # # ][ # # ]: 0 : if (name && !dm_task_set_name(dmt, name))
847 : 0 : goto out;
848 : :
849 [ # # ]: 0 : if (!dm_task_no_open_count(dmt))
850 : 0 : goto out;
851 : :
852 : 0 : r = dm_task_run(dmt);
853 : :
854 : : out:
855 : 0 : dm_task_destroy(dmt);
856 : 0 : return r;
857 : : }
858 : :
859 : 0 : int dm_driver_version(char *version, size_t size)
860 : : {
861 : : struct dm_task *dmt;
862 : 0 : int r = 0;
863 : :
864 [ # # ]: 0 : if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))
865 : 0 : return 0;
866 : :
867 [ # # ]: 0 : if (!dm_task_run(dmt))
868 [ # # ]: 0 : log_error("Failed to get driver version");
869 : :
870 [ # # ]: 0 : if (!dm_task_get_driver_version(dmt, version, size))
871 : 0 : goto out;
872 : :
873 : 0 : r = 1;
874 : :
875 : : out:
876 : 0 : dm_task_destroy(dmt);
877 : 0 : return r;
878 : : }
879 : :
880 : : #ifndef UDEV_SYNC_SUPPORT
881 : : void dm_udev_set_sync_support(int sync_with_udev)
882 : : {
883 : : }
884 : :
885 : : int dm_udev_get_sync_support(void)
886 : : {
887 : : return 0;
888 : : }
889 : :
890 : : void dm_udev_set_checking(int checking)
891 : : {
892 : : }
893 : :
894 : : int dm_udev_get_checking(void)
895 : : {
896 : : return 0;
897 : : }
898 : :
899 : : int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
900 : : {
901 : : if (dm_cookie_supported())
902 : : dmt->event_nr = flags << DM_UDEV_FLAGS_SHIFT;
903 : : *cookie = 0;
904 : :
905 : : return 1;
906 : : }
907 : :
908 : : int dm_udev_complete(uint32_t cookie)
909 : : {
910 : : return 1;
911 : : }
912 : :
913 : : int dm_udev_wait(uint32_t cookie)
914 : : {
915 : : return 1;
916 : : }
917 : :
918 : : #else /* UDEV_SYNC_SUPPORT */
919 : :
920 : :
921 : 0 : static int _check_udev_is_running(void)
922 : : {
923 : : struct udev *udev;
924 : : struct udev_queue *udev_queue;
925 : : int r;
926 : :
927 [ # # ]: 0 : if (!(udev = udev_new()))
928 [ # # ]: 0 : goto_bad;
929 : :
930 [ # # ]: 0 : if (!(udev_queue = udev_queue_new(udev))) {
931 : 0 : udev_unref(udev);
932 [ # # ]: 0 : goto_bad;
933 : : }
934 : :
935 [ # # ]: 0 : if (!(r = udev_queue_get_udev_is_active(udev_queue)))
936 [ # # ]: 0 : log_debug("Udev is not running. "
937 : : "Not using udev synchronisation code.");
938 : :
939 : 0 : udev_queue_unref(udev_queue);
940 : 0 : udev_unref(udev);
941 : :
942 : 0 : return r;
943 : :
944 : : bad:
945 [ # # ]: 0 : log_error("Could not get udev state. Assuming udev is not running.");
946 : 0 : return 0;
947 : : }
948 : :
949 : 0 : void dm_udev_set_sync_support(int sync_with_udev)
950 : : {
951 [ # # ]: 0 : if (_udev_running < 0)
952 : 0 : _udev_running = _check_udev_is_running();
953 : :
954 : 0 : _sync_with_udev = sync_with_udev;
955 : 0 : }
956 : :
957 : 0 : int dm_udev_get_sync_support(void)
958 : : {
959 [ # # ]: 0 : if (_udev_running < 0)
960 : 0 : _udev_running = _check_udev_is_running();
961 : :
962 [ # # ][ # # ]: 0 : return dm_cookie_supported() && _udev_running && _sync_with_udev;
[ # # ]
963 : : }
964 : :
965 : 0 : void dm_udev_set_checking(int checking)
966 : : {
967 [ # # ]: 0 : if ((_udev_checking = checking))
968 [ # # ]: 0 : log_debug("DM udev checking enabled");
969 : : else
970 [ # # ]: 0 : log_debug("DM udev checking disabled");
971 : 0 : }
972 : :
973 : 0 : int dm_udev_get_checking(void)
974 : : {
975 : 0 : return _udev_checking;
976 : : }
977 : :
978 : 0 : static int _get_cookie_sem(uint32_t cookie, int *semid)
979 : : {
980 [ # # ]: 0 : if (cookie >> 16 != DM_COOKIE_MAGIC) {
981 [ # # ]: 0 : log_error("Could not continue to access notification "
982 : : "semaphore identified by cookie value %"
983 : : PRIu32 " (0x%x). Incorrect cookie prefix.",
984 : : cookie, cookie);
985 : 0 : return 0;
986 : : }
987 : :
988 [ # # ]: 0 : if ((*semid = semget((key_t) cookie, 1, 0)) >= 0)
989 : 0 : return 1;
990 : :
991 [ # # # ]: 0 : switch (errno) {
992 : : case ENOENT:
993 [ # # ]: 0 : log_error("Could not find notification "
994 : : "semaphore identified by cookie "
995 : : "value %" PRIu32 " (0x%x)",
996 : : cookie, cookie);
997 : 0 : break;
998 : : case EACCES:
999 [ # # ]: 0 : log_error("No permission to access "
1000 : : "notificaton semaphore identified "
1001 : : "by cookie value %" PRIu32 " (0x%x)",
1002 : : cookie, cookie);
1003 : 0 : break;
1004 : : default:
1005 [ # # ]: 0 : log_error("Failed to access notification "
1006 : : "semaphore identified by cookie "
1007 : : "value %" PRIu32 " (0x%x): %s",
1008 : : cookie, cookie, strerror(errno));
1009 : : break;
1010 : : }
1011 : :
1012 : 0 : return 0;
1013 : : }
1014 : :
1015 : 0 : static int _udev_notify_sem_inc(uint32_t cookie, int semid)
1016 : : {
1017 : 0 : struct sembuf sb = {0, 1, 0};
1018 : :
1019 [ # # ]: 0 : if (semop(semid, &sb, 1) < 0) {
1020 [ # # ]: 0 : log_error("semid %d: semop failed for cookie 0x%" PRIx32 ": %s",
1021 : : semid, cookie, strerror(errno));
1022 : 0 : return 0;
1023 : : }
1024 : :
1025 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented",
1026 : : cookie, semid);
1027 : :
1028 : 0 : return 1;
1029 : : }
1030 : :
1031 : 0 : static int _udev_notify_sem_dec(uint32_t cookie, int semid)
1032 : : {
1033 : 0 : struct sembuf sb = {0, -1, IPC_NOWAIT};
1034 : :
1035 [ # # ]: 0 : if (semop(semid, &sb, 1) < 0) {
1036 [ # # ]: 0 : switch (errno) {
1037 : : case EAGAIN:
1038 [ # # ]: 0 : log_error("semid %d: semop failed for cookie "
1039 : : "0x%" PRIx32 ": "
1040 : : "incorrect semaphore state",
1041 : : semid, cookie);
1042 : 0 : break;
1043 : : default:
1044 [ # # ]: 0 : log_error("semid %d: semop failed for cookie "
1045 : : "0x%" PRIx32 ": %s",
1046 : : semid, cookie, strerror(errno));
1047 : : break;
1048 : : }
1049 : 0 : return 0;
1050 : : }
1051 : :
1052 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) decremented",
1053 : : cookie, semid);
1054 : :
1055 : 0 : return 1;
1056 : : }
1057 : :
1058 : 0 : static int _udev_notify_sem_destroy(uint32_t cookie, int semid)
1059 : : {
1060 [ # # ]: 0 : if (semctl(semid, 0, IPC_RMID, 0) < 0) {
1061 [ # # ]: 0 : log_error("Could not cleanup notification semaphore "
1062 : : "identified by cookie value %" PRIu32 " (0x%x): %s",
1063 : : cookie, cookie, strerror(errno));
1064 : 0 : return 0;
1065 : : }
1066 : :
1067 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) destroyed", cookie,
1068 : : semid);
1069 : :
1070 : 0 : return 1;
1071 : : }
1072 : :
1073 : 0 : static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
1074 : : {
1075 : : int fd;
1076 : : int gen_semid;
1077 : : uint16_t base_cookie;
1078 : : uint32_t gen_cookie;
1079 : :
1080 [ # # ]: 0 : if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
1081 [ # # ]: 0 : log_error("Failed to open /dev/urandom "
1082 : : "to create random cookie value");
1083 : 0 : *cookie = 0;
1084 : 0 : return 0;
1085 : : }
1086 : :
1087 : : /* Generate random cookie value. Be sure it is unique and non-zero. */
1088 : : do {
1089 : : /* FIXME Handle non-error returns from read(). Move _io() into libdm? */
1090 [ # # ]: 0 : if (read(fd, &base_cookie, sizeof(base_cookie)) != sizeof(base_cookie)) {
1091 [ # # ]: 0 : log_error("Failed to initialize notification cookie");
1092 : 0 : goto bad;
1093 : : }
1094 : :
1095 : 0 : gen_cookie = DM_COOKIE_MAGIC << 16 | base_cookie;
1096 : :
1097 [ # # ][ # # ]: 0 : if (base_cookie && (gen_semid = semget((key_t) gen_cookie,
1098 : : 1, 0600 | IPC_CREAT | IPC_EXCL)) < 0) {
1099 [ # # # # ]: 0 : switch (errno) {
1100 : : case EEXIST:
1101 : : /* if the semaphore key exists, we
1102 : : * simply generate another random one */
1103 : 0 : base_cookie = 0;
1104 : 0 : break;
1105 : : case ENOMEM:
1106 [ # # ]: 0 : log_error("Not enough memory to create "
1107 : : "notification semaphore");
1108 : 0 : goto bad;
1109 : : case ENOSPC:
1110 [ # # ]: 0 : log_error("Limit for the maximum number "
1111 : : "of semaphores reached. You can "
1112 : : "check and set the limits in "
1113 : : "/proc/sys/kernel/sem.");
1114 : 0 : goto bad;
1115 : : default:
1116 [ # # ]: 0 : log_error("Failed to create notification "
1117 : : "semaphore: %s", strerror(errno));
1118 : 0 : goto bad;
1119 : : }
1120 : : }
1121 [ # # ]: 0 : } while (!base_cookie);
1122 : :
1123 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) created",
1124 : : gen_cookie, gen_semid);
1125 : :
1126 [ # # ]: 0 : if (semctl(gen_semid, 0, SETVAL, 1) < 0) {
1127 [ # # ]: 0 : log_error("semid %d: semctl failed: %s", gen_semid, strerror(errno));
1128 : : /* We have to destroy just created semaphore
1129 : : * so it won't stay in the system. */
1130 : 0 : (void) _udev_notify_sem_destroy(gen_cookie, gen_semid);
1131 : 0 : goto bad;
1132 : : }
1133 : :
1134 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented",
1135 : : gen_cookie, gen_semid);
1136 : :
1137 [ # # ]: 0 : if (close(fd))
1138 [ # # ]: 0 : stack;
1139 : :
1140 : 0 : *semid = gen_semid;
1141 : 0 : *cookie = gen_cookie;
1142 : :
1143 : 0 : return 1;
1144 : :
1145 : : bad:
1146 [ # # ]: 0 : if (close(fd))
1147 [ # # ]: 0 : stack;
1148 : :
1149 : 0 : *cookie = 0;
1150 : :
1151 : 0 : return 0;
1152 : : }
1153 : :
1154 : 0 : int dm_udev_create_cookie(uint32_t *cookie)
1155 : : {
1156 : : int semid;
1157 : :
1158 [ # # ]: 0 : if (!dm_udev_get_sync_support()) {
1159 : 0 : *cookie = 0;
1160 : 0 : return 1;
1161 : : }
1162 : :
1163 : 0 : return _udev_notify_sem_create(cookie, &semid);
1164 : : }
1165 : :
1166 : 0 : int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
1167 : : {
1168 : : int semid;
1169 : :
1170 [ # # ]: 0 : if (dm_cookie_supported())
1171 : 0 : dmt->event_nr = flags << DM_UDEV_FLAGS_SHIFT;
1172 : :
1173 [ # # ]: 0 : if (!dm_udev_get_sync_support()) {
1174 : 0 : *cookie = 0;
1175 : 0 : return 1;
1176 : : }
1177 : :
1178 [ # # ]: 0 : if (*cookie) {
1179 [ # # ]: 0 : if (!_get_cookie_sem(*cookie, &semid))
1180 [ # # ]: 0 : goto_bad;
1181 [ # # ]: 0 : } else if (!_udev_notify_sem_create(cookie, &semid))
1182 [ # # ]: 0 : goto_bad;
1183 : :
1184 [ # # ]: 0 : if (!_udev_notify_sem_inc(*cookie, semid)) {
1185 [ # # ]: 0 : log_error("Could not set notification semaphore "
1186 : : "identified by cookie value %" PRIu32 " (0x%x)",
1187 : : *cookie, *cookie);
1188 : 0 : goto bad;
1189 : : }
1190 : :
1191 : 0 : dmt->event_nr |= ~DM_UDEV_FLAGS_MASK & *cookie;
1192 : 0 : dmt->cookie_set = 1;
1193 : :
1194 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d) assigned to dm_task "
1195 : : "with flags 0x%" PRIx16, *cookie, semid, flags);
1196 : :
1197 : 0 : return 1;
1198 : :
1199 : : bad:
1200 : 0 : dmt->event_nr = 0;
1201 : 0 : return 0;
1202 : : }
1203 : :
1204 : 0 : int dm_udev_complete(uint32_t cookie)
1205 : : {
1206 : : int semid;
1207 : :
1208 [ # # ][ # # ]: 0 : if (!cookie || !dm_udev_get_sync_support())
1209 : 0 : return 1;
1210 : :
1211 [ # # ]: 0 : if (!_get_cookie_sem(cookie, &semid))
1212 [ # # ]: 0 : return_0;
1213 : :
1214 [ # # ]: 0 : if (!_udev_notify_sem_dec(cookie, semid)) {
1215 [ # # ]: 0 : log_error("Could not signal waiting process using notification "
1216 : : "semaphore identified by cookie value %" PRIu32 " (0x%x)",
1217 : : cookie, cookie);
1218 : 0 : return 0;
1219 : : }
1220 : :
1221 : 0 : return 1;
1222 : : }
1223 : :
1224 : 0 : int dm_udev_wait(uint32_t cookie)
1225 : : {
1226 : : int semid;
1227 : 0 : struct sembuf sb = {0, 0, 0};
1228 : :
1229 [ # # ][ # # ]: 0 : if (!cookie || !dm_udev_get_sync_support())
1230 : 0 : return 1;
1231 : :
1232 [ # # ]: 0 : if (!_get_cookie_sem(cookie, &semid))
1233 [ # # ]: 0 : return_0;
1234 : :
1235 [ # # ]: 0 : if (!_udev_notify_sem_dec(cookie, semid)) {
1236 [ # # ]: 0 : log_error("Failed to set a proper state for notification "
1237 : : "semaphore identified by cookie value %" PRIu32 " (0x%x) "
1238 : : "to initialize waiting for incoming notifications.",
1239 : : cookie, cookie);
1240 : 0 : (void) _udev_notify_sem_destroy(cookie, semid);
1241 : 0 : return 0;
1242 : : }
1243 : :
1244 [ # # ]: 0 : log_debug("Udev cookie 0x%" PRIx32 " (semid %d): Waiting for zero",
1245 : : cookie, semid);
1246 : :
1247 : : repeat_wait:
1248 [ # # ]: 0 : if (semop(semid, &sb, 1) < 0) {
1249 [ # # ]: 0 : if (errno == EINTR)
1250 : 0 : goto repeat_wait;
1251 [ # # ]: 0 : else if (errno == EIDRM)
1252 : 0 : return 1;
1253 : :
1254 [ # # ]: 0 : log_error("Could not set wait state for notification semaphore "
1255 : : "identified by cookie value %" PRIu32 " (0x%x): %s",
1256 : : cookie, cookie, strerror(errno));
1257 : 0 : (void) _udev_notify_sem_destroy(cookie, semid);
1258 : 0 : return 0;
1259 : : }
1260 : :
1261 : 0 : return _udev_notify_sem_destroy(cookie, semid);
1262 : : }
1263 : :
1264 : : #endif /* UDEV_SYNC_SUPPORT */
|