Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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