]>
Commit | Line | Data |
---|---|---|
330345c2 MT |
1 | #include <stdlib.h> |
2 | #include <string.h> | |
3 | #include <unistd.h> | |
4 | #include <ctype.h> | |
5 | #include <stdio.h> | |
6 | #include <fcntl.h> | |
7 | ||
8 | static dev_t try_name(char *name, int part) | |
9 | { | |
10 | char path[64]; | |
11 | char buf[32]; | |
12 | int range; | |
13 | dev_t res; | |
14 | char *s; | |
15 | int len; | |
16 | int fd; | |
17 | unsigned int maj, min; | |
18 | ||
19 | /* read device number from .../dev */ | |
20 | ||
21 | sprintf(path, "/sys/block/%s/dev", name); | |
22 | fd = open(path, O_RDONLY); | |
23 | if (fd < 0) | |
24 | goto fail; | |
25 | len = read(fd, buf, 32); | |
26 | close(fd); | |
27 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | |
28 | goto fail; | |
29 | buf[len - 1] = '\0'; | |
30 | if (sscanf(buf, "%u:%u", &maj, &min) != 2) | |
31 | goto fail; | |
32 | res = makedev(maj, min); | |
33 | if (maj != major(res) || min != minor(res)) | |
34 | goto fail; | |
35 | ||
36 | /* if it's there and we are not looking for a partition - that's it */ | |
37 | if (!part) | |
38 | return res; | |
39 | ||
40 | /* otherwise read range from .../range */ | |
41 | snprintf(path, 64, "/sys/block/%s/range", name); | |
42 | fd = open(path, O_RDONLY); | |
43 | if (fd < 0) | |
44 | goto fail; | |
45 | len = read(fd, buf, 32); | |
46 | close(fd); | |
47 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | |
48 | goto fail; | |
49 | buf[len - 1] = '\0'; | |
50 | range = strtoul(buf, &s, 10); | |
51 | if (*s) | |
52 | goto fail; | |
53 | ||
54 | /* if partition is within range - we got it */ | |
55 | if (part < range) | |
56 | return res + part; | |
57 | fail: | |
58 | return 0; | |
59 | } | |
60 | ||
61 | /* | |
62 | * Convert a name into device number. We accept the following variants: | |
63 | * | |
64 | * 1) device number in hexadecimal represents itself | |
65 | * 2) /dev/nfs represents Root_NFS (0xff) | |
66 | * 3) /dev/<disk_name> represents the device number of disk | |
67 | * 4) /dev/<disk_name><decimal> represents the device number | |
68 | * of partition - device number of disk plus the partition number | |
69 | * 5) /dev/<disk_name>p<decimal> - same as the above, that form is | |
70 | * used when disk name of partitioned disk ends on a digit. | |
71 | * | |
72 | * If name doesn't have fall into the categories above, we return 0. | |
73 | * sysfs is used to check if something is a disk name - it has | |
74 | * all known disks under bus/block/devices. If the disk name | |
75 | * contains slashes, name of driverfs node has them replaced with | |
76 | * bangs. try_name() does the actual checks, assuming that sysfs | |
77 | * is mounted on /sys. | |
78 | * | |
79 | * Note that cases (1) and (2) are already handled by the kernel, | |
80 | * so we can ifdef them out, provided that we check real-root-dev | |
81 | * first. | |
82 | */ | |
83 | ||
84 | dev_t name_to_dev_t(char *name) | |
85 | { | |
86 | char s[32]; | |
87 | char *p; | |
88 | dev_t res = 0; | |
89 | int part; | |
90 | ||
91 | if (strncmp(name, "/dev/", 5) != 0) { | |
92 | #if 1 /* kernel used to do this */ | |
93 | unsigned maj, min; | |
94 | ||
95 | if (sscanf(name, "%u:%u", &maj, &min) == 2) { | |
96 | res = makedev(maj, min); | |
97 | if (maj != major(res) || min != minor(res)) | |
98 | return 0; | |
99 | } else { | |
100 | res = strtoul(name, &p, 16); | |
101 | if (*p) | |
102 | return 0; | |
103 | } | |
104 | #endif | |
105 | return res; | |
106 | } | |
107 | ||
108 | name += 5; | |
109 | ||
110 | #if 1 /* kernel used to do this */ | |
111 | if (strcmp(name, "nfs") == 0) | |
112 | return makedev(0, 255); | |
113 | #endif | |
114 | ||
115 | if (strlen(name) > 31) | |
116 | return 0; | |
117 | strcpy(s, name); | |
118 | for (p = s; *p; p++) | |
119 | if (*p == '/') | |
120 | *p = '!'; | |
121 | res = try_name(s, 0); | |
122 | if (res) | |
123 | return res; | |
124 | ||
125 | while (p > s && isdigit(p[-1])) | |
126 | p--; | |
127 | if (p == s || !*p || *p == '0') | |
128 | return 0; | |
129 | part = strtoul(p, NULL, 10); | |
130 | *p = '\0'; | |
131 | res = try_name(s, part); | |
132 | if (res) | |
133 | return res; | |
134 | ||
135 | if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') | |
136 | return 0; | |
137 | p[-1] = '\0'; | |
138 | return try_name(s, part); | |
139 | } |