Mercurial > hg > toybox
comparison toys/pending/mdev.c @ 820:c4284bb4016c
Move mdev into the pending directory, since it's not done yet.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 16 Mar 2013 10:54:38 -0500 |
parents | toys/other/mdev.c@786841fdb1e0 |
children | 63db77909fc8 |
comparison
equal
deleted
inserted
replaced
819:547f6c1d6972 | 820:c4284bb4016c |
---|---|
1 /* mdev.c - Populate /dev directory and handle hotplug events | |
2 * | |
3 * Copyright 2005, 2008 Rob Landley <rob@landley.net> | |
4 * Copyright 2005 Frank Sorenson <frank@tuxrocks.com> | |
5 | |
6 USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK)) | |
7 | |
8 config MDEV | |
9 bool "mdev" | |
10 default n | |
11 help | |
12 usage: mdev [-s] | |
13 | |
14 Create devices in /dev using information from /sys. | |
15 | |
16 -s Scan all entries in /sys to populate /dev. | |
17 | |
18 config MDEV_CONF | |
19 bool "Configuration file for mdev" | |
20 default y | |
21 depends on MDEV | |
22 help | |
23 The mdev config file (/etc/mdev.conf) contains lines that look like: | |
24 hd[a-z][0-9]* 0:3 660 | |
25 | |
26 Each line must contain three whitespace separated fields. The first | |
27 field is a regular expression matching one or more device names, and | |
28 the second and third fields are uid:gid and file permissions for | |
29 matching devies. | |
30 */ | |
31 | |
32 #include "toys.h" | |
33 #include "lib/xregcomp.h" | |
34 | |
35 // todo, open() block devices to trigger partition scanning. | |
36 | |
37 // mknod in /dev based on a path like "/sys/block/hda/hda1" | |
38 static void make_device(char *path) | |
39 { | |
40 char *device_name, *s, *temp; | |
41 int major, minor, type, len, fd; | |
42 int mode = 0660; | |
43 uid_t uid = 0; | |
44 gid_t gid = 0; | |
45 | |
46 // Try to read major/minor string | |
47 | |
48 temp = strrchr(path, '/'); | |
49 fd = open(path, O_RDONLY); | |
50 *temp=0; | |
51 temp = toybuf; | |
52 len = read(fd, temp, 64); | |
53 close(fd); | |
54 if (len<1) return; | |
55 temp[len] = 0; | |
56 | |
57 // Determine device name, type, major and minor | |
58 | |
59 device_name = strrchr(path, '/') + 1; | |
60 type = path[5]=='c' ? S_IFCHR : S_IFBLK; | |
61 major = minor = 0; | |
62 sscanf(temp, "%u:%u", &major, &minor); | |
63 | |
64 // If we have a config file, look up permissions for this device | |
65 | |
66 if (CFG_MDEV_CONF) { | |
67 char *conf, *pos, *end; | |
68 | |
69 // mmap the config file | |
70 if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) { | |
71 len = fdlength(fd); | |
72 conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); | |
73 if (conf) { | |
74 int line = 0; | |
75 | |
76 // Loop through lines in mmaped file | |
77 for (pos = conf; pos-conf<len;) { | |
78 int field; | |
79 char *end2; | |
80 | |
81 line++; | |
82 // find end of this line | |
83 for(end = pos; end-conf<len && *end!='\n'; end++); | |
84 | |
85 // Three fields: regex, uid:gid, mode | |
86 for (field = 3; field; field--) { | |
87 // Skip whitespace | |
88 while (pos<end && isspace(*pos)) pos++; | |
89 if (pos==end || *pos=='#') break; | |
90 for (end2 = pos; | |
91 end2<end && !isspace(*end2) && *end2!='#'; end2++); | |
92 switch(field) { | |
93 // Regex to match this device | |
94 case 3: | |
95 { | |
96 char *regex = strndup(pos, end2-pos); | |
97 regex_t match; | |
98 regmatch_t off; | |
99 int result; | |
100 | |
101 // Is this it? | |
102 xregcomp(&match, regex, REG_EXTENDED); | |
103 result=regexec(&match, device_name, 1, &off, 0); | |
104 regfree(&match); | |
105 free(regex); | |
106 | |
107 // If not this device, skip rest of line | |
108 if (result || off.rm_so | |
109 || off.rm_eo!=strlen(device_name)) | |
110 goto end_line; | |
111 | |
112 break; | |
113 } | |
114 // uid:gid | |
115 case 2: | |
116 { | |
117 char *s2; | |
118 | |
119 // Find : | |
120 for(s = pos; s<end2 && *s!=':'; s++); | |
121 if (s==end2) goto end_line; | |
122 | |
123 // Parse UID | |
124 uid = strtoul(pos,&s2,10); | |
125 if (s!=s2) { | |
126 struct passwd *pass; | |
127 char *str = strndup(pos, s-pos); | |
128 pass = getpwnam(str); | |
129 free(str); | |
130 if (!pass) goto end_line; | |
131 uid = pass->pw_uid; | |
132 } | |
133 s++; | |
134 // parse GID | |
135 gid = strtoul(s,&s2,10); | |
136 if (end2!=s2) { | |
137 struct group *grp; | |
138 char *str = strndup(s, end2-s); | |
139 grp = getgrnam(str); | |
140 free(str); | |
141 if (!grp) goto end_line; | |
142 gid = grp->gr_gid; | |
143 } | |
144 break; | |
145 } | |
146 // mode | |
147 case 1: | |
148 { | |
149 mode = strtoul(pos, &pos, 8); | |
150 if (pos!=end2) goto end_line; | |
151 goto found_device; | |
152 } | |
153 } | |
154 pos=end2; | |
155 } | |
156 end_line: | |
157 // Did everything parse happily? | |
158 if (field && field!=3) error_exit("Bad line %d", line); | |
159 | |
160 // Next line | |
161 pos = ++end; | |
162 } | |
163 found_device: | |
164 munmap(conf, len); | |
165 } | |
166 close(fd); | |
167 } | |
168 } | |
169 | |
170 sprintf(temp, "/dev/%s", device_name); | |
171 if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) | |
172 perror_exit("mknod %s failed", temp); | |
173 | |
174 if (CFG_MDEV_CONF) mode=chown(temp, uid, gid); | |
175 } | |
176 | |
177 static int callback(struct dirtree *node) | |
178 { | |
179 // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll | |
180 // get block devices out of /sys/block.) | |
181 if(!strcmp(node->name, "block")) return 0; | |
182 | |
183 // Does this directory have a "dev" entry in it? | |
184 // This is path based because the hotplug callbacks are | |
185 if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) { | |
186 int len=4; | |
187 char *dev = dirtree_path(node, &len); | |
188 strcpy(dev+len, "/dev"); | |
189 if (!access(dev, R_OK)) make_device(dev); | |
190 free(dev); | |
191 } | |
192 | |
193 // Circa 2.6.25 the entries more than 2 deep are all either redundant | |
194 // (mouse#, event#) or unnamed (every usb_* entry is called "device"). | |
195 | |
196 return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE; | |
197 } | |
198 | |
199 void mdev_main(void) | |
200 { | |
201 // Handle -s | |
202 | |
203 if (toys.optflags) { | |
204 dirtree_read("/sys/class", callback); | |
205 dirtree_read("/sys/block", callback); | |
206 } | |
207 | |
208 // hotplug support goes here | |
209 } |