diff options
author | Rob Landley <rob@landley.net> | 2006-06-26 14:11:33 +0000 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2006-06-26 14:11:33 +0000 |
commit | ef10d52745a72f524e36edc375a6a05d3365ede4 (patch) | |
tree | bd1ee024e81262ec2485c4d5f391ef910d85bd38 /util-linux/mdev.c | |
parent | cf7577d4171d517690e95e7225979bfde32fce7c (diff) | |
download | busybox-w32-ef10d52745a72f524e36edc375a6a05d3365ede4.tar.gz busybox-w32-ef10d52745a72f524e36edc375a6a05d3365ede4.tar.bz2 busybox-w32-ef10d52745a72f524e36edc375a6a05d3365ede4.zip |
Upgrade mdev to allow commands to be run on create/delete.
Both Jason Schoon and Giuseppe Ciotta deserve credit for this, I used elements
of both. It's been upgraded so that you can specify that a given command
should run at create, at delete, or at both using different special characters
(@, $, and * respectively). It uses the system() method of running command
lines which means you can use environment variables on the command line (it
sets $MDEV to the name of the current device being created/deleted, which is
useful if you matched it via regex), and the documentation warns that you need
a /bin/sh to make that work, so you probably want to pick a default shell.
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r-- | util-linux/mdev.c | 186 |
1 files changed, 95 insertions, 91 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 73a82314c..3c7cf7bd1 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -8,25 +8,14 @@ | |||
8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include "busybox.h" | ||
11 | #include <ctype.h> | 12 | #include <ctype.h> |
12 | #include <dirent.h> | ||
13 | #include <errno.h> | 13 | #include <errno.h> |
14 | #include <fcntl.h> | ||
15 | #include <stdio.h> | ||
16 | #include <string.h> | ||
17 | #include <sys/mman.h> | 14 | #include <sys/mman.h> |
18 | #include <sys/stat.h> | ||
19 | #include <sys/sysmacros.h> | 15 | #include <sys/sysmacros.h> |
20 | #include <sys/types.h> | ||
21 | #include <unistd.h> | ||
22 | #include <stdlib.h> | ||
23 | #include "busybox.h" | ||
24 | #include "xregex.h" | 16 | #include "xregex.h" |
25 | 17 | ||
26 | #define DEV_PATH "/dev" | 18 | #define DEV_PATH "/dev" |
27 | #define MDEV_CONF "/etc/mdev.conf" | ||
28 | |||
29 | #include <busybox.h> | ||
30 | 19 | ||
31 | struct mdev_globals | 20 | struct mdev_globals |
32 | { | 21 | { |
@@ -36,14 +25,15 @@ struct mdev_globals | |||
36 | #define bbg mdev_globals | 25 | #define bbg mdev_globals |
37 | 26 | ||
38 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" */ | 27 | /* mknod in /dev based on a path like "/sys/block/hda/hda1" */ |
39 | static void make_device(char *path) | 28 | static void make_device(char *path, int delete) |
40 | { | 29 | { |
41 | char *device_name, *s; | 30 | char *device_name; |
42 | int major, minor, type, len, fd; | 31 | int major, minor, type, len, fd; |
43 | int mode = 0660; | 32 | int mode = 0660; |
44 | uid_t uid = 0; | 33 | uid_t uid = 0; |
45 | gid_t gid = 0; | 34 | gid_t gid = 0; |
46 | char *temp = path + strlen(path); | 35 | char *temp = path + strlen(path); |
36 | char *command = NULL; | ||
47 | 37 | ||
48 | /* Try to read major/minor string. Note that the kernel puts \n after | 38 | /* Try to read major/minor string. Note that the kernel puts \n after |
49 | * the data, so we don't need to worry about null terminating the string | 39 | * the data, so we don't need to worry about null terminating the string |
@@ -69,7 +59,7 @@ static void make_device(char *path) | |||
69 | char *conf, *pos, *end; | 59 | char *conf, *pos, *end; |
70 | 60 | ||
71 | /* mmap the config file */ | 61 | /* mmap the config file */ |
72 | if (-1 != (fd=open(MDEV_CONF,O_RDONLY))) { | 62 | if (-1 != (fd=open("/etc/mdev.conf",O_RDONLY))) { |
73 | len = lseek(fd, 0, SEEK_END); | 63 | len = lseek(fd, 0, SEEK_END); |
74 | conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); | 64 | conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); |
75 | if (conf) { | 65 | if (conf) { |
@@ -86,88 +76,89 @@ static void make_device(char *path) | |||
86 | ; | 76 | ; |
87 | 77 | ||
88 | /* Three fields: regex, uid:gid, mode */ | 78 | /* Three fields: regex, uid:gid, mode */ |
89 | for (field=3; field; field--) { | 79 | for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC); |
80 | field++) | ||
81 | { | ||
90 | /* Skip whitespace */ | 82 | /* Skip whitespace */ |
91 | while (pos<end && isspace(*pos)) | 83 | while (pos<end && isspace(*pos)) pos++; |
92 | pos++; | 84 | if (pos==end || *pos=='#') break; |
93 | if (pos==end || *pos=='#') | 85 | for (end2=pos; |
94 | break; | 86 | end2<end && !isspace(*end2) && *end2!='#'; end2++) |
95 | for (end2=pos; end2<end && !isspace(*end2) && *end2!='#'; end2++) | ||
96 | ; | 87 | ; |
97 | 88 | ||
98 | switch (field) { | 89 | if (!field) { |
99 | /* Regex to match this device */ | 90 | /* Regex to match this device */ |
100 | case 3: | ||
101 | { | ||
102 | char *regex = strndupa(pos,end2-pos); | ||
103 | regex_t match; | ||
104 | regmatch_t off; | ||
105 | int result; | ||
106 | |||
107 | /* Is this it? */ | ||
108 | xregcomp(&match,regex,REG_EXTENDED); | ||
109 | result = regexec(&match,device_name,1,&off,0); | ||
110 | regfree(&match); | ||
111 | |||
112 | /* If not this device, skip rest of line */ | ||
113 | if (result || off.rm_so || off.rm_eo!=strlen(device_name)) | ||
114 | goto end_line; | ||
115 | 91 | ||
92 | char *regex = strndupa(pos, end2-pos); | ||
93 | regex_t match; | ||
94 | regmatch_t off; | ||
95 | int result; | ||
96 | |||
97 | /* Is this it? */ | ||
98 | xregcomp(&match,regex, REG_EXTENDED); | ||
99 | result = regexec(&match, device_name, 1, &off, 0); | ||
100 | regfree(&match); | ||
101 | |||
102 | /* If not this device, skip rest of line */ | ||
103 | if (result || off.rm_so | ||
104 | || off.rm_eo != strlen(device_name)) | ||
116 | break; | 105 | break; |
117 | } | 106 | |
107 | } else if (field == 1) { | ||
118 | /* uid:gid */ | 108 | /* uid:gid */ |
119 | case 2: | 109 | |
120 | { | 110 | char *s, *s2; |
121 | char *s2; | 111 | |
122 | 112 | /* Find : */ | |
123 | /* Find : */ | 113 | for(s=pos; s<end2 && *s!=':'; s++) |
124 | for(s=pos; s<end2 && *s!=':'; s++) | 114 | ; |
125 | ; | 115 | if (s == end2) break; |
126 | if (s == end2) | 116 | |
127 | goto end_line; | 117 | /* Parse UID */ |
128 | 118 | uid = strtoul(pos,&s2,10); | |
129 | /* Parse UID */ | 119 | if (s != s2) { |
130 | uid = strtoul(pos,&s2,10); | 120 | struct passwd *pass; |
131 | if (s != s2) { | 121 | pass = getpwnam(strndupa(pos, s-pos)); |
132 | struct passwd *pass; | 122 | if (!pass) break; |
133 | pass = getpwnam(strndupa(pos,s-pos)); | 123 | uid = pass->pw_uid; |
134 | if (!pass) | 124 | } |
135 | goto end_line; | 125 | s++; |
136 | uid = pass->pw_uid; | 126 | /* parse GID */ |
137 | } | 127 | gid = strtoul(s, &s2, 10); |
138 | s++; | 128 | if (end2 != s2) { |
139 | /* parse GID */ | 129 | struct group *grp; |
140 | gid = strtoul(s,&s2,10); | 130 | grp = getgrnam(strndupa(s, end2-s)); |
141 | if (end2 != s2) { | 131 | if (!grp) break; |
142 | struct group *grp; | 132 | gid = grp->gr_gid; |
143 | grp = getgrnam(strndupa(s,end2-s)); | ||
144 | if (!grp) | ||
145 | goto end_line; | ||
146 | gid = grp->gr_gid; | ||
147 | } | ||
148 | break; | ||
149 | } | 133 | } |
134 | } else if (field == 2) { | ||
150 | /* mode */ | 135 | /* mode */ |
151 | case 1: | 136 | |
152 | { | 137 | mode = strtoul(pos, &pos, 8); |
153 | mode = strtoul(pos,&pos,8); | 138 | if (pos != end2) break; |
154 | if (pos != end2) | 139 | } else if (ENABLE_FEATURE_MDEV_EXEC && field == 3) { |
155 | goto end_line; | 140 | // Command to run |
156 | else | 141 | char *s = "@$*", *s2; |
157 | goto found_device; | 142 | if (!(s2 = strchr(s, *pos++))) { |
143 | // Force error | ||
144 | field = 1; | ||
145 | break; | ||
158 | } | 146 | } |
147 | if ((s2-s+1) & (1<<delete)) | ||
148 | command = bb_xstrndup(pos, end-pos); | ||
159 | } | 149 | } |
150 | |||
160 | pos = end2; | 151 | pos = end2; |
161 | } | 152 | } |
162 | end_line: | 153 | |
163 | /* Did everything parse happily? */ | 154 | /* Did everything parse happily? */ |
164 | if (field && field!=3) | 155 | |
165 | bb_error_msg_and_die("Bad line %d",line); | 156 | if (field > 2) break; |
157 | if (field) bb_error_msg_and_die("Bad line %d",line); | ||
166 | 158 | ||
167 | /* Next line */ | 159 | /* Next line */ |
168 | pos = ++end; | 160 | pos = ++end; |
169 | } | 161 | } |
170 | found_device: | ||
171 | munmap(conf, len); | 162 | munmap(conf, len); |
172 | } | 163 | } |
173 | close(fd); | 164 | close(fd); |
@@ -175,13 +166,29 @@ found_device: | |||
175 | } | 166 | } |
176 | 167 | ||
177 | umask(0); | 168 | umask(0); |
178 | if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) | 169 | if (!delete) { |
179 | bb_perror_msg_and_die("mknod %s failed", device_name); | 170 | if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) |
171 | bb_perror_msg_and_die("mknod %s failed", device_name); | ||
180 | 172 | ||
181 | if (major==bbg.root_major && minor==bbg.root_minor) | 173 | if (major == bbg.root_major && minor == bbg.root_minor) |
182 | symlink(device_name, "root"); | 174 | symlink(device_name, "root"); |
183 | 175 | ||
184 | if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); | 176 | if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); |
177 | } | ||
178 | if (command) { | ||
179 | int rc; | ||
180 | char *s; | ||
181 | |||
182 | s=bb_xasprintf("MDEV=%s",device_name); | ||
183 | putenv(s); | ||
184 | rc = system(command); | ||
185 | s[4]=0; | ||
186 | putenv(s); | ||
187 | free(s); | ||
188 | free(command); | ||
189 | if (rc == -1) bb_perror_msg_and_die("Couldn't run %s", command); | ||
190 | } | ||
191 | if (delete) unlink(device_name); | ||
185 | } | 192 | } |
186 | 193 | ||
187 | /* Recursive search of /sys/block or /sys/class. path must be a writeable | 194 | /* Recursive search of /sys/block or /sys/class. path must be a writeable |
@@ -212,7 +219,7 @@ static void find_dev(char *path) | |||
212 | 219 | ||
213 | /* If there's a dev entry, mknod it */ | 220 | /* If there's a dev entry, mknod it */ |
214 | 221 | ||
215 | if (!strcmp(entry->d_name, "dev")) make_device(path); | 222 | if (!strcmp(entry->d_name, "dev")) make_device(path, 0); |
216 | } | 223 | } |
217 | 224 | ||
218 | closedir(dir); | 225 | closedir(dir); |
@@ -247,12 +254,9 @@ int mdev_main(int argc, char *argv[]) | |||
247 | if (!action || !env_path) | 254 | if (!action || !env_path) |
248 | bb_show_usage(); | 255 | bb_show_usage(); |
249 | 256 | ||
250 | if (!strcmp(action, "add")) { | 257 | sprintf(temp, "/sys%s", env_path); |
251 | sprintf(temp, "/sys%s", env_path); | 258 | if (!strcmp(action, "add")) make_device(temp,0); |
252 | make_device(temp); | 259 | else if (!strcmp(action, "remove")) make_device(temp,1); |
253 | } else if (!strcmp(action, "remove")) { | ||
254 | unlink(strrchr(env_path, '/') + 1); | ||
255 | } | ||
256 | } | 260 | } |
257 | 261 | ||
258 | if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp); | 262 | if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp); |