Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/name_to_dev.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (show annotations) (download)
Fri May 27 15:12:11 2011 UTC (13 years ago) by niro
File MIME type: text/plain
File size: 4545 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <sys/stat.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <alloca.h>
9 #include <inttypes.h>
10
11 #include "do_mounts.h"
12 #include "kinit.h"
13
14 #define BUF_SZ 65536
15
16 /* Find dev_t for e.g. "hda,NULL" or "hdb,2" */
17 static dev_t try_name(char *name, int part)
18 {
19 char path[BUF_SZ];
20 char buf[BUF_SZ];
21 int range;
22 unsigned int major_num, minor_num;
23 dev_t res;
24 char *s;
25 int len;
26 int fd;
27
28 /* read device number from /sys/block/.../dev */
29 snprintf(path, sizeof(path), "/sys/block/%s/dev", name);
30 fd = open(path, 0, 0);
31 if (fd < 0)
32 goto fail;
33 len = read(fd, buf, BUF_SZ);
34 close(fd);
35
36 if (len <= 0 || len == BUF_SZ || buf[len - 1] != '\n')
37 goto fail;
38 buf[len - 1] = '\0';
39 major_num = strtoul(buf, &s, 10);
40 if (*s != ':')
41 goto fail;
42 minor_num = strtoul(s + 1, &s, 10);
43 if (*s)
44 goto fail;
45 res = makedev(major_num, minor_num);
46
47 /* if it's there and we are not looking for a partition - that's it */
48 if (!part)
49 return res;
50
51 /* otherwise read range from .../range */
52 snprintf(path, sizeof(path), "/sys/block/%s/range", name);
53 fd = open(path, 0, 0);
54 if (fd < 0)
55 goto fail;
56 len = read(fd, buf, 32);
57 close(fd);
58 if (len <= 0 || len == 32 || buf[len - 1] != '\n')
59 goto fail;
60 buf[len - 1] = '\0';
61 range = strtoul(buf, &s, 10);
62 if (*s)
63 goto fail;
64
65 /* if partition is within range - we got it */
66 if (part < range) {
67 dprintf("kinit: try_name %s,%d = %s\n", name, part,
68 bdevname(res + part));
69 return res + part;
70 }
71
72 fail:
73 return (dev_t) 0;
74 }
75
76 /*
77 * Convert a name into device number. We accept the following variants:
78 *
79 * 1) device number in hexadecimal represents itself
80 * 2) device number in major:minor decimal represents itself
81 * 3) /dev/nfs represents Root_NFS
82 * 4) /dev/<disk_name> represents the device number of disk
83 * 5) /dev/<disk_name><decimal> represents the device number
84 * of partition - device number of disk plus the partition number
85 * 6) /dev/<disk_name>p<decimal> - same as the above, that form is
86 * used when disk name of partitioned disk ends on a digit.
87 * 7) an actual block device node in the initramfs filesystem
88 *
89 * If name doesn't have fall into the categories above, we return 0.
90 * Driverfs is used to check if something is a disk name - it has
91 * all known disks under bus/block/devices. If the disk name
92 * contains slashes, name of driverfs node has them replaced with
93 * dots. try_name() does the actual checks, assuming that driverfs
94 * is mounted on rootfs /sys.
95 */
96
97 static inline dev_t name_to_dev_t_real(const char *name)
98 {
99 char *p;
100 dev_t res = 0;
101 char *s;
102 int part;
103 struct stat st;
104 int len;
105 const char *devname;
106 char *cptr, *e1, *e2;
107 int major_num, minor_num;
108
109 /* Are we a multi root line? */
110 if (strchr(name, ','))
111 return Root_MULTI;
112
113 if (name[0] == '/') {
114 devname = name;
115 } else {
116 char *dname = alloca(strlen(name) + 6);
117 sprintf(dname, "/dev/%s", name);
118 devname = dname;
119 }
120
121 if (!stat(devname, &st) && S_ISBLK(st.st_mode))
122 return st.st_rdev;
123
124 if (strncmp(name, "/dev/", 5)) {
125 if ((cptr = strchr(devname+5, ':')) &&
126 cptr[1] != '\0') {
127 /* Colon-separated decimal device number */
128 *cptr = '\0';
129 major_num = strtoul(devname+5, &e1, 10);
130 minor_num = strtoul(cptr+1, &e2, 10);
131 if (!*e1 && !*e2)
132 return makedev(major_num, minor_num);
133 *cptr = ':';
134 } else {
135 /* Hexadecimal device number */
136 res = (dev_t) strtoul(name, &p, 16);
137 if (!*p)
138 return res;
139 }
140 } else {
141 name += 5;
142 }
143
144 if (!strcmp(name, "nfs"))
145 return Root_NFS;
146
147 if (!strcmp(name, "ram")) /* /dev/ram - historic alias for /dev/ram0 */
148 return Root_RAM0;
149
150 if (!strncmp(name, "mtd", 3))
151 return Root_MTD;
152
153 len = strlen(name);
154 s = alloca(len + 1);
155 memcpy(s, name, len + 1);
156
157 for (p = s; *p; p++)
158 if (*p == '/')
159 *p = '!';
160 res = try_name(s, 0);
161 if (res)
162 return res;
163
164 while (p > s && isdigit(p[-1]))
165 p--;
166 if (p == s || !*p || *p == '0')
167 goto fail;
168 part = strtoul(p, NULL, 10);
169 *p = '\0';
170 res = try_name(s, part);
171 if (res)
172 return res;
173
174 if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
175 goto fail;
176 p[-1] = '\0';
177 res = try_name(s, part);
178 return res;
179
180 fail:
181 return (dev_t) 0;
182 }
183
184 dev_t name_to_dev_t(const char *name)
185 {
186 dev_t dev = name_to_dev_t_real(name);
187
188 dprintf("kinit: name_to_dev_t(%s) = %s\n", name, bdevname(dev));
189 return dev;
190 }
191
192 #ifdef TEST_NAMETODEV /* Standalone test */
193
194 int main(int argc, char *argv[])
195 {
196 int i;
197
198 for (i = 1; i < argc; i++)
199 name_to_dev_t(argv[i]);
200
201 return 0;
202 }
203
204 #endif