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 }