Magellan Linux

Contents of /tags/mkinitrd-6_2_0/nash/name_to_dev_t.c

Parent Directory Parent Directory | Revision Log Revision Log


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