Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 4492 byte(s)
-updated to klibc-1.5.15
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 DEBUG(("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
111 if (name[0] == '/') {
112 devname = name;
113 } else {
114 char *dname = alloca(strlen(name) + 6);
115 sprintf(dname, "/dev/%s", name);
116 devname = dname;
117 }
118
119 if (!stat(devname, &st) && S_ISBLK(st.st_mode))
120 return st.st_rdev;
121
122 if (strncmp(name, "/dev/", 5)) {
123 if ((cptr = strchr(devname+5, ':')) &&
124 cptr[1] != '\0') {
125 /* Colon-separated decimal device number */
126 *cptr = '\0';
127 major_num = strtoul(devname+5, &e1, 10);
128 minor_num = strtoul(cptr+1, &e2, 10);
129 if (!*e1 && !*e2)
130 return makedev(major_num, minor_num);
131 *cptr = ':';
132 } else {
133 /* Hexadecimal device number */
134 res = (dev_t) strtoul(name, &p, 16);
135 if (!*p)
136 return res;
137 }
138 } else {
139 name += 5;
140 }
141
142 if (!strcmp(name, "nfs"))
143 return Root_NFS;
144
145 if (!strcmp(name, "ram")) /* /dev/ram - historic alias for /dev/ram0 */
146 return Root_RAM0;
147
148 if (!strncmp(name, "mtd", 3))
149 return Root_MTD;
150
151 len = strlen(name);
152 s = alloca(len + 1);
153 memcpy(s, name, len + 1);
154
155 for (p = s; *p; p++)
156 if (*p == '/')
157 *p = '!';
158 res = try_name(s, 0);
159 if (res)
160 return res;
161
162 while (p > s && isdigit(p[-1]))
163 p--;
164 if (p == s || !*p || *p == '0')
165 goto fail;
166 part = strtoul(p, NULL, 10);
167 *p = '\0';
168 res = try_name(s, part);
169 if (res)
170 return res;
171
172 if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
173 goto fail;
174 p[-1] = '\0';
175 res = try_name(s, part);
176 return res;
177
178 fail:
179 return (dev_t) 0;
180 }
181
182 dev_t name_to_dev_t(const char *name)
183 {
184 dev_t dev = name_to_dev_t_real(name);
185
186 DEBUG(("kinit: name_to_dev_t(%s) = %s\n", name, bdevname(dev)));
187 return dev;
188 }
189
190 #ifdef TEST_NAMETODEV /* Standalone test */
191
192 int main(int argc, char *argv[])
193 {
194 int i;
195
196 for (i = 1; i < argc; i++)
197 name_to_dev_t(argv[i]);
198
199 return 0;
200 }
201
202 #endif