aboutsummaryrefslogtreecommitdiff
path: root/libbb/find_root_device.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-13 23:59:52 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-13 23:59:52 +0000
commit16abcd90aefae8bdb9f7d80a555982dba6ca59b5 (patch)
treeb7e23fd3c844849d188813323076c93105a57d4d /libbb/find_root_device.c
parent334fa9bcb50df9a03288be252096750dcec14404 (diff)
downloadbusybox-w32-16abcd90aefae8bdb9f7d80a555982dba6ca59b5.tar.gz
busybox-w32-16abcd90aefae8bdb9f7d80a555982dba6ca59b5.tar.bz2
busybox-w32-16abcd90aefae8bdb9f7d80a555982dba6ca59b5.zip
teach find_root_device to deal with /dev/ subdirs
(by "Kirill K. Smirnov" <lich@math.spbu.ru>)
Diffstat (limited to 'libbb/find_root_device.c')
-rw-r--r--libbb/find_root_device.c59
1 files changed, 49 insertions, 10 deletions
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
index ea360eae5..7182102c7 100644
--- a/libbb/find_root_device.c
+++ b/libbb/find_root_device.c
@@ -9,26 +9,65 @@
9 9
10#include "libbb.h" 10#include "libbb.h"
11 11
12char *find_block_device(const char *path) 12/* Find block device /dev/XXX which contains specified file
13 * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */
14
15/* Do not reallocate all this stuff on each recursion */
16enum { DEVNAME_MAX = 256 };
17struct arena {
18 struct stat st;
19 dev_t dev;
20 /* Was PATH_MAX, but we recurse _/dev_. We can assume
21 * people are not crazy enough to have mega-deep tree there */
22 char devpath[DEVNAME_MAX];
23};
24
25static char *find_block_device_in_dir(struct arena *ap)
13{ 26{
14 DIR *dir; 27 DIR *dir;
15 struct dirent *entry; 28 struct dirent *entry;
16 struct stat st; 29 char *retpath = NULL;
17 dev_t dev; 30 int len, rem;
18 char *retpath=NULL; 31
32 dir = opendir(ap->devpath);
33 if (!dir)
34 return NULL;
19 35
20 if (stat(path, &st) || !(dir = opendir("/dev"))) 36 len = strlen(ap->devpath);
37 rem = DEVNAME_MAX-2 - len;
38 if (rem <= 0)
21 return NULL; 39 return NULL;
22 dev = (st.st_mode & S_IFMT) == S_IFBLK ? st.st_rdev : st.st_dev; 40 ap->devpath[len++] = '/';
41
23 while ((entry = readdir(dir)) != NULL) { 42 while ((entry = readdir(dir)) != NULL) {
24 char devpath[PATH_MAX]; 43 safe_strncpy(ap->devpath + len, entry->d_name, rem);
25 sprintf(devpath,"/dev/%s", entry->d_name); 44 if (stat(ap->devpath, &ap->st) != 0)
26 if (!stat(devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) { 45 continue;
27 retpath = xstrdup(devpath); 46 if (S_ISBLK(ap->st.st_mode) && ap->st.st_rdev == ap->dev) {
47 retpath = xstrdup(ap->devpath);
28 break; 48 break;
29 } 49 }
50 if (S_ISDIR(ap->st.st_mode)) {
51 /* Do not recurse for '.' and '..' */
52 if (DOT_OR_DOTDOT(entry->d_name))
53 continue;
54 retpath = find_block_device_in_dir(ap);
55 if (retpath)
56 break;
57 }
30 } 58 }
31 closedir(dir); 59 closedir(dir);
32 60
33 return retpath; 61 return retpath;
34} 62}
63
64char *find_block_device(const char *path)
65{
66 struct arena a;
67
68 if (stat(path, &a.st) != 0)
69 return NULL;
70 a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev;
71 strcpy(a.devpath, "/dev");
72 return find_block_device_in_dir(&a);
73}