~xnox/ubuntu/quantal/lvm2/merge95

« back to all changes in this revision

Viewing changes to .pc/avoid-dev-block.patch/lib/device/dev-cache.c

  • Committer: Dmitrijs Ledkovs
  • Date: 2012-08-15 09:45:58 UTC
  • Revision ID: dmitrijs.ledkovs@canonical.com-20120815094558-1fugetlxzs49g6g9
quilt push

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 
3
 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
 
4
 *
 
5
 * This file is part of LVM2.
 
6
 *
 
7
 * This copyrighted material is made available to anyone wishing to use,
 
8
 * modify, copy, or redistribute it subject to the terms and conditions
 
9
 * of the GNU Lesser General Public License v.2.1.
 
10
 *
 
11
 * You should have received a copy of the GNU Lesser General Public License
 
12
 * along with this program; if not, write to the Free Software Foundation,
 
13
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
14
 */
 
15
 
 
16
#include "lib.h"
 
17
#include "dev-cache.h"
 
18
#include "lvm-types.h"
 
19
#include "btree.h"
 
20
#include "filter.h"
 
21
#include "filter-persistent.h"
 
22
#include "toolcontext.h"
 
23
 
 
24
#include <unistd.h>
 
25
#include <sys/param.h>
 
26
#include <dirent.h>
 
27
 
 
28
struct dev_iter {
 
29
        struct btree_iter *current;
 
30
        struct dev_filter *filter;
 
31
};
 
32
 
 
33
struct dir_list {
 
34
        struct dm_list list;
 
35
        char dir[0];
 
36
};
 
37
 
 
38
static struct {
 
39
        struct dm_pool *mem;
 
40
        struct dm_hash_table *names;
 
41
        struct btree *devices;
 
42
        struct dm_regex *preferred_names_matcher;
 
43
        const char *dev_dir;
 
44
 
 
45
        int has_scanned;
 
46
        struct dm_list dirs;
 
47
        struct dm_list files;
 
48
 
 
49
} _cache;
 
50
 
 
51
#define _zalloc(x) dm_pool_zalloc(_cache.mem, (x))
 
52
#define _free(x) dm_pool_free(_cache.mem, (x))
 
53
#define _strdup(x) dm_pool_strdup(_cache.mem, (x))
 
54
 
 
55
static int _insert(const char *path, int rec, int check_with_udev_db);
 
56
 
 
57
/* Setup non-zero members of passed zeroed 'struct device' */
 
58
static void _dev_init(struct device *dev, int max_error_count)
 
59
{
 
60
        dev->block_size = -1;
 
61
        dev->fd = -1;
 
62
        dev->read_ahead = -1;
 
63
        dev->max_error_count = max_error_count;
 
64
 
 
65
        dm_list_init(&dev->aliases);
 
66
        dm_list_init(&dev->open_list);
 
67
}
 
68
 
 
69
struct device *dev_create_file(const char *filename, struct device *dev,
 
70
                               struct str_list *alias, int use_malloc)
 
71
{
 
72
        int allocate = !dev;
 
73
 
 
74
        if (allocate) {
 
75
                if (use_malloc) {
 
76
                        if (!(dev = dm_zalloc(sizeof(*dev)))) {
 
77
                                log_error("struct device allocation failed");
 
78
                                return NULL;
 
79
                        }
 
80
                        if (!(alias = dm_zalloc(sizeof(*alias)))) {
 
81
                                log_error("struct str_list allocation failed");
 
82
                                dm_free(dev);
 
83
                                return NULL;
 
84
                        }
 
85
                        if (!(alias->str = dm_strdup(filename))) {
 
86
                                log_error("filename strdup failed");
 
87
                                dm_free(dev);
 
88
                                dm_free(alias);
 
89
                                return NULL;
 
90
                        }
 
91
                } else {
 
92
                        if (!(dev = _zalloc(sizeof(*dev)))) {
 
93
                                log_error("struct device allocation failed");
 
94
                                return NULL;
 
95
                        }
 
96
                        if (!(alias = _zalloc(sizeof(*alias)))) {
 
97
                                log_error("struct str_list allocation failed");
 
98
                                _free(dev);
 
99
                                return NULL;
 
100
                        }
 
101
                        if (!(alias->str = _strdup(filename))) {
 
102
                                log_error("filename strdup failed");
 
103
                                return NULL;
 
104
                        }
 
105
                }
 
106
        } else if (!(alias->str = dm_strdup(filename))) {
 
107
                log_error("filename strdup failed");
 
108
                return NULL;
 
109
        }
 
110
 
 
111
        _dev_init(dev, NO_DEV_ERROR_COUNT_LIMIT);
 
112
        dev->flags = DEV_REGULAR | ((use_malloc) ? DEV_ALLOCED : 0);
 
113
        dm_list_add(&dev->aliases, &alias->list);
 
114
 
 
115
        return dev;
 
116
}
 
117
 
 
118
static struct device *_dev_create(dev_t d)
 
119
{
 
120
        struct device *dev;
 
121
 
 
122
        if (!(dev = _zalloc(sizeof(*dev)))) {
 
123
                log_error("struct device allocation failed");
 
124
                return NULL;
 
125
        }
 
126
 
 
127
        _dev_init(dev, dev_disable_after_error_count());
 
128
        dev->dev = d;
 
129
 
 
130
        return dev;
 
131
}
 
132
 
 
133
void dev_set_preferred_name(struct str_list *sl, struct device *dev)
 
134
{
 
135
        /*
 
136
         * Don't interfere with ordering specified in config file.
 
137
         */
 
138
        if (_cache.preferred_names_matcher)
 
139
                return;
 
140
 
 
141
        log_debug("%s: New preferred name", sl->str);
 
142
        dm_list_del(&sl->list);
 
143
        dm_list_add_h(&dev->aliases, &sl->list);
 
144
}
 
145
 
 
146
/*
 
147
 * Check whether path0 or path1 contains the subpath. The path that
 
148
 * *does not* contain the subpath wins (return 0 or 1). If both paths
 
149
 * contain the subpath, return -1. If none of them contains the subpath,
 
150
 * return -2.
 
151
 */
 
152
static int _builtin_preference(const char *path0, const char *path1,
 
153
                               size_t skip_prefix_count, const char *subpath)
 
154
{
 
155
        size_t subpath_len;
 
156
        int r0, r1;
 
157
 
 
158
        subpath_len = strlen(subpath);
 
159
 
 
160
        r0 = !strncmp(path0 + skip_prefix_count, subpath, subpath_len);
 
161
        r1 = !strncmp(path1 + skip_prefix_count, subpath, subpath_len);
 
162
 
 
163
        if (!r0 && r1)
 
164
                /* path0 does not have the subpath - it wins */
 
165
                return 0;
 
166
        else if (r0 && !r1)
 
167
                /* path1 does not have the subpath - it wins */
 
168
                return 1;
 
169
        else if (r0 && r1)
 
170
                /* both of them have the subpath */
 
171
                return -1;
 
172
 
 
173
        /* no path has the subpath */
 
174
        return -2;
 
175
}
 
176
 
 
177
static int _apply_builtin_path_preference_rules(const char *path0, const char *path1)
 
178
{
 
179
        size_t devdir_len;
 
180
        int r;
 
181
 
 
182
        devdir_len = strlen(_cache.dev_dir);
 
183
 
 
184
        if (!strncmp(path0, _cache.dev_dir, devdir_len) &&
 
185
            !strncmp(path1, _cache.dev_dir, devdir_len)) {
 
186
                /*
 
187
                 * We're trying to achieve the ordering:
 
188
                 *      /dev/block/ < /dev/dm-* < /dev/disk/ < /dev/mapper/ < anything else
 
189
                 */
 
190
 
 
191
                /* Prefer any other path over /dev/block/ path. */
 
192
                if ((r = _builtin_preference(path0, path1, devdir_len, "block/")) >= -1)
 
193
                        return r;
 
194
 
 
195
                /* Prefer any other path over /dev/dm-* path. */
 
196
                if ((r = _builtin_preference(path0, path1, devdir_len, "dm-")) >= -1)
 
197
                        return r;
 
198
 
 
199
                /* Prefer any other path over /dev/disk/ path. */
 
200
                if ((r = _builtin_preference(path0, path1, devdir_len, "disk/")) >= -1)
 
201
                        return r;
 
202
 
 
203
                /* Prefer any other path over /dev/mapper/ path. */
 
204
                if ((r = _builtin_preference(path0, path1, 0, dm_dir())) >= -1)
 
205
                        return r;
 
206
        }
 
207
 
 
208
        return -1;
 
209
}
 
210
 
 
211
/* Return 1 if we prefer path1 else return 0 */
 
212
static int _compare_paths(const char *path0, const char *path1)
 
213
{
 
214
        int slash0 = 0, slash1 = 0;
 
215
        int m0, m1;
 
216
        const char *p;
 
217
        char p0[PATH_MAX], p1[PATH_MAX];
 
218
        char *s0, *s1;
 
219
        struct stat stat0, stat1;
 
220
        int r;
 
221
 
 
222
        /*
 
223
         * FIXME Better to compare patterns one-at-a-time against all names.
 
224
         */
 
225
        if (_cache.preferred_names_matcher) {
 
226
                m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
 
227
                m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
 
228
 
 
229
                if (m0 != m1) {
 
230
                        if (m0 < 0)
 
231
                                return 1;
 
232
                        if (m1 < 0)
 
233
                                return 0;
 
234
                        if (m0 < m1)
 
235
                                return 1;
 
236
                        if (m1 < m0)
 
237
                                return 0;
 
238
                }
 
239
        }
 
240
 
 
241
        /* Apply built-in preference rules first. */
 
242
        if ((r = _apply_builtin_path_preference_rules(path0, path1)) >= 0)
 
243
                return r;
 
244
 
 
245
        /* Return the path with fewer slashes */
 
246
        for (p = path0; p++; p = (const char *) strchr(p, '/'))
 
247
                slash0++;
 
248
 
 
249
        for (p = path1; p++; p = (const char *) strchr(p, '/'))
 
250
                slash1++;
 
251
 
 
252
        if (slash0 < slash1)
 
253
                return 0;
 
254
        if (slash1 < slash0)
 
255
                return 1;
 
256
 
 
257
        strncpy(p0, path0, sizeof(p0) - 1);
 
258
        p0[sizeof(p0) - 1] = '\0';
 
259
        strncpy(p1, path1, sizeof(p1) - 1);
 
260
        p1[sizeof(p1) - 1] = '\0';
 
261
        s0 = p0 + 1;
 
262
        s1 = p1 + 1;
 
263
 
 
264
        /*
 
265
         * If we reach here, both paths are the same length.
 
266
         * Now skip past identical path components.
 
267
         */
 
268
        while (*s0 && *s0 == *s1)
 
269
                s0++, s1++;
 
270
 
 
271
        /* We prefer symlinks - they exist for a reason!
 
272
         * So we prefer a shorter path before the first symlink in the name.
 
273
         * FIXME Configuration option to invert this? */
 
274
        while (s0) {
 
275
                s0 = strchr(s0, '/');
 
276
                s1 = strchr(s1, '/');
 
277
                if (s0) {
 
278
                        *s0 = '\0';
 
279
                        *s1 = '\0';
 
280
                }
 
281
                if (lstat(p0, &stat0)) {
 
282
                        log_sys_very_verbose("lstat", p0);
 
283
                        return 1;
 
284
                }
 
285
                if (lstat(p1, &stat1)) {
 
286
                        log_sys_very_verbose("lstat", p1);
 
287
                        return 0;
 
288
                }
 
289
                if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
 
290
                        return 0;
 
291
                if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
 
292
                        return 1;
 
293
                if (s0) {
 
294
                        *s0++ = '/';
 
295
                        *s1++ = '/';
 
296
                }
 
297
        }
 
298
 
 
299
        /* ASCII comparison */
 
300
        if (strcmp(path0, path1) < 0)
 
301
                return 0;
 
302
        else
 
303
                return 1;
 
304
}
 
305
 
 
306
static int _add_alias(struct device *dev, const char *path)
 
307
{
 
308
        struct str_list *sl = _zalloc(sizeof(*sl));
 
309
        struct str_list *strl;
 
310
        const char *oldpath;
 
311
        int prefer_old = 1;
 
312
 
 
313
        if (!sl)
 
314
                return_0;
 
315
 
 
316
        /* Is name already there? */
 
317
        dm_list_iterate_items(strl, &dev->aliases) {
 
318
                if (!strcmp(strl->str, path)) {
 
319
                        log_debug("%s: Already in device cache", path);
 
320
                        return 1;
 
321
                }
 
322
        }
 
323
 
 
324
        sl->str = path;
 
325
 
 
326
        if (!dm_list_empty(&dev->aliases)) {
 
327
                oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
 
328
                prefer_old = _compare_paths(path, oldpath);
 
329
                log_debug("%s: Aliased to %s in device cache%s",
 
330
                          path, oldpath, prefer_old ? "" : " (preferred name)");
 
331
 
 
332
        } else
 
333
                log_debug("%s: Added to device cache", path);
 
334
 
 
335
        if (prefer_old)
 
336
                dm_list_add(&dev->aliases, &sl->list);
 
337
        else
 
338
                dm_list_add_h(&dev->aliases, &sl->list);
 
339
 
 
340
        return 1;
 
341
}
 
342
 
 
343
/*
 
344
 * Either creates a new dev, or adds an alias to
 
345
 * an existing dev.
 
346
 */
 
347
static int _insert_dev(const char *path, dev_t d)
 
348
{
 
349
        struct device *dev;
 
350
        static dev_t loopfile_count = 0;
 
351
        int loopfile = 0;
 
352
        char *path_copy;
 
353
 
 
354
        /* Generate pretend device numbers for loopfiles */
 
355
        if (!d) {
 
356
                if (dm_hash_lookup(_cache.names, path))
 
357
                        return 1;
 
358
                d = ++loopfile_count;
 
359
                loopfile = 1;
 
360
        }
 
361
 
 
362
        /* is this device already registered ? */
 
363
        if (!(dev = (struct device *) btree_lookup(_cache.devices,
 
364
                                                   (uint32_t) d))) {
 
365
                /* create new device */
 
366
                if (loopfile) {
 
367
                        if (!(dev = dev_create_file(path, NULL, NULL, 0)))
 
368
                                return_0;
 
369
                } else if (!(dev = _dev_create(d)))
 
370
                        return_0;
 
371
 
 
372
                if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
 
373
                        log_error("Couldn't insert device into binary tree.");
 
374
                        _free(dev);
 
375
                        return 0;
 
376
                }
 
377
        }
 
378
 
 
379
        if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
 
380
                log_error("Failed to duplicate path string.");
 
381
                return 0;
 
382
        }
 
383
 
 
384
        if (!loopfile && !_add_alias(dev, path_copy)) {
 
385
                log_error("Couldn't add alias to dev cache.");
 
386
                return 0;
 
387
        }
 
388
 
 
389
        if (!dm_hash_insert(_cache.names, path_copy, dev)) {
 
390
                log_error("Couldn't add name to hash in dev cache.");
 
391
                return 0;
 
392
        }
 
393
 
 
394
        return 1;
 
395
}
 
396
 
 
397
static char *_join(const char *dir, const char *name)
 
398
{
 
399
        size_t len = strlen(dir) + strlen(name) + 2;
 
400
        char *r = dm_malloc(len);
 
401
        if (r)
 
402
                snprintf(r, len, "%s/%s", dir, name);
 
403
 
 
404
        return r;
 
405
}
 
406
 
 
407
/*
 
408
 * Get rid of extra slashes in the path string.
 
409
 */
 
410
static void _collapse_slashes(char *str)
 
411
{
 
412
        char *ptr;
 
413
        int was_slash = 0;
 
414
 
 
415
        for (ptr = str; *ptr; ptr++) {
 
416
                if (*ptr == '/') {
 
417
                        if (was_slash)
 
418
                                continue;
 
419
 
 
420
                        was_slash = 1;
 
421
                } else
 
422
                        was_slash = 0;
 
423
                *str++ = *ptr;
 
424
        }
 
425
 
 
426
        *str = *ptr;
 
427
}
 
428
 
 
429
static int _insert_dir(const char *dir)
 
430
{
 
431
        int n, dirent_count, r = 1;
 
432
        struct dirent **dirent;
 
433
        char *path;
 
434
 
 
435
        dirent_count = scandir(dir, &dirent, NULL, alphasort);
 
436
        if (dirent_count > 0) {
 
437
                for (n = 0; n < dirent_count; n++) {
 
438
                        if (dirent[n]->d_name[0] == '.') {
 
439
                                free(dirent[n]);
 
440
                                continue;
 
441
                        }
 
442
 
 
443
                        if (!(path = _join(dir, dirent[n]->d_name)))
 
444
                                return_0;
 
445
 
 
446
                        _collapse_slashes(path);
 
447
                        r &= _insert(path, 1, 0);
 
448
                        dm_free(path);
 
449
 
 
450
                        free(dirent[n]);
 
451
                }
 
452
                free(dirent);
 
453
        }
 
454
 
 
455
        return r;
 
456
}
 
457
 
 
458
static int _insert_file(const char *path)
 
459
{
 
460
        struct stat info;
 
461
 
 
462
        if (stat(path, &info) < 0) {
 
463
                log_sys_very_verbose("stat", path);
 
464
                return 0;
 
465
        }
 
466
 
 
467
        if (!S_ISREG(info.st_mode)) {
 
468
                log_debug("%s: Not a regular file", path);
 
469
                return 0;
 
470
        }
 
471
 
 
472
        if (!_insert_dev(path, 0))
 
473
                return_0;
 
474
 
 
475
        return 1;
 
476
}
 
477
 
 
478
#ifdef UDEV_SYNC_SUPPORT
 
479
 
 
480
static int _device_in_udev_db(const dev_t d)
 
481
{
 
482
        struct udev *udev;
 
483
        struct udev_device *udev_device;
 
484
 
 
485
        if (!(udev = udev_get_library_context()))
 
486
                return_0;
 
487
 
 
488
        if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) {
 
489
                udev_device_unref(udev_device);
 
490
                return 1;
 
491
        }
 
492
 
 
493
        return 0;
 
494
}
 
495
 
 
496
static int _insert_udev_dir(struct udev *udev, const char *dir)
 
497
{
 
498
        struct udev_enumerate *udev_enum = NULL;
 
499
        struct udev_list_entry *device_entry, *symlink_entry;
 
500
        const char *node_name, *symlink_name;
 
501
        struct udev_device *device;
 
502
        int r = 1;
 
503
 
 
504
        if (!(udev_enum = udev_enumerate_new(udev)))
 
505
                goto bad;
 
506
 
 
507
        if (udev_enumerate_add_match_subsystem(udev_enum, "block") ||
 
508
            udev_enumerate_scan_devices(udev_enum))
 
509
                goto bad;
 
510
 
 
511
        udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) {
 
512
                if (!(device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(device_entry)))) {
 
513
                        log_warn("WARNING: udev failed to return a device entry.");
 
514
                        continue;
 
515
                }
 
516
 
 
517
                if (!(node_name = udev_device_get_devnode(device)))
 
518
                        log_warn("WARNING: udev failed to return a device node.");
 
519
                else
 
520
                        r &= _insert(node_name, 0, 0);
 
521
 
 
522
                udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) {
 
523
                        if (!(symlink_name = udev_list_entry_get_name(symlink_entry)))
 
524
                                log_warn("WARNING: udev failed to return a symlink name.");
 
525
                        else
 
526
                                r &= _insert(symlink_name, 0, 0);
 
527
                }
 
528
 
 
529
                udev_device_unref(device);
 
530
        }
 
531
 
 
532
        udev_enumerate_unref(udev_enum);
 
533
        return r;
 
534
 
 
535
bad:
 
536
        log_error("Failed to enumerate udev device list.");
 
537
        udev_enumerate_unref(udev_enum);
 
538
        return 0;
 
539
}
 
540
 
 
541
static void _insert_dirs(struct dm_list *dirs)
 
542
{
 
543
        struct dir_list *dl;
 
544
        struct udev *udev;
 
545
        int with_udev;
 
546
 
 
547
        with_udev = obtain_device_list_from_udev() &&
 
548
                    (udev = udev_get_library_context());
 
549
 
 
550
        dm_list_iterate_items(dl, &_cache.dirs) {
 
551
                if (with_udev) {
 
552
                        if (!_insert_udev_dir(udev, dl->dir))
 
553
                                log_debug("%s: Failed to insert devices from "
 
554
                                          "udev-managed directory to device "
 
555
                                          "cache fully", dl->dir);
 
556
                }
 
557
                else if (!_insert_dir(dl->dir))
 
558
                        log_debug("%s: Failed to insert devices to "
 
559
                                  "device cache fully", dl->dir);
 
560
        }
 
561
}
 
562
 
 
563
#else   /* UDEV_SYNC_SUPPORT */
 
564
 
 
565
static int _device_in_udev_db(const dev_t d)
 
566
{
 
567
        return 0;
 
568
}
 
569
 
 
570
static void _insert_dirs(struct dm_list *dirs)
 
571
{
 
572
        struct dir_list *dl;
 
573
 
 
574
        dm_list_iterate_items(dl, &_cache.dirs)
 
575
                _insert_dir(dl->dir);
 
576
}
 
577
 
 
578
#endif  /* UDEV_SYNC_SUPPORT */
 
579
 
 
580
static int _insert(const char *path, int rec, int check_with_udev_db)
 
581
{
 
582
        struct stat info;
 
583
        int r = 0;
 
584
 
 
585
        if (stat(path, &info) < 0) {
 
586
                log_sys_very_verbose("stat", path);
 
587
                return 0;
 
588
        }
 
589
 
 
590
        if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) {
 
591
                log_very_verbose("%s: Not in udev db", path);
 
592
                return 0;
 
593
        }
 
594
 
 
595
        if (S_ISDIR(info.st_mode)) {    /* add a directory */
 
596
                /* check it's not a symbolic link */
 
597
                if (lstat(path, &info) < 0) {
 
598
                        log_sys_very_verbose("lstat", path);
 
599
                        return 0;
 
600
                }
 
601
 
 
602
                if (S_ISLNK(info.st_mode)) {
 
603
                        log_debug("%s: Symbolic link to directory", path);
 
604
                        return 0;
 
605
                }
 
606
 
 
607
                if (rec)
 
608
                        r = _insert_dir(path);
 
609
 
 
610
        } else {                /* add a device */
 
611
                if (!S_ISBLK(info.st_mode)) {
 
612
                        log_debug("%s: Not a block device", path);
 
613
                        return 0;
 
614
                }
 
615
 
 
616
                if (!_insert_dev(path, info.st_rdev))
 
617
                        return_0;
 
618
 
 
619
                r = 1;
 
620
        }
 
621
 
 
622
        return r;
 
623
}
 
624
 
 
625
static void _full_scan(int dev_scan)
 
626
{
 
627
        struct dir_list *dl;
 
628
 
 
629
        if (_cache.has_scanned && !dev_scan)
 
630
                return;
 
631
 
 
632
        _insert_dirs(&_cache.dirs);
 
633
 
 
634
        dm_list_iterate_items(dl, &_cache.files)
 
635
                _insert_file(dl->dir);
 
636
 
 
637
        _cache.has_scanned = 1;
 
638
        init_full_scan_done(1);
 
639
}
 
640
 
 
641
int dev_cache_has_scanned(void)
 
642
{
 
643
        return _cache.has_scanned;
 
644
}
 
645
 
 
646
void dev_cache_scan(int do_scan)
 
647
{
 
648
        if (!do_scan)
 
649
                _cache.has_scanned = 1;
 
650
        else
 
651
                _full_scan(1);
 
652
}
 
653
 
 
654
static int _init_preferred_names(struct cmd_context *cmd)
 
655
{
 
656
        const struct dm_config_node *cn;
 
657
        const struct dm_config_value *v;
 
658
        struct dm_pool *scratch = NULL;
 
659
        const char **regex;
 
660
        unsigned count = 0;
 
661
        int i, r = 0;
 
662
 
 
663
        _cache.preferred_names_matcher = NULL;
 
664
 
 
665
        if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
 
666
            cn->v->type == DM_CFG_EMPTY_ARRAY) {
 
667
                log_very_verbose("devices/preferred_names not found in config file: "
 
668
                                 "using built-in preferences");
 
669
                return 1;
 
670
        }
 
671
 
 
672
        for (v = cn->v; v; v = v->next) {
 
673
                if (v->type != DM_CFG_STRING) {
 
674
                        log_error("preferred_names patterns must be enclosed in quotes");
 
675
                        return 0;
 
676
                }
 
677
 
 
678
                count++;
 
679
        }
 
680
 
 
681
        if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
 
682
                return_0;
 
683
 
 
684
        if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
 
685
                log_error("Failed to allocate preferred device name "
 
686
                          "pattern list.");
 
687
                goto out;
 
688
        }
 
689
 
 
690
        for (v = cn->v, i = count - 1; v; v = v->next, i--) {
 
691
                if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
 
692
                        log_error("Failed to allocate a preferred device name "
 
693
                                  "pattern.");
 
694
                        goto out;
 
695
                }
 
696
        }
 
697
 
 
698
        if (!(_cache.preferred_names_matcher =
 
699
                dm_regex_create(_cache.mem, regex, count))) {
 
700
                log_error("Preferred device name pattern matcher creation failed.");
 
701
                goto out;
 
702
        }
 
703
 
 
704
        r = 1;
 
705
 
 
706
out:
 
707
        dm_pool_destroy(scratch);
 
708
 
 
709
        return r;
 
710
}
 
711
 
 
712
int dev_cache_init(struct cmd_context *cmd)
 
713
{
 
714
        _cache.names = NULL;
 
715
        _cache.has_scanned = 0;
 
716
 
 
717
        if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
 
718
                return_0;
 
719
 
 
720
        if (!(_cache.names = dm_hash_create(128))) {
 
721
                dm_pool_destroy(_cache.mem);
 
722
                _cache.mem = 0;
 
723
                return_0;
 
724
        }
 
725
 
 
726
        if (!(_cache.devices = btree_create(_cache.mem))) {
 
727
                log_error("Couldn't create binary tree for dev-cache.");
 
728
                goto bad;
 
729
        }
 
730
 
 
731
        if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) {
 
732
                log_error("strdup dev_dir failed.");
 
733
                goto bad;
 
734
        }
 
735
 
 
736
        dm_list_init(&_cache.dirs);
 
737
        dm_list_init(&_cache.files);
 
738
 
 
739
        if (!_init_preferred_names(cmd))
 
740
                goto_bad;
 
741
 
 
742
        return 1;
 
743
 
 
744
      bad:
 
745
        dev_cache_exit();
 
746
        return 0;
 
747
}
 
748
 
 
749
static void _check_closed(struct device *dev)
 
750
{
 
751
        if (dev->fd >= 0)
 
752
                log_error("Device '%s' has been left open.", dev_name(dev));
 
753
}
 
754
 
 
755
static void _check_for_open_devices(void)
 
756
{
 
757
        dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
 
758
}
 
759
 
 
760
void dev_cache_exit(void)
 
761
{
 
762
        if (_cache.names)
 
763
                _check_for_open_devices();
 
764
 
 
765
        if (_cache.preferred_names_matcher)
 
766
                _cache.preferred_names_matcher = NULL;
 
767
 
 
768
        if (_cache.mem) {
 
769
                dm_pool_destroy(_cache.mem);
 
770
                _cache.mem = NULL;
 
771
        }
 
772
 
 
773
        if (_cache.names) {
 
774
                dm_hash_destroy(_cache.names);
 
775
                _cache.names = NULL;
 
776
        }
 
777
 
 
778
        _cache.devices = NULL;
 
779
        _cache.has_scanned = 0;
 
780
        dm_list_init(&_cache.dirs);
 
781
        dm_list_init(&_cache.files);
 
782
}
 
783
 
 
784
int dev_cache_add_dir(const char *path)
 
785
{
 
786
        struct dir_list *dl;
 
787
        struct stat st;
 
788
 
 
789
        if (stat(path, &st)) {
 
790
                log_error("Ignoring %s: %s", path, strerror(errno));
 
791
                /* But don't fail */
 
792
                return 1;
 
793
        }
 
794
 
 
795
        if (!S_ISDIR(st.st_mode)) {
 
796
                log_error("Ignoring %s: Not a directory", path);
 
797
                return 1;
 
798
        }
 
799
 
 
800
        if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
 
801
                log_error("dir_list allocation failed");
 
802
                return 0;
 
803
        }
 
804
 
 
805
        strcpy(dl->dir, path);
 
806
        dm_list_add(&_cache.dirs, &dl->list);
 
807
        return 1;
 
808
}
 
809
 
 
810
int dev_cache_add_loopfile(const char *path)
 
811
{
 
812
        struct dir_list *dl;
 
813
        struct stat st;
 
814
 
 
815
        if (stat(path, &st)) {
 
816
                log_error("Ignoring %s: %s", path, strerror(errno));
 
817
                /* But don't fail */
 
818
                return 1;
 
819
        }
 
820
 
 
821
        if (!S_ISREG(st.st_mode)) {
 
822
                log_error("Ignoring %s: Not a regular file", path);
 
823
                return 1;
 
824
        }
 
825
 
 
826
        if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
 
827
                log_error("dir_list allocation failed for file");
 
828
                return 0;
 
829
        }
 
830
 
 
831
        strcpy(dl->dir, path);
 
832
        dm_list_add(&_cache.files, &dl->list);
 
833
        return 1;
 
834
}
 
835
 
 
836
/* Check cached device name is still valid before returning it */
 
837
/* This should be a rare occurrence */
 
838
/* set quiet if the cache is expected to be out-of-date */
 
839
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
 
840
const char *dev_name_confirmed(struct device *dev, int quiet)
 
841
{
 
842
        struct stat buf;
 
843
        const char *name;
 
844
        int r;
 
845
 
 
846
        if ((dev->flags & DEV_REGULAR))
 
847
                return dev_name(dev);
 
848
 
 
849
        while ((r = stat(name = dm_list_item(dev->aliases.n,
 
850
                                          struct str_list)->str, &buf)) ||
 
851
               (buf.st_rdev != dev->dev)) {
 
852
                if (r < 0) {
 
853
                        if (quiet)
 
854
                                log_sys_debug("stat", name);
 
855
                        else
 
856
                                log_sys_error("stat", name);
 
857
                }
 
858
                if (quiet)
 
859
                        log_debug("Path %s no longer valid for device(%d,%d)",
 
860
                                  name, (int) MAJOR(dev->dev),
 
861
                                  (int) MINOR(dev->dev));
 
862
                else
 
863
                        log_error("Path %s no longer valid for device(%d,%d)",
 
864
                                  name, (int) MAJOR(dev->dev),
 
865
                                  (int) MINOR(dev->dev));
 
866
 
 
867
                /* Remove the incorrect hash entry */
 
868
                dm_hash_remove(_cache.names, name);
 
869
 
 
870
                /* Leave list alone if there isn't an alternative name */
 
871
                /* so dev_name will always find something to return. */
 
872
                /* Otherwise add the name to the correct device. */
 
873
                if (dm_list_size(&dev->aliases) > 1) {
 
874
                        dm_list_del(dev->aliases.n);
 
875
                        if (!r)
 
876
                                _insert(name, 0, obtain_device_list_from_udev());
 
877
                        continue;
 
878
                }
 
879
 
 
880
                /* Scanning issues this inappropriately sometimes. */
 
881
                log_debug("Aborting - please provide new pathname for what "
 
882
                          "used to be %s", name);
 
883
                return NULL;
 
884
        }
 
885
 
 
886
        return dev_name(dev);
 
887
}
 
888
 
 
889
struct device *dev_cache_get(const char *name, struct dev_filter *f)
 
890
{
 
891
        struct stat buf;
 
892
        struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
 
893
 
 
894
        if (d && (d->flags & DEV_REGULAR))
 
895
                return d;
 
896
 
 
897
        /* If the entry's wrong, remove it */
 
898
        if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
 
899
                dm_hash_remove(_cache.names, name);
 
900
                d = NULL;
 
901
        }
 
902
 
 
903
        if (!d) {
 
904
                _insert(name, 0, obtain_device_list_from_udev());
 
905
                d = (struct device *) dm_hash_lookup(_cache.names, name);
 
906
                if (!d) {
 
907
                        _full_scan(0);
 
908
                        d = (struct device *) dm_hash_lookup(_cache.names, name);
 
909
                }
 
910
        }
 
911
 
 
912
        return (d && (!f || (d->flags & DEV_REGULAR) ||
 
913
                      f->passes_filter(f, d))) ? d : NULL;
 
914
}
 
915
 
 
916
static struct device *_dev_cache_seek_devt(dev_t dev)
 
917
{
 
918
        struct device *d = NULL;
 
919
        struct dm_hash_node *n = dm_hash_get_first(_cache.names);
 
920
        while (n) {
 
921
                d = dm_hash_get_data(_cache.names, n);
 
922
                if (d->dev == dev)
 
923
                        return d;
 
924
                n = dm_hash_get_next(_cache.names, n);
 
925
        }
 
926
        return NULL;
 
927
}
 
928
 
 
929
/*
 
930
 * TODO This is very inefficient. We probably want a hash table indexed by
 
931
 * major:minor for keys to speed up these lookups.
 
932
 */
 
933
struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
 
934
{
 
935
        struct device *d = _dev_cache_seek_devt(dev);
 
936
 
 
937
        if (d && (d->flags & DEV_REGULAR))
 
938
                return d;
 
939
 
 
940
        if (!d) {
 
941
                _full_scan(0);
 
942
                d = _dev_cache_seek_devt(dev);
 
943
        }
 
944
 
 
945
        return (d && (!f || (d->flags & DEV_REGULAR) ||
 
946
                      f->passes_filter(f, d))) ? d : NULL;
 
947
}
 
948
 
 
949
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
 
950
{
 
951
        struct dev_iter *di = dm_malloc(sizeof(*di));
 
952
 
 
953
        if (!di) {
 
954
                log_error("dev_iter allocation failed");
 
955
                return NULL;
 
956
        }
 
957
 
 
958
        if (dev_scan && !trust_cache()) {
 
959
                /* Flag gets reset between each command */
 
960
                if (!full_scan_done())
 
961
                        persistent_filter_wipe(f); /* Calls _full_scan(1) */
 
962
        } else
 
963
                _full_scan(0);
 
964
 
 
965
        di->current = btree_first(_cache.devices);
 
966
        di->filter = f;
 
967
        di->filter->use_count++;
 
968
 
 
969
        return di;
 
970
}
 
971
 
 
972
void dev_iter_destroy(struct dev_iter *iter)
 
973
{
 
974
        iter->filter->use_count--;
 
975
        dm_free(iter);
 
976
}
 
977
 
 
978
static struct device *_iter_next(struct dev_iter *iter)
 
979
{
 
980
        struct device *d = btree_get_data(iter->current);
 
981
        iter->current = btree_next(iter->current);
 
982
        return d;
 
983
}
 
984
 
 
985
struct device *dev_iter_get(struct dev_iter *iter)
 
986
{
 
987
        while (iter->current) {
 
988
                struct device *d = _iter_next(iter);
 
989
                if (!iter->filter || (d->flags & DEV_REGULAR) ||
 
990
                    iter->filter->passes_filter(iter->filter, d))
 
991
                        return d;
 
992
        }
 
993
 
 
994
        return NULL;
 
995
}
 
996
 
 
997
void dev_reset_error_count(struct cmd_context *cmd)
 
998
{
 
999
        struct dev_iter iter;
 
1000
 
 
1001
        if (!_cache.devices)
 
1002
                return;
 
1003
 
 
1004
        iter.current = btree_first(_cache.devices);
 
1005
        while (iter.current)
 
1006
                _iter_next(&iter)->error_count = 0;
 
1007
}
 
1008
 
 
1009
int dev_fd(struct device *dev)
 
1010
{
 
1011
        return dev->fd;
 
1012
}
 
1013
 
 
1014
const char *dev_name(const struct device *dev)
 
1015
{
 
1016
        return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
 
1017
            "unknown device";
 
1018
}