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 #ifdef HAVE_DEVMAPPER 42 #include <libdevmapper.h> 43 #endif 44 45 /* 46 * Find a dev struct in the cache by device name, if available. 47 * 48 * If there is no entry with the specified device name, and the create 49 * flag is set, then create an empty device entry. 50 */ 51 blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) 52 { 53 blkid_dev dev = NULL, tmp; 54 struct list_head *p; 55 56 if (!cache || !devname) 57 return NULL; 58 59 list_for_each(p, &cache->bic_devs) { 60 tmp = list_entry(p, struct blkid_struct_dev, bid_devs); 61 if (strcmp(tmp->bid_name, devname)) 62 continue; 63 64 DBG(DEBUG_DEVNAME, 65 printf("found devname %s in cache\n", tmp->bid_name)); 66 dev = tmp; 67 break; 68 } 69 70 if (!dev && (flags & BLKID_DEV_CREATE)) { 71 dev = blkid_new_dev(); 72 if (!dev) 73 return NULL; 74 dev->bid_time = INT_MIN; 75 dev->bid_name = blkid_strdup(devname); 76 dev->bid_cache = cache; 77 list_add_tail(&dev->bid_devs, &cache->bic_devs); 78 cache->bic_flags |= BLKID_BIC_FL_CHANGED; 79 } 80 81 if (flags & BLKID_DEV_VERIFY) 82 dev = blkid_verify(cache, dev); 83 return dev; 84 } 85 86 #ifdef HAVE_DEVMAPPER 87 static int dm_device_is_leaf(const dev_t dev); 88 #endif 89 90 /* 91 * Probe a single block device to add to the device cache. 92 */ 93 static void probe_one(blkid_cache cache, const char *ptname, 94 dev_t devno, int pri, int only_if_new) 95 { 96 blkid_dev dev = NULL; 97 struct list_head *p; 98 const char **dir; 99 char *devname = NULL; 100 101 /* See if we already have this device number in the cache. */ 102 list_for_each(p, &cache->bic_devs) { 103 blkid_dev tmp = list_entry(p, struct blkid_struct_dev, 104 bid_devs); 105 #ifdef HAVE_DEVMAPPER 106 if (!dm_device_is_leaf(devno)) 107 continue; 108 #endif 109 if (tmp->bid_devno == devno) { 110 if (only_if_new) 111 return; 112 dev = blkid_verify(cache, tmp); 113 break; 114 } 115 } 116 if (dev && dev->bid_devno == devno) 117 goto set_pri; 118 119 /* 120 * Take a quick look at /dev/ptname for the device number. We check 121 * all of the likely device directories. If we don't find it, or if 122 * the stat information doesn't check out, use blkid_devno_to_devname() 123 * to find it via an exhaustive search for the device major/minor. 124 */ 125 for (dir = blkid_devdirs; *dir; dir++) { 126 struct stat st; 127 char device[256]; 128 129 sprintf(device, "%s/%s", *dir, ptname); 130 if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && 131 dev->bid_devno == devno) 132 goto set_pri; 133 134 if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) && 135 st.st_rdev == devno) { 136 devname = blkid_strdup(device); 137 break; 138 } 139 } 140 if (!devname) { 141 devname = blkid_devno_to_devname(devno); 142 if (!devname) 143 return; 144 } 145 dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); 146 free(devname); 147 148 set_pri: 149 if (!pri && !strncmp(ptname, "md", 2)) 150 pri = BLKID_PRI_MD; 151 if (dev) 152 dev->bid_pri = pri; 153 return; 154 } 155 156 #ifdef HAVE_DEVMAPPER 157 static void dm_quiet_log(int level __BLKID_ATTR((unused)), 158 const char *file __BLKID_ATTR((unused)), 159 int line __BLKID_ATTR((unused)), 160 const char *f __BLKID_ATTR((unused)), ...) 161 { 162 return; 163 } 164 165 /* 166 * device-mapper support 167 */ 168 static int dm_device_has_dep(const dev_t dev, const char *name) 169 { 170 struct dm_task *task; 171 struct dm_deps *deps; 172 struct dm_info info; 173 unsigned int i; 174 int ret = 0; 175 176 task = dm_task_create(DM_DEVICE_DEPS); 177 if (!task) 178 goto out; 179 180 if (!dm_task_set_name(task, name)) 181 goto out; 182 183 if (!dm_task_run(task)) 184 goto out; 185 186 if (!dm_task_get_info(task, &info)) 187 goto out; 188 189 if (!info.exists) 190 goto out; 191 192 deps = dm_task_get_deps(task); 193 if (!deps || deps->count == 0) 194 goto out; 195 196 for (i = 0; i < deps->count; i++) { 197 dev_t dep_dev = deps->device[i]; 198 199 if (dev == dep_dev) { 200 ret = 1; 201 goto out; 202 } 203 } 204 205 out: 206 if (task) 207 dm_task_destroy(task); 208 209 return ret; 210 } 211 212 static int dm_device_is_leaf(const dev_t dev) 213 { 214 struct dm_task *task; 215 struct dm_names *names; 216 unsigned int next = 0; 217 int n, ret = 1; 218 219 dm_log_init(dm_quiet_log); 220 task = dm_task_create(DM_DEVICE_LIST); 221 if (!task) 222 goto out; 223 224 dm_log_init(0); 225 226 if (!dm_task_run(task)) 227 goto out; 228 229 names = dm_task_get_names(task); 230 if (!names || !names->dev) 231 goto out; 232 233 n = 0; 234 do { 235 names = (struct dm_names *) ((char *)names + next); 236 237 if (dm_device_has_dep(dev, names->name)) 238 ret = 0; 239 240 next = names->next; 241 } while (next); 242 243 out: 244 if (task) 245 dm_task_destroy(task); 246 247 return ret; 248 } 249 250 static dev_t dm_get_devno(const char *name) 251 { 252 struct dm_task *task; 253 struct dm_info info; 254 dev_t ret = 0; 255 256 task = dm_task_create(DM_DEVICE_INFO); 257 if (!task) 258 goto out; 259 260 if (!dm_task_set_name(task, name)) 261 goto out; 262 263 if (!dm_task_run(task)) 264 goto out; 265 266 if (!dm_task_get_info(task, &info)) 267 goto out; 268 269 if (!info.exists) 270 goto out; 271 272 ret = makedev(info.major, info.minor); 273 274 out: 275 if (task) 276 dm_task_destroy(task); 277 278 return ret; 279 } 280 281 static void dm_probe_all(blkid_cache cache, int only_if_new) 282 { 283 struct dm_task *task; 284 struct dm_names *names; 285 unsigned int next = 0; 286 int n; 287 288 dm_log_init(dm_quiet_log); 289 task = dm_task_create(DM_DEVICE_LIST); 290 if (!task) 291 goto out; 292 dm_log_init(0); 293 294 if (!dm_task_run(task)) 295 goto out; 296 297 names = dm_task_get_names(task); 298 if (!names || !names->dev) 299 goto out; 300 301 n = 0; 302 do { 303 int rc; 304 char *device = NULL; 305 dev_t dev = 0; 306 307 names = (struct dm_names *) ((char *)names + next); 308 309 rc = asprintf(&device, "mapper/%s", names->name); 310 if (rc < 0) 311 goto try_next; 312 313 dev = dm_get_devno(names->name); 314 if (dev == 0) 315 goto try_next; 316 317 if (!dm_device_is_leaf(dev)) 318 goto try_next; 319 320 probe_one(cache, device, dev, BLKID_PRI_DM, only_if_new); 321 322 try_next: 323 free(device); 324 next = names->next; 325 } while (next); 326 327 out: 328 if (task) 329 dm_task_destroy(task); 330 } 331 #endif /* HAVE_DEVMAPPER */ 332 333 #define PROC_PARTITIONS "/proc/partitions" 334 #define VG_DIR "/proc/lvm/VGs" 335 336 /* 337 * This function initializes the UUID cache with devices from the LVM 338 * proc hierarchy. We currently depend on the names of the LVM 339 * hierarchy giving us the device structure in /dev. (XXX is this a 340 * safe thing to do?) 341 */ 342 #ifdef VG_DIR 343 #include <dirent.h> 344 static dev_t lvm_get_devno(const char *lvm_device) 345 { 346 FILE *lvf; 347 char buf[1024]; 348 int ma, mi; 349 dev_t ret = 0; 350 351 DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); 352 if ((lvf = fopen(lvm_device, "r")) == NULL) { 353 DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno, 354 strerror(errno))); 355 return 0; 356 } 357 358 while (fgets(buf, sizeof(buf), lvf)) { 359 if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { 360 ret = makedev(ma, mi); 361 break; 362 } 363 } 364 fclose(lvf); 365 366 return ret; 367 } 368 369 static void lvm_probe_all(blkid_cache cache, int only_if_new) 370 { 371 DIR *vg_list; 372 struct dirent *vg_iter; 373 int vg_len = strlen(VG_DIR); 374 dev_t dev; 375 376 if ((vg_list = opendir(VG_DIR)) == NULL) 377 return; 378 379 DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR)); 380 381 while ((vg_iter = readdir(vg_list)) != NULL) { 382 DIR *lv_list; 383 char *vdirname; 384 char *vg_name; 385 struct dirent *lv_iter; 386 387 vg_name = vg_iter->d_name; 388 if (!strcmp(vg_name, ".") || !strcmp(vg_name, "..")) 389 continue; 390 vdirname = malloc(vg_len + strlen(vg_name) + 8); 391 if (!vdirname) 392 goto exit; 393 sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); 394 395 lv_list = opendir(vdirname); 396 free(vdirname); 397 if (lv_list == NULL) 398 continue; 399 400 while ((lv_iter = readdir(lv_list)) != NULL) { 401 char *lv_name, *lvm_device; 402 403 lv_name = lv_iter->d_name; 404 if (!strcmp(lv_name, ".") || !strcmp(lv_name, "..")) 405 continue; 406 407 lvm_device = malloc(vg_len + strlen(vg_name) + 408 strlen(lv_name) + 8); 409 if (!lvm_device) { 410 closedir(lv_list); 411 goto exit; 412 } 413 sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, 414 lv_name); 415 dev = lvm_get_devno(lvm_device); 416 sprintf(lvm_device, "%s/%s", vg_name, lv_name); 417 DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n", 418 lvm_device, 419 (unsigned int) dev)); 420 probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, 421 only_if_new); 422 free(lvm_device); 423 } 424 closedir(lv_list); 425 } 426 exit: 427 closedir(vg_list); 428 } 429 #endif 430 431 #define PROC_EVMS_VOLUMES "/proc/evms/volumes" 432 433 static int 434 evms_probe_all(blkid_cache cache, int only_if_new) 435 { 436 char line[100]; 437 int ma, mi, sz, num = 0; 438 FILE *procpt; 439 char device[110]; 440 441 procpt = fopen(PROC_EVMS_VOLUMES, "r"); 442 if (!procpt) 443 return 0; 444 while (fgets(line, sizeof(line), procpt)) { 445 if (sscanf (line, " %d %d %d %*s %*s %[^\n ]", 446 &ma, &mi, &sz, device) != 4) 447 continue; 448 449 DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n", 450 device, ma, mi)); 451 452 probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, 453 only_if_new); 454 num++; 455 } 456 fclose(procpt); 457 return num; 458 } 459 460 /* 461 * Read the device data for all available block devices in the system. 462 */ 463 static int probe_all(blkid_cache cache, int only_if_new) 464 { 465 FILE *proc; 466 char line[1024]; 467 char ptname0[128], ptname1[128], *ptname = 0; 468 char *ptnames[2]; 469 dev_t devs[2]; 470 int ma, mi; 471 unsigned long long sz; 472 int lens[2] = { 0, 0 }; 473 int which = 0, last = 0; 474 475 ptnames[0] = ptname0; 476 ptnames[1] = ptname1; 477 478 if (!cache) 479 return -BLKID_ERR_PARAM; 480 481 if (cache->bic_flags & BLKID_BIC_FL_PROBED && 482 time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) 483 return 0; 484 485 blkid_read_cache(cache); 486 #ifdef HAVE_DEVMAPPER 487 dm_probe_all(cache, only_if_new); 488 #endif 489 evms_probe_all(cache, only_if_new); 490 #ifdef VG_DIR 491 lvm_probe_all(cache, only_if_new); 492 #endif 493 494 proc = fopen(PROC_PARTITIONS, "r"); 495 if (!proc) 496 return -BLKID_ERR_PROC; 497 498 while (fgets(line, sizeof(line), proc)) { 499 last = which; 500 which ^= 1; 501 ptname = ptnames[which]; 502 503 if (sscanf(line, " %d %d %llu %128[^\n ]", 504 &ma, &mi, &sz, ptname) != 4) 505 continue; 506 devs[which] = makedev(ma, mi); 507 508 DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); 509 510 /* Skip whole disk devs unless they have no partitions. 511 * If base name of device has changed, also 512 * check previous dev to see if it didn't have a partn. 513 * heuristic: partition name ends in a digit, & partition 514 * names contain whole device name as substring. 515 * 516 * Skip extended partitions. 517 * heuristic: size is 1 518 * 519 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs 520 */ 521 522 lens[which] = strlen(ptname); 523 524 /* ends in a digit, clearly a partition, so check */ 525 if (isdigit(ptname[lens[which] - 1])) { 526 DBG(DEBUG_DEVNAME, 527 printf("partition dev %s, devno 0x%04X\n", 528 ptname, (unsigned int) devs[which])); 529 530 if (sz > 1) 531 probe_one(cache, ptname, devs[which], 0, 532 only_if_new); 533 lens[which] = 0; /* mark as checked */ 534 } 535 536 /* 537 * If last was not checked because it looked like a whole-disk 538 * dev, and the device's base name has changed, 539 * check last as well. 540 */ 541 if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { 542 DBG(DEBUG_DEVNAME, 543 printf("whole dev %s, devno 0x%04X\n", 544 ptnames[last], (unsigned int) devs[last])); 545 probe_one(cache, ptnames[last], devs[last], 0, 546 only_if_new); 547 lens[last] = 0; 548 } 549 } 550 551 /* Handle the last device if it wasn't partitioned */ 552 if (lens[which]) 553 probe_one(cache, ptname, devs[which], 0, only_if_new); 554 555 fclose(proc); 556 blkid_flush_cache(cache); 557 return 0; 558 } 559 560 int blkid_probe_all(blkid_cache cache) 561 { 562 int ret; 563 564 DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n")); 565 ret = probe_all(cache, 0); 566 cache->bic_time = time(0); 567 cache->bic_flags |= BLKID_BIC_FL_PROBED; 568 DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n")); 569 return ret; 570 } 571 572 int blkid_probe_all_new(blkid_cache cache) 573 { 574 int ret; 575 576 DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n")); 577 ret = probe_all(cache, 1); 578 DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n")); 579 return ret; 580 } 581 582 583 #ifdef TEST_PROGRAM 584 int main(int argc, char **argv) 585 { 586 blkid_cache cache = NULL; 587 int ret; 588 589 blkid_debug_mask = DEBUG_ALL; 590 if (argc != 1) { 591 fprintf(stderr, "Usage: %s\n" 592 "Probe all devices and exit\n", argv[0]); 593 exit(1); 594 } 595 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { 596 fprintf(stderr, "%s: error creating cache (%d)\n", 597 argv[0], ret); 598 exit(1); 599 } 600 if (blkid_probe_all(cache) < 0) 601 printf("%s: error probing devices\n", argv[0]); 602 603 blkid_put_cache(cache); 604 return (0); 605 } 606 #endif 607