devname.c revision 7515a7447836708241b2b30ca7d70d1257265e75
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#if HAVE_UNISTD_H 20#include <unistd.h> 21#endif 22#include <stdlib.h> 23#include <string.h> 24#include <ctype.h> 25#if HAVE_SYS_TYPES_H 26#include <sys/types.h> 27#endif 28#if HAVE_SYS_STAT_H 29#include <sys/stat.h> 30#endif 31#if HAVE_ERRNO_H 32#include <errno.h> 33#endif 34#if HAVE_SYS_MKDEV_H 35#include <sys/mkdev.h> 36#endif 37#include <time.h> 38 39#include "blkidP.h" 40 41/* 42 * Find a dev struct in the cache by device name, if available. 43 * 44 * If there is no entry with the specified device name, and the create 45 * flag is set, then create an empty device entry. 46 */ 47blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) 48{ 49 blkid_dev dev = NULL, tmp; 50 struct list_head *p, *pnext; 51 52 if (!cache || !devname) 53 return NULL; 54 55 list_for_each(p, &cache->bic_devs) { 56 tmp = list_entry(p, struct blkid_struct_dev, bid_devs); 57 if (strcmp(tmp->bid_name, devname)) 58 continue; 59 60 DBG(DEBUG_DEVNAME, 61 printf("found devname %s in cache\n", tmp->bid_name)); 62 dev = tmp; 63 break; 64 } 65 66 if (!dev && (flags & BLKID_DEV_CREATE)) { 67 dev = blkid_new_dev(); 68 if (!dev) 69 return NULL; 70 dev->bid_time = INT_MIN; 71 dev->bid_name = blkid_strdup(devname); 72 dev->bid_cache = cache; 73 list_add_tail(&dev->bid_devs, &cache->bic_devs); 74 cache->bic_flags |= BLKID_BIC_FL_CHANGED; 75 } 76 77 if (flags & BLKID_DEV_VERIFY) { 78 dev = blkid_verify(cache, dev); 79 if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) 80 return dev; 81 /* 82 * If the device is verified, then search the blkid 83 * cache for any entries that match on the type, uuid, 84 * and label, and verify them; if a cache entry can 85 * not be verified, then it's stale and so we remove 86 * it. 87 */ 88 list_for_each_safe(p, pnext, &cache->bic_devs) { 89 blkid_dev dev2; 90 if (!p) 91 break; 92 dev2 = list_entry(p, struct blkid_struct_dev, bid_devs); 93 if (dev2->bid_flags & BLKID_BID_FL_VERIFIED) 94 continue; 95 if (!dev->bid_type || !dev2->bid_type || 96 strcmp(dev->bid_type, dev2->bid_type)) 97 continue; 98 if (dev->bid_label && dev2->bid_label && 99 strcmp(dev->bid_label, dev2->bid_label)) 100 continue; 101 if (dev->bid_uuid && dev2->bid_uuid && 102 strcmp(dev->bid_uuid, dev2->bid_uuid)) 103 continue; 104 if ((dev->bid_label && !dev2->bid_label) || 105 (!dev->bid_label && dev2->bid_label) || 106 (dev->bid_uuid && !dev2->bid_uuid) || 107 (!dev->bid_uuid && dev2->bid_uuid)) 108 continue; 109 dev2 = blkid_verify(cache, dev2); 110 if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED)) 111 blkid_free_dev(dev2); 112 } 113 } 114 return dev; 115} 116 117/* Directories where we will try to search for device names */ 118static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; 119 120/* 121 * Probe a single block device to add to the device cache. 122 */ 123static void probe_one(blkid_cache cache, const char *ptname, 124 dev_t devno, int pri, int only_if_new) 125{ 126 blkid_dev dev = NULL; 127 struct list_head *p, *pnext; 128 const char **dir; 129 char *devname = NULL; 130 131 /* See if we already have this device number in the cache. */ 132 list_for_each_safe(p, pnext, &cache->bic_devs) { 133 blkid_dev tmp = list_entry(p, struct blkid_struct_dev, 134 bid_devs); 135 if (tmp->bid_devno == devno) { 136 if (only_if_new && !access(tmp->bid_name, F_OK)) 137 return; 138 dev = blkid_verify(cache, tmp); 139 if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) 140 break; 141 dev = 0; 142 } 143 } 144 if (dev && dev->bid_devno == devno) 145 goto set_pri; 146 147 /* 148 * Take a quick look at /dev/ptname for the device number. We check 149 * all of the likely device directories. If we don't find it, or if 150 * the stat information doesn't check out, use blkid_devno_to_devname() 151 * to find it via an exhaustive search for the device major/minor. 152 */ 153 for (dir = dirlist; *dir; dir++) { 154 struct stat st; 155 char device[256]; 156 157 sprintf(device, "%s/%s", *dir, ptname); 158 if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && 159 dev->bid_devno == devno) 160 goto set_pri; 161 162 if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) && 163 st.st_rdev == devno) { 164 devname = blkid_strdup(device); 165 break; 166 } 167 } 168 /* Do a short-cut scan of /dev/mapper first */ 169 if (!devname) 170 blkid__scan_dir("/dev/mapper", devno, 0, &devname); 171 if (!devname) { 172 devname = blkid_devno_to_devname(devno); 173 if (!devname) 174 return; 175 } 176 dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); 177 free(devname); 178 179set_pri: 180 if (dev) { 181 if (pri) 182 dev->bid_pri = pri; 183 else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) 184 dev->bid_pri = BLKID_PRI_DM; 185 else if (!strncmp(ptname, "md", 2)) 186 dev->bid_pri = BLKID_PRI_MD; 187 } 188 return; 189} 190 191#define PROC_PARTITIONS "/proc/partitions" 192#define VG_DIR "/proc/lvm/VGs" 193 194/* 195 * This function initializes the UUID cache with devices from the LVM 196 * proc hierarchy. We currently depend on the names of the LVM 197 * hierarchy giving us the device structure in /dev. (XXX is this a 198 * safe thing to do?) 199 */ 200#ifdef VG_DIR 201#include <dirent.h> 202static dev_t lvm_get_devno(const char *lvm_device) 203{ 204 FILE *lvf; 205 char buf[1024]; 206 int ma, mi; 207 dev_t ret = 0; 208 209 DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); 210 if ((lvf = fopen(lvm_device, "r")) == NULL) { 211 DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno, 212 strerror(errno))); 213 return 0; 214 } 215 216 while (fgets(buf, sizeof(buf), lvf)) { 217 if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { 218 ret = makedev(ma, mi); 219 break; 220 } 221 } 222 fclose(lvf); 223 224 return ret; 225} 226 227static void lvm_probe_all(blkid_cache cache, int only_if_new) 228{ 229 DIR *vg_list; 230 struct dirent *vg_iter; 231 int vg_len = strlen(VG_DIR); 232 dev_t dev; 233 234 if ((vg_list = opendir(VG_DIR)) == NULL) 235 return; 236 237 DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR)); 238 239 while ((vg_iter = readdir(vg_list)) != NULL) { 240 DIR *lv_list; 241 char *vdirname; 242 char *vg_name; 243 struct dirent *lv_iter; 244 245 vg_name = vg_iter->d_name; 246 if (!strcmp(vg_name, ".") || !strcmp(vg_name, "..")) 247 continue; 248 vdirname = malloc(vg_len + strlen(vg_name) + 8); 249 if (!vdirname) 250 goto exit; 251 sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); 252 253 lv_list = opendir(vdirname); 254 free(vdirname); 255 if (lv_list == NULL) 256 continue; 257 258 while ((lv_iter = readdir(lv_list)) != NULL) { 259 char *lv_name, *lvm_device; 260 261 lv_name = lv_iter->d_name; 262 if (!strcmp(lv_name, ".") || !strcmp(lv_name, "..")) 263 continue; 264 265 lvm_device = malloc(vg_len + strlen(vg_name) + 266 strlen(lv_name) + 8); 267 if (!lvm_device) { 268 closedir(lv_list); 269 goto exit; 270 } 271 sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, 272 lv_name); 273 dev = lvm_get_devno(lvm_device); 274 sprintf(lvm_device, "%s/%s", vg_name, lv_name); 275 DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n", 276 lvm_device, 277 (unsigned int) dev)); 278 probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, 279 only_if_new); 280 free(lvm_device); 281 } 282 closedir(lv_list); 283 } 284exit: 285 closedir(vg_list); 286} 287#endif 288 289#define PROC_EVMS_VOLUMES "/proc/evms/volumes" 290 291static int 292evms_probe_all(blkid_cache cache, int only_if_new) 293{ 294 char line[100]; 295 int ma, mi, sz, num = 0; 296 FILE *procpt; 297 char device[110]; 298 299 procpt = fopen(PROC_EVMS_VOLUMES, "r"); 300 if (!procpt) 301 return 0; 302 while (fgets(line, sizeof(line), procpt)) { 303 if (sscanf (line, " %d %d %d %*s %*s %[^\n ]", 304 &ma, &mi, &sz, device) != 4) 305 continue; 306 307 DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n", 308 device, ma, mi)); 309 310 probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, 311 only_if_new); 312 num++; 313 } 314 fclose(procpt); 315 return num; 316} 317 318/* 319 * Read the device data for all available block devices in the system. 320 */ 321static int probe_all(blkid_cache cache, int only_if_new) 322{ 323 FILE *proc; 324 char line[1024]; 325 char ptname0[128], ptname1[128], *ptname = 0; 326 char *ptnames[2]; 327 dev_t devs[2]; 328 int ma, mi; 329 unsigned long long sz; 330 int lens[2] = { 0, 0 }; 331 int which = 0, last = 0; 332 333 ptnames[0] = ptname0; 334 ptnames[1] = ptname1; 335 336 if (!cache) 337 return -BLKID_ERR_PARAM; 338 339 if (cache->bic_flags & BLKID_BIC_FL_PROBED && 340 time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) 341 return 0; 342 343 blkid_read_cache(cache); 344 evms_probe_all(cache, only_if_new); 345#ifdef VG_DIR 346 lvm_probe_all(cache, only_if_new); 347#endif 348 349 proc = fopen(PROC_PARTITIONS, "r"); 350 if (!proc) 351 return -BLKID_ERR_PROC; 352 353 while (fgets(line, sizeof(line), proc)) { 354 last = which; 355 which ^= 1; 356 ptname = ptnames[which]; 357 358 if (sscanf(line, " %d %d %llu %128[^\n ]", 359 &ma, &mi, &sz, ptname) != 4) 360 continue; 361 devs[which] = makedev(ma, mi); 362 363 DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); 364 365 /* Skip whole disk devs unless they have no partitions. 366 * If base name of device has changed, also 367 * check previous dev to see if it didn't have a partn. 368 * heuristic: partition name ends in a digit, & partition 369 * names contain whole device name as substring. 370 * 371 * Skip extended partitions. 372 * heuristic: size is 1 373 * 374 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs 375 */ 376 377 lens[which] = strlen(ptname); 378 379 /* ends in a digit, clearly a partition, so check */ 380 if (isdigit(ptname[lens[which] - 1])) { 381 DBG(DEBUG_DEVNAME, 382 printf("partition dev %s, devno 0x%04X\n", 383 ptname, (unsigned int) devs[which])); 384 385 if (sz > 1) 386 probe_one(cache, ptname, devs[which], 0, 387 only_if_new); 388 lens[which] = 0; /* mark as checked */ 389 } 390 391 /* 392 * If last was not checked because it looked like a whole-disk 393 * dev, and the device's base name has changed, 394 * check last as well. 395 */ 396 if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { 397 DBG(DEBUG_DEVNAME, 398 printf("whole dev %s, devno 0x%04X\n", 399 ptnames[last], (unsigned int) devs[last])); 400 probe_one(cache, ptnames[last], devs[last], 0, 401 only_if_new); 402 lens[last] = 0; 403 } 404 } 405 406 /* Handle the last device if it wasn't partitioned */ 407 if (lens[which]) 408 probe_one(cache, ptname, devs[which], 0, only_if_new); 409 410 fclose(proc); 411 blkid_flush_cache(cache); 412 return 0; 413} 414 415int blkid_probe_all(blkid_cache cache) 416{ 417 int ret; 418 419 DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n")); 420 ret = probe_all(cache, 0); 421 cache->bic_time = time(0); 422 cache->bic_flags |= BLKID_BIC_FL_PROBED; 423 DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n")); 424 return ret; 425} 426 427int blkid_probe_all_new(blkid_cache cache) 428{ 429 int ret; 430 431 DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n")); 432 ret = probe_all(cache, 1); 433 DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n")); 434 return ret; 435} 436 437 438#ifdef TEST_PROGRAM 439int main(int argc, char **argv) 440{ 441 blkid_cache cache = NULL; 442 int ret; 443 444 blkid_debug_mask = DEBUG_ALL; 445 if (argc != 1) { 446 fprintf(stderr, "Usage: %s\n" 447 "Probe all devices and exit\n", argv[0]); 448 exit(1); 449 } 450 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { 451 fprintf(stderr, "%s: error creating cache (%d)\n", 452 argv[0], ret); 453 exit(1); 454 } 455 if (blkid_probe_all(cache) < 0) 456 printf("%s: error probing devices\n", argv[0]); 457 458 blkid_put_cache(cache); 459 return (0); 460} 461#endif 462