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