~ubuntu-branches/ubuntu/quantal/lvm2/quantal

« back to all changes in this revision

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

  • Committer: Steve Langasek
  • Date: 2012-04-14 02:57:53 UTC
  • mfrom: (3.1.22 sid)
  • Revision ID: steve.langasek@canonical.com-20120414025753-ejbdw9c8llik58y9
Merge version 2.02.88-2 from Debian testing

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