1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include "toys.h"
33
34
35static void make_device(char *path)
36{
37 char *device_name = 0, *s, *temp;
38 int major = 0, minor = 0, type, len, fd, mode = 0660;
39 uid_t uid = 0;
40 gid_t gid = 0;
41
42 if (path) {
43
44
45 temp = strrchr(path, '/');
46 fd = open(path, O_RDONLY);
47 *temp = 0;
48 len = read(fd, toybuf, 64);
49 close(fd);
50 if (len<1) return;
51 toybuf[len] = 0;
52
53
54
55 type = path[5]=='c' ? S_IFCHR : S_IFBLK;
56 sscanf(toybuf, "%u:%u", &major, &minor);
57 } else {
58
59
60 if (!(temp = getenv("MODALIAS"))) xrun((char *[]){"modprobe", temp, 0});
61 if (!(temp = getenv("SUBSYSTEM"))) return;
62 type = strcmp(temp, "block") ? S_IFCHR : S_IFBLK;
63 if (!(temp = getenv("MAJOR"))) return;
64 sscanf(temp, "%u", &major);
65 if (!(temp = getenv("MINOR"))) return;
66 sscanf(temp, "%u", &minor);
67 if (!(path = getenv("DEVPATH"))) return;
68 device_name = getenv("DEVNAME");
69 }
70 if (!device_name)
71 device_name = strrchr(path, '/') + 1;
72
73
74 while ((temp = strchr(device_name, '!'))) {
75 *temp = '/';
76 }
77
78
79
80 if (CFG_MDEV_CONF) {
81 char *conf, *pos, *end;
82
83
84 if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {
85 int line = 0;
86
87 len = fdlength(fd);
88 conf = xmmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
89
90
91 for (pos = conf; pos-conf<len;) {
92 int field;
93 char *end2;
94
95 line++;
96
97 for(end = pos; end-conf<len && *end!='\n'; end++);
98
99
100 for (field = 3; field; field--) {
101
102 while (pos<end && isspace(*pos)) pos++;
103 if (pos==end || *pos=='#') break;
104 for (end2 = pos;
105 end2<end && !isspace(*end2) && *end2!='#'; end2++);
106 switch(field) {
107
108 case 3:
109 {
110 char *regex = strndup(pos, end2-pos);
111 regex_t match;
112 regmatch_t off;
113 int result;
114
115
116 xregcomp(&match, regex, REG_EXTENDED);
117 result=regexec(&match, device_name, 1, &off, 0);
118 regfree(&match);
119 free(regex);
120
121
122 if (result || off.rm_so
123 || off.rm_eo!=strlen(device_name))
124 goto end_line;
125
126 break;
127 }
128
129 case 2:
130 {
131 char *s2;
132
133
134 for(s = pos; s<end2 && *s!=':'; s++);
135 if (s==end2) goto end_line;
136
137
138 uid = strtoul(pos,&s2,10);
139 if (s!=s2) {
140 struct passwd *pass;
141 char *str = strndup(pos, s-pos);
142 pass = getpwnam(str);
143 free(str);
144 if (!pass) goto end_line;
145 uid = pass->pw_uid;
146 }
147 s++;
148
149 gid = strtoul(s,&s2,10);
150 if (end2!=s2) {
151 struct group *grp;
152 char *str = strndup(s, end2-s);
153 grp = getgrnam(str);
154 free(str);
155 if (!grp) goto end_line;
156 gid = grp->gr_gid;
157 }
158 break;
159 }
160
161 case 1:
162 {
163 mode = strtoul(pos, &pos, 8);
164 if (pos!=end2) goto end_line;
165 goto found_device;
166 }
167 }
168 pos=end2;
169 }
170end_line:
171
172 if (field && field!=3) error_exit("Bad line %d", line);
173
174
175 pos = ++end;
176 }
177found_device:
178 munmap(conf, len);
179 }
180 close(fd);
181 }
182
183 sprintf(toybuf, "/dev/%s", device_name);
184
185 if ((temp=getenv("ACTION")) && !strcmp(temp, "remove")) {
186 unlink(toybuf);
187 return;
188 }
189
190 if (strchr(device_name, '/'))
191 mkpathat(AT_FDCWD, toybuf, 0, 2);
192 if (mknod(toybuf, mode | type, dev_makedev(major, minor)) && errno != EEXIST)
193 perror_exit("mknod %s failed", toybuf);
194
195
196 if (type == S_IFBLK) close(open(toybuf, O_RDONLY));
197
198 if (CFG_MDEV_CONF) mode=chown(toybuf, uid, gid);
199}
200
201static int callback(struct dirtree *node)
202{
203
204
205 if(!strcmp(node->name, "block")) return 0;
206
207
208
209 if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) {
210 int len=4;
211 char *dev = dirtree_path(node, &len);
212 strcpy(dev+len, "/dev");
213 if (!access(dev, R_OK)) make_device(dev);
214 free(dev);
215 }
216
217
218
219
220 return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE;
221}
222
223void mdev_main(void)
224{
225
226
227 if (toys.optflags) {
228 dirtree_read("/sys/class", callback);
229 if (!access("/sys/block", R_OK)) dirtree_read("/sys/block", callback);
230 } else {
231 make_device(NULL);
232 }
233}
234