/src/lvm2/libdm/libdm-common.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  | 
3  |  |  * Copyright (C) 2004-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  | 
14  |  |  */  | 
15  |  |  | 
16  |  | #include "libdm/misc/dmlib.h"  | 
17  |  | #include "libdm/ioctl/libdm-targets.h"  | 
18  |  | #include "libdm-common.h"  | 
19  |  | #include "libdm/misc/kdev_t.h"  | 
20  |  | #include "libdm/misc/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  |  | #  include <libudev.h>  | 
33  |  | #endif  | 
34  |  |  | 
35  |  | #ifdef __linux__  | 
36  |  | #  include <linux/fs.h>  | 
37  |  | #endif  | 
38  |  |  | 
39  |  | #ifdef HAVE_SELINUX  | 
40  |  | #  include <selinux/selinux.h>  | 
41  |  | #endif  | 
42  |  | #ifdef HAVE_SELINUX_LABEL_H  | 
43  |  | #  include <selinux/label.h>  | 
44  |  | #endif  | 
45  |  |  | 
46  | 6  | #define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"  | 
47  |  |  | 
48  |  | #define DEV_DIR "/dev/"  | 
49  |  |  | 
50  |  | #ifdef UDEV_SYNC_SUPPORT  | 
51  |  | #ifdef _SEM_SEMUN_UNDEFINED  | 
52  |  | union semun  | 
53  |  | { | 
54  |  |   int val;      /* value for SETVAL */  | 
55  |  |   struct semid_ds *buf;   /* buffer for IPC_STAT & IPC_SET */  | 
56  |  |   unsigned short int *array;  /* array for GETALL & SETALL */  | 
57  |  |   struct seminfo *__buf;    /* buffer for IPC_INFO */  | 
58  |  | };  | 
59  |  | #endif  | 
60  |  | #endif  | 
61  |  |  | 
62  |  | static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;  | 
63  |  | static char _sysfs_dir[PATH_MAX] = "/sys/";  | 
64  |  | static char _path0[PATH_MAX];           /* path buffer, safe 4kB on stack */  | 
65  |  | static const char _mountinfo[] = "/proc/self/mountinfo";  | 
66  |  |  | 
67  | 0  | #define DM_MAX_UUID_PREFIX_LEN  15  | 
68  |  | static char _default_uuid_prefix[DM_MAX_UUID_PREFIX_LEN + 1] = "LVM-";  | 
69  |  |  | 
70  |  | static int _verbose = 0;  | 
71  |  | static int _suspended_dev_counter = 0;  | 
72  |  | static dm_string_mangling_t _name_mangling_mode = DEFAULT_DM_NAME_MANGLING;  | 
73  |  |  | 
74  |  | #ifdef HAVE_SELINUX_LABEL_H  | 
75  |  | static struct selabel_handle *_selabel_handle = NULL;  | 
76  |  | #endif  | 
77  |  |  | 
78  |  | static int _udev_disabled = 0;  | 
79  |  |  | 
80  |  | #ifdef UDEV_SYNC_SUPPORT  | 
81  |  | static int _semaphore_supported = -1;  | 
82  |  | static int _udev_running = -1;  | 
83  |  | static int _sync_with_udev = 1;  | 
84  |  | static int _udev_checking = 1;  | 
85  |  | #endif  | 
86  |  |  | 
87  |  | void dm_lib_init(void)  | 
88  | 6  | { | 
89  | 6  |   const char *env;  | 
90  |  |  | 
91  | 6  |   if (getenv("DM_DISABLE_UDEV")) | 
92  | 0  |     _udev_disabled = 1;  | 
93  |  |  | 
94  | 6  |   _name_mangling_mode = DEFAULT_DM_NAME_MANGLING;  | 
95  | 6  |   if ((env = getenv(DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME))) { | 
96  | 0  |     if (!strcasecmp(env, "none"))  | 
97  | 0  |       _name_mangling_mode = DM_STRING_MANGLING_NONE;  | 
98  | 0  |     else if (!strcasecmp(env, "auto"))  | 
99  | 0  |       _name_mangling_mode = DM_STRING_MANGLING_AUTO;  | 
100  | 0  |     else if (!strcasecmp(env, "hex"))  | 
101  | 0  |       _name_mangling_mode = DM_STRING_MANGLING_HEX;  | 
102  | 0  |   }  | 
103  | 6  | }  | 
104  |  |  | 
105  |  | /*  | 
106  |  |  * Library users can provide their own logging  | 
107  |  |  * function.  | 
108  |  |  */  | 
109  |  |  | 
110  |  | __attribute__((format(printf, 5, 0)))  | 
111  |  | static void _default_log_line(int level, const char *file,  | 
112  |  |             int line, int dm_errno_or_class,  | 
113  |  |             const char *f, va_list ap)  | 
114  | 0  | { | 
115  | 0  |   static int _abort_on_internal_errors = -1;  | 
116  | 0  |   static int _debug_with_line_numbers = -1;  | 
117  | 0  |   FILE *out = log_stderr(level) ? stderr : stdout;  | 
118  |  | 
  | 
119  | 0  |   level = log_level(level);  | 
120  |  | 
  | 
121  | 0  |   if (level <= _LOG_WARN || _verbose) { | 
122  | 0  |     if (level < _LOG_WARN)  | 
123  | 0  |       out = stderr;  | 
124  |  | 
  | 
125  | 0  |     if (_debug_with_line_numbers < 0)  | 
126  |  |       /* Set when env DM_DEBUG_WITH_LINE_NUMBERS is not "0" */  | 
127  | 0  |       _debug_with_line_numbers =  | 
128  | 0  |         strcmp(getenv("DM_DEBUG_WITH_LINE_NUMBERS") ? : "0", "0"); | 
129  |  | 
  | 
130  | 0  |     if (_debug_with_line_numbers)  | 
131  | 0  |       fprintf(out, "%s:%d     ", file, line);  | 
132  |  | 
  | 
133  | 0  |     vfprintf(out, f, ap);  | 
134  | 0  |     fputc('\n', out); | 
135  | 0  |   }  | 
136  |  | 
  | 
137  | 0  |   if (_abort_on_internal_errors < 0)  | 
138  |  |     /* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */  | 
139  | 0  |     _abort_on_internal_errors =  | 
140  | 0  |       strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0"); | 
141  |  | 
  | 
142  | 0  |   if (_abort_on_internal_errors &&  | 
143  | 0  |       !strncmp(f, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))  | 
144  | 0  |     abort();  | 
145  | 0  | }  | 
146  |  |  | 
147  |  | __attribute__((format(printf, 5, 6)))  | 
148  |  | static void _default_log_with_errno(int level,  | 
149  |  |       const char *file, int line, int dm_errno_or_class,  | 
150  |  |       const char *f, ...)  | 
151  | 0  | { | 
152  | 0  |   va_list ap;  | 
153  |  | 
  | 
154  | 0  |   va_start(ap, f);  | 
155  | 0  |   _default_log_line(level, file, line, dm_errno_or_class, f, ap);  | 
156  | 0  |   va_end(ap);  | 
157  | 0  | }  | 
158  |  |  | 
159  |  | __attribute__((format(printf, 4, 5)))  | 
160  |  | static void _default_log(int level, const char *file,  | 
161  |  |        int line, const char *f, ...)  | 
162  | 0  | { | 
163  | 0  |   va_list ap;  | 
164  |  | 
  | 
165  | 0  |   va_start(ap, f);  | 
166  | 0  |   _default_log_line(level, file, line, 0, f, ap);  | 
167  | 0  |   va_end(ap);  | 
168  | 0  | }  | 
169  |  |  | 
170  |  | dm_log_fn dm_log = _default_log;  | 
171  |  | dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno;  | 
172  |  |  | 
173  |  | /*  | 
174  |  |  * Wrapper function to reformat new messages to and  | 
175  |  |  * old style logging which had not used errno parameter  | 
176  |  |  *  | 
177  |  |  * As we cannot simply pass '...' to old function we  | 
178  |  |  * need to process arg list locally and just pass '%s' + buffer  | 
179  |  |  */  | 
180  |  | __attribute__((format(printf, 5, 6)))  | 
181  |  | static void _log_to_default_log(int level,  | 
182  |  |       const char *file, int line, int dm_errno_or_class,  | 
183  |  |       const char *f, ...)  | 
184  | 0  | { | 
185  | 0  |   int n;  | 
186  | 0  |   va_list ap;  | 
187  | 0  |   char buf[2 * PATH_MAX + 256]; /* big enough for most messages */  | 
188  |  | 
  | 
189  | 0  |   va_start(ap, f);  | 
190  | 0  |   n = vsnprintf(buf, sizeof(buf), f, ap);  | 
191  | 0  |   va_end(ap);  | 
192  |  | 
  | 
193  | 0  |   if (n > 0) /* Could be truncated */  | 
194  | 0  |     dm_log(level, file, line, "%s", buf);  | 
195  | 0  | }  | 
196  |  |  | 
197  |  | /*  | 
198  |  |  * Wrapper function take 'old' style message without errno  | 
199  |  |  * and log it via new logging function with errno arg  | 
200  |  |  *  | 
201  |  |  * This minor case may happen if new libdm is used with old  | 
202  |  |  * recompiled tool that would decided to use new logging,  | 
203  |  |  * but still would like to use old binary plugins.  | 
204  |  |  */  | 
205  |  | __attribute__((format(printf, 4, 5)))  | 
206  |  | static void _log_to_default_log_with_errno(int level,  | 
207  |  |       const char *file, int line, const char *f, ...)  | 
208  | 0  | { | 
209  | 0  |   int n;  | 
210  | 0  |   va_list ap;  | 
211  | 0  |   char buf[2 * PATH_MAX + 256]; /* big enough for most messages */  | 
212  |  | 
  | 
213  | 0  |   va_start(ap, f);  | 
214  | 0  |   n = vsnprintf(buf, sizeof(buf), f, ap);  | 
215  | 0  |   va_end(ap);  | 
216  |  | 
  | 
217  | 0  |   if (n > 0) /* Could be truncated */  | 
218  | 0  |     dm_log_with_errno(level, file, line, 0, "%s", buf);  | 
219  | 0  | }  | 
220  |  |  | 
221  |  | void dm_log_init(dm_log_fn fn)  | 
222  | 22.5k  | { | 
223  | 22.5k  |   if (fn)  { | 
224  | 11.2k  |     dm_log = fn;  | 
225  | 11.2k  |     dm_log_with_errno = _log_to_default_log;  | 
226  | 11.2k  |   } else { | 
227  | 11.2k  |     dm_log = _default_log;  | 
228  | 11.2k  |     dm_log_with_errno = _default_log_with_errno;  | 
229  | 11.2k  |   }  | 
230  | 22.5k  | }  | 
231  |  |  | 
232  |  | int dm_log_is_non_default(void)  | 
233  | 0  | { | 
234  | 0  |   return (dm_log == _default_log && dm_log_with_errno == _default_log_with_errno) ? 0 : 1;  | 
235  | 0  | }  | 
236  |  |  | 
237  |  | void dm_log_with_errno_init(dm_log_with_errno_fn fn)  | 
238  | 0  | { | 
239  | 0  |   if (fn) { | 
240  | 0  |     dm_log = _log_to_default_log_with_errno;  | 
241  | 0  |     dm_log_with_errno = fn;  | 
242  | 0  |   } else { | 
243  | 0  |     dm_log = _default_log;  | 
244  | 0  |     dm_log_with_errno = _default_log_with_errno;  | 
245  | 0  |   }  | 
246  | 0  | }  | 
247  |  |  | 
248  |  | void dm_log_init_verbose(int level)  | 
249  | 22.5k  | { | 
250  | 22.5k  |   _verbose = level;  | 
251  | 22.5k  | }  | 
252  |  |  | 
253  |  | static int _build_dev_path(char *buffer, size_t len, const char *dev_name)  | 
254  | 0  | { | 
255  | 0  |   int r;  | 
256  |  |  | 
257  |  |   /* If there's a /, assume caller knows what they're doing */  | 
258  | 0  |   if (strchr(dev_name, '/'))  | 
259  | 0  |     r = dm_strncpy(buffer, dev_name, len);  | 
260  | 0  |   else  | 
261  | 0  |     r = (dm_snprintf(buffer, len, "%s/%s",  | 
262  | 0  |          _dm_dir, dev_name) < 0) ? 0 : 1;  | 
263  | 0  |   if (!r)  | 
264  | 0  |     log_error("Failed to build dev path for \"%s\".", dev_name); | 
265  |  | 
  | 
266  | 0  |   return r;  | 
267  | 0  | }  | 
268  |  |  | 
269  |  | int dm_get_library_version(char *version, size_t size)  | 
270  | 0  | { | 
271  | 0  |   return dm_strncpy(version, DM_LIB_VERSION, size);  | 
272  | 0  | }  | 
273  |  |  | 
274  |  | void inc_suspended(void)  | 
275  | 0  | { | 
276  | 0  |   _suspended_dev_counter++;  | 
277  | 0  |   log_debug_activation("Suspended device counter increased to %d", _suspended_dev_counter); | 
278  | 0  | }  | 
279  |  |  | 
280  |  | void dec_suspended(void)  | 
281  | 0  | { | 
282  | 0  |   if (!_suspended_dev_counter) { | 
283  | 0  |     log_error("Attempted to decrement suspended device counter below zero."); | 
284  | 0  |     return;  | 
285  | 0  |   }  | 
286  |  |  | 
287  | 0  |   _suspended_dev_counter--;  | 
288  | 0  |   log_debug_activation("Suspended device counter reduced to %d", _suspended_dev_counter); | 
289  | 0  | }  | 
290  |  |  | 
291  |  | int dm_get_suspended_counter(void)  | 
292  | 0  | { | 
293  | 0  |   return _suspended_dev_counter;  | 
294  | 0  | }  | 
295  |  |  | 
296  |  | int dm_set_name_mangling_mode(dm_string_mangling_t name_mangling_mode)  | 
297  | 0  | { | 
298  | 0  |   _name_mangling_mode = name_mangling_mode;  | 
299  |  | 
  | 
300  | 0  |   return 1;  | 
301  | 0  | }  | 
302  |  |  | 
303  |  | dm_string_mangling_t dm_get_name_mangling_mode(void)  | 
304  | 0  | { | 
305  | 0  |   return _name_mangling_mode;  | 
306  | 0  | }  | 
307  |  |  | 
308  |  | struct dm_task *dm_task_create(int type)  | 
309  | 0  | { | 
310  | 0  |   struct dm_task *dmt = dm_zalloc(sizeof(*dmt));  | 
311  |  | 
  | 
312  | 0  |   if (!dmt) { | 
313  | 0  |     log_error("dm_task_create: malloc(%" PRIsize_t ") failed", | 
314  | 0  |         sizeof(*dmt));  | 
315  | 0  |     return NULL;  | 
316  | 0  |   }  | 
317  |  |  | 
318  | 0  |   if (!dm_check_version()) { | 
319  | 0  |     dm_free(dmt);  | 
320  | 0  |     return_NULL;  | 
321  | 0  |   }  | 
322  |  |  | 
323  | 0  |   dmt->type = type;  | 
324  | 0  |   dmt->minor = -1;  | 
325  | 0  |   dmt->major = -1;  | 
326  | 0  |   dmt->allow_default_major_fallback = 1;  | 
327  | 0  |   dmt->uid = DM_DEVICE_UID;  | 
328  | 0  |   dmt->gid = DM_DEVICE_GID;  | 
329  | 0  |   dmt->mode = DM_DEVICE_MODE;  | 
330  | 0  |   dmt->no_open_count = 0;  | 
331  | 0  |   dmt->read_ahead = DM_READ_AHEAD_AUTO;  | 
332  | 0  |   dmt->read_ahead_flags = 0;  | 
333  | 0  |   dmt->event_nr = 0;  | 
334  | 0  |   dmt->cookie_set = 0;  | 
335  | 0  |   dmt->query_inactive_table = 0;  | 
336  | 0  |   dmt->new_uuid = 0;  | 
337  | 0  |   dmt->secure_data = 0;  | 
338  | 0  |   dmt->record_timestamp = 0;  | 
339  | 0  |   dmt->ima_measurement = 0;  | 
340  |  | 
  | 
341  | 0  |   return dmt;  | 
342  | 0  | }  | 
343  |  |  | 
344  |  | /*  | 
345  |  |  * Find the name associated with a given device number by scanning _dm_dir.  | 
346  |  |  */  | 
347  |  | static int _find_dm_name_of_device(dev_t st_rdev, char *buf, size_t buf_len)  | 
348  | 0  | { | 
349  | 0  |   const char *name;  | 
350  | 0  |   char path[PATH_MAX];  | 
351  | 0  |   struct dirent *dirent;  | 
352  | 0  |   DIR *d;  | 
353  | 0  |   struct stat st;  | 
354  | 0  |   int r = 0;  | 
355  |  | 
  | 
356  | 0  |   if (!(d = opendir(_dm_dir))) { | 
357  | 0  |     log_sys_error("opendir", _dm_dir); | 
358  | 0  |     return 0;  | 
359  | 0  |   }  | 
360  |  |  | 
361  | 0  |   while ((dirent = readdir(d))) { | 
362  | 0  |     name = dirent->d_name;  | 
363  |  | 
  | 
364  | 0  |     if (!strcmp(name, ".") || !strcmp(name, ".."))  | 
365  | 0  |       continue;  | 
366  |  |  | 
367  | 0  |     if (dm_snprintf(path, sizeof(path), "%s/%s", _dm_dir,  | 
368  | 0  |         name) == -1) { | 
369  | 0  |       log_error("Couldn't create path for %s", name); | 
370  | 0  |       continue;  | 
371  | 0  |     }  | 
372  |  |  | 
373  | 0  |     if (stat(path, &st))  | 
374  | 0  |       continue;  | 
375  |  |  | 
376  | 0  |     if (st.st_rdev == st_rdev) { | 
377  | 0  |       strncpy(buf, name, buf_len);  | 
378  | 0  |       r = 1;  | 
379  | 0  |       break;  | 
380  | 0  |     }  | 
381  | 0  |   }  | 
382  |  | 
  | 
383  | 0  |   if (closedir(d))  | 
384  | 0  |     log_sys_debug("closedir", _dm_dir); | 
385  |  | 
  | 
386  | 0  |   return r;  | 
387  | 0  | }  | 
388  |  |  | 
389  |  | static int _is_whitelisted_char(char c)  | 
390  | 0  | { | 
391  |  |   /*  | 
392  |  |    * Actually, DM supports any character in a device name.  | 
393  |  |    * This whitelist is just for proper integration with udev.  | 
394  |  |    */  | 
395  | 0  |         if ((c >= '0' && c <= '9') ||  | 
396  | 0  |             (c >= 'A' && c <= 'Z') ||  | 
397  | 0  |             (c >= 'a' && c <= 'z') ||  | 
398  | 0  |             strchr("#+-.:=@_", c) != NULL) | 
399  | 0  |                 return 1;  | 
400  |  |  | 
401  | 0  |         return 0;  | 
402  | 0  | }  | 
403  |  |  | 
404  |  | int check_multiple_mangled_string_allowed(const char *str, const char *str_name,  | 
405  |  |            dm_string_mangling_t mode)  | 
406  | 0  | { | 
407  | 0  |   if (mode == DM_STRING_MANGLING_AUTO && strstr(str, "\\x5cx")) { | 
408  | 0  |     log_error("The %s \"%s\" seems to be mangled more than once. " | 
409  | 0  |         "This is not allowed in auto mode.", str_name, str);  | 
410  | 0  |     return 0;  | 
411  | 0  |   }  | 
412  |  |  | 
413  | 0  |   return 1;  | 
414  | 0  | }  | 
415  |  |  | 
416  |  | /*  | 
417  |  |  * Mangle all characters in the input string which are not on a whitelist  | 
418  |  |  * with '\xNN' format where NN is the hex value of the character.  | 
419  |  |  */  | 
420  |  | int mangle_string(const char *str, const char *str_name, size_t len,  | 
421  |  |       char *buf, size_t buf_len, dm_string_mangling_t mode)  | 
422  | 0  | { | 
423  | 0  |   int need_mangling = -1; /* -1 don't know yet, 0 no, 1 yes */  | 
424  | 0  |   size_t i, j;  | 
425  |  | 
  | 
426  | 0  |   if (!str || !buf)  | 
427  | 0  |     return -1;  | 
428  |  |  | 
429  |  |   /* Is there anything to do at all? */  | 
430  | 0  |   if (!*str || !len)  | 
431  | 0  |     return 0;  | 
432  |  |  | 
433  | 0  |   if (buf_len < DM_NAME_LEN) { | 
434  | 0  |     log_error(INTERNAL_ERROR "mangle_string: supplied buffer too small");  | 
435  | 0  |     return -1;  | 
436  | 0  |   }  | 
437  |  |  | 
438  | 0  |   if (mode == DM_STRING_MANGLING_NONE)  | 
439  | 0  |     mode = DM_STRING_MANGLING_AUTO;  | 
440  |  | 
  | 
441  | 0  |   for (i = 0, j = 0; str[i]; i++) { | 
442  | 0  |     if (mode == DM_STRING_MANGLING_AUTO) { | 
443  |  |       /*  | 
444  |  |        * Detect already mangled part of the string and keep it.  | 
445  |  |        * Return error on mixture of mangled/not mangled!  | 
446  |  |        */  | 
447  | 0  |       if (str[i] == '\\' && str[i+1] == 'x') { | 
448  | 0  |         if ((len - i < 4) || (need_mangling == 1))  | 
449  | 0  |           goto bad1;  | 
450  | 0  |         if (buf_len - j < 4)  | 
451  | 0  |           goto bad2;  | 
452  |  |  | 
453  | 0  |         memcpy(&buf[j], &str[i], 4);  | 
454  | 0  |         i+=3; j+=4;  | 
455  |  | 
  | 
456  | 0  |         need_mangling = 0;  | 
457  | 0  |         continue;  | 
458  | 0  |       }  | 
459  | 0  |     }  | 
460  |  |  | 
461  | 0  |     if (_is_whitelisted_char(str[i])) { | 
462  |  |       /* whitelisted, keep it. */  | 
463  | 0  |       if (buf_len - j < 1)  | 
464  | 0  |         goto bad2;  | 
465  | 0  |       buf[j] = str[i];  | 
466  | 0  |       j++;  | 
467  | 0  |     } else { | 
468  |  |       /*  | 
469  |  |        * Not on a whitelist, mangle it.  | 
470  |  |        * Return error on mixture of mangled/not mangled  | 
471  |  |        * unless a DM_STRING_MANGLING_HEX is used!.  | 
472  |  |        */  | 
473  | 0  |       if ((mode != DM_STRING_MANGLING_HEX) && (need_mangling == 0))  | 
474  | 0  |         goto bad1;  | 
475  | 0  |       if (buf_len - j < 4)  | 
476  | 0  |         goto bad2;  | 
477  |  |  | 
478  | 0  |       sprintf(&buf[j], "\\x%02x", (unsigned char) str[i]);  | 
479  | 0  |       j+=4;  | 
480  |  | 
  | 
481  | 0  |       need_mangling = 1;  | 
482  | 0  |     }  | 
483  | 0  |   }  | 
484  |  |  | 
485  | 0  |   if (buf_len - j < 1)  | 
486  | 0  |     goto bad2;  | 
487  | 0  |   buf[j] = '\0';  | 
488  |  |  | 
489  |  |   /* All chars in the string whitelisted? */  | 
490  | 0  |   if (need_mangling == -1)  | 
491  | 0  |     need_mangling = 0;  | 
492  |  | 
  | 
493  | 0  |   return need_mangling;  | 
494  |  |  | 
495  | 0  | bad1:  | 
496  | 0  |   log_error("The %s \"%s\" contains mixed mangled and unmangled " | 
497  | 0  |       "characters or it's already mangled improperly.", str_name, str);  | 
498  | 0  |   return -1;  | 
499  | 0  | bad2:  | 
500  | 0  |   log_error("Mangled form of the %s too long for \"%s\".", str_name, str); | 
501  | 0  |   return -1;  | 
502  | 0  | }  | 
503  |  |  | 
504  |  | /*  | 
505  |  |  * Try to unmangle supplied string.  | 
506  |  |  * Return value: -1 on error, 0 when no unmangling needed, 1 when unmangling applied  | 
507  |  |  */  | 
508  |  | int unmangle_string(const char *str, const char *str_name, size_t len,  | 
509  |  |         char *buf, size_t buf_len, dm_string_mangling_t mode)  | 
510  | 0  | { | 
511  | 0  |   int strict = mode != DM_STRING_MANGLING_NONE;  | 
512  | 0  |   char str_rest[DM_NAME_LEN + 1];  | 
513  | 0  |   size_t i, j;  | 
514  | 0  |   unsigned int code;  | 
515  | 0  |   int r = 0;  | 
516  |  | 
  | 
517  | 0  |   if (!str || !buf)  | 
518  | 0  |     return -1;  | 
519  |  |  | 
520  |  |   /* Is there anything to do at all? */  | 
521  | 0  |   if (!*str || !len)  | 
522  | 0  |     return 0;  | 
523  |  |  | 
524  | 0  |   if (buf_len < DM_NAME_LEN) { | 
525  | 0  |     log_error(INTERNAL_ERROR "unmangle_string: supplied buffer too small");  | 
526  | 0  |     return -1;  | 
527  | 0  |   }  | 
528  |  |  | 
529  | 0  |   for (i = 0, j = 0; str[i]; i++, j++) { | 
530  | 0  |     if (strict && !(_is_whitelisted_char(str[i]) || str[i]=='\\')) { | 
531  | 0  |       log_error("The %s \"%s\" should be mangled but " | 
532  | 0  |           "it contains blacklisted characters.", str_name, str);  | 
533  | 0  |       j=0; r=-1;  | 
534  | 0  |       goto out;  | 
535  | 0  |     }  | 
536  |  |  | 
537  | 0  |     if (str[i] == '\\' && str[i+1] == 'x') { | 
538  | 0  |       if (!sscanf(&str[i+2], "%2x%" DM_TO_STRING(DM_NAME_LEN) "s",  | 
539  | 0  |             &code, str_rest)) { | 
540  | 0  |         log_debug_activation("Hex encoding mismatch detected in %s \"%s\" " | 
541  | 0  |                  "while trying to unmangle it.", str_name, str);  | 
542  | 0  |         goto out;  | 
543  | 0  |       }  | 
544  | 0  |       buf[j] = (unsigned char) code;  | 
545  |  |  | 
546  |  |       /* skip the encoded part we've just decoded! */  | 
547  | 0  |       i+= 3;  | 
548  |  |  | 
549  |  |       /* unmangling applied */  | 
550  | 0  |       r = 1;  | 
551  | 0  |     } else  | 
552  | 0  |       buf[j] = str[i];  | 
553  | 0  |   }  | 
554  |  |  | 
555  | 0  | out:  | 
556  | 0  |   buf[j] = '\0';  | 
557  | 0  |   return r;  | 
558  | 0  | }  | 
559  |  |  | 
560  |  | static int _dm_task_set_name(struct dm_task *dmt, const char *name,  | 
561  |  |            dm_string_mangling_t mangling_mode)  | 
562  | 0  | { | 
563  | 0  |   char mangled_name[DM_NAME_LEN];  | 
564  | 0  |   int r = 0;  | 
565  |  | 
  | 
566  | 0  |   dm_free(dmt->dev_name);  | 
567  | 0  |   dmt->dev_name = NULL;  | 
568  | 0  |   dm_free(dmt->mangled_dev_name);  | 
569  | 0  |   dmt->mangled_dev_name = NULL;  | 
570  |  | 
  | 
571  | 0  |   if (strlen(name) >= DM_NAME_LEN) { | 
572  | 0  |     log_error("Name \"%s\" too long.", name); | 
573  | 0  |     return 0;  | 
574  | 0  |   }  | 
575  |  |  | 
576  | 0  |   if (!check_multiple_mangled_string_allowed(name, "name", mangling_mode))  | 
577  | 0  |     return_0;  | 
578  |  |  | 
579  | 0  |   if (mangling_mode != DM_STRING_MANGLING_NONE &&  | 
580  | 0  |       (r = mangle_string(name, "name", strlen(name), mangled_name,  | 
581  | 0  |              sizeof(mangled_name), mangling_mode)) < 0) { | 
582  | 0  |     log_error("Failed to mangle device name \"%s\".", name); | 
583  | 0  |     return 0;  | 
584  | 0  |   }  | 
585  |  |  | 
586  |  |   /* Store mangled_dev_name only if it differs from dev_name! */  | 
587  | 0  |   if (r) { | 
588  | 0  |     log_debug_activation("Device name mangled [%s]: %s --> %s", | 
589  | 0  |              mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",  | 
590  | 0  |              name, mangled_name);  | 
591  | 0  |     if (!(dmt->mangled_dev_name = dm_strdup(mangled_name))) { | 
592  | 0  |       log_error("_dm_task_set_name: dm_strdup(%s) failed", mangled_name); | 
593  | 0  |       return 0;  | 
594  | 0  |     }  | 
595  | 0  |   }  | 
596  |  |  | 
597  | 0  |   if (!(dmt->dev_name = dm_strdup(name))) { | 
598  | 0  |     log_error("_dm_task_set_name: strdup(%s) failed", name); | 
599  | 0  |     return 0;  | 
600  | 0  |   }  | 
601  |  |  | 
602  | 0  |   return 1;  | 
603  | 0  | }  | 
604  |  |  | 
605  |  | static int _dm_task_set_name_from_path(struct dm_task *dmt, const char *path,  | 
606  |  |                const char *name)  | 
607  | 0  | { | 
608  | 0  |   char buf[PATH_MAX];  | 
609  | 0  |   struct stat st1, st2;  | 
610  | 0  |   const char *final_name = NULL;  | 
611  | 0  |   size_t len;  | 
612  |  | 
  | 
613  | 0  |   if (dmt->type == DM_DEVICE_CREATE) { | 
614  | 0  |     log_error("Name \"%s\" invalid. It contains \"/\".", path); | 
615  | 0  |     return 0;  | 
616  | 0  |   }  | 
617  |  |  | 
618  | 0  |   if (!stat(path, &st1)) { | 
619  |  |     /*  | 
620  |  |      * Found directly.  | 
621  |  |      * If supplied path points to same device as last component  | 
622  |  |      * under /dev/mapper, use that name directly.    | 
623  |  |      */  | 
624  | 0  |     if (dm_snprintf(buf, sizeof(buf), "%s/%s", _dm_dir, name) == -1) { | 
625  | 0  |       log_error("Couldn't create path for %s", name); | 
626  | 0  |       return 0;  | 
627  | 0  |     }  | 
628  |  |  | 
629  | 0  |     if (!stat(buf, &st2) && (st1.st_rdev == st2.st_rdev))  | 
630  | 0  |       final_name = name;  | 
631  | 0  |   } else { | 
632  |  |     /* Not found. */  | 
633  |  |     /* If there is exactly one '/' try a prefix of /dev */  | 
634  | 0  |     if ((len = strlen(path)) < 3 || path[0] == '/' ||  | 
635  | 0  |         dm_count_chars(path, len, '/') != 1) { | 
636  | 0  |       log_error("Device %s not found", path); | 
637  | 0  |       return 0;  | 
638  | 0  |     }  | 
639  | 0  |     if (dm_snprintf(buf, sizeof(buf), "%s/../%s", _dm_dir, path) == -1) { | 
640  | 0  |       log_error("Couldn't create /dev path for %s", path); | 
641  | 0  |       return 0;  | 
642  | 0  |     }  | 
643  | 0  |     if (stat(buf, &st1)) { | 
644  | 0  |       log_error("Device %s not found", path); | 
645  | 0  |       return 0;  | 
646  | 0  |     }  | 
647  |  |     /* Found */  | 
648  | 0  |   }  | 
649  |  |  | 
650  |  |   /*  | 
651  |  |    * If we don't have the dm name yet, Call _find_dm_name_of_device() to  | 
652  |  |    * scan _dm_dir for a match.  | 
653  |  |    */  | 
654  | 0  |   if (!final_name) { | 
655  | 0  |     if (_find_dm_name_of_device(st1.st_rdev, buf, sizeof(buf)))  | 
656  | 0  |       final_name = buf;  | 
657  | 0  |     else { | 
658  | 0  |       log_error("Device %s not found", name); | 
659  | 0  |       return 0;  | 
660  | 0  |     }  | 
661  | 0  |   }  | 
662  |  |  | 
663  |  |   /* This is an already existing path - do not mangle! */  | 
664  | 0  |   return _dm_task_set_name(dmt, final_name, DM_STRING_MANGLING_NONE);  | 
665  | 0  | }  | 
666  |  |  | 
667  |  | int dm_task_set_name(struct dm_task *dmt, const char *name)  | 
668  | 0  | { | 
669  | 0  |   char *pos;  | 
670  |  |  | 
671  |  |   /* Path supplied for existing device? */  | 
672  | 0  |   if ((pos = strrchr(name, '/')))  | 
673  | 0  |     return _dm_task_set_name_from_path(dmt, name, pos + 1);  | 
674  |  |  | 
675  | 0  |   return _dm_task_set_name(dmt, name, dm_get_name_mangling_mode());  | 
676  | 0  | }  | 
677  |  |  | 
678  |  | const char *dm_task_get_name(const struct dm_task *dmt)  | 
679  | 0  | { | 
680  | 0  |   return (dmt->dmi.v4->name);  | 
681  | 0  | }  | 
682  |  |  | 
683  |  | static char *_task_get_string_mangled(const char *str, const char *str_name,  | 
684  |  |               char *buf, size_t buf_size,  | 
685  |  |               dm_string_mangling_t mode)  | 
686  | 0  | { | 
687  | 0  |   char *rs;  | 
688  | 0  |   int r;  | 
689  |  | 
  | 
690  | 0  |   if ((r = mangle_string(str, str_name, strlen(str), buf, buf_size, mode)) < 0)  | 
691  | 0  |     return NULL;  | 
692  |  |  | 
693  | 0  |   if (!(rs = r ? dm_strdup(buf) : dm_strdup(str)))  | 
694  | 0  |     log_error("_task_get_string_mangled: dm_strdup failed"); | 
695  |  | 
  | 
696  | 0  |   return rs;  | 
697  | 0  | }  | 
698  |  |  | 
699  |  | static char *_task_get_string_unmangled(const char *str, const char *str_name,  | 
700  |  |           char *buf, size_t buf_size,  | 
701  |  |           dm_string_mangling_t mode)  | 
702  | 0  | { | 
703  | 0  |   char *rs;  | 
704  | 0  |   int r = 0;  | 
705  |  |  | 
706  |  |   /*  | 
707  |  |    * Unless the mode used is 'none', the string  | 
708  |  |    * is *already* unmangled on ioctl return!  | 
709  |  |    */  | 
710  | 0  |   if (mode == DM_STRING_MANGLING_NONE &&  | 
711  | 0  |       (r = unmangle_string(str, str_name, strlen(str), buf, buf_size, mode)) < 0)  | 
712  | 0  |     return NULL;  | 
713  |  |  | 
714  | 0  |   if (!(rs = r ? dm_strdup(buf) : dm_strdup(str)))  | 
715  | 0  |     log_error("_task_get_string_unmangled: dm_strdup failed"); | 
716  |  | 
  | 
717  | 0  |   return rs;  | 
718  | 0  | }  | 
719  |  |  | 
720  |  | char *dm_task_get_name_mangled(const struct dm_task *dmt)  | 
721  | 0  | { | 
722  | 0  |   const char *s = dm_task_get_name(dmt);  | 
723  | 0  |   char buf[DM_NAME_LEN];  | 
724  | 0  |   char *rs;  | 
725  |  | 
  | 
726  | 0  |   if (!(rs = _task_get_string_mangled(s, "name", buf, sizeof(buf), dm_get_name_mangling_mode())))  | 
727  | 0  |     log_error("Failed to mangle device name \"%s\".", s); | 
728  |  | 
  | 
729  | 0  |   return rs;  | 
730  | 0  | }  | 
731  |  |  | 
732  |  | char *dm_task_get_name_unmangled(const struct dm_task *dmt)  | 
733  | 0  | { | 
734  | 0  |   const char *s = dm_task_get_name(dmt);  | 
735  | 0  |   char buf[DM_NAME_LEN];  | 
736  | 0  |   char *rs;  | 
737  |  | 
  | 
738  | 0  |   if (!(rs = _task_get_string_unmangled(s, "name", buf, sizeof(buf), dm_get_name_mangling_mode())))  | 
739  | 0  |     log_error("Failed to unmangle device name \"%s\".", s); | 
740  |  | 
  | 
741  | 0  |   return rs;  | 
742  | 0  | }  | 
743  |  |  | 
744  |  | const char *dm_task_get_uuid(const struct dm_task *dmt)  | 
745  | 0  | { | 
746  | 0  |   return (dmt->dmi.v4->uuid);  | 
747  | 0  | }  | 
748  |  |  | 
749  |  | char *dm_task_get_uuid_mangled(const struct dm_task *dmt)  | 
750  | 0  | { | 
751  | 0  |   const char *s = dm_task_get_uuid(dmt);  | 
752  | 0  |   char buf[DM_UUID_LEN];  | 
753  | 0  |   char *rs;  | 
754  |  | 
  | 
755  | 0  |   if (!(rs = _task_get_string_mangled(s, "UUID", buf, sizeof(buf), dm_get_name_mangling_mode())))  | 
756  | 0  |     log_error("Failed to mangle device uuid \"%s\".", s); | 
757  |  | 
  | 
758  | 0  |   return rs;  | 
759  | 0  | }  | 
760  |  |  | 
761  |  | char *dm_task_get_uuid_unmangled(const struct dm_task *dmt)  | 
762  | 0  | { | 
763  | 0  |   const char *s = dm_task_get_uuid(dmt);  | 
764  | 0  |   char buf[DM_UUID_LEN];  | 
765  | 0  |   char *rs;  | 
766  |  | 
  | 
767  | 0  |   if (!(rs = _task_get_string_unmangled(s, "UUID", buf, sizeof(buf), dm_get_name_mangling_mode())))  | 
768  | 0  |     log_error("Failed to unmangle device uuid \"%s\".", s); | 
769  |  | 
  | 
770  | 0  |   return rs;  | 
771  | 0  | }  | 
772  |  |  | 
773  |  | int dm_task_set_newname(struct dm_task *dmt, const char *newname)  | 
774  | 0  | { | 
775  | 0  |   dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();  | 
776  | 0  |   char mangled_name[DM_NAME_LEN];  | 
777  | 0  |   int r = 0;  | 
778  |  | 
  | 
779  | 0  |   if (strchr(newname, '/')) { | 
780  | 0  |     log_error("Name \"%s\" invalid. It contains \"/\".", newname); | 
781  | 0  |     return 0;  | 
782  | 0  |   }  | 
783  |  |  | 
784  | 0  |   if (strlen(newname) >= DM_NAME_LEN) { | 
785  | 0  |     log_error("Name \"%s\" too long", newname); | 
786  | 0  |     return 0;  | 
787  | 0  |   }  | 
788  |  |  | 
789  | 0  |   if (!*newname) { | 
790  | 0  |     log_error("Non empty new name is required."); | 
791  | 0  |     return 0;  | 
792  | 0  |   }  | 
793  |  |  | 
794  | 0  |   if (!check_multiple_mangled_string_allowed(newname, "new name", mangling_mode))  | 
795  | 0  |     return_0;  | 
796  |  |  | 
797  | 0  |   if (mangling_mode != DM_STRING_MANGLING_NONE &&  | 
798  | 0  |       (r = mangle_string(newname, "new name", strlen(newname), mangled_name,  | 
799  | 0  |              sizeof(mangled_name), mangling_mode)) < 0) { | 
800  | 0  |     log_error("Failed to mangle new device name \"%s\"", newname); | 
801  | 0  |     return 0;  | 
802  | 0  |   }  | 
803  |  |  | 
804  | 0  |   if (r) { | 
805  | 0  |     log_debug_activation("New device name mangled [%s]: %s --> %s", | 
806  | 0  |              mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",  | 
807  | 0  |              newname, mangled_name);  | 
808  | 0  |     newname = mangled_name;  | 
809  | 0  |   }  | 
810  |  | 
  | 
811  | 0  |   dm_free(dmt->newname);  | 
812  | 0  |   if (!(dmt->newname = dm_strdup(newname))) { | 
813  | 0  |     log_error("dm_task_set_newname: strdup(%s) failed", newname); | 
814  | 0  |     return 0;  | 
815  | 0  |   }  | 
816  |  |  | 
817  | 0  |   dmt->new_uuid = 0;  | 
818  |  | 
  | 
819  | 0  |   return 1;  | 
820  | 0  | }  | 
821  |  |  | 
822  |  | int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)  | 
823  | 0  | { | 
824  | 0  |   char mangled_uuid[DM_UUID_LEN];  | 
825  | 0  |   dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();  | 
826  | 0  |   int r = 0;  | 
827  |  | 
  | 
828  | 0  |   dm_free(dmt->uuid);  | 
829  | 0  |   dmt->uuid = NULL;  | 
830  | 0  |   dm_free(dmt->mangled_uuid);  | 
831  | 0  |   dmt->mangled_uuid = NULL;  | 
832  |  | 
  | 
833  | 0  |   if (!check_multiple_mangled_string_allowed(uuid, "UUID", mangling_mode))  | 
834  | 0  |     return_0;  | 
835  |  |  | 
836  | 0  |   if (mangling_mode != DM_STRING_MANGLING_NONE &&  | 
837  | 0  |       (r = mangle_string(uuid, "UUID", strlen(uuid), mangled_uuid,  | 
838  | 0  |              sizeof(mangled_uuid), mangling_mode)) < 0) { | 
839  | 0  |     log_error("Failed to mangle device uuid \"%s\".", uuid); | 
840  | 0  |     return 0;  | 
841  | 0  |   }  | 
842  |  |  | 
843  | 0  |   if (r) { | 
844  | 0  |     log_debug_activation("Device uuid mangled [%s]: %s --> %s", | 
845  | 0  |              mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",  | 
846  | 0  |              uuid, mangled_uuid);  | 
847  |  | 
  | 
848  | 0  |     if (!(dmt->mangled_uuid = dm_strdup(mangled_uuid))) { | 
849  | 0  |       log_error("dm_task_set_uuid: dm_strdup(%s) failed", mangled_uuid); | 
850  | 0  |       return 0;  | 
851  | 0  |     }  | 
852  | 0  |   }  | 
853  |  |  | 
854  | 0  |   if (!(dmt->uuid = dm_strdup(uuid))) { | 
855  | 0  |     log_error("dm_task_set_uuid: strdup(%s) failed", uuid); | 
856  | 0  |     return 0;  | 
857  | 0  |   }  | 
858  |  |  | 
859  | 0  |   return 1;  | 
860  | 0  | }  | 
861  |  |  | 
862  |  | int dm_task_set_major(struct dm_task *dmt, int major)  | 
863  | 0  | { | 
864  | 0  |   dmt->major = major;  | 
865  | 0  |   dmt->allow_default_major_fallback = 0;  | 
866  |  | 
  | 
867  | 0  |   return 1;  | 
868  | 0  | }  | 
869  |  |  | 
870  |  | int dm_task_set_minor(struct dm_task *dmt, int minor)  | 
871  | 0  | { | 
872  | 0  |   dmt->minor = minor;  | 
873  |  | 
  | 
874  | 0  |   return 1;  | 
875  | 0  | }  | 
876  |  |  | 
877  |  | int dm_task_set_major_minor(struct dm_task *dmt, int major, int minor,  | 
878  |  |           int allow_default_major_fallback)  | 
879  | 0  | { | 
880  | 0  |   dmt->major = major;  | 
881  | 0  |   dmt->minor = minor;  | 
882  | 0  |   dmt->allow_default_major_fallback = allow_default_major_fallback;  | 
883  |  | 
  | 
884  | 0  |   return 1;  | 
885  | 0  | }  | 
886  |  |  | 
887  |  | int dm_task_set_uid(struct dm_task *dmt, uid_t uid)  | 
888  | 0  | { | 
889  | 0  |   dmt->uid = uid;  | 
890  |  | 
  | 
891  | 0  |   return 1;  | 
892  | 0  | }  | 
893  |  |  | 
894  |  | int dm_task_set_gid(struct dm_task *dmt, gid_t gid)  | 
895  | 0  | { | 
896  | 0  |   dmt->gid = gid;  | 
897  |  | 
  | 
898  | 0  |   return 1;  | 
899  | 0  | }  | 
900  |  |  | 
901  |  | int dm_task_set_mode(struct dm_task *dmt, mode_t mode)  | 
902  | 0  | { | 
903  | 0  |   dmt->mode = mode;  | 
904  |  | 
  | 
905  | 0  |   return 1;  | 
906  | 0  | }  | 
907  |  |  | 
908  |  | int dm_task_enable_checks(struct dm_task *dmt)  | 
909  | 0  | { | 
910  | 0  |   dmt->enable_checks = 1;  | 
911  |  | 
  | 
912  | 0  |   return 1;  | 
913  | 0  | }  | 
914  |  |  | 
915  |  | int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,  | 
916  |  |            const char *ttype, const char *params)  | 
917  | 0  | { | 
918  | 0  |   struct target *t = create_target(start, size, ttype, params);  | 
919  | 0  |   if (!t)  | 
920  | 0  |     return_0;  | 
921  |  |  | 
922  | 0  |   if (!dmt->head)  | 
923  | 0  |     dmt->head = dmt->tail = t;  | 
924  | 0  |   else { | 
925  | 0  |     dmt->tail->next = t;  | 
926  | 0  |     dmt->tail = t;  | 
927  | 0  |   }  | 
928  |  | 
  | 
929  | 0  |   return 1;  | 
930  | 0  | }  | 
931  |  |  | 
932  |  | #ifdef HAVE_SELINUX  | 
933  |  | static int _selabel_lookup(const char *path, mode_t mode,  | 
934  |  |          char **scontext)  | 
935  |  | { | 
936  |  | #ifdef HAVE_SELINUX_LABEL_H  | 
937  |  |   if (!_selabel_handle &&  | 
938  |  |       !(_selabel_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0))) { | 
939  |  |     log_error("selabel_open failed: %s", strerror(errno)); | 
940  |  |     return 0;  | 
941  |  |   }  | 
942  |  |  | 
943  |  |   if (selabel_lookup(_selabel_handle, scontext, path, mode)) { | 
944  |  |     log_debug_activation("selabel_lookup failed for %s: %s", | 
945  |  |              path, strerror(errno));  | 
946  |  |     return 0;  | 
947  |  |   }  | 
948  |  | #else  | 
949  |  |   if (matchpathcon(path, mode, scontext)) { | 
950  |  |     log_debug_activation("matchpathcon failed for %s: %s", | 
951  |  |              path, strerror(errno));  | 
952  |  |     return 0;  | 
953  |  |   }  | 
954  |  | #endif  | 
955  |  |   return 1;  | 
956  |  | }  | 
957  |  | #endif  | 
958  |  |  | 
959  |  | #ifdef HAVE_SELINUX  | 
960  |  | static int _is_selinux_enabled(void)  | 
961  |  | { | 
962  |  |   static int _tested = 0;  | 
963  |  |   static int _enabled;  | 
964  |  |  | 
965  |  |   if (!_tested) { | 
966  |  |     _tested = 1;  | 
967  |  |     _enabled = is_selinux_enabled();  | 
968  |  |   }  | 
969  |  |  | 
970  |  |   return _enabled;  | 
971  |  | }  | 
972  |  | #endif  | 
973  |  |  | 
974  |  | int dm_prepare_selinux_context(const char *path, mode_t mode)  | 
975  | 0  | { | 
976  |  | #ifdef HAVE_SELINUX  | 
977  |  |   char *scontext = NULL;  | 
978  |  |  | 
979  |  |   if (_is_selinux_enabled() <= 0)  | 
980  |  |     return 1;  | 
981  |  |  | 
982  |  |   if (path) { | 
983  |  |     if (!_selabel_lookup(path, mode, &scontext))  | 
984  |  |       return_0;  | 
985  |  |  | 
986  |  |     log_debug_activation("Preparing SELinux context for %s to %s.", path, scontext); | 
987  |  |   }  | 
988  |  |   else  | 
989  |  |     log_debug_activation("Resetting SELinux context to default value."); | 
990  |  |  | 
991  |  |   if (setfscreatecon(scontext) < 0) { | 
992  |  |     log_sys_error("setfscreatecon", (path ? : "SELinux context reset")); | 
993  |  |     freecon(scontext);  | 
994  |  |     return 0;  | 
995  |  |   }  | 
996  |  |  | 
997  |  |   freecon(scontext);  | 
998  |  | #endif  | 
999  | 0  |   return 1;  | 
1000  | 0  | }  | 
1001  |  |  | 
1002  |  | int dm_set_selinux_context(const char *path, mode_t mode)  | 
1003  | 0  | { | 
1004  |  | #ifdef HAVE_SELINUX  | 
1005  |  |   char *scontext = NULL;  | 
1006  |  |  | 
1007  |  |   if (_is_selinux_enabled() <= 0)  | 
1008  |  |     return 1;  | 
1009  |  |  | 
1010  |  |   if (!_selabel_lookup(path, mode, &scontext))  | 
1011  |  |     return_0;  | 
1012  |  |  | 
1013  |  |   log_debug_activation("Setting SELinux context for %s to %s.", path, scontext); | 
1014  |  |  | 
1015  |  |   if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) { | 
1016  |  |     log_sys_error("lsetfilecon", path); | 
1017  |  |     freecon(scontext);  | 
1018  |  |     return 0;  | 
1019  |  |   }  | 
1020  |  |  | 
1021  |  |   freecon(scontext);  | 
1022  |  | #endif  | 
1023  | 0  |   return 1;  | 
1024  | 0  | }  | 
1025  |  |  | 
1026  |  | void selinux_release(void)  | 
1027  | 0  | { | 
1028  |  | #ifdef HAVE_SELINUX_LABEL_H  | 
1029  |  |   if (_selabel_handle)  | 
1030  |  |     selabel_close(_selabel_handle);  | 
1031  |  |   _selabel_handle = NULL;  | 
1032  |  | #endif  | 
1033  | 0  | }  | 
1034  |  |  | 
1035  |  | static int _warn_if_op_needed(int warn_if_udev_failed)  | 
1036  | 0  | { | 
1037  | 0  |     return warn_if_udev_failed && dm_udev_get_sync_support() && dm_udev_get_checking();  | 
1038  | 0  | }  | 
1039  |  |  | 
1040  |  | static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,  | 
1041  |  |        uid_t uid, gid_t gid, mode_t mode, int warn_if_udev_failed)  | 
1042  | 0  | { | 
1043  | 0  |   char path[PATH_MAX];  | 
1044  | 0  |   struct stat info;  | 
1045  | 0  |   dev_t dev = MKDEV(major, minor);  | 
1046  | 0  |   mode_t old_mask;  | 
1047  |  | 
  | 
1048  | 0  |   if (!_build_dev_path(path, sizeof(path), dev_name))  | 
1049  | 0  |     return_0;  | 
1050  |  |  | 
1051  | 0  |   if (stat(path, &info) >= 0) { | 
1052  | 0  |     if (!S_ISBLK(info.st_mode)) { | 
1053  | 0  |       log_error("A non-block device file at '%s' " | 
1054  | 0  |           "is already present", path);  | 
1055  | 0  |       return 0;  | 
1056  | 0  |     }  | 
1057  |  |  | 
1058  |  |     /* If right inode already exists we don't touch uid etc. */  | 
1059  | 0  |     if (info.st_rdev == dev)  | 
1060  | 0  |       return 1;  | 
1061  |  |  | 
1062  | 0  |     if (unlink(path) && (errno != ENOENT)) { | 
1063  | 0  |       log_sys_error("unlink", path); | 
1064  | 0  |       return 0;  | 
1065  | 0  |     }  | 
1066  | 0  |   } else if (_warn_if_op_needed(warn_if_udev_failed))  | 
1067  | 0  |     log_warn("%s not set up by udev: Falling back to direct " | 
1068  | 0  |        "node creation.", path);  | 
1069  |  |  | 
1070  | 0  |   (void) dm_prepare_selinux_context(path, S_IFBLK);  | 
1071  | 0  |   old_mask = umask(0);  | 
1072  |  |  | 
1073  |  |   /* The node may already have been created by udev. So ignore EEXIST. */  | 
1074  | 0  |   if (mknod(path, S_IFBLK | mode, dev) < 0 && errno != EEXIST) { | 
1075  | 0  |     log_error("%s: mknod for %s failed: %s", path, dev_name, strerror(errno)); | 
1076  | 0  |     umask(old_mask);  | 
1077  | 0  |     (void) dm_prepare_selinux_context(NULL, 0);  | 
1078  | 0  |     return 0;  | 
1079  | 0  |   }  | 
1080  | 0  |   umask(old_mask);  | 
1081  | 0  |   (void) dm_prepare_selinux_context(NULL, 0);  | 
1082  |  | 
  | 
1083  | 0  |   if (chown(path, uid, gid) < 0) { | 
1084  | 0  |     log_sys_error("chown", path); | 
1085  | 0  |     return 0;  | 
1086  | 0  |   }  | 
1087  |  |  | 
1088  | 0  |   log_debug_activation("Created %s", path); | 
1089  |  | 
  | 
1090  | 0  |   return 1;  | 
1091  | 0  | }  | 
1092  |  |  | 
1093  |  | static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)  | 
1094  | 0  | { | 
1095  | 0  |   char path[PATH_MAX];  | 
1096  | 0  |   struct stat info;  | 
1097  |  | 
  | 
1098  | 0  |   if (!_build_dev_path(path, sizeof(path), dev_name))  | 
1099  | 0  |     return_0;  | 
1100  | 0  |   if (lstat(path, &info) < 0)  | 
1101  | 0  |     return 1;  | 
1102  | 0  |   else if (_warn_if_op_needed(warn_if_udev_failed))  | 
1103  | 0  |     log_warn("Node %s was not removed by udev. " | 
1104  | 0  |        "Falling back to direct node removal.", path);  | 
1105  |  |  | 
1106  |  |   /* udev may already have deleted the node. Ignore ENOENT. */  | 
1107  | 0  |   if (unlink(path) && (errno != ENOENT)) { | 
1108  | 0  |     log_sys_error("unlink", path); | 
1109  | 0  |     return 0;  | 
1110  | 0  |   }  | 
1111  |  |  | 
1112  | 0  |   log_debug_activation("Removed %s", path); | 
1113  |  | 
  | 
1114  | 0  |   return 1;  | 
1115  | 0  | }  | 
1116  |  |  | 
1117  |  | static int _rename_dev_node(const char *old_name, const char *new_name,  | 
1118  |  |           int warn_if_udev_failed)  | 
1119  | 0  | { | 
1120  | 0  |   char oldpath[PATH_MAX];  | 
1121  | 0  |   char newpath[PATH_MAX];  | 
1122  | 0  |   struct stat info, info2;  | 
1123  | 0  |   struct stat *info_block_dev;  | 
1124  |  | 
  | 
1125  | 0  |   if (!_build_dev_path(oldpath, sizeof(oldpath), old_name) ||  | 
1126  | 0  |       !_build_dev_path(newpath, sizeof(newpath), new_name))  | 
1127  | 0  |     return_0;  | 
1128  |  |  | 
1129  | 0  |   if (lstat(newpath, &info) == 0) { | 
1130  | 0  |     if (S_ISLNK(info.st_mode)) { | 
1131  | 0  |       if (stat(newpath, &info2) == 0)  | 
1132  | 0  |         info_block_dev = &info2;  | 
1133  | 0  |       else { | 
1134  | 0  |         log_sys_error("stat", newpath); | 
1135  | 0  |         return 0;  | 
1136  | 0  |       }  | 
1137  | 0  |     } else  | 
1138  | 0  |       info_block_dev = &info;  | 
1139  |  |  | 
1140  | 0  |     if (!S_ISBLK(info_block_dev->st_mode)) { | 
1141  | 0  |       log_error("A non-block device file at '%s' " | 
1142  | 0  |           "is already present", newpath);  | 
1143  | 0  |       return 0;  | 
1144  | 0  |     }  | 
1145  | 0  |     else if (_warn_if_op_needed(warn_if_udev_failed)) { | 
1146  | 0  |       if (lstat(oldpath, &info) < 0 &&  | 
1147  | 0  |          errno == ENOENT)  | 
1148  |  |         /* assume udev already deleted this */  | 
1149  | 0  |         return 1;  | 
1150  |  |  | 
1151  | 0  |       log_warn("The node %s should have been renamed to %s " | 
1152  | 0  |          "by udev but old node is still present. "  | 
1153  | 0  |          "Falling back to direct old node removal.",  | 
1154  | 0  |          oldpath, newpath);  | 
1155  | 0  |       return _rm_dev_node(old_name, 0);  | 
1156  | 0  |     }  | 
1157  |  |  | 
1158  | 0  |     if (unlink(newpath) < 0) { | 
1159  | 0  |       if (errno == EPERM) { | 
1160  |  |         /* devfs, entry has already been renamed */  | 
1161  | 0  |         return 1;  | 
1162  | 0  |       }  | 
1163  | 0  |       log_error("Unable to unlink device node for '%s'", | 
1164  | 0  |           new_name);  | 
1165  | 0  |       return 0;  | 
1166  | 0  |     }  | 
1167  | 0  |   }  | 
1168  | 0  |   else if (_warn_if_op_needed(warn_if_udev_failed))  | 
1169  | 0  |     log_warn("The node %s should have been renamed to %s " | 
1170  | 0  |        "by udev but new node is not present. "  | 
1171  | 0  |        "Falling back to direct node rename.",  | 
1172  | 0  |        oldpath, newpath);  | 
1173  |  |  | 
1174  |  |   /* udev may already have renamed the node. Ignore ENOENT. */  | 
1175  |  |   /* FIXME: when renaming to target mangling mode "none" with udev  | 
1176  |  |    * while there are some blacklisted characters in the node name,  | 
1177  |  |    * udev will remove the old_node, but fails to properly rename  | 
1178  |  |    * to new_node. The libdevmapper code tries to call  | 
1179  |  |    * rename(old_node,new_node), but that won't do anything  | 
1180  |  |    * since the old node is already removed by udev.  | 
1181  |  |    * For example renaming 'a\x20b' to 'a b':  | 
1182  |  |    *   - udev removes 'a\x20b'  | 
1183  |  |    *   - udev creates 'a' and 'b' (since it considers the ' ' as a delimiter  | 
1184  |  |    *   - libdevmapper checks udev has done the rename properly  | 
1185  |  |    *   - libdevmapper calls stat(new_node) and it does not see it  | 
1186  |  |    *   - libdevmapper calls rename(old_node,new_node)  | 
1187  |  |    *   - the rename is a NOP since the old_node does not exist anymore  | 
1188  |  |    *  | 
1189  |  |    * However, this situation is very rare - why would anyone need  | 
1190  |  |    * to rename to an unsupported mode??? So a fix for this would be  | 
1191  |  |    * just for completeness.  | 
1192  |  |    */  | 
1193  | 0  |   if (rename(oldpath, newpath) < 0 && errno != ENOENT) { | 
1194  | 0  |     log_error("Unable to rename device node from '%s' to '%s'", | 
1195  | 0  |         old_name, new_name);  | 
1196  | 0  |     return 0;  | 
1197  | 0  |   }  | 
1198  |  |  | 
1199  | 0  |   log_debug_activation("Renamed %s to %s", oldpath, newpath); | 
1200  |  | 
  | 
1201  | 0  |   return 1;  | 
1202  | 0  | }  | 
1203  |  |  | 
1204  |  | #ifdef __linux__  | 
1205  |  | static int _open_dev_node(const char *dev_name)  | 
1206  | 0  | { | 
1207  | 0  |   int fd = -1;  | 
1208  | 0  |   char path[PATH_MAX];  | 
1209  |  | 
  | 
1210  | 0  |   if (!_build_dev_path(path, sizeof(path), dev_name))  | 
1211  | 0  |     return fd;  | 
1212  |  |  | 
1213  | 0  |   if ((fd = open(path, O_RDONLY, 0)) < 0)  | 
1214  | 0  |     log_sys_error("open", path); | 
1215  |  | 
  | 
1216  | 0  |   return fd;  | 
1217  | 0  | }  | 
1218  |  |  | 
1219  |  | int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,  | 
1220  |  |           uint32_t *read_ahead)  | 
1221  | 0  | { | 
1222  | 0  |   char buf[24];  | 
1223  | 0  |   int len;  | 
1224  | 0  |   int r = 1;  | 
1225  | 0  |   int fd;  | 
1226  | 0  |   long read_ahead_long = 0;  | 
1227  |  |  | 
1228  |  |   /*  | 
1229  |  |    * If we know the device number, use sysfs if we can.  | 
1230  |  |    * Otherwise use BLKRAGET ioctl.  | 
1231  |  |    */  | 
1232  | 0  |   if (*_sysfs_dir && major != 0) { | 
1233  | 0  |     if (dm_snprintf(_path0, sizeof(_path0), "%sdev/block/%" PRIu32  | 
1234  | 0  |         ":%" PRIu32 "/bdi/read_ahead_kb", _sysfs_dir,  | 
1235  | 0  |         major, minor) < 0) { | 
1236  | 0  |       log_error("Failed to build sysfs_path."); | 
1237  | 0  |       return 0;  | 
1238  | 0  |     }  | 
1239  |  |  | 
1240  | 0  |     if ((fd = open(_path0, O_RDONLY, 0)) != -1) { | 
1241  |  |       /* Reading from sysfs, expecting number\n */  | 
1242  | 0  |       if ((len = read(fd, buf, sizeof(buf) - 1)) < 1) { | 
1243  | 0  |         log_sys_error("read", _path0); | 
1244  | 0  |         r = 0;  | 
1245  | 0  |       } else { | 
1246  | 0  |         buf[len] = 0; /* kill \n and ensure \0 */  | 
1247  | 0  |         *read_ahead = atoi(buf) * 2;  | 
1248  | 0  |         log_debug_activation("%s (%d:%d): read ahead is %" PRIu32, | 
1249  | 0  |                  dev_name, major, minor, *read_ahead);  | 
1250  | 0  |       }  | 
1251  |  | 
  | 
1252  | 0  |       if (close(fd))  | 
1253  | 0  |         log_sys_debug("close", _path0); | 
1254  |  | 
  | 
1255  | 0  |       return r;  | 
1256  | 0  |     }  | 
1257  |  |  | 
1258  | 0  |     log_sys_debug("open", _path0); | 
1259  |  |     /* Fall back to use dev_name */  | 
1260  | 0  |   }  | 
1261  |  |  | 
1262  |  |   /*  | 
1263  |  |    * Open/close dev_name may block the process  | 
1264  |  |    * (i.e. overfilled thin pool volume)  | 
1265  |  |    */  | 
1266  | 0  |   if (!*dev_name) { | 
1267  | 0  |     log_error("Empty device name passed to BLKRAGET"); | 
1268  | 0  |     return 0;  | 
1269  | 0  |   }  | 
1270  |  |  | 
1271  | 0  |   if ((fd = _open_dev_node(dev_name)) < 0)  | 
1272  | 0  |     return_0;  | 
1273  |  |  | 
1274  | 0  |   if (ioctl(fd, BLKRAGET, &read_ahead_long)) { | 
1275  | 0  |     log_sys_error("BLKRAGET", dev_name); | 
1276  | 0  |     *read_ahead = 0;  | 
1277  | 0  |     r = 0;  | 
1278  | 0  |   } else { | 
1279  | 0  |     *read_ahead = (uint32_t) read_ahead_long;  | 
1280  | 0  |     log_debug_activation("%s: read ahead is %" PRIu32, dev_name, *read_ahead); | 
1281  | 0  |   }  | 
1282  |  | 
  | 
1283  | 0  |   if (close(fd))  | 
1284  | 0  |     log_sys_debug("close", dev_name); | 
1285  |  | 
  | 
1286  | 0  |   return r;  | 
1287  | 0  | }  | 
1288  |  |  | 
1289  |  | static int _set_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,  | 
1290  |  |          uint32_t read_ahead)  | 
1291  | 0  | { | 
1292  | 0  |   char buf[24];  | 
1293  | 0  |   int len;  | 
1294  | 0  |   int r = 1;  | 
1295  | 0  |   int fd;  | 
1296  | 0  |   long read_ahead_long = (long) read_ahead;  | 
1297  |  | 
  | 
1298  | 0  |   log_debug_activation("%s (%d:%d): Setting read ahead to %" PRIu32, dev_name, | 
1299  | 0  |            major, minor, read_ahead);  | 
1300  |  |  | 
1301  |  |   /*  | 
1302  |  |    * If we know the device number, use sysfs if we can.  | 
1303  |  |    * Otherwise use BLKRASET ioctl. RA is set after resume.  | 
1304  |  |    */  | 
1305  | 0  |   if (*_sysfs_dir && major != 0) { | 
1306  | 0  |     if (dm_snprintf(_path0, sizeof(_path0), "%sdev/block/%" PRIu32  | 
1307  | 0  |         ":%" PRIu32 "/bdi/read_ahead_kb",  | 
1308  | 0  |         _sysfs_dir, major, minor) < 0) { | 
1309  | 0  |       log_error("Failed to build sysfs_path."); | 
1310  | 0  |       return 0;  | 
1311  | 0  |     }  | 
1312  |  |  | 
1313  |  |     /* Sysfs is kB based, round up to kB */  | 
1314  | 0  |     if ((len = dm_snprintf(buf, sizeof(buf), FMTu32,  | 
1315  | 0  |                (read_ahead + 1) / 2)) < 0) { | 
1316  | 0  |       log_error("Failed to build size in kB."); | 
1317  | 0  |       return 0;  | 
1318  | 0  |     }  | 
1319  |  |  | 
1320  | 0  |     if ((fd = open(_path0, O_WRONLY, 0)) != -1) { | 
1321  | 0  |       if (write(fd, buf, len) < len) { | 
1322  | 0  |         log_sys_error("write", _path0); | 
1323  | 0  |         r = 0;  | 
1324  | 0  |       }  | 
1325  |  | 
  | 
1326  | 0  |       if (close(fd))  | 
1327  | 0  |         log_sys_debug("close", _path0); | 
1328  |  | 
  | 
1329  | 0  |       return r;  | 
1330  | 0  |     }  | 
1331  |  |  | 
1332  | 0  |     log_sys_debug("open", _path0); | 
1333  |  |     /* Fall back to use dev_name */  | 
1334  | 0  |   }  | 
1335  |  |  | 
1336  | 0  |   if (!*dev_name) { | 
1337  | 0  |     log_error("Empty device name passed to BLKRAGET"); | 
1338  | 0  |     return 0;  | 
1339  | 0  |   }  | 
1340  |  |  | 
1341  | 0  |   if ((fd = _open_dev_node(dev_name)) < 0)  | 
1342  | 0  |     return_0;  | 
1343  |  |  | 
1344  | 0  |   if (ioctl(fd, BLKRASET, read_ahead_long)) { | 
1345  | 0  |     log_sys_error("BLKRASET", dev_name); | 
1346  | 0  |     r = 0;  | 
1347  | 0  |   }  | 
1348  |  | 
  | 
1349  | 0  |   if (close(fd))  | 
1350  | 0  |     log_sys_debug("close", dev_name); | 
1351  |  | 
  | 
1352  | 0  |   return r;  | 
1353  | 0  | }  | 
1354  |  |  | 
1355  |  | static int _set_dev_node_read_ahead(const char *dev_name,  | 
1356  |  |             uint32_t major, uint32_t minor,  | 
1357  |  |             uint32_t read_ahead, uint32_t read_ahead_flags)  | 
1358  | 0  | { | 
1359  | 0  |   uint32_t current_read_ahead;  | 
1360  |  | 
  | 
1361  | 0  |   if (read_ahead == DM_READ_AHEAD_AUTO)  | 
1362  | 0  |     return 1;  | 
1363  |  |  | 
1364  | 0  |   if (read_ahead == DM_READ_AHEAD_NONE)  | 
1365  | 0  |     read_ahead = 0;  | 
1366  |  | 
  | 
1367  | 0  |   if (read_ahead_flags & DM_READ_AHEAD_MINIMUM_FLAG) { | 
1368  | 0  |     if (!get_dev_node_read_ahead(dev_name, major, minor, ¤t_read_ahead))  | 
1369  | 0  |       return_0;  | 
1370  |  |  | 
1371  | 0  |     if (current_read_ahead >= read_ahead) { | 
1372  | 0  |       log_debug_activation("%s: retaining kernel read ahead of %" PRIu32 | 
1373  | 0  |           " (requested %" PRIu32 ")",             | 
1374  | 0  |           dev_name, current_read_ahead, read_ahead);  | 
1375  | 0  |       return 1;  | 
1376  | 0  |     }  | 
1377  | 0  |   }  | 
1378  |  |  | 
1379  | 0  |   return _set_read_ahead(dev_name, major, minor, read_ahead);  | 
1380  | 0  | }  | 
1381  |  |  | 
1382  |  | #else  | 
1383  |  |  | 
1384  |  | int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)  | 
1385  |  | { | 
1386  |  |   *read_ahead = 0;  | 
1387  |  |  | 
1388  |  |   return 1;  | 
1389  |  | }  | 
1390  |  |  | 
1391  |  | static int _set_dev_node_read_ahead(const char *dev_name,  | 
1392  |  |             uint32_t major, uint32_t minor,  | 
1393  |  |             uint32_t read_ahead, uint32_t read_ahead_flags)  | 
1394  |  | { | 
1395  |  |   return 1;  | 
1396  |  | }  | 
1397  |  | #endif  | 
1398  |  |  | 
1399  |  | typedef enum { | 
1400  |  |   NODE_ADD,  | 
1401  |  |   NODE_DEL,  | 
1402  |  |   NODE_RENAME,  | 
1403  |  |   NODE_READ_AHEAD,  | 
1404  |  |   NUM_NODES  | 
1405  |  | } node_op_t;  | 
1406  |  |  | 
1407  |  | static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,  | 
1408  |  |            uint32_t minor, uid_t uid, gid_t gid, mode_t mode,  | 
1409  |  |            const char *old_name, uint32_t read_ahead,  | 
1410  |  |            uint32_t read_ahead_flags, int warn_if_udev_failed)  | 
1411  | 0  | { | 
1412  | 0  |   switch (type) { | 
1413  | 0  |   case NODE_ADD:  | 
1414  | 0  |     return _add_dev_node(dev_name, major, minor, uid, gid,  | 
1415  | 0  |              mode, warn_if_udev_failed);  | 
1416  | 0  |   case NODE_DEL:  | 
1417  | 0  |     return _rm_dev_node(dev_name, warn_if_udev_failed);  | 
1418  | 0  |   case NODE_RENAME:  | 
1419  | 0  |     return _rename_dev_node(old_name, dev_name, warn_if_udev_failed);  | 
1420  | 0  |   case NODE_READ_AHEAD:  | 
1421  | 0  |     return _set_dev_node_read_ahead(dev_name, major, minor,  | 
1422  | 0  |             read_ahead, read_ahead_flags);  | 
1423  | 0  |   default:  | 
1424  | 0  |     ; /* NOTREACHED */  | 
1425  | 0  |   }  | 
1426  |  |  | 
1427  | 0  |   return 1;  | 
1428  | 0  | }  | 
1429  |  |  | 
1430  |  | static DM_LIST_INIT(_node_ops);  | 
1431  |  | static int _count_node_ops[NUM_NODES];  | 
1432  |  |  | 
1433  |  | struct node_op_parms { | 
1434  |  |   struct dm_list list;  | 
1435  |  |   node_op_t type;  | 
1436  |  |   char *dev_name;  | 
1437  |  |   uint32_t major;  | 
1438  |  |   uint32_t minor;  | 
1439  |  |   uid_t uid;  | 
1440  |  |   gid_t gid;  | 
1441  |  |   mode_t mode;  | 
1442  |  |   uint32_t read_ahead;  | 
1443  |  |   uint32_t read_ahead_flags;  | 
1444  |  |   char *old_name;  | 
1445  |  |   int warn_if_udev_failed;  | 
1446  |  |   unsigned rely_on_udev;  | 
1447  |  |   char names[0];  | 
1448  |  | };  | 
1449  |  |  | 
1450  |  | static void _store_str(char **pos, char **ptr, const char *str)  | 
1451  | 0  | { | 
1452  | 0  |   size_t len = strlen(str) + 1;  | 
1453  | 0  |   memcpy(*pos, str, len);  | 
1454  | 0  |   *ptr = *pos;  | 
1455  | 0  |   *pos += len;  | 
1456  | 0  | }  | 
1457  |  |  | 
1458  |  | static void _del_node_op(struct node_op_parms *nop)  | 
1459  | 0  | { | 
1460  | 0  |   _count_node_ops[nop->type]--;  | 
1461  | 0  |   dm_list_del(&nop->list);  | 
1462  | 0  |   dm_free(nop);  | 
1463  |  | 
  | 
1464  | 0  | }  | 
1465  |  |  | 
1466  |  | /* Check if there is other the type of node operation stacked */  | 
1467  |  | static int _other_node_ops(node_op_t type)  | 
1468  | 0  | { | 
1469  | 0  |   unsigned i;  | 
1470  |  | 
  | 
1471  | 0  |   for (i = 0; i < NUM_NODES; i++)  | 
1472  | 0  |     if (type != i && _count_node_ops[i])  | 
1473  | 0  |       return 1;  | 
1474  | 0  |   return 0;  | 
1475  | 0  | }  | 
1476  |  |  | 
1477  |  | static void _log_node_op(const char *action_str, struct node_op_parms *nop)  | 
1478  | 0  | { | 
1479  | 0  |   const char *rely = nop->rely_on_udev ? " [trust_udev]" : "" ;  | 
1480  | 0  |   const char *verify = nop->warn_if_udev_failed ? " [verify_udev]" : "";  | 
1481  |  | 
  | 
1482  | 0  |   switch (nop->type) { | 
1483  | 0  |   case NODE_ADD:  | 
1484  | 0  |     log_debug_activation("%s: %s NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o%s%s", | 
1485  | 0  |              nop->dev_name, action_str, nop->major, nop->minor, nop->uid, nop->gid, nop->mode,  | 
1486  | 0  |              rely, verify);  | 
1487  | 0  |     break;  | 
1488  | 0  |   case NODE_DEL:  | 
1489  | 0  |     log_debug_activation("%s: %s NODE_DEL%s%s", nop->dev_name, action_str, rely, verify); | 
1490  | 0  |     break;  | 
1491  | 0  |   case NODE_RENAME:  | 
1492  | 0  |     log_debug_activation("%s: %s NODE_RENAME to %s%s%s", nop->old_name, action_str, nop->dev_name, rely, verify); | 
1493  | 0  |     break;  | 
1494  | 0  |   case NODE_READ_AHEAD:  | 
1495  | 0  |     log_debug_activation("%s: %s NODE_READ_AHEAD %" PRIu32 " (flags=%" PRIu32 ")%s%s", | 
1496  | 0  |              nop->dev_name, action_str, nop->read_ahead, nop->read_ahead_flags, rely, verify);  | 
1497  | 0  |     break;  | 
1498  | 0  |   default:  | 
1499  | 0  |     ; /* NOTREACHED */  | 
1500  | 0  |   }  | 
1501  | 0  | }  | 
1502  |  |  | 
1503  |  | static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,  | 
1504  |  |         uint32_t minor, uid_t uid, gid_t gid, mode_t mode,  | 
1505  |  |         const char *old_name, uint32_t read_ahead,  | 
1506  |  |         uint32_t read_ahead_flags, int warn_if_udev_failed,  | 
1507  |  |         unsigned rely_on_udev)  | 
1508  | 0  | { | 
1509  | 0  |   struct node_op_parms *nop;  | 
1510  | 0  |   struct dm_list *noph, *nopht;  | 
1511  | 0  |   size_t len = strlen(dev_name) + strlen(old_name) + 2;  | 
1512  | 0  |   char *pos;  | 
1513  |  |  | 
1514  |  |   /*  | 
1515  |  |    * Note: warn_if_udev_failed must have valid content  | 
1516  |  |    */  | 
1517  | 0  |   if ((type == NODE_DEL) && _other_node_ops(type))  | 
1518  |  |     /*  | 
1519  |  |      * Ignore any outstanding operations on the node if deleting it.  | 
1520  |  |      */  | 
1521  | 0  |     dm_list_iterate_safe(noph, nopht, &_node_ops) { | 
1522  | 0  |       nop = dm_list_item(noph, struct node_op_parms);  | 
1523  | 0  |       if (!strcmp(dev_name, nop->dev_name)) { | 
1524  | 0  |         _log_node_op("Unstacking", nop); | 
1525  | 0  |         _del_node_op(nop);  | 
1526  | 0  |         if (!_other_node_ops(type))  | 
1527  | 0  |           break; /* no other non DEL ops */  | 
1528  | 0  |       }  | 
1529  | 0  |     }  | 
1530  | 0  |   else if ((type == NODE_ADD) && _count_node_ops[NODE_DEL])  | 
1531  |  |     /*  | 
1532  |  |      * Ignore previous DEL operation on added node.  | 
1533  |  |      * (No other operations for this device then DEL could be stacked here).  | 
1534  |  |      */  | 
1535  | 0  |     dm_list_iterate_safe(noph, nopht, &_node_ops) { | 
1536  | 0  |       nop = dm_list_item(noph, struct node_op_parms);  | 
1537  | 0  |       if ((nop->type == NODE_DEL) &&  | 
1538  | 0  |           !strcmp(dev_name, nop->dev_name)) { | 
1539  | 0  |         _log_node_op("Unstacking", nop); | 
1540  | 0  |         _del_node_op(nop);  | 
1541  | 0  |         break; /* no other DEL ops */  | 
1542  | 0  |       }  | 
1543  | 0  |     }  | 
1544  | 0  |   else if (type == NODE_RENAME)  | 
1545  |  |     /*  | 
1546  |  |      * Ignore any outstanding operations if renaming it.  | 
1547  |  |      *  | 
1548  |  |      * Currently  RENAME operation happens through 'suspend -> resume'.  | 
1549  |  |      * On 'resume' device is added with read_ahead settings, so it is  | 
1550  |  |      * safe to remove any stacked ADD, RENAME, READ_AHEAD operation  | 
1551  |  |      * There cannot be any DEL operation on the renamed device.  | 
1552  |  |      */  | 
1553  | 0  |     dm_list_iterate_safe(noph, nopht, &_node_ops) { | 
1554  | 0  |       nop = dm_list_item(noph, struct node_op_parms);  | 
1555  | 0  |       if (!strcmp(old_name, nop->dev_name)) { | 
1556  | 0  |         _log_node_op("Unstacking", nop); | 
1557  | 0  |         _del_node_op(nop);  | 
1558  | 0  |       }  | 
1559  | 0  |     }  | 
1560  | 0  |   else if (type == NODE_READ_AHEAD) { | 
1561  |  |     /* udev doesn't process readahead */  | 
1562  | 0  |     rely_on_udev = 0;  | 
1563  | 0  |     warn_if_udev_failed = 0;  | 
1564  | 0  |   }  | 
1565  |  | 
  | 
1566  | 0  |   if (!(nop = dm_malloc(sizeof(*nop) + len))) { | 
1567  | 0  |     log_error("Insufficient memory to stack mknod operation"); | 
1568  | 0  |     return 0;  | 
1569  | 0  |   }  | 
1570  |  |  | 
1571  | 0  |   pos = nop->names;  | 
1572  | 0  |   nop->type = type;  | 
1573  | 0  |   nop->major = major;  | 
1574  | 0  |   nop->minor = minor;  | 
1575  | 0  |   nop->uid = uid;  | 
1576  | 0  |   nop->gid = gid;  | 
1577  | 0  |   nop->mode = mode;  | 
1578  | 0  |   nop->read_ahead = read_ahead;  | 
1579  | 0  |   nop->read_ahead_flags = read_ahead_flags;  | 
1580  | 0  |   nop->rely_on_udev = rely_on_udev;  | 
1581  |  |  | 
1582  |  |   /*  | 
1583  |  |    * Clear warn_if_udev_failed if rely_on_udev is set.  It doesn't get  | 
1584  |  |    * checked in this case - this just removes the flag from log messages.  | 
1585  |  |    */  | 
1586  | 0  |   nop->warn_if_udev_failed = rely_on_udev ? 0 : warn_if_udev_failed;  | 
1587  |  | 
  | 
1588  | 0  |   _store_str(&pos, &nop->dev_name, dev_name);  | 
1589  | 0  |   _store_str(&pos, &nop->old_name, old_name);  | 
1590  |  | 
  | 
1591  | 0  |   _count_node_ops[type]++;  | 
1592  | 0  |   dm_list_add(&_node_ops, &nop->list);  | 
1593  |  | 
  | 
1594  | 0  |   _log_node_op("Stacking", nop); | 
1595  |  | 
  | 
1596  | 0  |   return 1;  | 
1597  | 0  | }  | 
1598  |  |  | 
1599  |  | static void _pop_node_ops(void)  | 
1600  | 11.2k  | { | 
1601  | 11.2k  |   struct dm_list *noph, *nopht;  | 
1602  | 11.2k  |   struct node_op_parms *nop;  | 
1603  |  |  | 
1604  | 11.2k  |   dm_list_iterate_safe(noph, nopht, &_node_ops) { | 
1605  | 0  |     nop = dm_list_item(noph, struct node_op_parms);  | 
1606  | 0  |     if (!nop->rely_on_udev) { | 
1607  | 0  |       _log_node_op("Processing", nop); | 
1608  | 0  |       _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,  | 
1609  | 0  |             nop->uid, nop->gid, nop->mode, nop->old_name,  | 
1610  | 0  |             nop->read_ahead, nop->read_ahead_flags,  | 
1611  | 0  |             nop->warn_if_udev_failed);  | 
1612  | 0  |     } else  | 
1613  | 0  |       _log_node_op("Skipping", nop); | 
1614  | 0  |     _del_node_op(nop);  | 
1615  | 0  |   }  | 
1616  | 11.2k  | }  | 
1617  |  |  | 
1618  |  | int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,  | 
1619  |  |      uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev)  | 
1620  | 0  | { | 
1621  | 0  |   return _stack_node_op(NODE_ADD, dev_name, major, minor, uid,  | 
1622  | 0  |             gid, mode, "", 0, 0, check_udev, rely_on_udev);  | 
1623  | 0  | }  | 
1624  |  |  | 
1625  |  | int rename_dev_node(const char *old_name, const char *new_name, int check_udev, unsigned rely_on_udev)  | 
1626  | 0  | { | 
1627  | 0  |   return _stack_node_op(NODE_RENAME, new_name, 0, 0, 0,  | 
1628  | 0  |             0, 0, old_name, 0, 0, check_udev, rely_on_udev);  | 
1629  | 0  | }  | 
1630  |  |  | 
1631  |  | int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev)  | 
1632  | 0  | { | 
1633  | 0  |   return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0,  | 
1634  | 0  |             0, 0, "", 0, 0, check_udev, rely_on_udev);  | 
1635  | 0  | }  | 
1636  |  |  | 
1637  |  | int set_dev_node_read_ahead(const char *dev_name,  | 
1638  |  |                             uint32_t major, uint32_t minor,  | 
1639  |  |           uint32_t read_ahead, uint32_t read_ahead_flags)  | 
1640  | 0  | { | 
1641  | 0  |   if (read_ahead == DM_READ_AHEAD_AUTO)  | 
1642  | 0  |     return 1;  | 
1643  |  |  | 
1644  | 0  |   return _stack_node_op(NODE_READ_AHEAD, dev_name, major, minor, 0, 0,  | 
1645  | 0  |                               0, "", read_ahead, read_ahead_flags, 0, 0);  | 
1646  | 0  | }  | 
1647  |  |  | 
1648  |  | void update_devs(void)  | 
1649  | 11.2k  | { | 
1650  | 11.2k  |   _pop_node_ops();  | 
1651  | 11.2k  | }  | 
1652  |  |  | 
1653  |  | static int _canonicalize_and_set_dir(const char *src, const char *suffix, size_t max_len, char *dir)  | 
1654  | 0  | { | 
1655  | 0  |   size_t len;  | 
1656  | 0  |   const char *slash;  | 
1657  |  | 
  | 
1658  | 0  |   if (*src != '/') { | 
1659  | 0  |     log_debug_activation("Invalid directory value, %s: " | 
1660  | 0  |              "not an absolute name.", src);  | 
1661  | 0  |     return 0;  | 
1662  | 0  |   }  | 
1663  |  |  | 
1664  | 0  |   len = strlen(src);  | 
1665  | 0  |   slash = src[len-1] == '/' ? "" : "/";  | 
1666  |  | 
  | 
1667  | 0  |   if (dm_snprintf(dir, max_len, "%s%s%s", src, slash, suffix ? suffix : "") < 0) { | 
1668  | 0  |     log_debug_activation("Invalid directory value, %s: name too long.", src); | 
1669  | 0  |     return 0;  | 
1670  | 0  |   }  | 
1671  |  |  | 
1672  | 0  |   return 1;  | 
1673  | 0  | }  | 
1674  |  |  | 
1675  |  | int dm_set_dev_dir(const char *dev_dir)  | 
1676  | 0  | { | 
1677  | 0  |   return _canonicalize_and_set_dir(dev_dir, DM_DIR, sizeof _dm_dir, _dm_dir);  | 
1678  | 0  | }  | 
1679  |  |  | 
1680  |  | const char *dm_dir(void)  | 
1681  | 0  | { | 
1682  | 0  |   return _dm_dir;  | 
1683  | 0  | }  | 
1684  |  |  | 
1685  |  | int dm_set_sysfs_dir(const char *sysfs_dir)  | 
1686  | 0  | { | 
1687  | 0  |   if (!sysfs_dir || !*sysfs_dir) { | 
1688  | 0  |     _sysfs_dir[0] = '\0';  | 
1689  | 0  |     return 1;  | 
1690  | 0  |   }  | 
1691  |  |  | 
1692  | 0  |   return _canonicalize_and_set_dir(sysfs_dir, NULL, sizeof _sysfs_dir, _sysfs_dir);  | 
1693  | 0  | }  | 
1694  |  |  | 
1695  |  | const char *dm_sysfs_dir(void)  | 
1696  | 0  | { | 
1697  | 0  |   return _sysfs_dir;  | 
1698  | 0  | }  | 
1699  |  |  | 
1700  |  | /*  | 
1701  |  |  * Replace existing uuid_prefix provided it isn't too long.  | 
1702  |  |  */  | 
1703  |  | int dm_set_uuid_prefix(const char *uuid_prefix)  | 
1704  | 0  | { | 
1705  | 0  |   size_t len;  | 
1706  |  | 
  | 
1707  | 0  |   if (!uuid_prefix)  | 
1708  | 0  |     return_0;  | 
1709  |  |  | 
1710  | 0  |   if ((len = strlen(uuid_prefix)) > DM_MAX_UUID_PREFIX_LEN) { | 
1711  | 0  |     log_error("New uuid prefix %s too long.", uuid_prefix); | 
1712  | 0  |     return 0;  | 
1713  | 0  |   }  | 
1714  |  |  | 
1715  | 0  |   memcpy(_default_uuid_prefix, uuid_prefix, len + 1);  | 
1716  |  | 
  | 
1717  | 0  |   return 1;  | 
1718  | 0  | }  | 
1719  |  |  | 
1720  |  | const char *dm_uuid_prefix(void)  | 
1721  | 0  | { | 
1722  | 0  |   return _default_uuid_prefix;  | 
1723  | 0  | }  | 
1724  |  |  | 
1725  |  | static int _is_octal(int a)  | 
1726  | 0  | { | 
1727  | 0  |   return (((a) & ~7) == '0');  | 
1728  | 0  | }  | 
1729  |  |  | 
1730  |  | /* Convert mangled mountinfo into normal ASCII string */  | 
1731  |  | static void _unmangle_mountinfo_string(const char *src, char *buf)  | 
1732  | 0  | { | 
1733  | 0  |   while (*src) { | 
1734  | 0  |     if ((*src == '\\') &&  | 
1735  | 0  |         _is_octal(src[1]) && _is_octal(src[2]) && _is_octal(src[3])) { | 
1736  | 0  |       *buf++ = 64 * (src[1] & 7) + 8 * (src[2] & 7) + (src[3] & 7);  | 
1737  | 0  |       src += 4;  | 
1738  | 0  |     } else  | 
1739  | 0  |       *buf++ = *src++;  | 
1740  | 0  |   }  | 
1741  | 0  |   *buf = '\0';  | 
1742  | 0  | }  | 
1743  |  |  | 
1744  |  | /* coverity[+tainted_string_sanitize_content:arg-0] */  | 
1745  | 0  | static int _sanitize_line(const char *line) { return 1; } | 
1746  |  |  | 
1747  |  | /* Parse one line of mountinfo and unmangled target line */  | 
1748  |  | static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)  | 
1749  | 0  | { | 
1750  | 0  |   char root[PATH_MAX + 1]; /* sscanf needs extra '\0' */  | 
1751  | 0  |   char target[PATH_MAX + 1];  | 
1752  | 0  |   char *devmapper;  | 
1753  | 0  |   struct dm_task *dmt;  | 
1754  | 0  |   struct dm_info info;  | 
1755  | 0  |   unsigned i;  | 
1756  |  |  | 
1757  |  |   /* TODO: maybe detect availability of  %ms  glib support ? */  | 
1758  | 0  |   if (sscanf(line, "%*u %*u %u:%u %" DM_TO_STRING(PATH_MAX)  | 
1759  | 0  |        "s %" DM_TO_STRING(PATH_MAX) "s",  | 
1760  | 0  |        maj, min, root, target) < 4) { | 
1761  | 0  |     log_error("Failed to parse mountinfo line."); | 
1762  | 0  |     return 0;  | 
1763  | 0  |   }  | 
1764  |  |  | 
1765  |  |   /* btrfs fakes device numbers, but there is still /dev/mapper name  | 
1766  |  |    * placed in mountinfo, so try to detect proper major:minor via this */  | 
1767  | 0  |   if (*maj == 0 && (devmapper = strstr(line, "/dev/mapper/"))) { | 
1768  | 0  |     if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { | 
1769  | 0  |       log_error("Mount info task creation failed."); | 
1770  | 0  |       return 0;  | 
1771  | 0  |     }  | 
1772  | 0  |     devmapper += 12; /* skip fixed prefix */  | 
1773  | 0  |     for (i = 0; devmapper[i] && devmapper[i] != ' ' && i < sizeof(root)-1; ++i)  | 
1774  | 0  |       root[i] = devmapper[i];  | 
1775  | 0  |     root[i] = 0;  | 
1776  | 0  |     _unmangle_mountinfo_string(root, buf);  | 
1777  | 0  |     buf[DM_NAME_LEN] = 0; /* cut away */  | 
1778  |  | 
  | 
1779  | 0  |     if (dm_task_set_name(dmt, buf) &&  | 
1780  | 0  |         dm_task_no_open_count(dmt) &&  | 
1781  | 0  |         dm_task_run(dmt) &&  | 
1782  | 0  |         dm_task_get_info(dmt, &info)) { | 
1783  | 0  |       log_debug("Replacing mountinfo device (%u:%u) with matching DM device %s (%u:%u).", | 
1784  | 0  |           *maj, *min, buf, info.major, info.minor);  | 
1785  | 0  |       *maj = info.major;  | 
1786  | 0  |       *min = info.minor;  | 
1787  | 0  |     }  | 
1788  | 0  |     dm_task_destroy(dmt);  | 
1789  | 0  |   }  | 
1790  |  |  | 
1791  | 0  |   _unmangle_mountinfo_string(target, buf);  | 
1792  |  | 
  | 
1793  | 0  |   return 1;  | 
1794  | 0  | }  | 
1795  |  |  | 
1796  |  | /*  | 
1797  |  |  * Function to operate on individual mountinfo line,  | 
1798  |  |  * minor, major and mount target are parsed and unmangled  | 
1799  |  |  */  | 
1800  |  | int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)  | 
1801  | 0  | { | 
1802  | 0  |   FILE *minfo;  | 
1803  | 0  |   char buffer[2 * PATH_MAX];  | 
1804  | 0  |   char target[PATH_MAX];  | 
1805  | 0  |   unsigned maj, min;  | 
1806  | 0  |   int r = 1;  | 
1807  |  | 
  | 
1808  | 0  |   if (!(minfo = fopen(_mountinfo, "r"))) { | 
1809  | 0  |     if (errno != ENOENT)  | 
1810  | 0  |       log_sys_error("fopen", _mountinfo); | 
1811  | 0  |     else  | 
1812  | 0  |       log_sys_debug("fopen", _mountinfo); | 
1813  | 0  |     return 0;  | 
1814  | 0  |   }  | 
1815  |  |  | 
1816  | 0  |   while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo))  | 
1817  | 0  |     if (!_sanitize_line(buffer) ||  | 
1818  | 0  |         !_mountinfo_parse_line(buffer, &maj, &min, target) ||  | 
1819  | 0  |         !read_fn(buffer, maj, min, target, cb_data)) { | 
1820  | 0  |       stack;  | 
1821  | 0  |       r = 0;  | 
1822  | 0  |       break;  | 
1823  | 0  |     }  | 
1824  |  | 
  | 
1825  | 0  |   if (fclose(minfo))  | 
1826  | 0  |     log_sys_error("fclose", _mountinfo); | 
1827  |  | 
  | 
1828  | 0  |   return r;  | 
1829  | 0  | }  | 
1830  |  |  | 
1831  |  | static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)  | 
1832  | 0  | { | 
1833  | 0  |   char *sysfs_path, *temp_buf = NULL;  | 
1834  | 0  |   FILE *fp = NULL;  | 
1835  | 0  |   int r = 0;  | 
1836  | 0  |   size_t len;  | 
1837  |  | 
  | 
1838  | 0  |   if (!(sysfs_path = dm_malloc(PATH_MAX)) ||  | 
1839  | 0  |       !(temp_buf = dm_malloc(PATH_MAX))) { | 
1840  | 0  |     log_error("_sysfs_get_dm_name: failed to allocate temporary buffers"); | 
1841  | 0  |     goto bad;  | 
1842  | 0  |   }  | 
1843  |  |  | 
1844  | 0  |   if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32  | 
1845  | 0  |       "/dm/name", _sysfs_dir, major, minor) < 0) { | 
1846  | 0  |     log_error("_sysfs_get_dm_name: dm_snprintf failed"); | 
1847  | 0  |     goto bad;  | 
1848  | 0  |   }  | 
1849  |  |  | 
1850  | 0  |   if (!(fp = fopen(sysfs_path, "r"))) { | 
1851  | 0  |     if (errno != ENOENT)  | 
1852  | 0  |       log_sys_error("fopen", sysfs_path); | 
1853  | 0  |     else  | 
1854  | 0  |       log_sys_debug("fopen", sysfs_path); | 
1855  | 0  |     goto bad;  | 
1856  | 0  |   }  | 
1857  |  |  | 
1858  | 0  |   if (!fgets(temp_buf, PATH_MAX, fp)) { | 
1859  | 0  |     log_sys_error("fgets", sysfs_path); | 
1860  | 0  |     goto bad;  | 
1861  | 0  |   }  | 
1862  |  |  | 
1863  | 0  |   len = strlen(temp_buf);  | 
1864  |  | 
  | 
1865  | 0  |   if (len > buf_size) { | 
1866  | 0  |     log_error("_sysfs_get_dm_name: supplied buffer too small"); | 
1867  | 0  |     goto bad;  | 
1868  | 0  |   }  | 
1869  |  |  | 
1870  | 0  |   temp_buf[len ? len - 1 : 0] = '\0'; /* \n */  | 
1871  | 0  |   strcpy(buf, temp_buf);  | 
1872  | 0  |   r = 1;  | 
1873  | 0  | bad:  | 
1874  | 0  |   if (fp && fclose(fp))  | 
1875  | 0  |     log_sys_error("fclose", sysfs_path); | 
1876  |  | 
  | 
1877  | 0  |   dm_free(temp_buf);  | 
1878  | 0  |   dm_free(sysfs_path);  | 
1879  |  | 
  | 
1880  | 0  |   return r;  | 
1881  | 0  | }  | 
1882  |  |  | 
1883  |  | static int _sysfs_get_dev_major_minor(const char *path, uint32_t major, uint32_t minor)  | 
1884  | 0  | { | 
1885  | 0  |   FILE *fp;  | 
1886  | 0  |   uint32_t ma, mi;  | 
1887  | 0  |   int r;  | 
1888  |  | 
  | 
1889  | 0  |   if (!(fp = fopen(path, "r")))  | 
1890  | 0  |     return 0;  | 
1891  |  |  | 
1892  | 0  |   r = (fscanf(fp, "%" PRIu32 ":%" PRIu32 , &ma, &mi) == 2) &&  | 
1893  | 0  |     (ma == major) && (mi == minor);  | 
1894  |  |   // log_debug("Checking %s  %u:%u  -> %d", path, ma, mi, r); | 
1895  |  | 
  | 
1896  | 0  |   if (fclose(fp))  | 
1897  | 0  |     log_sys_error("fclose", path); | 
1898  |  | 
  | 
1899  | 0  |   return r;  | 
1900  | 0  | }  | 
1901  |  |  | 
1902  |  |  | 
1903  |  | static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)  | 
1904  | 0  | { | 
1905  | 0  |   const char *name, *name_dev;  | 
1906  | 0  |   char path[PATH_MAX];  | 
1907  | 0  |   struct dirent *dirent, *dirent_dev;  | 
1908  | 0  |   DIR *d, *d_dev;  | 
1909  | 0  |   struct stat st;  | 
1910  | 0  |   int r = 0, sz;  | 
1911  |  | 
  | 
1912  | 0  |   if (!*_sysfs_dir ||  | 
1913  | 0  |       dm_snprintf(path, sizeof(path), "%s/block/", _sysfs_dir) < 0) { | 
1914  | 0  |     log_error("Failed to build sysfs_path."); | 
1915  | 0  |     return 0;  | 
1916  | 0  |   }  | 
1917  |  |  | 
1918  | 0  |   if (!(d = opendir(path))) { | 
1919  | 0  |     log_sys_error("opendir", path); | 
1920  | 0  |     return 0;  | 
1921  | 0  |   }  | 
1922  |  |  | 
1923  | 0  |   while (!r && (dirent = readdir(d))) { | 
1924  | 0  |     name = dirent->d_name;  | 
1925  |  | 
  | 
1926  | 0  |     if (!strcmp(name, ".") || !strcmp(name, ".."))  | 
1927  | 0  |       continue;  | 
1928  |  |  | 
1929  | 0  |     if ((sz = dm_snprintf(path, sizeof(path), "%sblock/%s/dev",  | 
1930  | 0  |               _sysfs_dir, name)) < 5) { | 
1931  | 0  |       log_warn("Couldn't create path for %s.", name); | 
1932  | 0  |       continue;  | 
1933  | 0  |     }  | 
1934  |  |  | 
1935  | 0  |     if (_sysfs_get_dev_major_minor(path, major, minor)) { | 
1936  | 0  |       r = dm_strncpy(buf, name, buf_size);  | 
1937  | 0  |       break; /* found */  | 
1938  | 0  |     }  | 
1939  |  |  | 
1940  | 0  |     path[sz - 4] = 0; /* strip /dev from end of path string */  | 
1941  | 0  |     if (stat(path, &st))  | 
1942  | 0  |       continue;  | 
1943  |  |  | 
1944  | 0  |     if (S_ISDIR(st.st_mode)) { | 
1945  |  |  | 
1946  |  |       /* let's assume there is no tree-complex device in past systems */  | 
1947  | 0  |       if (!(d_dev = opendir(path))) { | 
1948  | 0  |         log_sys_debug("opendir", path); | 
1949  | 0  |         continue;  | 
1950  | 0  |       }  | 
1951  |  |  | 
1952  | 0  |       while ((dirent_dev = readdir(d_dev))) { | 
1953  | 0  |         name_dev = dirent_dev->d_name;  | 
1954  |  |  | 
1955  |  |         /* skip known ignorable paths */  | 
1956  | 0  |         if (!strcmp(name_dev, ".") || !strcmp(name_dev, "..") ||  | 
1957  | 0  |             !strcmp(name_dev, "bdi") ||  | 
1958  | 0  |             !strcmp(name_dev, "dev") ||  | 
1959  | 0  |             !strcmp(name_dev, "device") ||  | 
1960  | 0  |             !strcmp(name_dev, "holders") ||  | 
1961  | 0  |             !strcmp(name_dev, "integrity") ||  | 
1962  | 0  |             !strcmp(name_dev, "loop") ||  | 
1963  | 0  |             !strcmp(name_dev, "queue") ||  | 
1964  | 0  |             !strcmp(name_dev, "md") ||  | 
1965  | 0  |             !strcmp(name_dev, "mq") ||  | 
1966  | 0  |             !strcmp(name_dev, "power") ||  | 
1967  | 0  |             !strcmp(name_dev, "removable") ||  | 
1968  | 0  |             !strcmp(name_dev, "slave") ||  | 
1969  | 0  |             !strcmp(name_dev, "slaves") ||  | 
1970  | 0  |             !strcmp(name_dev, "subsystem") ||  | 
1971  | 0  |             !strcmp(name_dev, "trace") ||  | 
1972  | 0  |             !strcmp(name_dev, "uevent"))  | 
1973  | 0  |           continue;  | 
1974  |  |  | 
1975  | 0  |         if (dm_snprintf(path, sizeof(path), "%sblock/%s/%s/dev",  | 
1976  | 0  |             _sysfs_dir, name, name_dev) == -1) { | 
1977  | 0  |           log_warn("Couldn't create path for %s/%s.", name, name_dev); | 
1978  | 0  |           continue;  | 
1979  | 0  |         }  | 
1980  |  |  | 
1981  | 0  |         if (_sysfs_get_dev_major_minor(path, major, minor)) { | 
1982  | 0  |           r = dm_strncpy(buf, name_dev, buf_size);  | 
1983  | 0  |           break; /* found */  | 
1984  | 0  |         }  | 
1985  | 0  |       }  | 
1986  |  | 
  | 
1987  | 0  |       if (closedir(d_dev))  | 
1988  | 0  |         log_sys_debug("closedir", name); | 
1989  | 0  |     }  | 
1990  | 0  |   }  | 
1991  |  | 
  | 
1992  | 0  |   if (closedir(d))  | 
1993  | 0  |     log_sys_debug("closedir", path); | 
1994  |  | 
  | 
1995  | 0  |   return r;  | 
1996  | 0  | }  | 
1997  |  |  | 
1998  |  | static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)  | 
1999  | 0  | { | 
2000  | 0  |   char *name, *sysfs_path, *temp_buf = NULL;  | 
2001  | 0  |   ssize_t size;  | 
2002  | 0  |   size_t len;  | 
2003  | 0  |   int r = 0;  | 
2004  |  | 
  | 
2005  | 0  |   if (!(sysfs_path = dm_malloc(PATH_MAX)) ||  | 
2006  | 0  |       !(temp_buf = dm_malloc(PATH_MAX))) { | 
2007  | 0  |     log_error("_sysfs_get_kernel_name: failed to allocate temporary buffers"); | 
2008  | 0  |     goto bad;  | 
2009  | 0  |   }  | 
2010  |  |  | 
2011  | 0  |   if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32,  | 
2012  | 0  |       _sysfs_dir, major, minor) < 0) { | 
2013  | 0  |     log_error("_sysfs_get_kernel_name: dm_snprintf failed"); | 
2014  | 0  |     goto bad;  | 
2015  | 0  |   }  | 
2016  |  |  | 
2017  | 0  |   if ((size = readlink(sysfs_path, temp_buf, PATH_MAX - 1)) < 0) { | 
2018  | 0  |     if (errno != ENOENT)  | 
2019  | 0  |       log_sys_error("readlink", sysfs_path); | 
2020  | 0  |     else { | 
2021  | 0  |       log_sys_debug("readlink", sysfs_path); | 
2022  | 0  |       r = _sysfs_find_kernel_name(major, minor, buf, buf_size);  | 
2023  | 0  |       goto out;  | 
2024  | 0  |     }  | 
2025  | 0  |     goto bad;  | 
2026  | 0  |   }  | 
2027  | 0  |   temp_buf[size] = '\0';  | 
2028  |  | 
  | 
2029  | 0  |   if (!(name = strrchr(temp_buf, '/'))) { | 
2030  | 0  |     log_error("Could not locate device kernel name in sysfs path %s", temp_buf); | 
2031  | 0  |     goto bad;  | 
2032  | 0  |   }  | 
2033  | 0  |   name += 1;  | 
2034  | 0  |   len = size - (name - temp_buf) + 1;  | 
2035  |  | 
  | 
2036  | 0  |   if (len > buf_size) { | 
2037  | 0  |     log_error("_sysfs_get_kernel_name: output buffer too small"); | 
2038  | 0  |     goto bad;  | 
2039  | 0  |   }  | 
2040  |  |  | 
2041  | 0  |   strcpy(buf, name);  | 
2042  | 0  |   r = 1;  | 
2043  | 0  | bad:  | 
2044  | 0  | out:  | 
2045  | 0  |   dm_free(temp_buf);  | 
2046  | 0  |   dm_free(sysfs_path);  | 
2047  |  | 
  | 
2048  | 0  |   return r;  | 
2049  | 0  | }  | 
2050  |  |  | 
2051  |  | int dm_device_get_name(uint32_t major, uint32_t minor, int prefer_kernel_name,  | 
2052  |  |            char *buf, size_t buf_size)  | 
2053  | 0  | { | 
2054  | 0  |   if (!*_sysfs_dir)  | 
2055  | 0  |     return 0;  | 
2056  |  |  | 
2057  |  |   /*  | 
2058  |  |    * device-mapper devices and prefer_kernel_name = 0  | 
2059  |  |    * get dm name by reading /sys/dev/block/major:minor/dm/name,  | 
2060  |  |    * fallback to _sysfs_get_kernel_name if not successful  | 
2061  |  |    */  | 
2062  | 0  |   if (dm_is_dm_major(major) && !prefer_kernel_name) { | 
2063  | 0  |     if (_sysfs_get_dm_name(major, minor, buf, buf_size))  | 
2064  | 0  |       return 1;  | 
2065  | 0  |     else  | 
2066  | 0  |       stack;  | 
2067  | 0  |   }  | 
2068  |  |  | 
2069  |  |   /*  | 
2070  |  |    * non-device-mapper devices or prefer_kernel_name = 1  | 
2071  |  |    * get kernel name using readlink /sys/dev/block/major:minor -> .../dm-X  | 
2072  |  |    */  | 
2073  | 0  |   return _sysfs_get_kernel_name(major, minor, buf, buf_size);  | 
2074  | 0  | }  | 
2075  |  |  | 
2076  |  | int dm_device_has_holders(uint32_t major, uint32_t minor)  | 
2077  | 0  | { | 
2078  | 0  |   char sysfs_path[PATH_MAX];  | 
2079  | 0  |   struct stat st;  | 
2080  |  | 
  | 
2081  | 0  |   if (!*_sysfs_dir)  | 
2082  | 0  |     return 0;  | 
2083  |  |  | 
2084  | 0  |   if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32  | 
2085  | 0  |       ":%" PRIu32 "/holders", _sysfs_dir, major, minor) < 0) { | 
2086  | 0  |     log_warn("WARNING: sysfs_path dm_snprintf failed."); | 
2087  | 0  |     return 0;  | 
2088  | 0  |   }  | 
2089  |  |  | 
2090  | 0  |   if (stat(sysfs_path, &st)) { | 
2091  | 0  |     if (errno != ENOENT)  | 
2092  | 0  |       log_sys_debug("stat", sysfs_path); | 
2093  | 0  |     return 0;  | 
2094  | 0  |   }  | 
2095  |  |  | 
2096  | 0  |   return !dm_is_empty_dir(sysfs_path);  | 
2097  | 0  | }  | 
2098  |  |  | 
2099  |  | static int _mounted_fs_on_device(const char *kernel_dev_name)  | 
2100  | 0  | { | 
2101  | 0  |   char sysfs_path[PATH_MAX];  | 
2102  | 0  |   struct dirent *dirent;  | 
2103  | 0  |   DIR *d;  | 
2104  | 0  |   struct stat st;  | 
2105  | 0  |   int r = 0;  | 
2106  |  | 
  | 
2107  | 0  |   if (dm_snprintf(sysfs_path, PATH_MAX, "%sfs", _sysfs_dir) < 0) { | 
2108  | 0  |     log_warn("WARNING: sysfs_path dm_snprintf failed."); | 
2109  | 0  |     return 0;  | 
2110  | 0  |   }  | 
2111  |  |  | 
2112  | 0  |   if (!(d = opendir(sysfs_path))) { | 
2113  | 0  |     if (errno != ENOENT)  | 
2114  | 0  |       log_sys_debug("opendir", sysfs_path); | 
2115  | 0  |     return 0;  | 
2116  | 0  |   }  | 
2117  |  |  | 
2118  | 0  |   while ((dirent = readdir(d))) { | 
2119  | 0  |     if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))  | 
2120  | 0  |       continue;  | 
2121  |  |  | 
2122  | 0  |     if (dm_snprintf(sysfs_path, PATH_MAX, "%sfs/%s/%s",  | 
2123  | 0  |         _sysfs_dir, dirent->d_name, kernel_dev_name) < 0) { | 
2124  | 0  |       log_warn("WARNING: sysfs_path dm_snprintf failed."); | 
2125  | 0  |       break;  | 
2126  | 0  |     }  | 
2127  |  |  | 
2128  | 0  |     if (!stat(sysfs_path, &st)) { | 
2129  |  |       /* found! */  | 
2130  | 0  |       r = 1;  | 
2131  | 0  |       break;  | 
2132  | 0  |     }  | 
2133  | 0  |     else if (errno != ENOENT) { | 
2134  | 0  |       log_sys_debug("stat", sysfs_path); | 
2135  | 0  |       break;  | 
2136  | 0  |     }  | 
2137  | 0  |   }  | 
2138  |  | 
  | 
2139  | 0  |   if (closedir(d))  | 
2140  | 0  |     log_sys_debug("closedir", kernel_dev_name); | 
2141  |  | 
  | 
2142  | 0  |   return r;  | 
2143  | 0  | }  | 
2144  |  |  | 
2145  |  | struct mountinfo_s { | 
2146  |  |   unsigned maj;  | 
2147  |  |   unsigned min;  | 
2148  |  |   int mounted;  | 
2149  |  | };  | 
2150  |  |  | 
2151  |  | static int _device_has_mounted_fs(char *buffer, unsigned major, unsigned minor,  | 
2152  |  |           char *target, void *cb_data)  | 
2153  | 0  | { | 
2154  | 0  |   struct mountinfo_s *data = cb_data;  | 
2155  | 0  |   char kernel_dev_name[PATH_MAX];  | 
2156  |  | 
  | 
2157  | 0  |   if ((major == data->maj) && (minor == data->min)) { | 
2158  | 0  |     if (!dm_device_get_name(major, minor, 1, kernel_dev_name,  | 
2159  | 0  |           sizeof(kernel_dev_name))) { | 
2160  | 0  |       stack;  | 
2161  | 0  |       *kernel_dev_name = '\0';  | 
2162  | 0  |     }  | 
2163  | 0  |     log_verbose("Device %s (%u:%u) appears to be mounted on %s.", | 
2164  | 0  |           kernel_dev_name, major, minor, target);  | 
2165  | 0  |     data->mounted = 1;  | 
2166  | 0  |   }  | 
2167  |  | 
  | 
2168  | 0  |   return 1;  | 
2169  | 0  | }  | 
2170  |  |  | 
2171  |  | int dm_device_has_mounted_fs(uint32_t major, uint32_t minor)  | 
2172  | 0  | { | 
2173  | 0  |   char kernel_dev_name[PATH_MAX];  | 
2174  | 0  |   struct mountinfo_s data = { | 
2175  | 0  |     .maj = major,  | 
2176  | 0  |     .min = minor,  | 
2177  | 0  |   };  | 
2178  |  | 
  | 
2179  | 0  |   if (!dm_mountinfo_read(_device_has_mounted_fs, &data))  | 
2180  | 0  |     stack;  | 
2181  |  | 
  | 
2182  | 0  |   if (data.mounted)  | 
2183  | 0  |     return 1;  | 
2184  |  |   /*  | 
2185  |  |    * TODO: Verify dm_mountinfo_read() is superset  | 
2186  |  |    * and remove sysfs check (namespaces)  | 
2187  |  |    */  | 
2188  |  |   /* Get kernel device name first */  | 
2189  | 0  |   if (!dm_device_get_name(major, minor, 1, kernel_dev_name, PATH_MAX))  | 
2190  | 0  |     return 0;  | 
2191  |  |  | 
2192  |  |   /* Check /sys/fs/<fs_name>/<kernel_dev_name> presence */  | 
2193  | 0  |   return _mounted_fs_on_device(kernel_dev_name);  | 
2194  | 0  | }  | 
2195  |  |  | 
2196  |  | int dm_mknodes(const char *name)  | 
2197  | 0  | { | 
2198  | 0  |   struct dm_task *dmt;  | 
2199  | 0  |   int r = 0;  | 
2200  |  | 
  | 
2201  | 0  |   if (!(dmt = dm_task_create(DM_DEVICE_MKNODES)))  | 
2202  | 0  |     return_0;  | 
2203  |  |  | 
2204  | 0  |   if (name && !dm_task_set_name(dmt, name))  | 
2205  | 0  |     goto out;  | 
2206  |  |  | 
2207  | 0  |   if (!dm_task_no_open_count(dmt))  | 
2208  | 0  |     goto out;  | 
2209  |  |  | 
2210  | 0  |   r = dm_task_run(dmt);  | 
2211  |  | 
  | 
2212  | 0  | out:  | 
2213  | 0  |   dm_task_destroy(dmt);  | 
2214  | 0  |   return r;  | 
2215  | 0  | }  | 
2216  |  |  | 
2217  |  | int dm_driver_version(char *version, size_t size)  | 
2218  | 0  | { | 
2219  | 0  |   struct dm_task *dmt;  | 
2220  | 0  |   int r = 0;  | 
2221  |  | 
  | 
2222  | 0  |   if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))  | 
2223  | 0  |     return_0;  | 
2224  |  |  | 
2225  | 0  |   if (!dm_task_run(dmt))  | 
2226  | 0  |     log_error("Failed to get driver version"); | 
2227  |  | 
  | 
2228  | 0  |   if (!dm_task_get_driver_version(dmt, version, size))  | 
2229  | 0  |     goto out;  | 
2230  |  |  | 
2231  | 0  |   r = 1;  | 
2232  |  | 
  | 
2233  | 0  | out:  | 
2234  | 0  |   dm_task_destroy(dmt);  | 
2235  | 0  |   return r;  | 
2236  | 0  | }  | 
2237  |  |  | 
2238  |  | static void _set_cookie_flags(struct dm_task *dmt, uint16_t flags)  | 
2239  | 0  | { | 
2240  | 0  |   if (!dm_cookie_supported())  | 
2241  | 0  |     return;  | 
2242  |  |  | 
2243  | 0  |   if (_udev_disabled) { | 
2244  |  |     /*  | 
2245  |  |      * If udev is disabled, hardcode this functionality:  | 
2246  |  |      *   - we want libdm to create the nodes  | 
2247  |  |      *   - we don't want the /dev/mapper and any subsystem  | 
2248  |  |      *     related content to be created by udev if udev  | 
2249  |  |      *     rules are installed  | 
2250  |  |      */  | 
2251  | 0  |     flags &= ~DM_UDEV_DISABLE_LIBRARY_FALLBACK;  | 
2252  | 0  |     flags |= DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;  | 
2253  | 0  |   }  | 
2254  |  | 
  | 
2255  | 0  |   dmt->event_nr = flags << DM_UDEV_FLAGS_SHIFT;  | 
2256  | 0  | }  | 
2257  |  |  | 
2258  |  | #ifndef UDEV_SYNC_SUPPORT  | 
2259  |  | void dm_udev_set_sync_support(int sync_with_udev)  | 
2260  | 0  | { | 
2261  | 0  | }  | 
2262  |  |  | 
2263  |  | int dm_udev_get_sync_support(void)  | 
2264  | 0  | { | 
2265  | 0  |   return 0;  | 
2266  | 0  | }  | 
2267  |  |  | 
2268  |  | void dm_udev_set_checking(int checking)  | 
2269  | 0  | { | 
2270  | 0  | }  | 
2271  |  |  | 
2272  |  | int dm_udev_get_checking(void)  | 
2273  | 0  | { | 
2274  | 0  |   return 0;  | 
2275  | 0  | }  | 
2276  |  |  | 
2277  |  | int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)  | 
2278  | 0  | { | 
2279  | 0  |   _set_cookie_flags(dmt, flags);  | 
2280  |  | 
  | 
2281  | 0  |   *cookie = 0;  | 
2282  | 0  |   dmt->cookie_set = 1;  | 
2283  |  | 
  | 
2284  | 0  |   return 1;  | 
2285  | 0  | }  | 
2286  |  |  | 
2287  |  | int dm_udev_complete(uint32_t cookie)  | 
2288  | 0  | { | 
2289  | 0  |   return 1;  | 
2290  | 0  | }  | 
2291  |  |  | 
2292  |  | int dm_udev_wait(uint32_t cookie)  | 
2293  | 0  | { | 
2294  | 0  |   update_devs();  | 
2295  |  | 
  | 
2296  | 0  |   return 1;  | 
2297  | 0  | }  | 
2298  |  |  | 
2299  |  | int dm_udev_wait_immediate(uint32_t cookie, int *ready)  | 
2300  | 0  | { | 
2301  | 0  |   update_devs();  | 
2302  | 0  |   *ready = 1;  | 
2303  |  | 
  | 
2304  | 0  |   return 1;  | 
2305  | 0  | }  | 
2306  |  |  | 
2307  |  | #else   /* UDEV_SYNC_SUPPORT */  | 
2308  |  |  | 
2309  |  | static int _check_semaphore_is_supported(void)  | 
2310  |  | { | 
2311  |  |   int maxid;  | 
2312  |  |   union semun arg;  | 
2313  |  |   struct seminfo seminfo;  | 
2314  |  |  | 
2315  |  |   arg.__buf = &seminfo;  | 
2316  |  |   maxid = semctl(0, 0, SEM_INFO, arg);  | 
2317  |  |  | 
2318  |  |   if (maxid < 0) { | 
2319  |  |     log_warn("Kernel not configured for semaphores (System V IPC). " | 
2320  |  |        "Not using udev synchronization code.");  | 
2321  |  |     return 0;  | 
2322  |  |   }  | 
2323  |  |  | 
2324  |  |   return 1;  | 
2325  |  | }  | 
2326  |  |  | 
2327  |  | static int _check_udev_is_running(void)  | 
2328  |  | { | 
2329  |  |   struct udev *udev;  | 
2330  |  |   struct udev_queue *udev_queue;  | 
2331  |  |   int r;  | 
2332  |  |  | 
2333  |  |   if (!(udev = udev_new()))  | 
2334  |  |     goto_bad;  | 
2335  |  |  | 
2336  |  |   if (!(udev_queue = udev_queue_new(udev))) { | 
2337  |  |     udev_unref(udev);  | 
2338  |  |     goto_bad;  | 
2339  |  |   }  | 
2340  |  |  | 
2341  |  |   if (!(r = udev_queue_get_udev_is_active(udev_queue)))  | 
2342  |  |     log_debug_activation("Udev is not running. " | 
2343  |  |              "Not using udev synchronization code.");  | 
2344  |  |  | 
2345  |  |   udev_queue_unref(udev_queue);  | 
2346  |  |   udev_unref(udev);  | 
2347  |  |  | 
2348  |  |   return r;  | 
2349  |  |  | 
2350  |  | bad:  | 
2351  |  |   log_error("Could not get udev state. Assuming udev is not running."); | 
2352  |  |   return 0;  | 
2353  |  | }  | 
2354  |  |  | 
2355  |  | static void _check_udev_sync_requirements_once(void)  | 
2356  |  | { | 
2357  |  |   if (_semaphore_supported < 0)  | 
2358  |  |     _semaphore_supported = _check_semaphore_is_supported();  | 
2359  |  |  | 
2360  |  |   if (_udev_running < 0) { | 
2361  |  |     _udev_running = _check_udev_is_running();  | 
2362  |  |     if (_udev_disabled && _udev_running)  | 
2363  |  |       log_warn("Udev is running and DM_DISABLE_UDEV environment variable is set. " | 
2364  |  |          "Bypassing udev, device-mapper library will manage device "  | 
2365  |  |          "nodes in device directory.");  | 
2366  |  |   }  | 
2367  |  | }  | 
2368  |  |  | 
2369  |  | void dm_udev_set_sync_support(int sync_with_udev)  | 
2370  |  | { | 
2371  |  |   _check_udev_sync_requirements_once();  | 
2372  |  |   _sync_with_udev = sync_with_udev;  | 
2373  |  | }  | 
2374  |  |  | 
2375  |  | int dm_udev_get_sync_support(void)  | 
2376  |  | { | 
2377  |  |   _check_udev_sync_requirements_once();  | 
2378  |  |  | 
2379  |  |   return !_udev_disabled && _semaphore_supported &&  | 
2380  |  |     dm_cookie_supported() &&_udev_running && _sync_with_udev;  | 
2381  |  | }  | 
2382  |  |  | 
2383  |  | void dm_udev_set_checking(int checking)  | 
2384  |  | { | 
2385  |  |   if ((_udev_checking = checking))  | 
2386  |  |     log_debug_activation("DM udev checking enabled"); | 
2387  |  |   else  | 
2388  |  |     log_debug_activation("DM udev checking disabled"); | 
2389  |  | }  | 
2390  |  |  | 
2391  |  | int dm_udev_get_checking(void)  | 
2392  |  | { | 
2393  |  |   return _udev_checking;  | 
2394  |  | }  | 
2395  |  |  | 
2396  |  | static int _get_cookie_sem(uint32_t cookie, int *semid)  | 
2397  |  | { | 
2398  |  |   if (cookie >> 16 != DM_COOKIE_MAGIC) { | 
2399  |  |     log_error("Could not continue to access notification " | 
2400  |  |         "semaphore identified by cookie value %"  | 
2401  |  |         PRIu32 " (0x%x). Incorrect cookie prefix.",  | 
2402  |  |         cookie, cookie);  | 
2403  |  |     return 0;  | 
2404  |  |   }  | 
2405  |  |  | 
2406  |  |   if ((*semid = semget((key_t) cookie, 1, 0)) >= 0)  | 
2407  |  |     return 1;  | 
2408  |  |  | 
2409  |  |   switch (errno) { | 
2410  |  |     case ENOENT:  | 
2411  |  |       log_error("Could not find notification " | 
2412  |  |           "semaphore identified by cookie "  | 
2413  |  |           "value %" PRIu32 " (0x%x)",  | 
2414  |  |           cookie, cookie);  | 
2415  |  |       break;  | 
2416  |  |     case EACCES:  | 
2417  |  |       log_error("No permission to access " | 
2418  |  |           "notification semaphore identified "  | 
2419  |  |           "by cookie value %" PRIu32 " (0x%x)",  | 
2420  |  |           cookie, cookie);  | 
2421  |  |       break;  | 
2422  |  |     default:  | 
2423  |  |       log_error("Failed to access notification " | 
2424  |  |            "semaphore identified by cookie "  | 
2425  |  |            "value %" PRIu32 " (0x%x): %s",  | 
2426  |  |           cookie, cookie, strerror(errno));  | 
2427  |  |       break;  | 
2428  |  |   }  | 
2429  |  |  | 
2430  |  |   return 0;  | 
2431  |  | }  | 
2432  |  |  | 
2433  |  | static int _udev_notify_sem_inc(uint32_t cookie, int semid)  | 
2434  |  | { | 
2435  |  |   struct sembuf sb = {0, 1, 0}; | 
2436  |  |   int val;  | 
2437  |  |  | 
2438  |  |   if (semop(semid, &sb, 1) < 0) { | 
2439  |  |     log_error("cookie inc: semid %d: semop failed for cookie 0x%" PRIx32 ": %s", | 
2440  |  |         semid, cookie, strerror(errno));  | 
2441  |  |     return 0;  | 
2442  |  |   }  | 
2443  |  |  | 
2444  |  |   if ((val = semctl(semid, 0, GETVAL)) < 0) { | 
2445  |  |     log_warn("cookie inc: semid %d: sem_ctl GETVAL failed for " | 
2446  |  |         "cookie 0x%" PRIx32 ": %s",  | 
2447  |  |         semid, cookie, strerror(errno));  | 
2448  |  |     log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented.", | 
2449  |  |               cookie, semid);  | 
2450  |  |   } else  | 
2451  |  |     log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d", | 
2452  |  |              cookie, semid, val);  | 
2453  |  |  | 
2454  |  |   return 1;  | 
2455  |  | }  | 
2456  |  |  | 
2457  |  | static int _udev_notify_sem_dec(uint32_t cookie, int semid)  | 
2458  |  | { | 
2459  |  |   struct sembuf sb = {0, -1, IPC_NOWAIT}; | 
2460  |  |   int val;  | 
2461  |  |  | 
2462  |  |   if ((val = semctl(semid, 0, GETVAL)) < 0)  | 
2463  |  |     log_warn("cookie dec: semid %d: sem_ctl GETVAL failed for " | 
2464  |  |        "cookie 0x%" PRIx32 ": %s",  | 
2465  |  |        semid, cookie, strerror(errno));  | 
2466  |  |  | 
2467  |  |   if (semop(semid, &sb, 1) < 0) { | 
2468  |  |     switch (errno) { | 
2469  |  |       case EAGAIN:  | 
2470  |  |         log_error("cookie dec: semid %d: semop failed for cookie " | 
2471  |  |             "0x%" PRIx32 ": "  | 
2472  |  |             "incorrect semaphore state",  | 
2473  |  |             semid, cookie);  | 
2474  |  |         break;  | 
2475  |  |       default:  | 
2476  |  |         log_error("cookie dec: semid %d: semop failed for cookie " | 
2477  |  |             "0x%" PRIx32 ": %s",  | 
2478  |  |             semid, cookie, strerror(errno));  | 
2479  |  |         break;  | 
2480  |  |     }  | 
2481  |  |     return 0;  | 
2482  |  |   }  | 
2483  |  |  | 
2484  |  |   if (val < 0)  | 
2485  |  |     log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented.", | 
2486  |  |              cookie, semid);  | 
2487  |  |   else  | 
2488  |  |     log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d", | 
2489  |  |              cookie, semid, val - 1);  | 
2490  |  |   return 1;  | 
2491  |  | }  | 
2492  |  |  | 
2493  |  | static int _udev_notify_sem_destroy(uint32_t cookie, int semid)  | 
2494  |  | { | 
2495  |  |   if (semctl(semid, 0, IPC_RMID, 0) < 0) { | 
2496  |  |     log_error("Could not cleanup notification semaphore " | 
2497  |  |         "identified by cookie value %" PRIu32 " (0x%x): %s",  | 
2498  |  |         cookie, cookie, strerror(errno));  | 
2499  |  |     return 0;  | 
2500  |  |   }  | 
2501  |  |  | 
2502  |  |   log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) destroyed", cookie, | 
2503  |  |            semid);  | 
2504  |  |  | 
2505  |  |   return 1;  | 
2506  |  | }  | 
2507  |  |  | 
2508  |  | static int _udev_notify_sem_create(uint32_t *cookie, int *semid)  | 
2509  |  | { | 
2510  |  |   int fd;  | 
2511  |  |   int gen_semid;  | 
2512  |  |   int val;  | 
2513  |  |   uint16_t base_cookie;  | 
2514  |  |   uint32_t gen_cookie;  | 
2515  |  |   union semun sem_arg;  | 
2516  |  |  | 
2517  |  |   if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { | 
2518  |  |     log_error("Failed to open /dev/urandom " | 
2519  |  |         "to create random cookie value");  | 
2520  |  |     *cookie = 0;  | 
2521  |  |     return 0;  | 
2522  |  |   }  | 
2523  |  |  | 
2524  |  |   /* Generate random cookie value. Be sure it is unique and non-zero. */  | 
2525  |  |   do { | 
2526  |  |     /* FIXME Handle non-error returns from read(). Move _io() into libdm? */  | 
2527  |  |     if (read(fd, &base_cookie, sizeof(base_cookie)) != sizeof(base_cookie)) { | 
2528  |  |       log_error("Failed to initialize notification cookie"); | 
2529  |  |       goto bad;  | 
2530  |  |     }  | 
2531  |  |  | 
2532  |  |     gen_cookie = DM_COOKIE_MAGIC << 16 | base_cookie;  | 
2533  |  |  | 
2534  |  |     if (base_cookie && (gen_semid = semget((key_t) gen_cookie,  | 
2535  |  |             1, 0600 | IPC_CREAT | IPC_EXCL)) < 0) { | 
2536  |  |       switch (errno) { | 
2537  |  |         case EEXIST:  | 
2538  |  |           /* if the semaphore key exists, we  | 
2539  |  |            * simply generate another random one */  | 
2540  |  |           base_cookie = 0;  | 
2541  |  |           break;  | 
2542  |  |         case ENOMEM:  | 
2543  |  |           log_error("Not enough memory to create " | 
2544  |  |               "notification semaphore");  | 
2545  |  |           goto bad;  | 
2546  |  |         case ENOSPC:  | 
2547  |  |           log_error("Limit for the maximum number " | 
2548  |  |               "of semaphores reached. You can "  | 
2549  |  |               "check and set the limits in "  | 
2550  |  |               "/proc/sys/kernel/sem.");  | 
2551  |  |           goto bad;  | 
2552  |  |         default:  | 
2553  |  |           log_error("Failed to create notification " | 
2554  |  |               "semaphore: %s", strerror(errno));  | 
2555  |  |           goto bad;  | 
2556  |  |       }  | 
2557  |  |     }  | 
2558  |  |   } while (!base_cookie);  | 
2559  |  |  | 
2560  |  |   log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) created", | 
2561  |  |            gen_cookie, gen_semid);  | 
2562  |  |  | 
2563  |  |   sem_arg.val = 1;  | 
2564  |  |  | 
2565  |  |   if (semctl(gen_semid, 0, SETVAL, sem_arg) < 0) { | 
2566  |  |     log_error("cookie create: semid %d: semctl failed: %s", gen_semid, strerror(errno)); | 
2567  |  |     /* We have to destroy just created semaphore  | 
2568  |  |      * so it won't stay in the system. */  | 
2569  |  |     (void) _udev_notify_sem_destroy(gen_cookie, gen_semid);  | 
2570  |  |     goto bad;  | 
2571  |  |   }  | 
2572  |  |  | 
2573  |  |   if ((val = semctl(gen_semid, 0, GETVAL)) < 0) { | 
2574  |  |     log_error("cookie create: semid %d: sem_ctl GETVAL failed for " | 
2575  |  |         "cookie 0x%" PRIx32 ": %s",  | 
2576  |  |         gen_semid, gen_cookie, strerror(errno));  | 
2577  |  |     (void) _udev_notify_sem_destroy(gen_cookie, gen_semid);  | 
2578  |  |     goto bad;  | 
2579  |  |   }  | 
2580  |  |  | 
2581  |  |   log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d", | 
2582  |  |            gen_cookie, gen_semid, val);  | 
2583  |  |  | 
2584  |  |   if (close(fd))  | 
2585  |  |     stack;  | 
2586  |  |  | 
2587  |  |   *semid = gen_semid;  | 
2588  |  |   *cookie = gen_cookie;  | 
2589  |  |  | 
2590  |  |   return 1;  | 
2591  |  |  | 
2592  |  | bad:  | 
2593  |  |   if (close(fd))  | 
2594  |  |     stack;  | 
2595  |  |  | 
2596  |  |   *cookie = 0;  | 
2597  |  |  | 
2598  |  |   return 0;  | 
2599  |  | }  | 
2600  |  |  | 
2601  |  | int dm_udev_create_cookie(uint32_t *cookie)  | 
2602  |  | { | 
2603  |  |   int semid;  | 
2604  |  |  | 
2605  |  |   if (!dm_udev_get_sync_support()) { | 
2606  |  |     *cookie = 0;  | 
2607  |  |     return 1;  | 
2608  |  |   }  | 
2609  |  |  | 
2610  |  |   return _udev_notify_sem_create(cookie, &semid);  | 
2611  |  | }  | 
2612  |  |  | 
2613  |  | static const char *_task_type_disp(int type)  | 
2614  |  | { | 
2615  |  |   switch(type) { | 
2616  |  |   case DM_DEVICE_CREATE:  | 
2617  |  |     return "CREATE";  | 
2618  |  |         case DM_DEVICE_RELOAD:  | 
2619  |  |     return "RELOAD";  | 
2620  |  |         case DM_DEVICE_REMOVE:  | 
2621  |  |     return "REMOVE";  | 
2622  |  |         case DM_DEVICE_REMOVE_ALL:  | 
2623  |  |     return "REMOVE_ALL";  | 
2624  |  |         case DM_DEVICE_SUSPEND:  | 
2625  |  |     return "SUSPEND";  | 
2626  |  |         case DM_DEVICE_RESUME:  | 
2627  |  |     return "RESUME";  | 
2628  |  |         case DM_DEVICE_INFO:  | 
2629  |  |     return "INFO";  | 
2630  |  |         case DM_DEVICE_DEPS:  | 
2631  |  |     return "DEPS";  | 
2632  |  |         case DM_DEVICE_RENAME:  | 
2633  |  |     return "RENAME";  | 
2634  |  |         case DM_DEVICE_VERSION:  | 
2635  |  |     return "VERSION";  | 
2636  |  |         case DM_DEVICE_STATUS:  | 
2637  |  |     return "STATUS";  | 
2638  |  |         case DM_DEVICE_TABLE:  | 
2639  |  |     return "TABLE";  | 
2640  |  |         case DM_DEVICE_WAITEVENT:  | 
2641  |  |     return "WAITEVENT";  | 
2642  |  |         case DM_DEVICE_LIST:  | 
2643  |  |     return "LIST";  | 
2644  |  |         case DM_DEVICE_CLEAR:  | 
2645  |  |     return "CLEAR";  | 
2646  |  |         case DM_DEVICE_MKNODES:  | 
2647  |  |     return "MKNODES";  | 
2648  |  |         case DM_DEVICE_LIST_VERSIONS:  | 
2649  |  |     return "LIST_VERSIONS";  | 
2650  |  |         case DM_DEVICE_TARGET_MSG:  | 
2651  |  |     return "TARGET_MSG";  | 
2652  |  |         case DM_DEVICE_SET_GEOMETRY:  | 
2653  |  |     return "SET_GEOMETRY";  | 
2654  |  |   }  | 
2655  |  |   return "unknown";  | 
2656  |  | }  | 
2657  |  |  | 
2658  |  | int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)  | 
2659  |  | { | 
2660  |  |   int semid;  | 
2661  |  |  | 
2662  |  |   _set_cookie_flags(dmt, flags);  | 
2663  |  |  | 
2664  |  |   if (!dm_udev_get_sync_support()) { | 
2665  |  |     *cookie = 0;  | 
2666  |  |     dmt->cookie_set = 1;  | 
2667  |  |     return 1;  | 
2668  |  |   }  | 
2669  |  |  | 
2670  |  |   if (*cookie) { | 
2671  |  |     if (!_get_cookie_sem(*cookie, &semid))  | 
2672  |  |       goto_bad;  | 
2673  |  |   } else if (!_udev_notify_sem_create(cookie, &semid))  | 
2674  |  |     goto_bad;  | 
2675  |  |  | 
2676  |  |   if (!_udev_notify_sem_inc(*cookie, semid)) { | 
2677  |  |     log_error("Could not set notification semaphore " | 
2678  |  |         "identified by cookie value %" PRIu32 " (0x%x)",  | 
2679  |  |         *cookie, *cookie);  | 
2680  |  |     goto bad;  | 
2681  |  |   }  | 
2682  |  |  | 
2683  |  |   dmt->event_nr |= ~DM_UDEV_FLAGS_MASK & *cookie;  | 
2684  |  |   dmt->cookie_set = 1;  | 
2685  |  |  | 
2686  |  |   log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) assigned to " | 
2687  |  |            "%s task(%d) with flags%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s (0x%" PRIx16 ")",  | 
2688  |  |            *cookie, semid, _task_type_disp(dmt->type), dmt->type,  | 
2689  |  |            (flags & DM_UDEV_DISABLE_DM_RULES_FLAG) ? " DISABLE_DM_RULES" : "",  | 
2690  |  |            (flags & DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG) ? " DISABLE_SUBSYSTEM_RULES" : "",  | 
2691  |  |            (flags & DM_UDEV_DISABLE_DISK_RULES_FLAG) ? " DISABLE_DISK_RULES" : "",  | 
2692  |  |            (flags & DM_UDEV_DISABLE_OTHER_RULES_FLAG) ? " DISABLE_OTHER_RULES" : "",  | 
2693  |  |            (flags & DM_UDEV_LOW_PRIORITY_FLAG) ? " LOW_PRIORITY" : "",  | 
2694  |  |            (flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK) ? " DISABLE_LIBRARY_FALLBACK" : "",  | 
2695  |  |            (flags & DM_UDEV_PRIMARY_SOURCE_FLAG) ? " PRIMARY_SOURCE" : "",  | 
2696  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG0) ? " SUBSYSTEM_0" : " ",  | 
2697  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG1) ? " SUBSYSTEM_1" : " ",  | 
2698  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG2) ? " SUBSYSTEM_2" : " ",  | 
2699  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG3) ? " SUBSYSTEM_3" : " ",  | 
2700  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG4) ? " SUBSYSTEM_4" : " ",  | 
2701  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG5) ? " SUBSYSTEM_5" : " ",  | 
2702  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG6) ? " SUBSYSTEM_6" : " ",  | 
2703  |  |            (flags & DM_SUBSYSTEM_UDEV_FLAG7) ? " SUBSYSTEM_7" : " ",  | 
2704  |  |            flags);  | 
2705  |  |  | 
2706  |  |   return 1;  | 
2707  |  |  | 
2708  |  | bad:  | 
2709  |  |   dmt->event_nr = 0;  | 
2710  |  |   return 0;  | 
2711  |  | }  | 
2712  |  |  | 
2713  |  | int dm_udev_complete(uint32_t cookie)  | 
2714  |  | { | 
2715  |  |   int semid;  | 
2716  |  |  | 
2717  |  |   if (!cookie || !dm_udev_get_sync_support())  | 
2718  |  |     return 1;  | 
2719  |  |  | 
2720  |  |   if (!_get_cookie_sem(cookie, &semid))  | 
2721  |  |     return_0;  | 
2722  |  |  | 
2723  |  |   if (!_udev_notify_sem_dec(cookie, semid)) { | 
2724  |  |     log_error("Could not signal waiting process using notification " | 
2725  |  |         "semaphore identified by cookie value %" PRIu32 " (0x%x)",  | 
2726  |  |         cookie, cookie);  | 
2727  |  |     return 0;  | 
2728  |  |   }  | 
2729  |  |  | 
2730  |  |   return 1;  | 
2731  |  | }  | 
2732  |  |  | 
2733  |  | /*  | 
2734  |  |  * If *nowait is set, return immediately leaving it set if the semaphore  | 
2735  |  |  * is not ready to be decremented to 0.  *nowait is cleared if the wait  | 
2736  |  |  * succeeds.  | 
2737  |  |  */  | 
2738  |  | static int _udev_wait(uint32_t cookie, int *nowait)  | 
2739  |  | { | 
2740  |  |   int semid;  | 
2741  |  |   struct sembuf sb = {0, 0, 0}; | 
2742  |  |   int val;  | 
2743  |  |  | 
2744  |  |   if (!cookie || !dm_udev_get_sync_support())  | 
2745  |  |     return 1;  | 
2746  |  |  | 
2747  |  |   if (!_get_cookie_sem(cookie, &semid))  | 
2748  |  |     return_0;  | 
2749  |  |  | 
2750  |  |   /* Return immediately if the semaphore value exceeds 1? */  | 
2751  |  |   if (*nowait) { | 
2752  |  |     if ((val = semctl(semid, 0, GETVAL)) < 0) { | 
2753  |  |       log_error("semid %d: sem_ctl GETVAL failed for " | 
2754  |  |           "cookie 0x%" PRIx32 ": %s",  | 
2755  |  |           semid, cookie, strerror(errno));  | 
2756  |  |       return 0;     | 
2757  |  |     }  | 
2758  |  |  | 
2759  |  |     if (val > 1)  | 
2760  |  |       return 1;  | 
2761  |  |  | 
2762  |  |     *nowait = 0;  | 
2763  |  |   }  | 
2764  |  |  | 
2765  |  |   if (!_udev_notify_sem_dec(cookie, semid)) { | 
2766  |  |     log_error("Failed to set a proper state for notification " | 
2767  |  |         "semaphore identified by cookie value %" PRIu32 " (0x%x) "  | 
2768  |  |         "to initialize waiting for incoming notifications.",  | 
2769  |  |         cookie, cookie);  | 
2770  |  |     (void) _udev_notify_sem_destroy(cookie, semid);  | 
2771  |  |     return 0;  | 
2772  |  |   }  | 
2773  |  |  | 
2774  |  |   log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) waiting for zero", | 
2775  |  |            cookie, semid);  | 
2776  |  |  | 
2777  |  | repeat_wait:  | 
2778  |  |   if (semop(semid, &sb, 1) < 0) { | 
2779  |  |     if (errno == EINTR)  | 
2780  |  |       goto repeat_wait;  | 
2781  |  |     else if (errno == EIDRM)  | 
2782  |  |       return 1;  | 
2783  |  |  | 
2784  |  |     log_error("Could not set wait state for notification semaphore " | 
2785  |  |         "identified by cookie value %" PRIu32 " (0x%x): %s",  | 
2786  |  |         cookie, cookie, strerror(errno));  | 
2787  |  |     (void) _udev_notify_sem_destroy(cookie, semid);  | 
2788  |  |     return 0;  | 
2789  |  |   }  | 
2790  |  |  | 
2791  |  |   return _udev_notify_sem_destroy(cookie, semid);  | 
2792  |  | }  | 
2793  |  |  | 
2794  |  | int dm_udev_wait(uint32_t cookie)  | 
2795  |  | { | 
2796  |  |   int nowait = 0;  | 
2797  |  |   int r = _udev_wait(cookie, &nowait);  | 
2798  |  |  | 
2799  |  |   update_devs();  | 
2800  |  |  | 
2801  |  |   return r;  | 
2802  |  | }  | 
2803  |  |  | 
2804  |  | int dm_udev_wait_immediate(uint32_t cookie, int *ready)  | 
2805  |  | { | 
2806  |  |   int nowait = 1;  | 
2807  |  |   int r = _udev_wait(cookie, &nowait);  | 
2808  |  |  | 
2809  |  |   if (r && nowait) { | 
2810  |  |     *ready = 0;  | 
2811  |  |     return 1;  | 
2812  |  |   }  | 
2813  |  |  | 
2814  |  |   update_devs();  | 
2815  |  |   *ready = 1;  | 
2816  |  |  | 
2817  |  |   return r;  | 
2818  |  | }  | 
2819  |  | #endif    /* UDEV_SYNC_SUPPORT */  |