busybox/e2fsprogs/old_e2fsprogs/blkid/devname.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * devname.c - get a dev by its device inode name
   4 *
   5 * Copyright (C) Andries Brouwer
   6 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o
   7 * Copyright (C) 2001 Andreas Dilger
   8 *
   9 * %Begin-Header%
  10 * This file may be redistributed under the terms of the
  11 * GNU Lesser General Public License.
  12 * %End-Header%
  13 */
  14
  15#include <stdio.h>
  16#include <string.h>
  17#ifdef HAVE_UNISTD_H
  18#include <unistd.h>
  19#endif
  20#include <stdlib.h>
  21#include <string.h>
  22#include <ctype.h>
  23#ifdef HAVE_SYS_TYPES_H
  24#include <sys/types.h>
  25#endif
  26#include <sys/stat.h>
  27#ifdef HAVE_ERRNO_H
  28#include <errno.h>
  29#endif
  30#ifdef HAVE_SYS_MKDEV_H
  31#include <sys/mkdev.h>
  32#endif
  33#include <time.h>
  34
  35#include "blkidP.h"
  36
  37/*
  38 * Find a dev struct in the cache by device name, if available.
  39 *
  40 * If there is no entry with the specified device name, and the create
  41 * flag is set, then create an empty device entry.
  42 */
  43blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
  44{
  45        blkid_dev dev = NULL, tmp;
  46        struct list_head *p;
  47
  48        if (!cache || !devname)
  49                return NULL;
  50
  51        list_for_each(p, &cache->bic_devs) {
  52                tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
  53                if (strcmp(tmp->bid_name, devname))
  54                        continue;
  55
  56                DBG(DEBUG_DEVNAME,
  57                    printf("found devname %s in cache\n", tmp->bid_name));
  58                dev = tmp;
  59                break;
  60        }
  61
  62        if (!dev && (flags & BLKID_DEV_CREATE)) {
  63                dev = blkid_new_dev();
  64                if (!dev)
  65                        return NULL;
  66                dev->bid_name = blkid_strdup(devname);
  67                dev->bid_cache = cache;
  68                list_add_tail(&dev->bid_devs, &cache->bic_devs);
  69                cache->bic_flags |= BLKID_BIC_FL_CHANGED;
  70        }
  71
  72        if (flags & BLKID_DEV_VERIFY)
  73                dev = blkid_verify(cache, dev);
  74        return dev;
  75}
  76
  77/*
  78 * Probe a single block device to add to the device cache.
  79 */
  80static void probe_one(blkid_cache cache, const char *ptname,
  81                      dev_t devno, int pri)
  82{
  83        blkid_dev dev = NULL;
  84        struct list_head *p;
  85        const char **dir;
  86        char *devname = NULL;
  87
  88        /* See if we already have this device number in the cache. */
  89        list_for_each(p, &cache->bic_devs) {
  90                blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
  91                                           bid_devs);
  92                if (tmp->bid_devno == devno) {
  93                        dev = blkid_verify(cache, tmp);
  94                        break;
  95                }
  96        }
  97        if (dev && dev->bid_devno == devno)
  98                goto set_pri;
  99
 100        /*
 101         * Take a quick look at /dev/ptname for the device number.  We check
 102         * all of the likely device directories.  If we don't find it, or if
 103         * the stat information doesn't check out, use blkid_devno_to_devname()
 104         * to find it via an exhaustive search for the device major/minor.
 105         */
 106        for (dir = blkid_devdirs; *dir; dir++) {
 107                struct stat st;
 108                char device[256];
 109
 110                sprintf(device, "%s/%s", *dir, ptname);
 111                if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&
 112                    dev->bid_devno == devno)
 113                        goto set_pri;
 114
 115                if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
 116                    st.st_rdev == devno) {
 117                        devname = blkid_strdup(device);
 118                        break;
 119                }
 120        }
 121        if (!devname) {
 122                devname = blkid_devno_to_devname(devno);
 123                if (!devname)
 124                        return;
 125        }
 126        dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
 127        free(devname);
 128
 129set_pri:
 130        if (!pri && !strncmp(ptname, "md", 2))
 131                pri = BLKID_PRI_MD;
 132        if (dev)
 133                dev->bid_pri = pri;
 134}
 135
 136#define PROC_PARTITIONS "/proc/partitions"
 137#define VG_DIR          "/proc/lvm/VGs"
 138
 139/*
 140 * This function initializes the UUID cache with devices from the LVM
 141 * proc hierarchy.  We currently depend on the names of the LVM
 142 * hierarchy giving us the device structure in /dev.  (XXX is this a
 143 * safe thing to do?)
 144 */
 145#ifdef VG_DIR
 146#include <dirent.h>
 147static dev_t lvm_get_devno(const char *lvm_device)
 148{
 149        FILE *lvf;
 150        char buf[1024];
 151        int ma, mi;
 152        dev_t ret = 0;
 153
 154        DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
 155        if ((lvf = fopen_for_read(lvm_device)) == NULL) {
 156                DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno,
 157                                          strerror(errno)));
 158                return 0;
 159        }
 160
 161        while (fgets(buf, sizeof(buf), lvf)) {
 162                if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) {
 163                        ret = makedev(ma, mi);
 164                        break;
 165                }
 166        }
 167        fclose(lvf);
 168
 169        return ret;
 170}
 171
 172static void lvm_probe_all(blkid_cache cache)
 173{
 174        DIR             *vg_list;
 175        struct dirent   *vg_iter;
 176        int             vg_len = strlen(VG_DIR);
 177        dev_t           dev;
 178
 179        if ((vg_list = opendir(VG_DIR)) == NULL)
 180                return;
 181
 182        DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR));
 183
 184        while ((vg_iter = readdir(vg_list)) != NULL) {
 185                DIR             *lv_list;
 186                char            *vdirname;
 187                char            *vg_name;
 188                struct dirent   *lv_iter;
 189
 190                vg_name = vg_iter->d_name;
 191                if (LONE_CHAR(vg_name, '.') || !strcmp(vg_name, ".."))
 192                        continue;
 193                vdirname = xmalloc(vg_len + strlen(vg_name) + 8);
 194                sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
 195
 196                lv_list = opendir(vdirname);
 197                free(vdirname);
 198                if (lv_list == NULL)
 199                        continue;
 200
 201                while ((lv_iter = readdir(lv_list)) != NULL) {
 202                        char            *lv_name, *lvm_device;
 203
 204                        lv_name = lv_iter->d_name;
 205                        if (LONE_CHAR(lv_name, '.') || !strcmp(lv_name, ".."))
 206                                continue;
 207
 208                        lvm_device = xmalloc(vg_len + strlen(vg_name) +
 209                                            strlen(lv_name) + 8);
 210                        sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
 211                                lv_name);
 212                        dev = lvm_get_devno(lvm_device);
 213                        sprintf(lvm_device, "%s/%s", vg_name, lv_name);
 214                        DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
 215                                                  lvm_device,
 216                                                  (unsigned int) dev));
 217                        probe_one(cache, lvm_device, dev, BLKID_PRI_LVM);
 218                        free(lvm_device);
 219                }
 220                closedir(lv_list);
 221        }
 222        closedir(vg_list);
 223}
 224#endif
 225
 226#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
 227
 228static int
 229evms_probe_all(blkid_cache cache)
 230{
 231        char line[100];
 232        int ma, mi, sz, num = 0;
 233        FILE *procpt;
 234        char device[110];
 235
 236        procpt = fopen_for_read(PROC_EVMS_VOLUMES);
 237        if (!procpt)
 238                return 0;
 239        while (fgets(line, sizeof(line), procpt)) {
 240                if (sscanf(line, " %d %d %d %*s %*s %[^\n ]",
 241                            &ma, &mi, &sz, device) != 4)
 242                        continue;
 243
 244                DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
 245                                          device, ma, mi));
 246
 247                probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS);
 248                num++;
 249        }
 250        fclose(procpt);
 251        return num;
 252}
 253
 254/*
 255 * Read the device data for all available block devices in the system.
 256 */
 257int blkid_probe_all(blkid_cache cache)
 258{
 259        FILE *proc;
 260        char line[1024];
 261        char ptname0[128], ptname1[128], *ptname = NULL;
 262        char *ptnames[2];
 263        dev_t devs[2];
 264        int ma, mi;
 265        unsigned long long sz;
 266        int lens[2] = { 0, 0 };
 267        int which = 0, last = 0;
 268
 269        ptnames[0] = ptname0;
 270        ptnames[1] = ptname1;
 271
 272        if (!cache)
 273                return -BLKID_ERR_PARAM;
 274
 275        if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
 276            time(NULL) - cache->bic_time < BLKID_PROBE_INTERVAL)
 277                return 0;
 278
 279        blkid_read_cache(cache);
 280        evms_probe_all(cache);
 281#ifdef VG_DIR
 282        lvm_probe_all(cache);
 283#endif
 284
 285        proc = fopen_for_read(PROC_PARTITIONS);
 286        if (!proc)
 287                return -BLKID_ERR_PROC;
 288
 289        while (fgets(line, sizeof(line), proc)) {
 290                last = which;
 291                which ^= 1;
 292                ptname = ptnames[which];
 293
 294                if (sscanf(line, " %d %d %llu %128[^\n ]",
 295                           &ma, &mi, &sz, ptname) != 4)
 296                        continue;
 297                devs[which] = makedev(ma, mi);
 298
 299                DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname));
 300
 301                /* Skip whole disk devs unless they have no partitions
 302                 * If we don't have a partition on this dev, also
 303                 * check previous dev to see if it didn't have a partn.
 304                 * heuristic: partition name ends in a digit.
 305                 *
 306                 * Skip extended partitions.
 307                 * heuristic: size is 1
 308                 *
 309                 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
 310                 */
 311
 312                lens[which] = strlen(ptname);
 313                if (isdigit(ptname[lens[which] - 1])) {
 314                        DBG(DEBUG_DEVNAME,
 315                            printf("partition dev %s, devno 0x%04X\n",
 316                                   ptname, (unsigned int) devs[which]));
 317
 318                        if (sz > 1)
 319                                probe_one(cache, ptname, devs[which], 0);
 320                        lens[which] = 0;
 321                        lens[last] = 0;
 322                } else if (lens[last] && strncmp(ptnames[last], ptname,
 323                                                 lens[last])) {
 324                        DBG(DEBUG_DEVNAME,
 325                            printf("whole dev %s, devno 0x%04X\n",
 326                                   ptnames[last], (unsigned int) devs[last]));
 327                        probe_one(cache, ptnames[last], devs[last], 0);
 328                        lens[last] = 0;
 329                }
 330        }
 331
 332        /* Handle the last device if it wasn't partitioned */
 333        if (lens[which])
 334                probe_one(cache, ptname, devs[which], 0);
 335
 336        fclose(proc);
 337
 338        cache->bic_time = time(NULL);
 339        cache->bic_flags |= BLKID_BIC_FL_PROBED;
 340        blkid_flush_cache(cache);
 341        return 0;
 342}
 343
 344#ifdef TEST_PROGRAM
 345int main(int argc, char **argv)
 346{
 347        blkid_cache cache = NULL;
 348        int ret;
 349
 350        blkid_debug_mask = DEBUG_ALL;
 351        if (argc != 1) {
 352                fprintf(stderr, "Usage: %s\n"
 353                        "Probe all devices and exit\n", argv[0]);
 354                exit(1);
 355        }
 356        if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
 357                fprintf(stderr, "%s: error creating cache (%d)\n",
 358                        argv[0], ret);
 359                exit(1);
 360        }
 361        if (blkid_probe_all(cache) < 0)
 362                printf("%s: error probing devices\n", argv[0]);
 363
 364        blkid_put_cache(cache);
 365        return 0;
 366}
 367#endif
 368