aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-06-26 14:11:33 +0000
committerRob Landley <rob@landley.net>2006-06-26 14:11:33 +0000
commitef10d52745a72f524e36edc375a6a05d3365ede4 (patch)
treebd1ee024e81262ec2485c4d5f391ef910d85bd38 /util-linux/mdev.c
parentcf7577d4171d517690e95e7225979bfde32fce7c (diff)
downloadbusybox-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.c186
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
31struct mdev_globals 20struct 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" */
39static void make_device(char *path) 28static 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 }
162end_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 }
170found_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);