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 |
|
---|
10 | #include "libbb.h"
|
---|
11 |
|
---|
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 */
|
---|
16 | enum { DEVNAME_MAX = 256 };
|
---|
17 | struct 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 |
|
---|
25 | static char *find_block_device_in_dir(struct arena *ap)
|
---|
26 | {
|
---|
27 | DIR *dir;
|
---|
28 | struct dirent *entry;
|
---|
29 | char *retpath = NULL;
|
---|
30 | int len, rem;
|
---|
31 |
|
---|
32 | dir = opendir(ap->devpath);
|
---|
33 | if (!dir)
|
---|
34 | return NULL;
|
---|
35 |
|
---|
36 | len = strlen(ap->devpath);
|
---|
37 | rem = DEVNAME_MAX-2 - len;
|
---|
38 | if (rem <= 0)
|
---|
39 | return NULL;
|
---|
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 |
|
---|
65 | char* 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 | }
|
---|