LCOV - code coverage report
Current view: directory - libdm - libdm-common.c (source / functions) Found Hit Coverage
Test: unnamed Lines: 524 131 25.0 %
Date: 2010-04-13 Functions: 55 21 38.2 %

       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            3315 : 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            3315 :         int use_stderr = level & _LOG_STDERR;
      67                 : 
      68            3315 :         level &= ~_LOG_STDERR;
      69                 : 
      70            3315 :         if (level > _LOG_WARN && !_verbose)
      71            3315 :                 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            3315 : 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            3315 :         va_start(ap, f);
      92            3315 :         _default_log_line(level, file, line, dm_errno, f, ap);
      93            3315 :         va_end(ap);
      94            3315 : }
      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            3318 : int dm_log_is_non_default(void)
     120                 : {
     121            3318 :         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            1810 : struct dm_task *dm_task_create(int type)
     155                 : {
     156            1810 :         struct dm_task *dmt = dm_malloc(sizeof(*dmt));
     157                 : 
     158            1810 :         if (!dmt) {
     159               0 :                 log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
     160                 :                           sizeof(*dmt));
     161               0 :                 return NULL;
     162                 :         }
     163                 : 
     164            1810 :         if (!dm_check_version()) {
     165               0 :                 dm_free(dmt);
     166               0 :                 return NULL;
     167                 :         }
     168                 : 
     169            1810 :         memset(dmt, 0, sizeof(*dmt));
     170                 : 
     171            1810 :         dmt->type = type;
     172            1810 :         dmt->minor = -1;
     173            1810 :         dmt->major = -1;
     174            1810 :         dmt->allow_default_major_fallback = 1;
     175            1810 :         dmt->uid = DM_DEVICE_UID;
     176            1810 :         dmt->gid = DM_DEVICE_GID;
     177            1810 :         dmt->mode = DM_DEVICE_MODE;
     178            1810 :         dmt->no_open_count = 0;
     179            1810 :         dmt->read_ahead = DM_READ_AHEAD_AUTO;
     180            1810 :         dmt->read_ahead_flags = 0;
     181            1810 :         dmt->event_nr = 0;
     182            1810 :         dmt->cookie_set = 0;
     183            1810 :         dmt->query_inactive_table = 0;
     184                 : 
     185            1810 :         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            1506 : int dm_task_set_name(struct dm_task *dmt, const char *name)
     235                 : {
     236                 :         char *pos;
     237            1506 :         char *new_name = NULL;
     238                 :         char path[PATH_MAX];
     239                 :         struct stat st1, st2;
     240                 : 
     241            1506 :         if (dmt->dev_name) {
     242             300 :                 dm_free(dmt->dev_name);
     243             300 :                 dmt->dev_name = NULL;
     244                 :         }
     245                 : 
     246                 :         /*
     247                 :          * Path supplied for existing device?
     248                 :          */
     249            1506 :         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            1506 :         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            1506 :         if (new_name)
     289               0 :                 dmt->dev_name = new_name;
     290            1506 :         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            1506 :         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             301 : int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
     360                 :                        const char *ttype, const char *params)
     361                 : {
     362             301 :         struct target *t = create_target(start, size, ttype, params);
     363                 : 
     364             301 :         if (!t)
     365               0 :                 return 0;
     366                 : 
     367             301 :         if (!dmt->head)
     368             301 :                 dmt->head = dmt->tail = t;
     369                 :         else {
     370               0 :                 dmt->tail->next = t;
     371               0 :                 dmt->tail = t;
     372                 :         }
     373                 : 
     374             301 :         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, &current_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            1204 : static void _store_str(char **pos, char **ptr, const char *str)
     698                 : {
     699            1204 :         strcpy(*pos, str);
     700            1204 :         *ptr = *pos;
     701            1204 :         *pos += strlen(*ptr) + 1;
     702            1204 : }
     703                 : 
     704             602 : 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             602 :         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             602 :         if (type == NODE_DEL) {
     718           45451 :                 dm_list_iterate_safe(noph, nopht, &_node_ops) {
     719           45150 :                         nop = dm_list_item(noph, struct node_op_parms);
     720           45150 :                         if (!strcmp(dev_name, nop->dev_name)) {
     721               0 :                                 dm_list_del(&nop->list);
     722               0 :                                 dm_free(nop);
     723                 :                         }
     724                 :                 }
     725                 :         }
     726                 : 
     727             602 :         if (!(nop = dm_malloc(sizeof(*nop) + len))) {
     728               0 :                 log_error("Insufficient memory to stack mknod operation");
     729               0 :                 return 0;
     730                 :         }
     731                 : 
     732             602 :         pos = nop->names;
     733             602 :         nop->type = type;
     734             602 :         nop->major = major;
     735             602 :         nop->minor = minor;
     736             602 :         nop->uid = uid;
     737             602 :         nop->gid = gid;
     738             602 :         nop->mode = mode;
     739             602 :         nop->read_ahead = read_ahead;
     740             602 :         nop->read_ahead_flags = read_ahead_flags;
     741             602 :         nop->check_udev = check_udev;
     742                 : 
     743             602 :         _store_str(&pos, &nop->dev_name, dev_name);
     744             602 :         _store_str(&pos, &nop->old_name, old_name);
     745                 : 
     746             602 :         dm_list_add(&_node_ops, &nop->list);
     747                 : 
     748             602 :         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             301 : 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             301 :         log_debug("%s: Stacking NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o",
     771                 :                   dev_name, major, minor, uid, gid, mode);
     772                 : 
     773             301 :         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             301 : int rm_dev_node(const char *dev_name, int check_udev)
     786                 : {
     787             301 :         log_debug("%s: Stacking NODE_DEL (replaces other stacked ops)", dev_name);
     788                 : 
     789             301 :         return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0,
     790                 :                               0, 0, "", 0, 0, check_udev);
     791                 : }
     792                 : 
     793             602 : int set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
     794                 :                             uint32_t read_ahead_flags)
     795                 : {
     796             602 :         if (read_ahead == DM_READ_AHEAD_AUTO)
     797             602 :                 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             604 : const char *dm_dir(void)
     834                 : {
     835             604 :         return _dm_dir;
     836                 : }
     837                 : 
     838               1 : int dm_mknodes(const char *name)
     839                 : {
     840                 :         struct dm_task *dmt;
     841               1 :         int r = 0;
     842                 : 
     843               1 :         if (!(dmt = dm_task_create(DM_DEVICE_MKNODES)))
     844               0 :                 return 0;
     845                 : 
     846               1 :         if (name && !dm_task_set_name(dmt, name))
     847               0 :                 goto out;
     848                 : 
     849               1 :         if (!dm_task_no_open_count(dmt))
     850               0 :                 goto out;
     851                 : 
     852               1 :         r = dm_task_run(dmt);
     853                 : 
     854                 : out:
     855               1 :         dm_task_destroy(dmt);
     856               1 :         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             603 : static int _check_udev_is_running(void)
     922                 : {
     923                 :         struct udev *udev;
     924                 :         struct udev_queue *udev_queue;
     925                 :         int r;
     926                 : 
     927             603 :         if (!(udev = udev_new()))
     928               0 :                 goto_bad;
     929                 : 
     930             603 :         if (!(udev_queue = udev_queue_new(udev))) {
     931               0 :                 udev_unref(udev);
     932               0 :                 goto_bad;
     933                 :         }
     934                 : 
     935             603 :         if (!(r = udev_queue_get_udev_is_active(udev_queue)))
     936             603 :                 log_debug("Udev is not running. "
     937                 :                           "Not using udev synchronisation code.");
     938                 : 
     939             603 :         udev_queue_unref(udev_queue);
     940             603 :         udev_unref(udev);
     941                 : 
     942             603 :         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            2712 : int dm_udev_get_sync_support(void)
     958                 : {
     959            2712 :         if (_udev_running < 0)
     960             603 :                 _udev_running = _check_udev_is_running();
     961                 : 
     962            2712 :         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             602 : int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
    1167                 : {
    1168                 :         int semid;
    1169                 : 
    1170             602 :         if (dm_cookie_supported())
    1171             602 :                 dmt->event_nr = flags << DM_UDEV_FLAGS_SHIFT;
    1172                 : 
    1173             602 :         if (!dm_udev_get_sync_support()) {
    1174             602 :                 *cookie = 0;
    1175             602 :                 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             602 : int dm_udev_wait(uint32_t cookie)
    1225                 : {
    1226                 :         int semid;
    1227             602 :         struct sembuf sb = {0, 0, 0};
    1228                 : 
    1229             602 :         if (!cookie || !dm_udev_get_sync_support())
    1230             602 :                 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 */

Generated by: LCOV version 1.7