1*86d7f5d3SJohn Marino /* $NetBSD: dev-cache.c,v 1.4 2009/12/02 00:58:03 haad Exp $ */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * This file is part of LVM2.
8*86d7f5d3SJohn Marino *
9*86d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino *
13*86d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16*86d7f5d3SJohn Marino */
17*86d7f5d3SJohn Marino
18*86d7f5d3SJohn Marino #include "lib.h"
19*86d7f5d3SJohn Marino #include "dev-cache.h"
20*86d7f5d3SJohn Marino #include "lvm-types.h"
21*86d7f5d3SJohn Marino #include "btree.h"
22*86d7f5d3SJohn Marino #include "filter.h"
23*86d7f5d3SJohn Marino #include "filter-persistent.h"
24*86d7f5d3SJohn Marino #include "toolcontext.h"
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino #include <unistd.h>
27*86d7f5d3SJohn Marino #include <sys/param.h>
28*86d7f5d3SJohn Marino #include <dirent.h>
29*86d7f5d3SJohn Marino
30*86d7f5d3SJohn Marino #ifdef __NetBSD__
31*86d7f5d3SJohn Marino #include "netbsd.h"
32*86d7f5d3SJohn Marino #endif
33*86d7f5d3SJohn Marino
34*86d7f5d3SJohn Marino struct dev_iter {
35*86d7f5d3SJohn Marino struct btree_iter *current;
36*86d7f5d3SJohn Marino struct dev_filter *filter;
37*86d7f5d3SJohn Marino };
38*86d7f5d3SJohn Marino
39*86d7f5d3SJohn Marino struct dir_list {
40*86d7f5d3SJohn Marino struct dm_list list;
41*86d7f5d3SJohn Marino char dir[0];
42*86d7f5d3SJohn Marino };
43*86d7f5d3SJohn Marino
44*86d7f5d3SJohn Marino static struct {
45*86d7f5d3SJohn Marino struct dm_pool *mem;
46*86d7f5d3SJohn Marino struct dm_hash_table *names;
47*86d7f5d3SJohn Marino struct btree *devices;
48*86d7f5d3SJohn Marino struct dm_regex *preferred_names_matcher;
49*86d7f5d3SJohn Marino
50*86d7f5d3SJohn Marino int has_scanned;
51*86d7f5d3SJohn Marino struct dm_list dirs;
52*86d7f5d3SJohn Marino struct dm_list files;
53*86d7f5d3SJohn Marino
54*86d7f5d3SJohn Marino } _cache;
55*86d7f5d3SJohn Marino
56*86d7f5d3SJohn Marino #define _alloc(x) dm_pool_zalloc(_cache.mem, (x))
57*86d7f5d3SJohn Marino #define _free(x) dm_pool_free(_cache.mem, (x))
58*86d7f5d3SJohn Marino #define _strdup(x) dm_pool_strdup(_cache.mem, (x))
59*86d7f5d3SJohn Marino
60*86d7f5d3SJohn Marino static int _insert(const char *path, int rec);
61*86d7f5d3SJohn Marino
dev_create_file(const char * filename,struct device * dev,struct str_list * alias,int use_malloc)62*86d7f5d3SJohn Marino struct device *dev_create_file(const char *filename, struct device *dev,
63*86d7f5d3SJohn Marino struct str_list *alias, int use_malloc)
64*86d7f5d3SJohn Marino {
65*86d7f5d3SJohn Marino int allocate = !dev;
66*86d7f5d3SJohn Marino
67*86d7f5d3SJohn Marino if (allocate) {
68*86d7f5d3SJohn Marino if (use_malloc) {
69*86d7f5d3SJohn Marino if (!(dev = dm_malloc(sizeof(*dev)))) {
70*86d7f5d3SJohn Marino log_error("struct device allocation failed");
71*86d7f5d3SJohn Marino return NULL;
72*86d7f5d3SJohn Marino }
73*86d7f5d3SJohn Marino if (!(alias = dm_malloc(sizeof(*alias)))) {
74*86d7f5d3SJohn Marino log_error("struct str_list allocation failed");
75*86d7f5d3SJohn Marino dm_free(dev);
76*86d7f5d3SJohn Marino return NULL;
77*86d7f5d3SJohn Marino }
78*86d7f5d3SJohn Marino if (!(alias->str = dm_strdup(filename))) {
79*86d7f5d3SJohn Marino log_error("filename strdup failed");
80*86d7f5d3SJohn Marino dm_free(dev);
81*86d7f5d3SJohn Marino dm_free(alias);
82*86d7f5d3SJohn Marino return NULL;
83*86d7f5d3SJohn Marino }
84*86d7f5d3SJohn Marino dev->flags = DEV_ALLOCED;
85*86d7f5d3SJohn Marino } else {
86*86d7f5d3SJohn Marino if (!(dev = _alloc(sizeof(*dev)))) {
87*86d7f5d3SJohn Marino log_error("struct device allocation failed");
88*86d7f5d3SJohn Marino return NULL;
89*86d7f5d3SJohn Marino }
90*86d7f5d3SJohn Marino if (!(alias = _alloc(sizeof(*alias)))) {
91*86d7f5d3SJohn Marino log_error("struct str_list allocation failed");
92*86d7f5d3SJohn Marino _free(dev);
93*86d7f5d3SJohn Marino return NULL;
94*86d7f5d3SJohn Marino }
95*86d7f5d3SJohn Marino if (!(alias->str = _strdup(filename))) {
96*86d7f5d3SJohn Marino log_error("filename strdup failed");
97*86d7f5d3SJohn Marino return NULL;
98*86d7f5d3SJohn Marino }
99*86d7f5d3SJohn Marino }
100*86d7f5d3SJohn Marino } else if (!(alias->str = dm_strdup(filename))) {
101*86d7f5d3SJohn Marino log_error("filename strdup failed");
102*86d7f5d3SJohn Marino return NULL;
103*86d7f5d3SJohn Marino }
104*86d7f5d3SJohn Marino
105*86d7f5d3SJohn Marino dev->flags |= DEV_REGULAR;
106*86d7f5d3SJohn Marino dm_list_init(&dev->aliases);
107*86d7f5d3SJohn Marino dm_list_add(&dev->aliases, &alias->list);
108*86d7f5d3SJohn Marino dev->end = UINT64_C(0);
109*86d7f5d3SJohn Marino dev->dev = 0;
110*86d7f5d3SJohn Marino dev->fd = -1;
111*86d7f5d3SJohn Marino dev->open_count = 0;
112*86d7f5d3SJohn Marino dev->block_size = -1;
113*86d7f5d3SJohn Marino dev->read_ahead = -1;
114*86d7f5d3SJohn Marino memset(dev->pvid, 0, sizeof(dev->pvid));
115*86d7f5d3SJohn Marino dm_list_init(&dev->open_list);
116*86d7f5d3SJohn Marino
117*86d7f5d3SJohn Marino return dev;
118*86d7f5d3SJohn Marino }
119*86d7f5d3SJohn Marino
_dev_create(dev_t d)120*86d7f5d3SJohn Marino static struct device *_dev_create(dev_t d)
121*86d7f5d3SJohn Marino {
122*86d7f5d3SJohn Marino struct device *dev;
123*86d7f5d3SJohn Marino
124*86d7f5d3SJohn Marino if (!(dev = _alloc(sizeof(*dev)))) {
125*86d7f5d3SJohn Marino log_error("struct device allocation failed");
126*86d7f5d3SJohn Marino return NULL;
127*86d7f5d3SJohn Marino }
128*86d7f5d3SJohn Marino dev->flags = 0;
129*86d7f5d3SJohn Marino dm_list_init(&dev->aliases);
130*86d7f5d3SJohn Marino dev->dev = d;
131*86d7f5d3SJohn Marino dev->fd = -1;
132*86d7f5d3SJohn Marino dev->open_count = 0;
133*86d7f5d3SJohn Marino dev->block_size = -1;
134*86d7f5d3SJohn Marino dev->read_ahead = -1;
135*86d7f5d3SJohn Marino dev->end = UINT64_C(0);
136*86d7f5d3SJohn Marino memset(dev->pvid, 0, sizeof(dev->pvid));
137*86d7f5d3SJohn Marino dm_list_init(&dev->open_list);
138*86d7f5d3SJohn Marino
139*86d7f5d3SJohn Marino return dev;
140*86d7f5d3SJohn Marino }
141*86d7f5d3SJohn Marino
dev_set_preferred_name(struct str_list * sl,struct device * dev)142*86d7f5d3SJohn Marino void dev_set_preferred_name(struct str_list *sl, struct device *dev)
143*86d7f5d3SJohn Marino {
144*86d7f5d3SJohn Marino /*
145*86d7f5d3SJohn Marino * Don't interfere with ordering specified in config file.
146*86d7f5d3SJohn Marino */
147*86d7f5d3SJohn Marino if (_cache.preferred_names_matcher)
148*86d7f5d3SJohn Marino return;
149*86d7f5d3SJohn Marino
150*86d7f5d3SJohn Marino log_debug("%s: New preferred name", sl->str);
151*86d7f5d3SJohn Marino dm_list_del(&sl->list);
152*86d7f5d3SJohn Marino dm_list_add_h(&dev->aliases, &sl->list);
153*86d7f5d3SJohn Marino }
154*86d7f5d3SJohn Marino
155*86d7f5d3SJohn Marino /* Return 1 if we prefer path1 else return 0 */
_compare_paths(const char * path0,const char * path1)156*86d7f5d3SJohn Marino static int _compare_paths(const char *path0, const char *path1)
157*86d7f5d3SJohn Marino {
158*86d7f5d3SJohn Marino int slash0 = 0, slash1 = 0;
159*86d7f5d3SJohn Marino int m0, m1;
160*86d7f5d3SJohn Marino const char *p;
161*86d7f5d3SJohn Marino char p0[PATH_MAX], p1[PATH_MAX];
162*86d7f5d3SJohn Marino char *s0, *s1;
163*86d7f5d3SJohn Marino struct stat stat0, stat1;
164*86d7f5d3SJohn Marino
165*86d7f5d3SJohn Marino /*
166*86d7f5d3SJohn Marino * FIXME Better to compare patterns one-at-a-time against all names.
167*86d7f5d3SJohn Marino */
168*86d7f5d3SJohn Marino if (_cache.preferred_names_matcher) {
169*86d7f5d3SJohn Marino m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
170*86d7f5d3SJohn Marino m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
171*86d7f5d3SJohn Marino
172*86d7f5d3SJohn Marino if (m0 != m1) {
173*86d7f5d3SJohn Marino if (m0 < 0)
174*86d7f5d3SJohn Marino return 1;
175*86d7f5d3SJohn Marino if (m1 < 0)
176*86d7f5d3SJohn Marino return 0;
177*86d7f5d3SJohn Marino if (m0 < m1)
178*86d7f5d3SJohn Marino return 1;
179*86d7f5d3SJohn Marino if (m1 < m0)
180*86d7f5d3SJohn Marino return 0;
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino }
183*86d7f5d3SJohn Marino
184*86d7f5d3SJohn Marino /*
185*86d7f5d3SJohn Marino * Built-in rules.
186*86d7f5d3SJohn Marino */
187*86d7f5d3SJohn Marino
188*86d7f5d3SJohn Marino /* Return the path with fewer slashes */
189*86d7f5d3SJohn Marino for (p = path0; p++; p = (const char *) strchr(p, '/'))
190*86d7f5d3SJohn Marino slash0++;
191*86d7f5d3SJohn Marino
192*86d7f5d3SJohn Marino for (p = path1; p++; p = (const char *) strchr(p, '/'))
193*86d7f5d3SJohn Marino slash1++;
194*86d7f5d3SJohn Marino
195*86d7f5d3SJohn Marino if (slash0 < slash1)
196*86d7f5d3SJohn Marino return 0;
197*86d7f5d3SJohn Marino if (slash1 < slash0)
198*86d7f5d3SJohn Marino return 1;
199*86d7f5d3SJohn Marino
200*86d7f5d3SJohn Marino strncpy(p0, path0, PATH_MAX);
201*86d7f5d3SJohn Marino strncpy(p1, path1, PATH_MAX);
202*86d7f5d3SJohn Marino s0 = &p0[0] + 1;
203*86d7f5d3SJohn Marino s1 = &p1[0] + 1;
204*86d7f5d3SJohn Marino
205*86d7f5d3SJohn Marino /* We prefer symlinks - they exist for a reason!
206*86d7f5d3SJohn Marino * So we prefer a shorter path before the first symlink in the name.
207*86d7f5d3SJohn Marino * FIXME Configuration option to invert this? */
208*86d7f5d3SJohn Marino while (s0) {
209*86d7f5d3SJohn Marino s0 = strchr(s0, '/');
210*86d7f5d3SJohn Marino s1 = strchr(s1, '/');
211*86d7f5d3SJohn Marino if (s0) {
212*86d7f5d3SJohn Marino *s0 = '\0';
213*86d7f5d3SJohn Marino *s1 = '\0';
214*86d7f5d3SJohn Marino }
215*86d7f5d3SJohn Marino if (lstat(p0, &stat0)) {
216*86d7f5d3SJohn Marino log_sys_very_verbose("lstat", p0);
217*86d7f5d3SJohn Marino return 1;
218*86d7f5d3SJohn Marino }
219*86d7f5d3SJohn Marino if (lstat(p1, &stat1)) {
220*86d7f5d3SJohn Marino log_sys_very_verbose("lstat", p1);
221*86d7f5d3SJohn Marino return 0;
222*86d7f5d3SJohn Marino }
223*86d7f5d3SJohn Marino if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
224*86d7f5d3SJohn Marino return 0;
225*86d7f5d3SJohn Marino if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
226*86d7f5d3SJohn Marino return 1;
227*86d7f5d3SJohn Marino if (s0) {
228*86d7f5d3SJohn Marino *s0++ = '/';
229*86d7f5d3SJohn Marino *s1++ = '/';
230*86d7f5d3SJohn Marino }
231*86d7f5d3SJohn Marino }
232*86d7f5d3SJohn Marino
233*86d7f5d3SJohn Marino /* ASCII comparison */
234*86d7f5d3SJohn Marino if (strcmp(path0, path1) < 0)
235*86d7f5d3SJohn Marino return 0;
236*86d7f5d3SJohn Marino else
237*86d7f5d3SJohn Marino return 1;
238*86d7f5d3SJohn Marino }
239*86d7f5d3SJohn Marino
_add_alias(struct device * dev,const char * path)240*86d7f5d3SJohn Marino static int _add_alias(struct device *dev, const char *path)
241*86d7f5d3SJohn Marino {
242*86d7f5d3SJohn Marino struct str_list *sl = _alloc(sizeof(*sl));
243*86d7f5d3SJohn Marino struct str_list *strl;
244*86d7f5d3SJohn Marino const char *oldpath;
245*86d7f5d3SJohn Marino int prefer_old = 1;
246*86d7f5d3SJohn Marino
247*86d7f5d3SJohn Marino if (!sl)
248*86d7f5d3SJohn Marino return_0;
249*86d7f5d3SJohn Marino
250*86d7f5d3SJohn Marino /* Is name already there? */
251*86d7f5d3SJohn Marino dm_list_iterate_items(strl, &dev->aliases) {
252*86d7f5d3SJohn Marino if (!strcmp(strl->str, path)) {
253*86d7f5d3SJohn Marino log_debug("%s: Already in device cache", path);
254*86d7f5d3SJohn Marino return 1;
255*86d7f5d3SJohn Marino }
256*86d7f5d3SJohn Marino }
257*86d7f5d3SJohn Marino
258*86d7f5d3SJohn Marino if (!(sl->str = dm_pool_strdup(_cache.mem, path)))
259*86d7f5d3SJohn Marino return_0;
260*86d7f5d3SJohn Marino
261*86d7f5d3SJohn Marino if (!dm_list_empty(&dev->aliases)) {
262*86d7f5d3SJohn Marino oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
263*86d7f5d3SJohn Marino prefer_old = _compare_paths(path, oldpath);
264*86d7f5d3SJohn Marino log_debug("%s: Aliased to %s in device cache%s",
265*86d7f5d3SJohn Marino path, oldpath, prefer_old ? "" : " (preferred name)");
266*86d7f5d3SJohn Marino
267*86d7f5d3SJohn Marino } else
268*86d7f5d3SJohn Marino log_debug("%s: Added to device cache", path);
269*86d7f5d3SJohn Marino
270*86d7f5d3SJohn Marino if (prefer_old)
271*86d7f5d3SJohn Marino dm_list_add(&dev->aliases, &sl->list);
272*86d7f5d3SJohn Marino else
273*86d7f5d3SJohn Marino dm_list_add_h(&dev->aliases, &sl->list);
274*86d7f5d3SJohn Marino
275*86d7f5d3SJohn Marino return 1;
276*86d7f5d3SJohn Marino }
277*86d7f5d3SJohn Marino
278*86d7f5d3SJohn Marino /*
279*86d7f5d3SJohn Marino * Either creates a new dev, or adds an alias to
280*86d7f5d3SJohn Marino * an existing dev.
281*86d7f5d3SJohn Marino */
_insert_dev(const char * path,dev_t d)282*86d7f5d3SJohn Marino static int _insert_dev(const char *path, dev_t d)
283*86d7f5d3SJohn Marino {
284*86d7f5d3SJohn Marino struct device *dev;
285*86d7f5d3SJohn Marino static dev_t loopfile_count = 0;
286*86d7f5d3SJohn Marino int loopfile = 0;
287*86d7f5d3SJohn Marino
288*86d7f5d3SJohn Marino /* Generate pretend device numbers for loopfiles */
289*86d7f5d3SJohn Marino if (!d) {
290*86d7f5d3SJohn Marino if (dm_hash_lookup(_cache.names, path))
291*86d7f5d3SJohn Marino return 1;
292*86d7f5d3SJohn Marino d = ++loopfile_count;
293*86d7f5d3SJohn Marino loopfile = 1;
294*86d7f5d3SJohn Marino }
295*86d7f5d3SJohn Marino
296*86d7f5d3SJohn Marino /* is this device already registered ? */
297*86d7f5d3SJohn Marino if (!(dev = (struct device *) btree_lookup(_cache.devices,
298*86d7f5d3SJohn Marino (uint32_t) d))) {
299*86d7f5d3SJohn Marino /* create new device */
300*86d7f5d3SJohn Marino if (loopfile) {
301*86d7f5d3SJohn Marino if (!(dev = dev_create_file(path, NULL, NULL, 0)))
302*86d7f5d3SJohn Marino return_0;
303*86d7f5d3SJohn Marino } else if (!(dev = _dev_create(d)))
304*86d7f5d3SJohn Marino return_0;
305*86d7f5d3SJohn Marino
306*86d7f5d3SJohn Marino if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
307*86d7f5d3SJohn Marino log_error("Couldn't insert device into binary tree.");
308*86d7f5d3SJohn Marino _free(dev);
309*86d7f5d3SJohn Marino return 0;
310*86d7f5d3SJohn Marino }
311*86d7f5d3SJohn Marino }
312*86d7f5d3SJohn Marino
313*86d7f5d3SJohn Marino if (!loopfile && !_add_alias(dev, path)) {
314*86d7f5d3SJohn Marino log_error("Couldn't add alias to dev cache.");
315*86d7f5d3SJohn Marino return 0;
316*86d7f5d3SJohn Marino }
317*86d7f5d3SJohn Marino
318*86d7f5d3SJohn Marino if (!dm_hash_insert(_cache.names, path, dev)) {
319*86d7f5d3SJohn Marino log_error("Couldn't add name to hash in dev cache.");
320*86d7f5d3SJohn Marino return 0;
321*86d7f5d3SJohn Marino }
322*86d7f5d3SJohn Marino
323*86d7f5d3SJohn Marino return 1;
324*86d7f5d3SJohn Marino }
325*86d7f5d3SJohn Marino
_join(const char * dir,const char * name)326*86d7f5d3SJohn Marino static char *_join(const char *dir, const char *name)
327*86d7f5d3SJohn Marino {
328*86d7f5d3SJohn Marino size_t len = strlen(dir) + strlen(name) + 2;
329*86d7f5d3SJohn Marino char *r = dm_malloc(len);
330*86d7f5d3SJohn Marino if (r)
331*86d7f5d3SJohn Marino snprintf(r, len, "%s/%s", dir, name);
332*86d7f5d3SJohn Marino
333*86d7f5d3SJohn Marino return r;
334*86d7f5d3SJohn Marino }
335*86d7f5d3SJohn Marino
336*86d7f5d3SJohn Marino /*
337*86d7f5d3SJohn Marino * Get rid of extra slashes in the path string.
338*86d7f5d3SJohn Marino */
_collapse_slashes(char * str)339*86d7f5d3SJohn Marino static void _collapse_slashes(char *str)
340*86d7f5d3SJohn Marino {
341*86d7f5d3SJohn Marino char *ptr;
342*86d7f5d3SJohn Marino int was_slash = 0;
343*86d7f5d3SJohn Marino
344*86d7f5d3SJohn Marino for (ptr = str; *ptr; ptr++) {
345*86d7f5d3SJohn Marino if (*ptr == '/') {
346*86d7f5d3SJohn Marino if (was_slash)
347*86d7f5d3SJohn Marino continue;
348*86d7f5d3SJohn Marino
349*86d7f5d3SJohn Marino was_slash = 1;
350*86d7f5d3SJohn Marino } else
351*86d7f5d3SJohn Marino was_slash = 0;
352*86d7f5d3SJohn Marino *str++ = *ptr;
353*86d7f5d3SJohn Marino }
354*86d7f5d3SJohn Marino
355*86d7f5d3SJohn Marino *str = *ptr;
356*86d7f5d3SJohn Marino }
357*86d7f5d3SJohn Marino
_insert_dir(const char * dir)358*86d7f5d3SJohn Marino static int _insert_dir(const char *dir)
359*86d7f5d3SJohn Marino {
360*86d7f5d3SJohn Marino int n, dirent_count, r = 1;
361*86d7f5d3SJohn Marino struct dirent **dirent;
362*86d7f5d3SJohn Marino char *path;
363*86d7f5d3SJohn Marino
364*86d7f5d3SJohn Marino dirent_count = scandir(dir, &dirent, NULL, alphasort);
365*86d7f5d3SJohn Marino if (dirent_count > 0) {
366*86d7f5d3SJohn Marino for (n = 0; n < dirent_count; n++) {
367*86d7f5d3SJohn Marino if (dirent[n]->d_name[0] == '.') {
368*86d7f5d3SJohn Marino free(dirent[n]);
369*86d7f5d3SJohn Marino continue;
370*86d7f5d3SJohn Marino }
371*86d7f5d3SJohn Marino
372*86d7f5d3SJohn Marino if (!(path = _join(dir, dirent[n]->d_name)))
373*86d7f5d3SJohn Marino return_0;
374*86d7f5d3SJohn Marino
375*86d7f5d3SJohn Marino _collapse_slashes(path);
376*86d7f5d3SJohn Marino r &= _insert(path, 1);
377*86d7f5d3SJohn Marino dm_free(path);
378*86d7f5d3SJohn Marino
379*86d7f5d3SJohn Marino free(dirent[n]);
380*86d7f5d3SJohn Marino }
381*86d7f5d3SJohn Marino free(dirent);
382*86d7f5d3SJohn Marino }
383*86d7f5d3SJohn Marino
384*86d7f5d3SJohn Marino return r;
385*86d7f5d3SJohn Marino }
386*86d7f5d3SJohn Marino
_insert_file(const char * path)387*86d7f5d3SJohn Marino static int _insert_file(const char *path)
388*86d7f5d3SJohn Marino {
389*86d7f5d3SJohn Marino struct stat info;
390*86d7f5d3SJohn Marino
391*86d7f5d3SJohn Marino if (stat(path, &info) < 0) {
392*86d7f5d3SJohn Marino log_sys_very_verbose("stat", path);
393*86d7f5d3SJohn Marino return 0;
394*86d7f5d3SJohn Marino }
395*86d7f5d3SJohn Marino
396*86d7f5d3SJohn Marino if (!S_ISREG(info.st_mode)) {
397*86d7f5d3SJohn Marino log_debug("%s: Not a regular file", path);
398*86d7f5d3SJohn Marino return 0;
399*86d7f5d3SJohn Marino }
400*86d7f5d3SJohn Marino
401*86d7f5d3SJohn Marino if (!_insert_dev(path, 0))
402*86d7f5d3SJohn Marino return_0;
403*86d7f5d3SJohn Marino
404*86d7f5d3SJohn Marino return 1;
405*86d7f5d3SJohn Marino }
406*86d7f5d3SJohn Marino
407*86d7f5d3SJohn Marino #if defined(__DragonFly__)
408*86d7f5d3SJohn Marino int dragonfly_check_dev(int major, const char *path);
409*86d7f5d3SJohn Marino #endif
410*86d7f5d3SJohn Marino
_insert(const char * path,int rec)411*86d7f5d3SJohn Marino static int _insert(const char *path, int rec)
412*86d7f5d3SJohn Marino {
413*86d7f5d3SJohn Marino struct stat info;
414*86d7f5d3SJohn Marino int r = 0;
415*86d7f5d3SJohn Marino
416*86d7f5d3SJohn Marino if (stat(path, &info) < 0) {
417*86d7f5d3SJohn Marino log_sys_very_verbose("stat", path);
418*86d7f5d3SJohn Marino return 0;
419*86d7f5d3SJohn Marino }
420*86d7f5d3SJohn Marino
421*86d7f5d3SJohn Marino if (S_ISDIR(info.st_mode)) { /* add a directory */
422*86d7f5d3SJohn Marino /* check it's not a symbolic link */
423*86d7f5d3SJohn Marino if (lstat(path, &info) < 0) {
424*86d7f5d3SJohn Marino log_sys_very_verbose("lstat", path);
425*86d7f5d3SJohn Marino return 0;
426*86d7f5d3SJohn Marino }
427*86d7f5d3SJohn Marino
428*86d7f5d3SJohn Marino if (S_ISLNK(info.st_mode)) {
429*86d7f5d3SJohn Marino log_debug("%s: Symbolic link to directory", path);
430*86d7f5d3SJohn Marino return 0;
431*86d7f5d3SJohn Marino }
432*86d7f5d3SJohn Marino
433*86d7f5d3SJohn Marino if (rec)
434*86d7f5d3SJohn Marino r = _insert_dir(path);
435*86d7f5d3SJohn Marino
436*86d7f5d3SJohn Marino } else {
437*86d7f5d3SJohn Marino /* add a device */
438*86d7f5d3SJohn Marino #ifdef __NetBSD__
439*86d7f5d3SJohn Marino /*
440*86d7f5d3SJohn Marino * In NetBSD we have two different types of devices
441*86d7f5d3SJohn Marino * raw and block. I can insert only existing
442*86d7f5d3SJohn Marino * raw and block device.
443*86d7f5d3SJohn Marino */
444*86d7f5d3SJohn Marino if (S_ISBLK(info.st_mode)) {
445*86d7f5d3SJohn Marino log_debug("%s: Not a raw device", path);
446*86d7f5d3SJohn Marino return_0;
447*86d7f5d3SJohn Marino }
448*86d7f5d3SJohn Marino if (nbsd_check_dev(MAJOR(info.st_rdev),path) < 0) {
449*86d7f5d3SJohn Marino log_debug("%s: Not a known raw device", path);
450*86d7f5d3SJohn Marino return_0;
451*86d7f5d3SJohn Marino }
452*86d7f5d3SJohn Marino #elif defined(__DragonFly__)
453*86d7f5d3SJohn Marino if (dragonfly_check_dev(MAJOR(info.st_rdev),path) < 0) {
454*86d7f5d3SJohn Marino log_debug("%s: Device not added to cache", path);
455*86d7f5d3SJohn Marino return_0;
456*86d7f5d3SJohn Marino }
457*86d7f5d3SJohn Marino
458*86d7f5d3SJohn Marino #else
459*86d7f5d3SJohn Marino if (!S_ISBLK(info.st_mode))
460*86d7f5d3SJohn Marino log_debug("%s: Not a block device", path);
461*86d7f5d3SJohn Marino #endif
462*86d7f5d3SJohn Marino if (!_insert_dev(path, info.st_rdev)) {
463*86d7f5d3SJohn Marino return_0;
464*86d7f5d3SJohn Marino }
465*86d7f5d3SJohn Marino
466*86d7f5d3SJohn Marino r = 1;
467*86d7f5d3SJohn Marino }
468*86d7f5d3SJohn Marino
469*86d7f5d3SJohn Marino return r;
470*86d7f5d3SJohn Marino }
471*86d7f5d3SJohn Marino
_full_scan(int dev_scan)472*86d7f5d3SJohn Marino static void _full_scan(int dev_scan)
473*86d7f5d3SJohn Marino {
474*86d7f5d3SJohn Marino struct dir_list *dl;
475*86d7f5d3SJohn Marino
476*86d7f5d3SJohn Marino if (_cache.has_scanned && !dev_scan)
477*86d7f5d3SJohn Marino return;
478*86d7f5d3SJohn Marino
479*86d7f5d3SJohn Marino dm_list_iterate_items(dl, &_cache.dirs)
480*86d7f5d3SJohn Marino _insert_dir(dl->dir);
481*86d7f5d3SJohn Marino
482*86d7f5d3SJohn Marino dm_list_iterate_items(dl, &_cache.files)
483*86d7f5d3SJohn Marino _insert_file(dl->dir);
484*86d7f5d3SJohn Marino
485*86d7f5d3SJohn Marino _cache.has_scanned = 1;
486*86d7f5d3SJohn Marino init_full_scan_done(1);
487*86d7f5d3SJohn Marino }
488*86d7f5d3SJohn Marino
dev_cache_has_scanned(void)489*86d7f5d3SJohn Marino int dev_cache_has_scanned(void)
490*86d7f5d3SJohn Marino {
491*86d7f5d3SJohn Marino return _cache.has_scanned;
492*86d7f5d3SJohn Marino }
493*86d7f5d3SJohn Marino
dev_cache_scan(int do_scan)494*86d7f5d3SJohn Marino void dev_cache_scan(int do_scan)
495*86d7f5d3SJohn Marino {
496*86d7f5d3SJohn Marino if (!do_scan)
497*86d7f5d3SJohn Marino _cache.has_scanned = 1;
498*86d7f5d3SJohn Marino else
499*86d7f5d3SJohn Marino _full_scan(1);
500*86d7f5d3SJohn Marino }
501*86d7f5d3SJohn Marino
_init_preferred_names(struct cmd_context * cmd)502*86d7f5d3SJohn Marino static int _init_preferred_names(struct cmd_context *cmd)
503*86d7f5d3SJohn Marino {
504*86d7f5d3SJohn Marino const struct config_node *cn;
505*86d7f5d3SJohn Marino struct config_value *v;
506*86d7f5d3SJohn Marino struct dm_pool *scratch = NULL;
507*86d7f5d3SJohn Marino char **regex;
508*86d7f5d3SJohn Marino unsigned count = 0;
509*86d7f5d3SJohn Marino int i, r = 0;
510*86d7f5d3SJohn Marino
511*86d7f5d3SJohn Marino _cache.preferred_names_matcher = NULL;
512*86d7f5d3SJohn Marino
513*86d7f5d3SJohn Marino if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
514*86d7f5d3SJohn Marino cn->v->type == CFG_EMPTY_ARRAY) {
515*86d7f5d3SJohn Marino log_very_verbose("devices/preferred_names not found in config file: "
516*86d7f5d3SJohn Marino "using built-in preferences");
517*86d7f5d3SJohn Marino return 1;
518*86d7f5d3SJohn Marino }
519*86d7f5d3SJohn Marino
520*86d7f5d3SJohn Marino for (v = cn->v; v; v = v->next) {
521*86d7f5d3SJohn Marino if (v->type != CFG_STRING) {
522*86d7f5d3SJohn Marino log_error("preferred_names patterns must be enclosed in quotes");
523*86d7f5d3SJohn Marino return 0;
524*86d7f5d3SJohn Marino }
525*86d7f5d3SJohn Marino
526*86d7f5d3SJohn Marino count++;
527*86d7f5d3SJohn Marino }
528*86d7f5d3SJohn Marino
529*86d7f5d3SJohn Marino if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
530*86d7f5d3SJohn Marino return_0;
531*86d7f5d3SJohn Marino
532*86d7f5d3SJohn Marino if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
533*86d7f5d3SJohn Marino log_error("Failed to allocate preferred device name "
534*86d7f5d3SJohn Marino "pattern list.");
535*86d7f5d3SJohn Marino goto out;
536*86d7f5d3SJohn Marino }
537*86d7f5d3SJohn Marino
538*86d7f5d3SJohn Marino for (v = cn->v, i = count - 1; v; v = v->next, i--) {
539*86d7f5d3SJohn Marino if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
540*86d7f5d3SJohn Marino log_error("Failed to allocate a preferred device name "
541*86d7f5d3SJohn Marino "pattern.");
542*86d7f5d3SJohn Marino goto out;
543*86d7f5d3SJohn Marino }
544*86d7f5d3SJohn Marino }
545*86d7f5d3SJohn Marino
546*86d7f5d3SJohn Marino if (!(_cache.preferred_names_matcher =
547*86d7f5d3SJohn Marino dm_regex_create(_cache.mem,(const char **) regex, count))) {
548*86d7f5d3SJohn Marino log_error("Preferred device name pattern matcher creation failed.");
549*86d7f5d3SJohn Marino goto out;
550*86d7f5d3SJohn Marino }
551*86d7f5d3SJohn Marino
552*86d7f5d3SJohn Marino r = 1;
553*86d7f5d3SJohn Marino
554*86d7f5d3SJohn Marino out:
555*86d7f5d3SJohn Marino dm_pool_destroy(scratch);
556*86d7f5d3SJohn Marino
557*86d7f5d3SJohn Marino return r;
558*86d7f5d3SJohn Marino }
559*86d7f5d3SJohn Marino
dev_cache_init(struct cmd_context * cmd)560*86d7f5d3SJohn Marino int dev_cache_init(struct cmd_context *cmd)
561*86d7f5d3SJohn Marino {
562*86d7f5d3SJohn Marino _cache.names = NULL;
563*86d7f5d3SJohn Marino _cache.has_scanned = 0;
564*86d7f5d3SJohn Marino
565*86d7f5d3SJohn Marino if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
566*86d7f5d3SJohn Marino return_0;
567*86d7f5d3SJohn Marino
568*86d7f5d3SJohn Marino if (!(_cache.names = dm_hash_create(128))) {
569*86d7f5d3SJohn Marino dm_pool_destroy(_cache.mem);
570*86d7f5d3SJohn Marino _cache.mem = 0;
571*86d7f5d3SJohn Marino return_0;
572*86d7f5d3SJohn Marino }
573*86d7f5d3SJohn Marino
574*86d7f5d3SJohn Marino if (!(_cache.devices = btree_create(_cache.mem))) {
575*86d7f5d3SJohn Marino log_error("Couldn't create binary tree for dev-cache.");
576*86d7f5d3SJohn Marino goto bad;
577*86d7f5d3SJohn Marino }
578*86d7f5d3SJohn Marino
579*86d7f5d3SJohn Marino dm_list_init(&_cache.dirs);
580*86d7f5d3SJohn Marino dm_list_init(&_cache.files);
581*86d7f5d3SJohn Marino
582*86d7f5d3SJohn Marino if (!_init_preferred_names(cmd))
583*86d7f5d3SJohn Marino goto_bad;
584*86d7f5d3SJohn Marino
585*86d7f5d3SJohn Marino return 1;
586*86d7f5d3SJohn Marino
587*86d7f5d3SJohn Marino bad:
588*86d7f5d3SJohn Marino dev_cache_exit();
589*86d7f5d3SJohn Marino return 0;
590*86d7f5d3SJohn Marino }
591*86d7f5d3SJohn Marino
_check_closed(struct device * dev)592*86d7f5d3SJohn Marino static void _check_closed(struct device *dev)
593*86d7f5d3SJohn Marino {
594*86d7f5d3SJohn Marino if (dev->fd >= 0)
595*86d7f5d3SJohn Marino log_error("Device '%s' has been left open.", dev_name(dev));
596*86d7f5d3SJohn Marino }
597*86d7f5d3SJohn Marino
_check_for_open_devices(void)598*86d7f5d3SJohn Marino static void _check_for_open_devices(void)
599*86d7f5d3SJohn Marino {
600*86d7f5d3SJohn Marino dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
601*86d7f5d3SJohn Marino }
602*86d7f5d3SJohn Marino
dev_cache_exit(void)603*86d7f5d3SJohn Marino void dev_cache_exit(void)
604*86d7f5d3SJohn Marino {
605*86d7f5d3SJohn Marino if (_cache.names)
606*86d7f5d3SJohn Marino _check_for_open_devices();
607*86d7f5d3SJohn Marino
608*86d7f5d3SJohn Marino if (_cache.preferred_names_matcher)
609*86d7f5d3SJohn Marino _cache.preferred_names_matcher = NULL;
610*86d7f5d3SJohn Marino
611*86d7f5d3SJohn Marino if (_cache.mem) {
612*86d7f5d3SJohn Marino dm_pool_destroy(_cache.mem);
613*86d7f5d3SJohn Marino _cache.mem = NULL;
614*86d7f5d3SJohn Marino }
615*86d7f5d3SJohn Marino
616*86d7f5d3SJohn Marino if (_cache.names) {
617*86d7f5d3SJohn Marino dm_hash_destroy(_cache.names);
618*86d7f5d3SJohn Marino _cache.names = NULL;
619*86d7f5d3SJohn Marino }
620*86d7f5d3SJohn Marino
621*86d7f5d3SJohn Marino _cache.devices = NULL;
622*86d7f5d3SJohn Marino _cache.has_scanned = 0;
623*86d7f5d3SJohn Marino dm_list_init(&_cache.dirs);
624*86d7f5d3SJohn Marino dm_list_init(&_cache.files);
625*86d7f5d3SJohn Marino }
626*86d7f5d3SJohn Marino
dev_cache_add_dir(const char * path)627*86d7f5d3SJohn Marino int dev_cache_add_dir(const char *path)
628*86d7f5d3SJohn Marino {
629*86d7f5d3SJohn Marino struct dir_list *dl;
630*86d7f5d3SJohn Marino struct stat st;
631*86d7f5d3SJohn Marino
632*86d7f5d3SJohn Marino if (stat(path, &st)) {
633*86d7f5d3SJohn Marino log_error("Ignoring %s: %s", path, strerror(errno));
634*86d7f5d3SJohn Marino /* But don't fail */
635*86d7f5d3SJohn Marino return 1;
636*86d7f5d3SJohn Marino }
637*86d7f5d3SJohn Marino
638*86d7f5d3SJohn Marino if (!S_ISDIR(st.st_mode)) {
639*86d7f5d3SJohn Marino log_error("Ignoring %s: Not a directory", path);
640*86d7f5d3SJohn Marino return 1;
641*86d7f5d3SJohn Marino }
642*86d7f5d3SJohn Marino
643*86d7f5d3SJohn Marino if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
644*86d7f5d3SJohn Marino log_error("dir_list allocation failed");
645*86d7f5d3SJohn Marino return 0;
646*86d7f5d3SJohn Marino }
647*86d7f5d3SJohn Marino
648*86d7f5d3SJohn Marino strcpy(dl->dir, path);
649*86d7f5d3SJohn Marino dm_list_add(&_cache.dirs, &dl->list);
650*86d7f5d3SJohn Marino return 1;
651*86d7f5d3SJohn Marino }
652*86d7f5d3SJohn Marino
dev_cache_add_loopfile(const char * path)653*86d7f5d3SJohn Marino int dev_cache_add_loopfile(const char *path)
654*86d7f5d3SJohn Marino {
655*86d7f5d3SJohn Marino struct dir_list *dl;
656*86d7f5d3SJohn Marino struct stat st;
657*86d7f5d3SJohn Marino
658*86d7f5d3SJohn Marino if (stat(path, &st)) {
659*86d7f5d3SJohn Marino log_error("Ignoring %s: %s", path, strerror(errno));
660*86d7f5d3SJohn Marino /* But don't fail */
661*86d7f5d3SJohn Marino return 1;
662*86d7f5d3SJohn Marino }
663*86d7f5d3SJohn Marino
664*86d7f5d3SJohn Marino if (!S_ISREG(st.st_mode)) {
665*86d7f5d3SJohn Marino log_error("Ignoring %s: Not a regular file", path);
666*86d7f5d3SJohn Marino return 1;
667*86d7f5d3SJohn Marino }
668*86d7f5d3SJohn Marino
669*86d7f5d3SJohn Marino if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
670*86d7f5d3SJohn Marino log_error("dir_list allocation failed for file");
671*86d7f5d3SJohn Marino return 0;
672*86d7f5d3SJohn Marino }
673*86d7f5d3SJohn Marino
674*86d7f5d3SJohn Marino strcpy(dl->dir, path);
675*86d7f5d3SJohn Marino dm_list_add(&_cache.files, &dl->list);
676*86d7f5d3SJohn Marino return 1;
677*86d7f5d3SJohn Marino }
678*86d7f5d3SJohn Marino
679*86d7f5d3SJohn Marino /* Check cached device name is still valid before returning it */
680*86d7f5d3SJohn Marino /* This should be a rare occurrence */
681*86d7f5d3SJohn Marino /* set quiet if the cache is expected to be out-of-date */
682*86d7f5d3SJohn Marino /* FIXME Make rest of code pass/cache struct device instead of dev_name */
dev_name_confirmed(struct device * dev,int quiet)683*86d7f5d3SJohn Marino const char *dev_name_confirmed(struct device *dev, int quiet)
684*86d7f5d3SJohn Marino {
685*86d7f5d3SJohn Marino struct stat buf;
686*86d7f5d3SJohn Marino const char *name;
687*86d7f5d3SJohn Marino int r;
688*86d7f5d3SJohn Marino
689*86d7f5d3SJohn Marino if ((dev->flags & DEV_REGULAR))
690*86d7f5d3SJohn Marino return dev_name(dev);
691*86d7f5d3SJohn Marino
692*86d7f5d3SJohn Marino while ((r = stat(name = dm_list_item(dev->aliases.n,
693*86d7f5d3SJohn Marino struct str_list)->str, &buf)) ||
694*86d7f5d3SJohn Marino (buf.st_rdev != dev->dev)) {
695*86d7f5d3SJohn Marino if (r < 0) {
696*86d7f5d3SJohn Marino if (quiet)
697*86d7f5d3SJohn Marino log_sys_debug("stat", name);
698*86d7f5d3SJohn Marino else
699*86d7f5d3SJohn Marino log_sys_error("stat", name);
700*86d7f5d3SJohn Marino }
701*86d7f5d3SJohn Marino if (quiet)
702*86d7f5d3SJohn Marino log_debug("Path %s no longer valid for device(%d,%d)",
703*86d7f5d3SJohn Marino name, (int) MAJOR(dev->dev),
704*86d7f5d3SJohn Marino (int) MINOR(dev->dev));
705*86d7f5d3SJohn Marino else
706*86d7f5d3SJohn Marino log_error("Path %s no longer valid for device(%d,%d)",
707*86d7f5d3SJohn Marino name, (int) MAJOR(dev->dev),
708*86d7f5d3SJohn Marino (int) MINOR(dev->dev));
709*86d7f5d3SJohn Marino
710*86d7f5d3SJohn Marino /* Remove the incorrect hash entry */
711*86d7f5d3SJohn Marino dm_hash_remove(_cache.names, name);
712*86d7f5d3SJohn Marino
713*86d7f5d3SJohn Marino /* Leave list alone if there isn't an alternative name */
714*86d7f5d3SJohn Marino /* so dev_name will always find something to return. */
715*86d7f5d3SJohn Marino /* Otherwise add the name to the correct device. */
716*86d7f5d3SJohn Marino if (dm_list_size(&dev->aliases) > 1) {
717*86d7f5d3SJohn Marino dm_list_del(dev->aliases.n);
718*86d7f5d3SJohn Marino if (!r)
719*86d7f5d3SJohn Marino _insert(name, 0);
720*86d7f5d3SJohn Marino continue;
721*86d7f5d3SJohn Marino }
722*86d7f5d3SJohn Marino
723*86d7f5d3SJohn Marino /* Scanning issues this inappropriately sometimes. */
724*86d7f5d3SJohn Marino log_debug("Aborting - please provide new pathname for what "
725*86d7f5d3SJohn Marino "used to be %s", name);
726*86d7f5d3SJohn Marino return NULL;
727*86d7f5d3SJohn Marino }
728*86d7f5d3SJohn Marino
729*86d7f5d3SJohn Marino return dev_name(dev);
730*86d7f5d3SJohn Marino }
731*86d7f5d3SJohn Marino
dev_cache_get(const char * name,struct dev_filter * f)732*86d7f5d3SJohn Marino struct device *dev_cache_get(const char *name, struct dev_filter *f)
733*86d7f5d3SJohn Marino {
734*86d7f5d3SJohn Marino struct stat buf;
735*86d7f5d3SJohn Marino struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
736*86d7f5d3SJohn Marino
737*86d7f5d3SJohn Marino if (d && (d->flags & DEV_REGULAR))
738*86d7f5d3SJohn Marino return d;
739*86d7f5d3SJohn Marino
740*86d7f5d3SJohn Marino /* If the entry's wrong, remove it */
741*86d7f5d3SJohn Marino if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
742*86d7f5d3SJohn Marino dm_hash_remove(_cache.names, name);
743*86d7f5d3SJohn Marino d = NULL;
744*86d7f5d3SJohn Marino }
745*86d7f5d3SJohn Marino
746*86d7f5d3SJohn Marino if (!d) {
747*86d7f5d3SJohn Marino _insert(name, 0);
748*86d7f5d3SJohn Marino d = (struct device *) dm_hash_lookup(_cache.names, name);
749*86d7f5d3SJohn Marino if (!d) {
750*86d7f5d3SJohn Marino _full_scan(0);
751*86d7f5d3SJohn Marino d = (struct device *) dm_hash_lookup(_cache.names, name);
752*86d7f5d3SJohn Marino }
753*86d7f5d3SJohn Marino }
754*86d7f5d3SJohn Marino
755*86d7f5d3SJohn Marino return (d && (!f || (d->flags & DEV_REGULAR) ||
756*86d7f5d3SJohn Marino f->passes_filter(f, d))) ? d : NULL;
757*86d7f5d3SJohn Marino }
758*86d7f5d3SJohn Marino
dev_iter_create(struct dev_filter * f,int dev_scan)759*86d7f5d3SJohn Marino struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
760*86d7f5d3SJohn Marino {
761*86d7f5d3SJohn Marino struct dev_iter *di = dm_malloc(sizeof(*di));
762*86d7f5d3SJohn Marino
763*86d7f5d3SJohn Marino if (!di) {
764*86d7f5d3SJohn Marino log_error("dev_iter allocation failed");
765*86d7f5d3SJohn Marino return NULL;
766*86d7f5d3SJohn Marino }
767*86d7f5d3SJohn Marino
768*86d7f5d3SJohn Marino if (dev_scan && !trust_cache()) {
769*86d7f5d3SJohn Marino /* Flag gets reset between each command */
770*86d7f5d3SJohn Marino if (!full_scan_done())
771*86d7f5d3SJohn Marino persistent_filter_wipe(f); /* Calls _full_scan(1) */
772*86d7f5d3SJohn Marino } else
773*86d7f5d3SJohn Marino _full_scan(0);
774*86d7f5d3SJohn Marino
775*86d7f5d3SJohn Marino di->current = btree_first(_cache.devices);
776*86d7f5d3SJohn Marino di->filter = f;
777*86d7f5d3SJohn Marino
778*86d7f5d3SJohn Marino return di;
779*86d7f5d3SJohn Marino }
780*86d7f5d3SJohn Marino
dev_iter_destroy(struct dev_iter * iter)781*86d7f5d3SJohn Marino void dev_iter_destroy(struct dev_iter *iter)
782*86d7f5d3SJohn Marino {
783*86d7f5d3SJohn Marino dm_free(iter);
784*86d7f5d3SJohn Marino }
785*86d7f5d3SJohn Marino
_iter_next(struct dev_iter * iter)786*86d7f5d3SJohn Marino static struct device *_iter_next(struct dev_iter *iter)
787*86d7f5d3SJohn Marino {
788*86d7f5d3SJohn Marino struct device *d = btree_get_data(iter->current);
789*86d7f5d3SJohn Marino iter->current = btree_next(iter->current);
790*86d7f5d3SJohn Marino return d;
791*86d7f5d3SJohn Marino }
792*86d7f5d3SJohn Marino
dev_iter_get(struct dev_iter * iter)793*86d7f5d3SJohn Marino struct device *dev_iter_get(struct dev_iter *iter)
794*86d7f5d3SJohn Marino {
795*86d7f5d3SJohn Marino while (iter->current) {
796*86d7f5d3SJohn Marino struct device *d = _iter_next(iter);
797*86d7f5d3SJohn Marino if (!iter->filter || (d->flags & DEV_REGULAR) ||
798*86d7f5d3SJohn Marino iter->filter->passes_filter(iter->filter, d))
799*86d7f5d3SJohn Marino return d;
800*86d7f5d3SJohn Marino }
801*86d7f5d3SJohn Marino
802*86d7f5d3SJohn Marino return NULL;
803*86d7f5d3SJohn Marino }
804*86d7f5d3SJohn Marino
dev_fd(struct device * dev)805*86d7f5d3SJohn Marino int dev_fd(struct device *dev)
806*86d7f5d3SJohn Marino {
807*86d7f5d3SJohn Marino return dev->fd;
808*86d7f5d3SJohn Marino }
809*86d7f5d3SJohn Marino
dev_name(const struct device * dev)810*86d7f5d3SJohn Marino const char *dev_name(const struct device *dev)
811*86d7f5d3SJohn Marino {
812*86d7f5d3SJohn Marino return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
813*86d7f5d3SJohn Marino "unknown device";
814*86d7f5d3SJohn Marino }
815