/src/util-linux/libblkid/src/devname.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * devname.c - get a dev by its device inode name  | 
3  |  |  *  | 
4  |  |  * Copyright (C) Andries Brouwer  | 
5  |  |  * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o  | 
6  |  |  * Copyright (C) 2001 Andreas Dilger  | 
7  |  |  *  | 
8  |  |  * %Begin-Header%  | 
9  |  |  * This file may be redistributed under the terms of the  | 
10  |  |  * GNU Lesser General Public License.  | 
11  |  |  * %End-Header%  | 
12  |  |  */  | 
13  |  |  | 
14  |  | #define _GNU_SOURCE 1  | 
15  |  |  | 
16  |  | #include <stdio.h>  | 
17  |  | #include <string.h>  | 
18  |  | #include <limits.h>  | 
19  |  | #ifdef HAVE_UNISTD_H  | 
20  |  | #include <unistd.h>  | 
21  |  | #endif  | 
22  |  | #include <stdlib.h>  | 
23  |  | #include <ctype.h>  | 
24  |  | #include <fcntl.h>  | 
25  |  | #ifdef HAVE_SYS_TYPES_H  | 
26  |  | #include <sys/types.h>  | 
27  |  | #endif  | 
28  |  | #include <dirent.h>  | 
29  |  | #ifdef HAVE_SYS_STAT_H  | 
30  |  | #include <sys/stat.h>  | 
31  |  | #endif  | 
32  |  | #ifdef HAVE_ERRNO_H  | 
33  |  | #include <errno.h>  | 
34  |  | #endif  | 
35  |  | #include <time.h>  | 
36  |  |  | 
37  |  | #include "blkidP.h"  | 
38  |  |  | 
39  |  | #include "canonicalize.h"   /* $(top_srcdir)/include */  | 
40  |  | #include "pathnames.h"  | 
41  |  | #include "sysfs.h"  | 
42  |  | #include "fileutils.h"  | 
43  |  |  | 
44  |  | /*  | 
45  |  |  * Find a dev struct in the cache by device name, if available.  | 
46  |  |  *  | 
47  |  |  * If there is no entry with the specified device name, and the create  | 
48  |  |  * flag is set, then create an empty device entry.  | 
49  |  |  */  | 
50  |  | blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)  | 
51  | 0  | { | 
52  | 0  |   blkid_dev dev = NULL, tmp;  | 
53  | 0  |   struct list_head *p, *pnext;  | 
54  | 0  |   char *cn = NULL;  | 
55  |  | 
  | 
56  | 0  |   if (!cache || !devname)  | 
57  | 0  |     return NULL;  | 
58  |  |  | 
59  |  |   /* search by name */  | 
60  | 0  |   list_for_each(p, &cache->bic_devs) { | 
61  | 0  |     tmp = list_entry(p, struct blkid_struct_dev, bid_devs);  | 
62  | 0  |     if (strcmp(tmp->bid_name, devname) != 0)  | 
63  | 0  |       continue;  | 
64  | 0  |     dev = tmp;  | 
65  | 0  |     break;  | 
66  | 0  |   }  | 
67  |  |  | 
68  |  |   /* try canonicalize the name */  | 
69  | 0  |   if (!dev && (cn = canonicalize_path(devname))) { | 
70  | 0  |     if (strcmp(cn, devname) != 0) { | 
71  | 0  |       DBG(DEVNAME, ul_debug("search canonical %s", cn)); | 
72  | 0  |       list_for_each(p, &cache->bic_devs) { | 
73  | 0  |         tmp = list_entry(p, struct blkid_struct_dev, bid_devs);  | 
74  | 0  |         if (strcmp(tmp->bid_name, cn) != 0)  | 
75  | 0  |           continue;  | 
76  | 0  |         dev = tmp;  | 
77  |  |  | 
78  |  |         /* update name returned by blkid_dev_devname() */  | 
79  | 0  |         free(dev->bid_xname);  | 
80  | 0  |         dev->bid_xname = strdup(devname);  | 
81  | 0  |         break;  | 
82  | 0  |       }  | 
83  | 0  |     } else { | 
84  | 0  |       free(cn);  | 
85  | 0  |       cn = NULL;  | 
86  | 0  |     }  | 
87  | 0  |   }  | 
88  |  | 
  | 
89  | 0  |   if (!dev && (flags & BLKID_DEV_CREATE)) { | 
90  | 0  |     if (access(devname, F_OK) < 0)  | 
91  | 0  |       goto done;  | 
92  | 0  |     dev = blkid_new_dev();  | 
93  | 0  |     if (!dev)  | 
94  | 0  |       goto done;  | 
95  | 0  |     dev->bid_time = (uintmax_t)1 << (sizeof(time_t) * 8 - 1);  | 
96  | 0  |     if (cn) { | 
97  | 0  |       dev->bid_name = cn;  | 
98  | 0  |       dev->bid_xname = strdup(devname);  | 
99  | 0  |       cn = NULL;  /* see free() below */  | 
100  | 0  |     } else  | 
101  | 0  |       dev->bid_name = strdup(devname);  | 
102  |  | 
  | 
103  | 0  |     dev->bid_cache = cache;  | 
104  | 0  |     list_add_tail(&dev->bid_devs, &cache->bic_devs);  | 
105  | 0  |     cache->bic_flags |= BLKID_BIC_FL_CHANGED;  | 
106  | 0  |   }  | 
107  |  |  | 
108  | 0  |   if (flags & BLKID_DEV_VERIFY) { | 
109  | 0  |     dev = blkid_verify(cache, dev);  | 
110  | 0  |     if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED))  | 
111  | 0  |       goto done;  | 
112  |  |     /*  | 
113  |  |      * If the device is verified, then search the blkid  | 
114  |  |      * cache for any entries that match on the type, uuid,  | 
115  |  |      * and label, and verify them; if a cache entry can  | 
116  |  |      * not be verified, then it's stale and so we remove  | 
117  |  |      * it.  | 
118  |  |      */  | 
119  | 0  |     list_for_each_safe(p, pnext, &cache->bic_devs) { | 
120  | 0  |       blkid_dev dev2 = list_entry(p, struct blkid_struct_dev, bid_devs);  | 
121  | 0  |       if (dev2->bid_flags & BLKID_BID_FL_VERIFIED)  | 
122  | 0  |         continue;  | 
123  | 0  |       if (!dev->bid_type || !dev2->bid_type ||  | 
124  | 0  |           strcmp(dev->bid_type, dev2->bid_type) != 0)  | 
125  | 0  |         continue;  | 
126  | 0  |       if (dev->bid_label && dev2->bid_label &&  | 
127  | 0  |           strcmp(dev->bid_label, dev2->bid_label) != 0)  | 
128  | 0  |         continue;  | 
129  | 0  |       if (dev->bid_uuid && dev2->bid_uuid &&  | 
130  | 0  |           strcmp(dev->bid_uuid, dev2->bid_uuid) != 0)  | 
131  | 0  |         continue;  | 
132  | 0  |       if ((dev->bid_label && !dev2->bid_label) ||  | 
133  | 0  |           (!dev->bid_label && dev2->bid_label) ||  | 
134  | 0  |           (dev->bid_uuid && !dev2->bid_uuid) ||  | 
135  | 0  |           (!dev->bid_uuid && dev2->bid_uuid))  | 
136  | 0  |         continue;  | 
137  | 0  |       dev2 = blkid_verify(cache, dev2);  | 
138  | 0  |       if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED))  | 
139  | 0  |         blkid_free_dev(dev2);  | 
140  | 0  |     }  | 
141  | 0  |   }  | 
142  | 0  | done:  | 
143  | 0  |   if (dev)  | 
144  | 0  |     DBG(DEVNAME, ul_debug("%s requested, found %s in cache", devname, dev->bid_name)); | 
145  | 0  |   free(cn);  | 
146  | 0  |   return dev;  | 
147  | 0  | }  | 
148  |  |  | 
149  |  | /* Directories where we will try to search for device names */  | 
150  |  | static const char *const dirlist[] = { "/dev", "/devfs", "/devices", NULL }; | 
151  |  |  | 
152  |  | /*  | 
153  |  |  * Return 1 if the device is a device-mapper 'leaf' node  | 
154  |  |  * not holding any other devices in its hierarchy.  | 
155  |  |  */  | 
156  |  | static int is_dm_leaf(const char *devname)  | 
157  | 0  | { | 
158  | 0  |   DIR *dir;  | 
159  | 0  |   char path[NAME_MAX + 18 + 1];  | 
160  | 0  |   int ret;  | 
161  |  | 
  | 
162  | 0  |   snprintf(path, sizeof(path), "/sys/block/%s/holders", devname);  | 
163  | 0  |   if ((dir = opendir(path)) == NULL)  | 
164  | 0  |     return 0;  | 
165  |  |  | 
166  | 0  |   ret = xreaddir(dir) == NULL ? 1 : 0; /* 'leaf' has no entries */  | 
167  |  | 
  | 
168  | 0  |   closedir(dir);  | 
169  | 0  |   return ret;  | 
170  | 0  | }  | 
171  |  |  | 
172  |  | /*  | 
173  |  |  * Probe a single block device to add to the device cache.  | 
174  |  |  */  | 
175  |  | static void probe_one(blkid_cache cache, const char *ptname,  | 
176  |  |           dev_t devno, int pri, int only_if_new, int removable)  | 
177  | 0  | { | 
178  | 0  |   blkid_dev dev = NULL;  | 
179  | 0  |   struct list_head *p, *pnext;  | 
180  | 0  |   const char *const*dir;  | 
181  | 0  |   char *devname = NULL;  | 
182  |  |  | 
183  |  |   /* See if we already have this device number in the cache. */  | 
184  | 0  |   list_for_each_safe(p, pnext, &cache->bic_devs) { | 
185  | 0  |     blkid_dev tmp = list_entry(p, struct blkid_struct_dev,  | 
186  | 0  |              bid_devs);  | 
187  | 0  |     if (tmp->bid_devno == devno) { | 
188  | 0  |       if (only_if_new && !access(tmp->bid_name, F_OK))  | 
189  | 0  |         return;  | 
190  | 0  |       dev = blkid_verify(cache, tmp);  | 
191  | 0  |       if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))  | 
192  | 0  |         break;  | 
193  | 0  |       dev = NULL;  | 
194  | 0  |     }  | 
195  | 0  |   }  | 
196  | 0  |   if (dev && dev->bid_devno == devno)  | 
197  | 0  |     goto set_pri;  | 
198  |  |  | 
199  |  |   /* Try to translate private device-mapper dm-<N> names  | 
200  |  |    * to standard /dev/mapper/<name>.  | 
201  |  |    */  | 
202  | 0  |   if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { | 
203  | 0  |     devname = canonicalize_dm_name(ptname);  | 
204  | 0  |     if (!devname)  | 
205  | 0  |       blkid__scan_dir("/dev/mapper", devno, NULL, &devname); | 
206  | 0  |     if (devname)  | 
207  | 0  |       goto get_dev;  | 
208  | 0  |   }  | 
209  |  |  | 
210  |  |   /*  | 
211  |  |    * Take a quick look at /dev/ptname for the device number.  We check  | 
212  |  |    * all of the likely device directories.  If we don't find it, or if  | 
213  |  |    * the stat information doesn't check out, use blkid_devno_to_devname()  | 
214  |  |    * to find it via an exhaustive search for the device major/minor.  | 
215  |  |    */  | 
216  | 0  |   for (dir = dirlist; *dir; dir++) { | 
217  | 0  |     struct stat st;  | 
218  | 0  |     char device[256];  | 
219  |  | 
  | 
220  | 0  |     snprintf(device, sizeof(device), "%s/%s", *dir, ptname);  | 
221  | 0  |     if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&  | 
222  | 0  |         dev->bid_devno == devno)  | 
223  | 0  |       goto set_pri;  | 
224  |  |  | 
225  | 0  |     if (stat(device, &st) == 0 &&  | 
226  | 0  |         (S_ISBLK(st.st_mode) ||  | 
227  | 0  |          (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) &&  | 
228  | 0  |         st.st_rdev == devno) { | 
229  | 0  |       devname = strdup(device);  | 
230  | 0  |       goto get_dev;  | 
231  | 0  |     }  | 
232  | 0  |   }  | 
233  |  |   /* Do a short-cut scan of /dev/mapper first */  | 
234  | 0  |   if (!devname)  | 
235  | 0  |     blkid__scan_dir("/dev/mapper", devno, NULL, &devname); | 
236  | 0  |   if (!devname) { | 
237  | 0  |     devname = blkid_devno_to_devname(devno);  | 
238  | 0  |     if (!devname)  | 
239  | 0  |       return;  | 
240  | 0  |   }  | 
241  |  |  | 
242  | 0  | get_dev:  | 
243  | 0  |   dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);  | 
244  | 0  |   free(devname);  | 
245  |  | 
  | 
246  | 0  | set_pri:  | 
247  | 0  |   if (dev) { | 
248  | 0  |     if (pri)  | 
249  | 0  |       dev->bid_pri = pri;  | 
250  | 0  |     else if (!strncmp(dev->bid_name, "/dev/mapper/", 12)) { | 
251  | 0  |       dev->bid_pri = BLKID_PRI_DM;  | 
252  | 0  |       if (is_dm_leaf(ptname))  | 
253  | 0  |         dev->bid_pri += 5;  | 
254  | 0  |     } else if (!strncmp(ptname, "md", 2))  | 
255  | 0  |       dev->bid_pri = BLKID_PRI_MD;  | 
256  | 0  |     if (removable)  | 
257  | 0  |       dev->bid_flags |= BLKID_BID_FL_REMOVABLE;  | 
258  | 0  |   }  | 
259  | 0  | }  | 
260  |  |  | 
261  |  | #define PROC_PARTITIONS "/proc/partitions"  | 
262  | 0  | #define VG_DIR    "/proc/lvm/VGs"  | 
263  |  |  | 
264  |  | /*  | 
265  |  |  * This function initializes the UUID cache with devices from the LVM  | 
266  |  |  * proc hierarchy.  We currently depend on the names of the LVM  | 
267  |  |  * hierarchy giving us the device structure in /dev.  (XXX is this a  | 
268  |  |  * safe thing to do?)  | 
269  |  |  */  | 
270  |  | #ifdef VG_DIR  | 
271  |  | static dev_t lvm_get_devno(const char *lvm_device)  | 
272  | 0  | { | 
273  | 0  |   FILE *lvf;  | 
274  | 0  |   char buf[1024];  | 
275  | 0  |   int ma, mi;  | 
276  | 0  |   dev_t ret = 0;  | 
277  |  | 
  | 
278  | 0  |   DBG(DEVNAME, ul_debug("opening %s", lvm_device)); | 
279  | 0  |   if ((lvf = fopen(lvm_device, "r" UL_CLOEXECSTR)) == NULL) { | 
280  | 0  |     DBG(DEVNAME, ul_debug("%s: (%d) %m", lvm_device, errno)); | 
281  | 0  |     return 0;  | 
282  | 0  |   }  | 
283  |  |  | 
284  | 0  |   while (fgets(buf, sizeof(buf), lvf)) { | 
285  | 0  |     if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { | 
286  | 0  |       ret = makedev(ma, mi);  | 
287  | 0  |       break;  | 
288  | 0  |     }  | 
289  | 0  |   }  | 
290  | 0  |   fclose(lvf);  | 
291  |  | 
  | 
292  | 0  |   return ret;  | 
293  | 0  | }  | 
294  |  |  | 
295  |  | static void lvm_probe_all(blkid_cache cache, int only_if_new)  | 
296  | 0  | { | 
297  | 0  |   DIR   *vg_list;  | 
298  | 0  |   struct dirent *vg_iter;  | 
299  | 0  |   int   vg_len = strlen(VG_DIR);  | 
300  | 0  |   dev_t   dev;  | 
301  |  | 
  | 
302  | 0  |   if ((vg_list = opendir(VG_DIR)) == NULL)  | 
303  | 0  |     return;  | 
304  |  |  | 
305  | 0  |   DBG(DEVNAME, ul_debug("probing LVM devices under %s", VG_DIR)); | 
306  |  | 
  | 
307  | 0  |   while ((vg_iter = readdir(vg_list)) != NULL) { | 
308  | 0  |     DIR   *lv_list;  | 
309  | 0  |     char    *vdirname;  | 
310  | 0  |     char    *vg_name;  | 
311  | 0  |     struct dirent *lv_iter;  | 
312  | 0  |     size_t    len;  | 
313  |  | 
  | 
314  | 0  |     vg_name = vg_iter->d_name;  | 
315  | 0  |     if (!strcmp(vg_name, ".") || !strcmp(vg_name, ".."))  | 
316  | 0  |       continue;  | 
317  | 0  |     len = vg_len + strlen(vg_name) + 8;  | 
318  | 0  |     vdirname = malloc(len);  | 
319  | 0  |     if (!vdirname)  | 
320  | 0  |       goto exit;  | 
321  | 0  |     snprintf(vdirname, len, "%s/%s/LVs", VG_DIR, vg_name);  | 
322  |  | 
  | 
323  | 0  |     lv_list = opendir(vdirname);  | 
324  | 0  |     free(vdirname);  | 
325  | 0  |     if (lv_list == NULL)  | 
326  | 0  |       continue;  | 
327  |  |  | 
328  | 0  |     while ((lv_iter = readdir(lv_list)) != NULL) { | 
329  | 0  |       char    *lv_name, *lvm_device;  | 
330  |  | 
  | 
331  | 0  |       lv_name = lv_iter->d_name;  | 
332  | 0  |       if (!strcmp(lv_name, ".") || !strcmp(lv_name, ".."))  | 
333  | 0  |         continue;  | 
334  |  |  | 
335  | 0  |       len = vg_len + strlen(vg_name) + strlen(lv_name) + 8;  | 
336  | 0  |       lvm_device = malloc(len);  | 
337  | 0  |       if (!lvm_device) { | 
338  | 0  |         closedir(lv_list);  | 
339  | 0  |         goto exit;  | 
340  | 0  |       }  | 
341  | 0  |       snprintf(lvm_device, len, "%s/%s/LVs/%s", VG_DIR, vg_name,  | 
342  | 0  |         lv_name);  | 
343  | 0  |       dev = lvm_get_devno(lvm_device);  | 
344  | 0  |       snprintf(lvm_device, len, "%s/%s", vg_name, lv_name);  | 
345  | 0  |       DBG(DEVNAME, ul_debug("Probe LVM dev %s: devno 0x%04X", | 
346  | 0  |               lvm_device,  | 
347  | 0  |               (unsigned int) dev));  | 
348  | 0  |       probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,  | 
349  | 0  |           only_if_new, 0);  | 
350  | 0  |       free(lvm_device);  | 
351  | 0  |     }  | 
352  | 0  |     closedir(lv_list);  | 
353  | 0  |   }  | 
354  | 0  | exit:  | 
355  | 0  |   closedir(vg_list);  | 
356  | 0  | }  | 
357  |  | #endif  | 
358  |  |  | 
359  |  | static void  | 
360  |  | ubi_probe_all(blkid_cache cache, int only_if_new)  | 
361  | 0  | { | 
362  | 0  |   const char *const*dirname;  | 
363  |  | 
  | 
364  | 0  |   for (dirname = dirlist; *dirname; dirname++) { | 
365  | 0  |     DIR   *dir;  | 
366  | 0  |     struct dirent *iter;  | 
367  |  | 
  | 
368  | 0  |     DBG(DEVNAME, ul_debug("probing UBI volumes under %s", | 
369  | 0  |             *dirname));  | 
370  |  | 
  | 
371  | 0  |     dir = opendir(*dirname);  | 
372  | 0  |     if (dir == NULL)  | 
373  | 0  |       continue ;  | 
374  |  |  | 
375  | 0  |     while ((iter = readdir(dir)) != NULL) { | 
376  | 0  |       char    *name;  | 
377  | 0  |       struct stat st;  | 
378  | 0  |       dev_t   dev;  | 
379  |  | 
  | 
380  | 0  |       name = iter->d_name;  | 
381  | 0  | #ifdef _DIRENT_HAVE_D_TYPE  | 
382  | 0  |       if (iter->d_type != DT_UNKNOWN &&  | 
383  | 0  |           iter->d_type != DT_CHR && iter->d_type != DT_LNK)  | 
384  | 0  |         continue;  | 
385  | 0  | #endif  | 
386  | 0  |       if (!strcmp(name, ".") || !strcmp(name, "..") ||  | 
387  | 0  |           !strstr(name, "ubi"))  | 
388  | 0  |         continue;  | 
389  | 0  |       if (!strcmp(name, "ubi_ctrl"))  | 
390  | 0  |         continue;  | 
391  | 0  |       if (fstatat(dirfd(dir), name, &st, 0))  | 
392  | 0  |         continue;  | 
393  |  |  | 
394  | 0  |       dev = st.st_rdev;  | 
395  |  | 
  | 
396  | 0  |       if (!S_ISCHR(st.st_mode) || !minor(dev))  | 
397  | 0  |         continue;  | 
398  | 0  |       DBG(DEVNAME, ul_debug("Probe UBI vol %s/%s: devno 0x%04X", | 
399  | 0  |           *dirname, name, (int) dev));  | 
400  | 0  |       probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0);  | 
401  | 0  |     }  | 
402  | 0  |     closedir(dir);  | 
403  | 0  |   }  | 
404  | 0  | }  | 
405  |  |  | 
406  |  | /*  | 
407  |  |  * This function uses /sys to read all block devices in way compatible with  | 
408  |  |  * /proc/partitions (like the original libblkid implementation)  | 
409  |  |  */  | 
410  |  | static int  | 
411  |  | sysfs_probe_all(blkid_cache cache, int only_if_new, int only_removable)  | 
412  | 0  | { | 
413  | 0  |   DIR *sysfs;  | 
414  | 0  |   struct dirent *dev;  | 
415  |  | 
  | 
416  | 0  |   sysfs = opendir(_PATH_SYS_BLOCK);  | 
417  | 0  |   if (!sysfs)  | 
418  | 0  |     return -BLKID_ERR_SYSFS;  | 
419  |  |  | 
420  | 0  |   DBG(DEVNAME, ul_debug(" probe /sys/block")); | 
421  |  |  | 
422  |  |   /* scan /sys/block */  | 
423  | 0  |   while ((dev = xreaddir(sysfs))) { | 
424  | 0  |     DIR *dir = NULL;  | 
425  | 0  |     dev_t devno;  | 
426  | 0  |     size_t nparts = 0;  | 
427  | 0  |     unsigned int maxparts = 0, removable = 0;  | 
428  | 0  |     struct dirent *part;  | 
429  | 0  |     struct path_cxt *pc = NULL;  | 
430  | 0  |     uint64_t size = 0;  | 
431  |  | 
  | 
432  | 0  |     DBG(DEVNAME, ul_debug("checking %s", dev->d_name)); | 
433  |  | 
  | 
434  | 0  |     devno = sysfs_devname_to_devno(dev->d_name);  | 
435  | 0  |     if (!devno)  | 
436  | 0  |       goto next;  | 
437  | 0  |     pc = ul_new_sysfs_path(devno, NULL, NULL);  | 
438  | 0  |     if (!pc)  | 
439  | 0  |       goto next;  | 
440  |  |  | 
441  | 0  |     if (ul_path_read_u64(pc, &size, "size") != 0)  | 
442  | 0  |       size = 0;  | 
443  | 0  |     if (ul_path_read_u32(pc, &removable, "removable") != 0)  | 
444  | 0  |       removable = 0;  | 
445  |  |  | 
446  |  |     /* ignore empty devices */  | 
447  | 0  |     if (!size)  | 
448  | 0  |       goto next;  | 
449  |  |  | 
450  |  |     /* accept removable if only removable requested */  | 
451  | 0  |     if (only_removable) { | 
452  | 0  |       if (!removable)  | 
453  | 0  |         goto next;  | 
454  |  |  | 
455  |  |     /* emulate /proc/partitions  | 
456  |  |      * -- ignore empty devices and non-partitionable removable devices */  | 
457  | 0  |     } else { | 
458  | 0  |       if (ul_path_read_u32(pc, &maxparts, "ext_range") != 0)  | 
459  | 0  |         maxparts = 0;  | 
460  | 0  |       if (!maxparts && removable)  | 
461  | 0  |         goto next;  | 
462  | 0  |     }  | 
463  |  |  | 
464  | 0  |     DBG(DEVNAME, ul_debug("read device name %s", dev->d_name)); | 
465  |  | 
  | 
466  | 0  |     dir = ul_path_opendir(pc, NULL);  | 
467  | 0  |     if (!dir)  | 
468  | 0  |       goto next;  | 
469  |  |  | 
470  |  |     /* read /sys/block/<name>/ do get partitions */  | 
471  | 0  |     while ((part = xreaddir(dir))) { | 
472  | 0  |       dev_t partno;  | 
473  |  | 
  | 
474  | 0  |       if (!sysfs_blkdev_is_partition_dirent(dir, part, dev->d_name))  | 
475  | 0  |         continue;  | 
476  |  |  | 
477  |  |       /* ignore extended partitions  | 
478  |  |        * -- recount size to blocks like /proc/partitions */  | 
479  | 0  |       if (ul_path_readf_u64(pc, &size, "%s/size", part->d_name) == 0  | 
480  | 0  |           && (size >> 1) == 1)  | 
481  | 0  |         continue;  | 
482  | 0  |       partno = __sysfs_devname_to_devno(NULL, part->d_name, dev->d_name);  | 
483  | 0  |       if (!partno)  | 
484  | 0  |         continue;  | 
485  |  |  | 
486  | 0  |       DBG(DEVNAME, ul_debug(" Probe partition dev %s, devno 0x%04X", | 
487  | 0  |                                    part->d_name, (unsigned int) partno));  | 
488  | 0  |       nparts++;  | 
489  | 0  |       probe_one(cache, part->d_name, partno, 0, only_if_new, 0);  | 
490  | 0  |     }  | 
491  |  | 
  | 
492  | 0  |     if (!nparts) { | 
493  |  |       /* add non-partitioned whole disk to cache */  | 
494  | 0  |       DBG(DEVNAME, ul_debug(" Probe whole dev %s, devno 0x%04X", | 
495  | 0  |            dev->d_name, (unsigned int) devno));  | 
496  | 0  |       probe_one(cache, dev->d_name, devno, 0, only_if_new, 0);  | 
497  | 0  |     } else { | 
498  |  |       /* remove partitioned whole-disk from cache */  | 
499  | 0  |       struct list_head *p, *pnext;  | 
500  |  | 
  | 
501  | 0  |       list_for_each_safe(p, pnext, &cache->bic_devs) { | 
502  | 0  |         blkid_dev tmp = list_entry(p, struct blkid_struct_dev,  | 
503  | 0  |               bid_devs);  | 
504  | 0  |         if (tmp->bid_devno == devno) { | 
505  | 0  |           DBG(DEVNAME, ul_debug(" freeing %s", tmp->bid_name)); | 
506  | 0  |           blkid_free_dev(tmp);  | 
507  | 0  |           cache->bic_flags |= BLKID_BIC_FL_CHANGED;  | 
508  | 0  |           break;  | 
509  | 0  |         }  | 
510  | 0  |       }  | 
511  | 0  |     }  | 
512  | 0  |   next:  | 
513  | 0  |     if (dir)  | 
514  | 0  |       closedir(dir);  | 
515  | 0  |     if (pc)  | 
516  | 0  |       ul_unref_path(pc);  | 
517  | 0  |   }  | 
518  |  |  | 
519  | 0  |   closedir(sysfs);  | 
520  | 0  |   return 0;  | 
521  | 0  | }  | 
522  |  |  | 
523  |  | /*  | 
524  |  |  * Read the device data for all available block devices in the system.  | 
525  |  |  */  | 
526  |  | static int probe_all(blkid_cache cache, int only_if_new, int update_interval)  | 
527  | 0  | { | 
528  | 0  |   int rc;  | 
529  |  | 
  | 
530  | 0  |   if (!cache)  | 
531  | 0  |     return -BLKID_ERR_PARAM;  | 
532  |  |  | 
533  | 0  |   if (cache->bic_flags & BLKID_BIC_FL_PROBED &&  | 
534  | 0  |       time(NULL) - cache->bic_time < BLKID_PROBE_INTERVAL) { | 
535  | 0  |     DBG(PROBE, ul_debug("don't re-probe [delay < %d]", BLKID_PROBE_INTERVAL)); | 
536  | 0  |     return 0;  | 
537  | 0  |   }  | 
538  |  |  | 
539  | 0  |   blkid_read_cache(cache);  | 
540  | 0  | #ifdef VG_DIR  | 
541  | 0  |   lvm_probe_all(cache, only_if_new);  | 
542  | 0  | #endif  | 
543  | 0  |   ubi_probe_all(cache, only_if_new);  | 
544  |  | 
  | 
545  | 0  |   rc = sysfs_probe_all(cache, only_if_new, 0);  | 
546  |  |  | 
547  |  |   /* Don't mark the change as "probed" if /sys not available */  | 
548  | 0  |   if (update_interval && rc == 0) { | 
549  | 0  |     cache->bic_time = time(NULL);  | 
550  | 0  |     cache->bic_flags |= BLKID_BIC_FL_PROBED;  | 
551  | 0  |   }  | 
552  |  | 
  | 
553  | 0  |   blkid_flush_cache(cache);  | 
554  | 0  |   return 0;  | 
555  | 0  | }  | 
556  |  |  | 
557  |  | /**  | 
558  |  |  * blkid_probe_all:  | 
559  |  |  * @cache: cache handler  | 
560  |  |  *  | 
561  |  |  * Probes all block devices.  | 
562  |  |  *  | 
563  |  |  * Returns: 0 on success, or number less than zero in case of error.  | 
564  |  |  */  | 
565  |  | int blkid_probe_all(blkid_cache cache)  | 
566  | 0  | { | 
567  | 0  |   int ret;  | 
568  |  | 
  | 
569  | 0  |   DBG(PROBE, ul_debug("Begin blkid_probe_all()")); | 
570  | 0  |   ret = probe_all(cache, 0, 1);  | 
571  | 0  |   DBG(PROBE, ul_debug("End blkid_probe_all() [rc=%d]", ret)); | 
572  | 0  |   return ret;  | 
573  | 0  | }  | 
574  |  |  | 
575  |  | /**  | 
576  |  |  * blkid_probe_all_new:  | 
577  |  |  * @cache: cache handler  | 
578  |  |  *  | 
579  |  |  * Probes all new block devices.  | 
580  |  |  *  | 
581  |  |  * Returns: 0 on success, or number less than zero in case of error.  | 
582  |  |  */  | 
583  |  | int blkid_probe_all_new(blkid_cache cache)  | 
584  | 0  | { | 
585  | 0  |   int ret;  | 
586  |  | 
  | 
587  | 0  |   DBG(PROBE, ul_debug("Begin blkid_probe_all_new()")); | 
588  | 0  |   ret = probe_all(cache, 1, 0);  | 
589  | 0  |   DBG(PROBE, ul_debug("End blkid_probe_all_new() [rc=%d]", ret)); | 
590  | 0  |   return ret;  | 
591  | 0  | }  | 
592  |  |  | 
593  |  | /**  | 
594  |  |  * blkid_probe_all_removable:  | 
595  |  |  * @cache: cache handler  | 
596  |  |  *  | 
597  |  |  * The libblkid probing is based on devices from /proc/partitions by default.  | 
598  |  |  * This file usually does not contain removable devices (e.g. CDROMs) and this kind  | 
599  |  |  * of devices are invisible for libblkid.  | 
600  |  |  *  | 
601  |  |  * This function adds removable block devices to @cache (probing is based on  | 
602  |  |  * information from the /sys directory). Don't forget that removable devices  | 
603  |  |  * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call  | 
604  |  |  * this function by default.  | 
605  |  |  *  | 
606  |  |  * Note that devices which were detected by this function won't be written to  | 
607  |  |  * blkid.tab cache file.  | 
608  |  |  *  | 
609  |  |  * Returns: 0 on success, or number less than zero in case of error.  | 
610  |  |  */  | 
611  |  | int blkid_probe_all_removable(blkid_cache cache)  | 
612  | 0  | { | 
613  | 0  |   int ret;  | 
614  |  | 
  | 
615  | 0  |   DBG(PROBE, ul_debug("Begin blkid_probe_all_removable()")); | 
616  | 0  |   ret = sysfs_probe_all(cache, 0, 1);  | 
617  | 0  |   DBG(PROBE, ul_debug("End blkid_probe_all_removable() [rc=%d]", ret)); | 
618  | 0  |   return ret;  | 
619  | 0  | }  | 
620  |  |  | 
621  |  | #ifdef TEST_PROGRAM  | 
622  |  | int main(int argc, char **argv)  | 
623  |  | { | 
624  |  |   blkid_cache cache = NULL;  | 
625  |  |   int ret;  | 
626  |  |  | 
627  |  |   blkid_init_debug(BLKID_DEBUG_ALL);  | 
628  |  |   if (argc != 1) { | 
629  |  |     fprintf(stderr, "Usage: %s\n"  | 
630  |  |       "Probe all devices and exit\n", argv[0]);  | 
631  |  |     exit(1);  | 
632  |  |   }  | 
633  |  |   if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { | 
634  |  |     fprintf(stderr, "%s: error creating cache (%d)\n",  | 
635  |  |       argv[0], ret);  | 
636  |  |     exit(1);  | 
637  |  |   }  | 
638  |  |   if (blkid_probe_all(cache) < 0)  | 
639  |  |     printf("%s: error probing devices\n", argv[0]); | 
640  |  |  | 
641  |  |   if (blkid_probe_all_removable(cache) < 0)  | 
642  |  |     printf("%s: error probing removable devices\n", argv[0]); | 
643  |  |  | 
644  |  |   blkid_put_cache(cache);  | 
645  |  |   return (0);  | 
646  |  | }  | 
647  |  | #endif  |