1 /* $NetBSD: libdm-common.c,v 1.4 2009/12/02 00:58:03 haad Exp $ */
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 the device-mapper userspace tools.
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
19 #include "libdm-targets.h"
20 #include "libdm-common.h"
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
32 #ifdef UDEV_SYNC_SUPPORT
33 # include <sys/types.h>
36 #ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE
37 # define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
43 # include <linux/fs.h>
47 # include <selinux/selinux.h>
51 #include "libdm-netbsd.h"
54 #define DEV_DIR "/dev/"
56 static char _dm_dir
[PATH_MAX
] = DEV_DIR DM_DIR
;
58 static int _verbose
= 0;
60 #ifdef UDEV_SYNC_SUPPORT
61 static int _udev_running
= -1;
62 static int _sync_with_udev
= 1;
66 * Library users can provide their own logging
70 static void _default_log_line(int level
,
71 const char *file
__attribute((unused
)),
72 int line
__attribute((unused
)), int dm_errno
,
73 const char *f
, va_list ap
)
75 int use_stderr
= level
& _LOG_STDERR
;
77 level
&= ~_LOG_STDERR
;
79 if (level
> _LOG_WARN
&& !_verbose
)
82 if (level
< _LOG_WARN
)
83 vfprintf(stderr
, f
, ap
);
85 vfprintf(use_stderr
? stderr
: stdout
, f
, ap
);
87 if (level
< _LOG_WARN
)
88 fprintf(stderr
, "\n");
90 fprintf(use_stderr
? stderr
: stdout
, "\n");
93 static void _default_log_with_errno(int level
,
94 const char *file
__attribute((unused
)),
95 int line
__attribute((unused
)), int dm_errno
,
101 _default_log_line(level
, file
, line
, dm_errno
, f
, ap
);
105 static void _default_log(int level
, const char *file
,
106 int line
, const char *f
, ...)
111 _default_log_line(level
, file
, line
, 0, f
, ap
);
115 dm_log_fn dm_log
= _default_log
;
116 dm_log_with_errno_fn dm_log_with_errno
= _default_log_with_errno
;
118 void dm_log_init(dm_log_fn fn
)
123 dm_log
= _default_log
;
125 dm_log_with_errno
= _default_log_with_errno
;
128 int dm_log_is_non_default(void)
130 return (dm_log
== _default_log
) ? 0 : 1;
133 void dm_log_with_errno_init(dm_log_with_errno_fn fn
)
136 dm_log_with_errno
= fn
;
138 dm_log_with_errno
= _default_log_with_errno
;
140 dm_log
= _default_log
;
143 void dm_log_init_verbose(int level
)
148 static void _build_dev_path(char *buffer
, size_t len
, const char *dev_name
)
150 /* If there's a /, assume caller knows what they're doing */
151 if (strchr(dev_name
, '/'))
152 snprintf(buffer
, len
, "%s", dev_name
);
154 snprintf(buffer
, len
, "%s/%s", _dm_dir
, dev_name
);
157 int dm_get_library_version(char *version
, size_t size
)
159 strncpy(version
, DM_LIB_VERSION
, size
);
163 struct dm_task
*dm_task_create(int type
)
165 struct dm_task
*dmt
= dm_malloc(sizeof(*dmt
));
168 log_error("dm_task_create: malloc(%" PRIsize_t
") failed",
173 if (!dm_check_version()) {
178 memset(dmt
, 0, sizeof(*dmt
));
183 dmt
->allow_default_major_fallback
= 1;
184 dmt
->uid
= DM_DEVICE_UID
;
185 dmt
->gid
= DM_DEVICE_GID
;
186 dmt
->mode
= DM_DEVICE_MODE
;
187 dmt
->no_open_count
= 0;
188 dmt
->read_ahead
= DM_READ_AHEAD_AUTO
;
189 dmt
->read_ahead_flags
= 0;
192 dmt
->query_inactive_table
= 0;
198 * Find the name associated with a given device number by scanning _dm_dir.
200 static char *_find_dm_name_of_device(dev_t st_rdev
)
204 struct dirent
*dirent
;
207 char *new_name
= NULL
;
209 if (!(d
= opendir(_dm_dir
))) {
210 log_sys_error("opendir", _dm_dir
);
214 while ((dirent
= readdir(d
))) {
215 name
= dirent
->d_name
;
217 if (!strcmp(name
, ".") || !strcmp(name
, ".."))
220 if (dm_snprintf(path
, sizeof(path
), "%s/%s", _dm_dir
,
222 log_error("Couldn't create path for %s", name
);
226 if (stat(path
, &buf
))
229 if (buf
.st_rdev
== st_rdev
) {
230 if (!(new_name
= dm_strdup(name
)))
231 log_error("dm_task_set_name: strdup(%s) failed",
238 log_sys_error("closedir", _dm_dir
);
243 int dm_task_set_name(struct dm_task
*dmt
, const char *name
)
246 char *new_name
= NULL
;
248 struct stat st1
, st2
;
251 dm_free(dmt
->dev_name
);
252 dmt
->dev_name
= NULL
;
256 * Path supplied for existing device?
258 if ((pos
= strrchr(name
, '/'))) {
259 if (dmt
->type
== DM_DEVICE_CREATE
) {
260 log_error("Name \"%s\" invalid. It contains \"/\".", name
);
264 if (stat(name
, &st1
)) {
265 log_error("Device %s not found", name
);
270 * If supplied path points to same device as last component
271 * under /dev/mapper, use that name directly. Otherwise call
272 * _find_dm_name_of_device() to scan _dm_dir for a match.
274 if (dm_snprintf(path
, sizeof(path
), "%s/%s", _dm_dir
,
276 log_error("Couldn't create path for %s", pos
+ 1);
280 if (!stat(path
, &st2
) && (st1
.st_rdev
== st2
.st_rdev
))
282 else if ((new_name
= _find_dm_name_of_device(st1
.st_rdev
)))
285 log_error("Device %s not found", name
);
290 if (strlen(name
) >= DM_NAME_LEN
) {
291 log_error("Name \"%s\" too long", name
);
298 dmt
->dev_name
= new_name
;
299 else if (!(dmt
->dev_name
= dm_strdup(name
))) {
300 log_error("dm_task_set_name: strdup(%s) failed", name
);
307 int dm_task_set_uuid(struct dm_task
*dmt
, const char *uuid
)
314 if (!(dmt
->uuid
= dm_strdup(uuid
))) {
315 log_error("dm_task_set_uuid: strdup(%s) failed", uuid
);
322 int dm_task_set_major(struct dm_task
*dmt
, int major
)
325 dmt
->allow_default_major_fallback
= 0;
330 int dm_task_set_minor(struct dm_task
*dmt
, int minor
)
337 int dm_task_set_major_minor(struct dm_task
*dmt
, int major
, int minor
,
338 int allow_default_major_fallback
)
342 dmt
->allow_default_major_fallback
= allow_default_major_fallback
;
347 int dm_task_set_uid(struct dm_task
*dmt
, uid_t uid
)
354 int dm_task_set_gid(struct dm_task
*dmt
, gid_t gid
)
361 int dm_task_set_mode(struct dm_task
*dmt
, mode_t mode
)
368 int dm_task_add_target(struct dm_task
*dmt
, uint64_t start
, uint64_t size
,
369 const char *ttype
, const char *params
)
371 struct target
*t
= create_target(start
, size
, ttype
, params
);
377 dmt
->head
= dmt
->tail
= t
;
386 int dm_set_selinux_context(const char *path
, mode_t mode
)
389 security_context_t scontext
;
391 if (is_selinux_enabled() <= 0)
394 if (matchpathcon(path
, mode
, &scontext
) < 0) {
395 log_error("%s: matchpathcon %07o failed: %s", path
, mode
,
400 log_debug("Setting SELinux context for %s to %s.", path
, scontext
);
402 if ((lsetfilecon(path
, scontext
) < 0) && (errno
!= ENOTSUP
)) {
403 log_sys_error("lsetfilecon", path
);
413 static int _add_dev_node(const char *dev_name
, uint32_t major
, uint32_t minor
,
414 uid_t uid
, gid_t gid
, mode_t mode
, int check_udev
)
418 dev_t dev
= MKDEV(major
, minor
);
422 char rpath
[PATH_MAX
];
425 char raw_devname
[DM_NAME_LEN
+1]; /* r + other device name */
427 nbsd_get_dm_major(&raw_major
,DM_CHAR_MAJOR
);
428 rdev
= MKDEV(raw_major
,minor
);
430 snprintf(raw_devname
,sizeof(raw_devname
),"r%s",dev_name
);
432 _build_dev_path(rpath
, sizeof(rpath
), raw_devname
);
434 if (stat(rpath
, &info
) >= 0) {
435 if (!S_ISCHR(info
.st_mode
)) {
436 log_error("A non-raw device file at '%s' "
437 "is already present", rpath
);
441 /* If right inode already exists we don't touch uid etc. */
442 if (info
.st_rdev
== rdev
)
445 if (unlink(rpath
) < 0) {
446 log_error("Unable to unlink device node for '%s'",
454 if (mknod(rpath
, S_IFCHR
| mode
, rdev
) < 0) {
455 log_error("Unable to make device node for '%s'", raw_devname
);
460 _build_dev_path(path
, sizeof(path
), dev_name
);
462 if (stat(path
, &info
) >= 0) {
463 if (!S_ISBLK(info
.st_mode
)) {
464 log_error("A non-block device file at '%s' "
465 "is already present", path
);
469 /* If right inode already exists we don't touch uid etc. */
470 if (info
.st_rdev
== dev
)
473 if (unlink(path
) < 0) {
474 log_error("Unable to unlink device node for '%s'",
478 } else if (dm_udev_get_sync_support() && check_udev
)
479 log_warn("%s not set up by udev: Falling back to direct "
480 "node creation.", path
);
483 if (mknod(path
, S_IFBLK
| mode
, dev
) < 0) {
485 log_error("Unable to make device node for '%s'", dev_name
);
490 if (chown(path
, uid
, gid
) < 0) {
491 log_sys_error("chown", path
);
495 log_debug("Created %s", path
);
497 if (!dm_set_selinux_context(path
, S_IFBLK
))
503 static int _rm_dev_node(const char *dev_name
, int check_udev
)
509 char rpath
[PATH_MAX
];
510 char raw_devname
[DM_NAME_LEN
+1]; /* r + other device name */
512 snprintf(raw_devname
,sizeof(raw_devname
),"r%s",dev_name
);
514 _build_dev_path(rpath
, sizeof(rpath
), raw_devname
);
516 if (stat(rpath
, &info
) < 0)
519 if (unlink(rpath
) < 0) {
520 log_error("Unable to unlink device node for '%s'", raw_devname
);
524 log_debug("Removed %s", rpath
);
527 _build_dev_path(path
, sizeof(path
), dev_name
);
529 if (stat(path
, &info
) < 0)
531 else if (dm_udev_get_sync_support() && check_udev
)
532 log_warn("Node %s was not removed by udev. "
533 "Falling back to direct node removal.", path
);
535 if (unlink(path
) < 0) {
536 log_error("Unable to unlink device node for '%s'", dev_name
);
540 log_debug("Removed %s", path
);
545 static int _rename_dev_node(const char *old_name
, const char *new_name
,
548 char oldpath
[PATH_MAX
];
549 char newpath
[PATH_MAX
];
553 char rpath
[PATH_MAX
];
554 char nrpath
[PATH_MAX
];
555 char raw_devname
[DM_NAME_LEN
+1]; /* r + other device name */
556 char nraw_devname
[DM_NAME_LEN
+1]; /* r + other device name */
558 snprintf(nraw_devname
,sizeof(raw_devname
),"r%s",new_name
);
559 snprintf(raw_devname
,sizeof(raw_devname
),"r%s",old_name
);
561 _build_dev_path(nrpath
, sizeof(nrpath
), nraw_devname
);
562 _build_dev_path(rpath
, sizeof(rpath
), raw_devname
);
564 if (stat(nrpath
, &info
) == 0) {
565 if (S_ISBLK(info
.st_mode
)) {
566 log_error("A block device file at '%s' "
567 "is present where raw device should be.", newpath
);
571 if (unlink(nrpath
) < 0) {
572 log_error("Unable to unlink device node for '%s'",
578 if (rename(rpath
, nrpath
) < 0) {
579 log_error("Unable to rename device node from '%s' to '%s'",
580 raw_devname
, nraw_devname
);
584 log_debug("Renamed %s to %s", rpath
, nrpath
);
588 _build_dev_path(oldpath
, sizeof(oldpath
), old_name
);
589 _build_dev_path(newpath
, sizeof(newpath
), new_name
);
591 if (stat(newpath
, &info
) == 0) {
592 if (!S_ISBLK(info
.st_mode
)) {
593 log_error("A non-block device file at '%s' "
594 "is already present", newpath
);
597 else if (dm_udev_get_sync_support() && check_udev
) {
598 if (stat(oldpath
, &info
) < 0 &&
600 /* assume udev already deleted this */
603 log_warn("The node %s should have been renamed to %s "
604 "by udev but old node is still present. "
605 "Falling back to direct old node removal.",
607 return _rm_dev_node(old_name
, 0);
611 if (unlink(newpath
) < 0) {
612 if (errno
== EPERM
) {
613 /* devfs, entry has already been renamed */
616 log_error("Unable to unlink device node for '%s'",
621 else if (dm_udev_get_sync_support() && check_udev
)
622 log_warn("The node %s should have been renamed to %s "
623 "by udev but new node is not present. "
624 "Falling back to direct node rename.",
627 if (rename(oldpath
, newpath
) < 0) {
628 log_error("Unable to rename device node from '%s' to '%s'",
633 log_debug("Renamed %s to %s", oldpath
, newpath
);
639 static int _open_dev_node(const char *dev_name
)
644 _build_dev_path(path
, sizeof(path
), dev_name
);
646 if ((fd
= open(path
, O_RDONLY
, 0)) < 0)
647 log_sys_error("open", path
);
652 int get_dev_node_read_ahead(const char *dev_name
, uint32_t *read_ahead
)
656 long read_ahead_long
;
659 log_error("Empty device name passed to BLKRAGET");
663 if ((fd
= _open_dev_node(dev_name
)) < 0)
666 if (ioctl(fd
, BLKRAGET
, &read_ahead_long
)) {
667 log_sys_error("BLKRAGET", dev_name
);
671 *read_ahead
= (uint32_t) read_ahead_long
;
672 log_debug("%s: read ahead is %" PRIu32
, dev_name
, *read_ahead
);
681 static int _set_read_ahead(const char *dev_name
, uint32_t read_ahead
)
685 long read_ahead_long
= (long) read_ahead
;
688 log_error("Empty device name passed to BLKRAGET");
692 if ((fd
= _open_dev_node(dev_name
)) < 0)
695 log_debug("%s: Setting read ahead to %" PRIu32
, dev_name
, read_ahead
);
697 if (ioctl(fd
, BLKRASET
, read_ahead_long
)) {
698 log_sys_error("BLKRASET", dev_name
);
708 static int _set_dev_node_read_ahead(const char *dev_name
, uint32_t read_ahead
,
709 uint32_t read_ahead_flags
)
711 uint32_t current_read_ahead
;
713 if (read_ahead
== DM_READ_AHEAD_AUTO
)
716 if (read_ahead
== DM_READ_AHEAD_NONE
)
719 if (read_ahead_flags
& DM_READ_AHEAD_MINIMUM_FLAG
) {
720 if (!get_dev_node_read_ahead(dev_name
, ¤t_read_ahead
))
723 if (current_read_ahead
> read_ahead
) {
724 log_debug("%s: retaining kernel read ahead of %" PRIu32
725 " (requested %" PRIu32
")",
726 dev_name
, current_read_ahead
, read_ahead
);
731 return _set_read_ahead(dev_name
, read_ahead
);
736 int get_dev_node_read_ahead(const char *dev_name
, uint32_t *read_ahead
)
743 static int _set_dev_node_read_ahead(const char *dev_name
, uint32_t read_ahead
,
744 uint32_t read_ahead_flags
)
757 static int _do_node_op(node_op_t type
, const char *dev_name
, uint32_t major
,
758 uint32_t minor
, uid_t uid
, gid_t gid
, mode_t mode
,
759 const char *old_name
, uint32_t read_ahead
,
760 uint32_t read_ahead_flags
, int check_udev
)
764 return _add_dev_node(dev_name
, major
, minor
, uid
, gid
,
767 return _rm_dev_node(dev_name
, check_udev
);
769 return _rename_dev_node(old_name
, dev_name
, check_udev
);
770 case NODE_READ_AHEAD
:
771 return _set_dev_node_read_ahead(dev_name
, read_ahead
,
778 static DM_LIST_INIT(_node_ops
);
780 struct node_op_parms
{
790 uint32_t read_ahead_flags
;
796 static void _store_str(char **pos
, char **ptr
, const char *str
)
800 *pos
+= strlen(*ptr
) + 1;
803 static int _stack_node_op(node_op_t type
, const char *dev_name
, uint32_t major
,
804 uint32_t minor
, uid_t uid
, gid_t gid
, mode_t mode
,
805 const char *old_name
, uint32_t read_ahead
,
806 uint32_t read_ahead_flags
, int check_udev
)
808 struct node_op_parms
*nop
;
809 struct dm_list
*noph
, *nopht
;
810 size_t len
= strlen(dev_name
) + strlen(old_name
) + 2;
814 * Ignore any outstanding operations on the node if deleting it
816 if (type
== NODE_DEL
) {
817 dm_list_iterate_safe(noph
, nopht
, &_node_ops
) {
818 nop
= dm_list_item(noph
, struct node_op_parms
);
819 if (!strcmp(dev_name
, nop
->dev_name
)) {
820 dm_list_del(&nop
->list
);
826 if (!(nop
= dm_malloc(sizeof(*nop
) + len
))) {
827 log_error("Insufficient memory to stack mknod operation");
838 nop
->read_ahead
= read_ahead
;
839 nop
->read_ahead_flags
= read_ahead_flags
;
840 nop
->check_udev
= check_udev
;
842 _store_str(&pos
, &nop
->dev_name
, dev_name
);
843 _store_str(&pos
, &nop
->old_name
, old_name
);
845 dm_list_add(&_node_ops
, &nop
->list
);
850 static void _pop_node_ops(void)
852 struct dm_list
*noph
, *nopht
;
853 struct node_op_parms
*nop
;
855 dm_list_iterate_safe(noph
, nopht
, &_node_ops
) {
856 nop
= dm_list_item(noph
, struct node_op_parms
);
857 _do_node_op(nop
->type
, nop
->dev_name
, nop
->major
, nop
->minor
,
858 nop
->uid
, nop
->gid
, nop
->mode
, nop
->old_name
,
859 nop
->read_ahead
, nop
->read_ahead_flags
,
861 dm_list_del(&nop
->list
);
866 int add_dev_node(const char *dev_name
, uint32_t major
, uint32_t minor
,
867 uid_t uid
, gid_t gid
, mode_t mode
, int check_udev
)
869 log_debug("%s: Stacking NODE_ADD (%" PRIu32
",%" PRIu32
") %u:%u 0%o",
870 dev_name
, major
, minor
, uid
, gid
, mode
);
872 return _stack_node_op(NODE_ADD
, dev_name
, major
, minor
, uid
,
873 gid
, mode
, "", 0, 0, check_udev
);
876 int rename_dev_node(const char *old_name
, const char *new_name
, int check_udev
)
878 log_debug("%s: Stacking NODE_RENAME to %s", old_name
, new_name
);
880 return _stack_node_op(NODE_RENAME
, new_name
, 0, 0, 0,
881 0, 0, old_name
, 0, 0, check_udev
);
884 int rm_dev_node(const char *dev_name
, int check_udev
)
886 log_debug("%s: Stacking NODE_DEL (replaces other stacked ops)", dev_name
);
888 return _stack_node_op(NODE_DEL
, dev_name
, 0, 0, 0,
889 0, 0, "", 0, 0, check_udev
);
892 int set_dev_node_read_ahead(const char *dev_name
, uint32_t read_ahead
,
893 uint32_t read_ahead_flags
)
895 if (read_ahead
== DM_READ_AHEAD_AUTO
)
898 log_debug("%s: Stacking NODE_READ_AHEAD %" PRIu32
" (flags=%" PRIu32
899 ")", dev_name
, read_ahead
, read_ahead_flags
);
901 return _stack_node_op(NODE_READ_AHEAD
, dev_name
, 0, 0, 0, 0,
902 0, "", read_ahead
, read_ahead_flags
, 0);
905 void update_devs(void)
910 int dm_set_dev_dir(const char *dev_dir
)
914 if (*dev_dir
!= '/') {
915 log_debug("Invalid dev_dir value, %s: "
916 "not an absolute name.", dev_dir
);
920 len
= strlen(dev_dir
);
921 slash
= dev_dir
[len
-1] == '/' ? "" : "/";
923 if (snprintf(_dm_dir
, sizeof _dm_dir
, "%s%s%s", dev_dir
, slash
, DM_DIR
)
925 log_debug("Invalid dev_dir value, %s: name too long.", dev_dir
);
932 const char *dm_dir(void)
937 int dm_mknodes(const char *name
)
942 if (!(dmt
= dm_task_create(DM_DEVICE_MKNODES
)))
945 if (name
&& !dm_task_set_name(dmt
, name
))
948 if (!dm_task_no_open_count(dmt
))
951 r
= dm_task_run(dmt
);
954 dm_task_destroy(dmt
);
958 int dm_driver_version(char *version
, size_t size
)
963 if (!(dmt
= dm_task_create(DM_DEVICE_VERSION
)))
966 if (!dm_task_run(dmt
))
967 log_error("Failed to get driver version");
969 if (!dm_task_get_driver_version(dmt
, version
, size
))
975 dm_task_destroy(dmt
);
979 #ifndef UDEV_SYNC_SUPPORT
980 void dm_udev_set_sync_support(int sync_with_udev
)
984 int dm_udev_get_sync_support(void)
989 int dm_task_set_cookie(struct dm_task
*dmt
, uint32_t *cookie
, uint16_t flags
)
991 if (dm_cookie_supported())
992 dmt
->event_nr
= flags
<< DM_UDEV_FLAGS_SHIFT
;
998 int dm_udev_complete(uint32_t cookie
)
1003 int dm_udev_wait(uint32_t cookie
)
1008 #else /* UDEV_SYNC_SUPPORT */
1011 static int _check_udev_is_running(void)
1014 # ifndef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE
1016 log_debug("Could not get udev state because libudev library "
1017 "was not found and it was not compiled in. "
1018 "Assuming udev is not running.");
1021 # else /* HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE */
1024 struct udev_queue
*udev_queue
;
1027 if (!(udev
= udev_new()))
1030 if (!(udev_queue
= udev_queue_new(udev
))) {
1035 if (!(r
= udev_queue_get_udev_is_active(udev_queue
)))
1036 log_debug("Udev is not running. "
1037 "Not using udev synchronisation code.");
1039 udev_queue_unref(udev_queue
);
1045 log_error("Could not get udev state. Assuming udev is not running.");
1048 # endif /* HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE */
1052 void dm_udev_set_sync_support(int sync_with_udev
)
1054 if (_udev_running
< 0)
1055 _udev_running
= _check_udev_is_running();
1057 _sync_with_udev
= sync_with_udev
;
1060 int dm_udev_get_sync_support(void)
1062 if (_udev_running
< 0)
1063 _udev_running
= _check_udev_is_running();
1065 return dm_cookie_supported() && _udev_running
&& _sync_with_udev
;
1068 static int _get_cookie_sem(uint32_t cookie
, int *semid
)
1070 if (cookie
>> 16 != DM_COOKIE_MAGIC
) {
1071 log_error("Could not continue to access notification "
1072 "semaphore identified by cookie value %"
1073 PRIu32
" (0x%x). Incorrect cookie prefix.",
1078 if ((*semid
= semget((key_t
) cookie
, 1, 0)) >= 0)
1083 log_error("Could not find notification "
1084 "semaphore identified by cookie "
1085 "value %" PRIu32
" (0x%x)",
1089 log_error("No permission to access "
1090 "notificaton semaphore identified "
1091 "by cookie value %" PRIu32
" (0x%x)",
1095 log_error("Failed to access notification "
1096 "semaphore identified by cookie "
1097 "value %" PRIu32
" (0x%x): %s",
1098 cookie
, cookie
, strerror(errno
));
1105 static int _udev_notify_sem_inc(uint32_t cookie
, int semid
)
1107 struct sembuf sb
= {0, 1, 0};
1109 if (semop(semid
, &sb
, 1) < 0) {
1110 log_error("semid %d: semop failed for cookie 0x%" PRIx32
": %s",
1111 semid
, cookie
, strerror(errno
));
1115 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) incremented",
1121 static int _udev_notify_sem_dec(uint32_t cookie
, int semid
)
1123 struct sembuf sb
= {0, -1, IPC_NOWAIT
};
1125 if (semop(semid
, &sb
, 1) < 0) {
1128 log_error("semid %d: semop failed for cookie "
1130 "incorrect semaphore state",
1134 log_error("semid %d: semop failed for cookie "
1135 "0x%" PRIx32
": %s",
1136 semid
, cookie
, strerror(errno
));
1142 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) decremented",
1148 static int _udev_notify_sem_destroy(uint32_t cookie
, int semid
)
1150 if (semctl(semid
, 0, IPC_RMID
, 0) < 0) {
1151 log_error("Could not cleanup notification semaphore "
1152 "identified by cookie value %" PRIu32
" (0x%x): %s",
1153 cookie
, cookie
, strerror(errno
));
1157 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) destroyed", cookie
,
1163 static int _udev_notify_sem_create(uint32_t *cookie
, int *semid
)
1167 uint16_t base_cookie
;
1168 uint32_t gen_cookie
;
1170 if ((fd
= open("/dev/urandom", O_RDONLY
)) < 0) {
1171 log_error("Failed to open /dev/urandom "
1172 "to create random cookie value");
1177 /* Generate random cookie value. Be sure it is unique and non-zero. */
1179 /* FIXME Handle non-error returns from read(). Move _io() into libdm? */
1180 if (read(fd
, &base_cookie
, sizeof(base_cookie
)) != sizeof(base_cookie
)) {
1181 log_error("Failed to initialize notification cookie");
1185 gen_cookie
= DM_COOKIE_MAGIC
<< 16 | base_cookie
;
1187 if (base_cookie
&& (gen_semid
= semget((key_t
) gen_cookie
,
1188 1, 0600 | IPC_CREAT
| IPC_EXCL
)) < 0) {
1191 /* if the semaphore key exists, we
1192 * simply generate another random one */
1196 log_error("Not enough memory to create "
1197 "notification semaphore");
1200 log_error("Limit for the maximum number "
1201 "of semaphores reached. You can "
1202 "check and set the limits in "
1203 "/proc/sys/kernel/sem.");
1206 log_error("Failed to create notification "
1207 "semaphore: %s", strerror(errno
));
1211 } while (!base_cookie
);
1213 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) created",
1214 gen_cookie
, gen_semid
);
1216 if (semctl(gen_semid
, 0, SETVAL
, 1) < 0) {
1217 log_error("semid %d: semctl failed: %s", gen_semid
, strerror(errno
));
1218 /* We have to destroy just created semaphore
1219 * so it won't stay in the system. */
1220 (void) _udev_notify_sem_destroy(gen_cookie
, gen_semid
);
1224 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) incremented",
1225 gen_cookie
, gen_semid
);
1231 *cookie
= gen_cookie
;
1244 int dm_task_set_cookie(struct dm_task
*dmt
, uint32_t *cookie
, uint16_t flags
)
1248 if (dm_cookie_supported())
1249 dmt
->event_nr
= flags
<< DM_UDEV_FLAGS_SHIFT
;
1251 if (!dm_udev_get_sync_support()) {
1257 if (!_get_cookie_sem(*cookie
, &semid
))
1259 } else if (!_udev_notify_sem_create(cookie
, &semid
))
1262 if (!_udev_notify_sem_inc(*cookie
, semid
)) {
1263 log_error("Could not set notification semaphore "
1264 "identified by cookie value %" PRIu32
" (0x%x)",
1269 dmt
->event_nr
|= ~DM_UDEV_FLAGS_MASK
& *cookie
;
1270 dmt
->cookie_set
= 1;
1272 log_debug("Udev cookie 0x%" PRIx32
" (semid %d) assigned to dm_task "
1273 "with flags 0x%" PRIx16
, *cookie
, semid
, flags
);
1282 int dm_udev_complete(uint32_t cookie
)
1286 if (!cookie
|| !dm_udev_get_sync_support())
1289 if (!_get_cookie_sem(cookie
, &semid
))
1292 if (!_udev_notify_sem_dec(cookie
, semid
)) {
1293 log_error("Could not signal waiting process using notification "
1294 "semaphore identified by cookie value %" PRIu32
" (0x%x)",
1302 int dm_udev_wait(uint32_t cookie
)
1305 struct sembuf sb
= {0, 0, 0};
1307 if (!cookie
|| !dm_udev_get_sync_support())
1310 if (!_get_cookie_sem(cookie
, &semid
))
1313 if (!_udev_notify_sem_dec(cookie
, semid
)) {
1314 log_error("Failed to set a proper state for notification "
1315 "semaphore identified by cookie value %" PRIu32
" (0x%x) "
1316 "to initialize waiting for incoming notifications.",
1318 (void) _udev_notify_sem_destroy(cookie
, semid
);
1322 log_debug("Udev cookie 0x%" PRIx32
" (semid %d): Waiting for zero",
1326 if (semop(semid
, &sb
, 1) < 0) {
1329 else if (errno
== EIDRM
)
1332 log_error("Could not set wait state for notification semaphore "
1333 "identified by cookie value %" PRIu32
" (0x%x): %s",
1334 cookie
, cookie
, strerror(errno
));
1335 (void) _udev_notify_sem_destroy(cookie
, semid
);
1339 return _udev_notify_sem_destroy(cookie
, semid
);
1342 #endif /* UDEV_SYNC_SUPPORT */