aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-29 13:10:57 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-29 13:10:57 +0000
commit4461564c77260351fe3d82386eebf81085347b34 (patch)
tree6a7d926942063a825e6582dacbc586e28bbf3886 /util-linux/mdev.c
parent7cb808e1c5d6184dc3846f65344c7879f60de4f3 (diff)
downloadbusybox-w32-4461564c77260351fe3d82386eebf81085347b34.tar.gz
busybox-w32-4461564c77260351fe3d82386eebf81085347b34.tar.bz2
busybox-w32-4461564c77260351fe3d82386eebf81085347b34.zip
mdev: fix a bug where it was not stopping on first matching rule
(testsuite entry added). Revamped line parsing while at it. function old new delta next_field - 36 +36 make_device 1104 1022 -82 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 36/-82) Total: -46 bytes
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r--util-linux/mdev.c208
1 files changed, 99 insertions, 109 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index f86ce14ce..a2866054c 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -24,6 +24,16 @@ struct globals {
24/* We use additional 64+ bytes in make_device() */ 24/* We use additional 64+ bytes in make_device() */
25#define SCRATCH_SIZE 80 25#define SCRATCH_SIZE 80
26 26
27static char *next_field(char *s)
28{
29 char *end = skip_non_whitespace(s);
30 s = skip_whitespace(end);
31 *end = '\0';
32 if (*s == '\0')
33 s = NULL;
34 return s;
35}
36
27/* mknod in /dev based on a path like "/sys/block/hda/hda1" */ 37/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
28/* NB: "mdev -s" may call us many times, do not leak memory/fds! */ 38/* NB: "mdev -s" may call us many times, do not leak memory/fds! */
29static void make_device(char *path, int delete) 39static void make_device(char *path, int delete)
@@ -63,135 +73,115 @@ static void make_device(char *path, int delete)
63 73
64 if (ENABLE_FEATURE_MDEV_CONF) { 74 if (ENABLE_FEATURE_MDEV_CONF) {
65 FILE *fp; 75 FILE *fp;
66 char *line, *vline; 76 char *line, *val, *next;
67 unsigned lineno = 0; 77 unsigned lineno = 0;
68 78
69 /* If we have a config file, look up the user settings */ 79 /* If we have config file, look up user settings */
70 fp = fopen_or_warn("/etc/mdev.conf", "r"); 80 fp = fopen_or_warn("/etc/mdev.conf", "r");
71 if (!fp) 81 if (!fp)
72 goto end_parse; 82 goto end_parse;
73 83
74 while ((vline = line = xmalloc_fgetline(fp)) != NULL) { 84 while ((line = xmalloc_fgetline(fp)) != NULL) {
75 int field;
76 char *orig_line;
77
78 if (ENABLE_FEATURE_MDEV_EXEC)
79 orig_line = xstrdup(line); /* pristine copy for command execution. */
80
81 ++lineno; 85 ++lineno;
82 86 trim(line);
83// TODO: get rid of loop, 87 if (!line[0])
84// just linear skip_whitespace() style code will do! 88 goto next_line;
85// (will also get rid of orig_line).
86 89
87 /* Fields: regex uid:gid mode [alias] [cmd] */ 90 /* Fields: regex uid:gid mode [alias] [cmd] */
88 for (field = 0; field < (3 + ENABLE_FEATURE_MDEV_RENAME + ENABLE_FEATURE_MDEV_EXEC); ++field) {
89
90 /* Find a non-empty field */
91 char *val;
92 do {
93 val = strtok(vline, " \t");
94 vline = NULL;
95 } while (val && !*val);
96 if (!val) {
97 if (field)
98 break;
99 else
100 goto next_line;
101 }
102
103 if (field == 0) {
104
105 /* Regex to match this device */
106 regex_t match;
107 regmatch_t off;
108 int result;
109
110 /* Is this it? */
111 xregcomp(&match, val, REG_EXTENDED);
112 result = regexec(&match, device_name, 1, &off, 0);
113 regfree(&match);
114
115 /* If not this device, skip rest of line */
116 if (result || off.rm_so || off.rm_eo != strlen(device_name))
117 goto next_line;
118
119 } else if (field == 1) {
120
121 /* uid:gid device ownership */
122 struct passwd *pass;
123 struct group *grp;
124 91
125 char *str_uid = val; 92 /* 1st field: regex to match this device */
126 char *str_gid = strchrnul(val, ':'); 93 next = next_field(line);
127 if (*str_gid) 94 {
128 *str_gid++ = '\0'; 95 regex_t match;
129 96 regmatch_t off;
130 /* Parse UID */ 97 int result;
131 pass = getpwnam(str_uid); 98
132 if (pass) 99 /* Is this it? */
133 uid = pass->pw_uid; 100 xregcomp(&match, line, REG_EXTENDED);
134 else 101 result = regexec(&match, device_name, 1, &off, 0);
135 uid = strtoul(str_uid, NULL, 10); 102 regfree(&match);
136 103
137 /* Parse GID */ 104 /* If not this device, skip rest of line */
138 grp = getgrnam(str_gid); 105 if (result || off.rm_so || off.rm_eo != strlen(device_name))
139 if (grp) 106 goto next_line;
140 gid = grp->gr_gid; 107 }
141 else
142 gid = strtoul(str_gid, NULL, 10);
143
144 } else if (field == 2) {
145
146 /* Mode device permissions */
147 mode = strtoul(val, NULL, 8);
148 108
149 } else if (ENABLE_FEATURE_MDEV_RENAME && field == 3) { 109 /* This line matches: stop parsing the file
110 * after parsing the rest of fields */
150 111
151 if (*val != '>') 112 /* 2nd field: uid:gid - device ownership */
152 ++field; 113 if (!next) /* field must exist */
153 else { 114 bb_error_msg_and_die("bad line %u", lineno);
154 free(alias); /* don't leak in case we matched it on prev line */ 115 val = next;
155 alias = xstrdup(val + 1); 116 next = next_field(val);
156 } 117 {
118 struct passwd *pass;
119 struct group *grp;
120 char *str_uid = val;
121 char *str_gid = strchrnul(val, ':');
122
123 if (*str_gid)
124 *str_gid++ = '\0';
125 /* Parse UID */
126 pass = getpwnam(str_uid);
127 if (pass)
128 uid = pass->pw_uid;
129 else
130 uid = strtoul(str_uid, NULL, 10);
131 /* Parse GID */
132 grp = getgrnam(str_gid);
133 if (grp)
134 gid = grp->gr_gid;
135 else
136 gid = strtoul(str_gid, NULL, 10);
137 }
157 138
139 /* 3rd field: mode - device permissions */
140 if (!next) /* field must exist */
141 bb_error_msg_and_die("bad line %u", lineno);
142 val = next;
143 next = next_field(val);
144 mode = strtoul(val, NULL, 8);
145
146 /* 4th field (opt): >alias */
147 if (ENABLE_FEATURE_MDEV_RENAME) {
148 if (!next)
149 break;
150 val = next;
151 next = next_field(val);
152 if (*val == '>') {
153 alias = xstrdup(val + 1);
158 } 154 }
155 }
159 156
160 if (ENABLE_FEATURE_MDEV_EXEC && field == 3 + ENABLE_FEATURE_MDEV_RENAME) { 157 /* The rest (opt): command to run */
161 158 if (!next)
162 /* Optional command to run */ 159 break;
163 const char *s = "@$*"; 160 val = next;
164 const char *s2 = strchr(s, *val); 161 if (ENABLE_FEATURE_MDEV_EXEC) {
165 162 const char *s = "@$*";
166 if (!s2) { 163 const char *s2 = strchr(s, *val);
167 /* Force error */ 164
168 field = 1; 165 if (!s2)
169 break; 166 bb_error_msg_and_die("bad line %u", lineno);
170 } 167
171 168 /* Correlate the position in the "@$*" with the delete
172 /* Correlate the position in the "@$*" with the delete 169 * step so that we get the proper behavior:
173 * step so that we get the proper behavior: 170 * @cmd: run on create
174 * @cmd: run on create 171 * $cmd: run on delete
175 * $cmd: run on delete 172 * *cmd: run on both
176 * *cmd: run on both 173 */
177 */ 174 if ((s2 - s + 1) /*1/2/3*/ & /*1/2*/ (1 + delete)) {
178 if ((s2 - s + 1) /*1/2/3*/ & /*1/2*/ (1 + delete)) { 175 command = xstrdup(val + 1);
179 free(command); /* don't leak in case we matched it on prev line */
180 command = xstrdup(orig_line + (val + 1 - line));
181 }
182 } 176 }
183 } /* end of "for every field" */ 177 }
184 178 /* end of field parsing */
185 /* Did everything parse happily? */ 179 break; /* we found matching line, stop */
186 if (field <= 2)
187 bb_error_msg_and_die("bad line %u", lineno);
188
189 next_line: 180 next_line:
190 free(line); 181 free(line);
191 if (ENABLE_FEATURE_MDEV_EXEC)
192 free(orig_line);
193 } /* end of "while line is read from /etc/mdev.conf" */ 182 } /* end of "while line is read from /etc/mdev.conf" */
194 183
184 free(line); /* in case we used "break" to get here */
195 fclose(fp); 185 fclose(fp);
196 } 186 }
197 end_parse: 187 end_parse: