busybox/libbb/find_root_device.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Utility routines.
   4 *
   5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9#include "libbb.h"
  10
  11/* Find block device /dev/XXX which contains specified file
  12 * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */
  13
  14/* Do not reallocate all this stuff on each recursion */
  15enum { DEVNAME_MAX = 256 };
  16struct arena {
  17        struct stat st;
  18        dev_t dev;
  19        /* Was PATH_MAX, but we recurse _/dev_. We can assume
  20         * people are not crazy enough to have mega-deep tree there */
  21        char devpath[DEVNAME_MAX];
  22};
  23
  24static char *find_block_device_in_dir(struct arena *ap)
  25{
  26        DIR *dir;
  27        struct dirent *entry;
  28        char *retpath = NULL;
  29        int len, rem;
  30
  31        len = strlen(ap->devpath);
  32        rem = DEVNAME_MAX-2 - len;
  33        if (rem <= 0)
  34                return NULL;
  35
  36        dir = opendir(ap->devpath);
  37        if (!dir)
  38                return NULL;
  39
  40        ap->devpath[len++] = '/';
  41
  42        while ((entry = readdir(dir)) != NULL) {
  43                safe_strncpy(ap->devpath + len, entry->d_name, rem);
  44                /* lstat: do not follow links */
  45                if (lstat(ap->devpath, &ap->st) != 0)
  46                        continue;
  47                if (S_ISBLK(ap->st.st_mode) && ap->st.st_rdev == ap->dev) {
  48                        retpath = xstrdup(ap->devpath);
  49                        break;
  50                }
  51                if (S_ISDIR(ap->st.st_mode)) {
  52                        /* Do not recurse for '.' and '..' */
  53                        if (DOT_OR_DOTDOT(entry->d_name))
  54                                continue;
  55                        retpath = find_block_device_in_dir(ap);
  56                        if (retpath)
  57                                break;
  58                }
  59        }
  60        closedir(dir);
  61
  62        return retpath;
  63}
  64
  65char* FAST_FUNC find_block_device(const char *path)
  66{
  67        struct arena a;
  68
  69        if (stat(path, &a.st) != 0)
  70                return NULL;
  71        a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev;
  72        strcpy(a.devpath, "/dev");
  73        return find_block_device_in_dir(&a);
  74}
  75