]>
Commit | Line | Data |
---|---|---|
19feb351 GKH |
1 | /* |
2 | * namedev_parse.c | |
3 | * | |
4 | * Userspace devfs | |
5 | * | |
274812b5 | 6 | * Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> |
19feb351 GKH |
7 | * |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation version 2 of the License. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
20 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | * | |
22 | */ | |
23 | ||
851cd18d GKH |
24 | #ifdef DEBUG |
25 | /* define this to enable parsing debugging also */ | |
19feb351 | 26 | /* #define DEBUG_PARSER */ |
851cd18d | 27 | #endif |
19feb351 GKH |
28 | |
29 | #include <stddef.h> | |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
32 | #include <stdio.h> | |
33 | #include <fcntl.h> | |
34 | #include <ctype.h> | |
35 | #include <unistd.h> | |
36 | #include <errno.h> | |
37 | ||
38 | #include "udev.h" | |
54988802 | 39 | #include "logging.h" |
19feb351 GKH |
40 | #include "namedev.h" |
41 | ||
a8b01705 GKH |
42 | static int add_config_dev(struct config_device *new_dev) |
43 | { | |
44 | struct config_device *tmp_dev; | |
45 | ||
46 | tmp_dev = malloc(sizeof(*tmp_dev)); | |
47 | if (tmp_dev == NULL) | |
48 | return -ENOMEM; | |
49 | memcpy(tmp_dev, new_dev, sizeof(*tmp_dev)); | |
50 | list_add_tail(&tmp_dev->node, &config_device_list); | |
51 | //dump_config_dev(tmp_dev); | |
52 | return 0; | |
53 | } | |
54 | ||
19feb351 GKH |
55 | void dump_config_dev(struct config_device *dev) |
56 | { | |
ac28b86d KS |
57 | /*FIXME dump all sysfs's */ |
58 | dbg_parse("name='%s', symlink='%s', bus='%s', place='%s', id='%s', " | |
59 | "sysfs_file[0]='%s', sysfs_value[0]='%s', " | |
60 | "kernel='%s', program='%s', result='%s'", | |
61 | dev->name, dev->symlink, dev->bus, dev->place, dev->id, | |
62 | dev->sysfs_pair[0].file, dev->sysfs_pair[0].value, | |
63 | dev->kernel, dev->program, dev->result); | |
19feb351 GKH |
64 | } |
65 | ||
66 | void dump_config_dev_list(void) | |
67 | { | |
843d1a84 | 68 | struct config_device *dev; |
19feb351 | 69 | |
843d1a84 | 70 | list_for_each_entry(dev, &config_device_list, node) |
19feb351 | 71 | dump_config_dev(dev); |
19feb351 | 72 | } |
61219c75 GKH |
73 | |
74 | void dump_perm_dev(struct perm_device *dev) | |
75 | { | |
76 | dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", | |
77 | dev->name, dev->owner, dev->group, dev->mode); | |
78 | } | |
79 | ||
80 | void dump_perm_dev_list(void) | |
81 | { | |
843d1a84 | 82 | struct perm_device *dev; |
61219c75 | 83 | |
843d1a84 | 84 | list_for_each_entry(dev, &perm_device_list, node) |
61219c75 | 85 | dump_perm_dev(dev); |
61219c75 GKH |
86 | } |
87 | ||
bb738647 KS |
88 | /* extract possible KEY{attr} or KEY_attr */ |
89 | static char *get_key_attribute(char *str) | |
90 | { | |
91 | char *pos; | |
92 | char *attr; | |
93 | ||
bb738647 KS |
94 | attr = strchr(str, '{'); |
95 | if (attr != NULL) { | |
96 | attr++; | |
97 | pos = strchr(attr, '}'); | |
98 | if (pos == NULL) { | |
99 | dbg("missing closing brace for format"); | |
100 | return NULL; | |
101 | } | |
102 | pos[0] = '\0'; | |
103 | dbg("attribute='%s'", attr); | |
104 | return attr; | |
105 | } | |
106 | ||
50e5de03 KS |
107 | attr = strchr(str, '_'); |
108 | if (attr != NULL) { | |
109 | attr++; | |
110 | dbg("attribute='%s'", attr); | |
111 | return attr; | |
112 | } | |
113 | ||
bb738647 KS |
114 | return NULL; |
115 | } | |
116 | ||
e8baccca | 117 | int namedev_init_rules(void) |
19feb351 GKH |
118 | { |
119 | char line[255]; | |
120 | int lineno; | |
121 | char *temp; | |
122 | char *temp2; | |
123 | char *temp3; | |
bb738647 | 124 | char *attr; |
19feb351 | 125 | FILE *fd; |
ac28b86d | 126 | int program_given = 0; |
19feb351 GKH |
127 | int retval = 0; |
128 | struct config_device dev; | |
129 | ||
e8baccca GKH |
130 | fd = fopen(udev_rules_filename, "r"); |
131 | if (fd != NULL) { | |
132 | dbg("reading '%s' as rules file", udev_rules_filename); | |
133 | } else { | |
134 | dbg("can't open '%s' as a rules file", udev_rules_filename); | |
19feb351 GKH |
135 | return -ENODEV; |
136 | } | |
137 | ||
138 | /* loop through the whole file */ | |
139 | lineno = 0; | |
140 | while (1) { | |
141 | /* get a line */ | |
142 | temp = fgets(line, sizeof(line), fd); | |
143 | if (temp == NULL) | |
144 | goto exit; | |
145 | lineno++; | |
19feb351 GKH |
146 | dbg_parse("read '%s'", temp); |
147 | ||
093bf8f4 RK |
148 | /* eat the whitespace */ |
149 | while (isspace(*temp)) | |
150 | ++temp; | |
151 | ||
19feb351 | 152 | /* empty line? */ |
e15b5ed5 | 153 | if ((*temp == '\0') || (*temp == '\n')) |
19feb351 GKH |
154 | continue; |
155 | ||
156 | /* see if this is a comment */ | |
157 | if (*temp == COMMENT_CHARACTER) | |
158 | continue; | |
159 | ||
160 | memset(&dev, 0x00, sizeof(struct config_device)); | |
161 | ||
d94df232 KS |
162 | /* get all known keys */ |
163 | while (1) { | |
274812b5 | 164 | retval = parse_get_pair(&temp, &temp2, &temp3); |
19feb351 GKH |
165 | if (retval) |
166 | break; | |
3d150dfb | 167 | |
d94df232 KS |
168 | if (strcasecmp(temp2, FIELD_BUS) == 0) { |
169 | strfieldcpy(dev.bus, temp3); | |
170 | continue; | |
171 | } | |
172 | ||
173 | if (strcasecmp(temp2, FIELD_ID) == 0) { | |
174 | strfieldcpy(dev.id, temp3); | |
175 | continue; | |
176 | } | |
177 | ||
178 | if (strcasecmp(temp2, FIELD_PLACE) == 0) { | |
179 | strfieldcpy(dev.place, temp3); | |
180 | continue; | |
181 | } | |
182 | ||
183 | if (strncasecmp(temp2, FIELD_SYSFS, sizeof(FIELD_SYSFS)-1) == 0) { | |
a8b01705 GKH |
184 | struct sysfs_pair *pair = &dev.sysfs_pair[0]; |
185 | int sysfs_pair_num = 0; | |
186 | ||
187 | /* find first unused pair */ | |
188 | while (pair->file[0] != '\0') { | |
189 | ++sysfs_pair_num; | |
190 | if (sysfs_pair_num >= MAX_SYSFS_PAIRS) { | |
191 | pair = NULL; | |
192 | break; | |
193 | } | |
194 | ++pair; | |
195 | } | |
196 | if (pair) { | |
bb738647 KS |
197 | attr = get_key_attribute(temp2 + sizeof(FIELD_SYSFS)-1); |
198 | if (attr == NULL) { | |
199 | dbg("error parsing " FIELD_SYSFS " attribute"); | |
200 | continue; | |
201 | } | |
202 | strfieldcpy(pair->file, attr); | |
a8b01705 GKH |
203 | strfieldcpy(pair->value, temp3); |
204 | } | |
d94df232 KS |
205 | continue; |
206 | } | |
207 | ||
208 | if (strcasecmp(temp2, FIELD_KERNEL) == 0) { | |
ac28b86d | 209 | strfieldcpy(dev.kernel, temp3); |
d94df232 KS |
210 | continue; |
211 | } | |
212 | ||
213 | if (strcasecmp(temp2, FIELD_PROGRAM) == 0) { | |
ac28b86d KS |
214 | program_given = 1; |
215 | strfieldcpy(dev.program, temp3); | |
216 | continue; | |
217 | } | |
218 | ||
219 | if (strcasecmp(temp2, FIELD_RESULT) == 0) { | |
220 | strfieldcpy(dev.result, temp3); | |
d94df232 KS |
221 | continue; |
222 | } | |
223 | ||
50e5de03 KS |
224 | if (strncasecmp(temp2, FIELD_NAME, sizeof(FIELD_NAME)-1) == 0) { |
225 | attr = get_key_attribute(temp2 + sizeof(FIELD_NAME)-1); | |
226 | if (attr != NULL) | |
227 | if (strcasecmp(attr, ATTR_PARTITIONS) == 0) { | |
228 | dbg_parse("creation of partition nodes requested"); | |
229 | dev.partitions = PARTITIONS_COUNT; | |
230 | } | |
d94df232 KS |
231 | strfieldcpy(dev.name, temp3); |
232 | continue; | |
233 | } | |
234 | ||
235 | if (strcasecmp(temp2, FIELD_SYMLINK) == 0) { | |
3d150dfb | 236 | strfieldcpy(dev.symlink, temp3); |
d94df232 KS |
237 | continue; |
238 | } | |
3d150dfb | 239 | |
851cd18d GKH |
240 | dbg("unknown type of field '%s'", temp2); |
241 | dbg("You might be using a rules file in the old format, please fix."); | |
242 | goto error; | |
d94df232 KS |
243 | } |
244 | ||
ac28b86d KS |
245 | /* simple plausibility check for given keys */ |
246 | if ((dev.sysfs_pair[0].file[0] == '\0') ^ | |
247 | (dev.sysfs_pair[0].value[0] == '\0')) { | |
bb738647 | 248 | dbg("inconsistency in " FIELD_SYSFS " key"); |
ac28b86d KS |
249 | goto error; |
250 | } | |
251 | ||
252 | if ((dev.result[0] != '\0') && (program_given == 0)) { | |
bb738647 KS |
253 | dbg(FIELD_RESULT " is only useful when " |
254 | FIELD_PROGRAM " is called in any rule before"); | |
d94df232 | 255 | goto error; |
19feb351 GKH |
256 | } |
257 | ||
54988802 | 258 | dev.config_line = lineno; |
19feb351 GKH |
259 | retval = add_config_dev(&dev); |
260 | if (retval) { | |
261 | dbg("add_config_dev returned with error %d", retval); | |
d94df232 | 262 | continue; |
ac28b86d | 263 | error: |
851cd18d | 264 | dbg("%s:%d:%d: parse error, rule skipped", |
ac28b86d | 265 | udev_rules_filename, lineno, temp - line); |
19feb351 GKH |
266 | } |
267 | } | |
19feb351 GKH |
268 | exit: |
269 | fclose(fd); | |
270 | return retval; | |
d94df232 | 271 | } |
19feb351 GKH |
272 | |
273 | int namedev_init_permissions(void) | |
274 | { | |
275 | char line[255]; | |
276 | char *temp; | |
277 | char *temp2; | |
278 | FILE *fd; | |
279 | int retval = 0; | |
61219c75 | 280 | struct perm_device dev; |
19feb351 | 281 | |
3836a3c4 | 282 | fd = fopen(udev_permissions_filename, "r"); |
e8baccca | 283 | if (fd != NULL) { |
3836a3c4 | 284 | dbg("reading '%s' as permissions file", udev_permissions_filename); |
e8baccca | 285 | } else { |
3836a3c4 | 286 | dbg("can't open '%s' as permissions file", udev_permissions_filename); |
19feb351 GKH |
287 | return -ENODEV; |
288 | } | |
289 | ||
290 | /* loop through the whole file */ | |
291 | while (1) { | |
292 | temp = fgets(line, sizeof(line), fd); | |
293 | if (temp == NULL) | |
294 | break; | |
295 | ||
296 | dbg_parse("read '%s'", temp); | |
297 | ||
298 | /* eat the whitespace at the beginning of the line */ | |
299 | while (isspace(*temp)) | |
300 | ++temp; | |
301 | ||
302 | /* empty line? */ | |
e15b5ed5 | 303 | if ((*temp == '\0') || (*temp == '\n')) |
19feb351 GKH |
304 | continue; |
305 | ||
306 | /* see if this is a comment */ | |
307 | if (*temp == COMMENT_CHARACTER) | |
308 | continue; | |
309 | ||
310 | memset(&dev, 0x00, sizeof(dev)); | |
311 | ||
312 | /* parse the line */ | |
313 | temp2 = strsep(&temp, ":"); | |
314 | if (!temp2) { | |
315 | dbg("cannot parse line '%s'", line); | |
316 | continue; | |
317 | } | |
318 | strncpy(dev.name, temp2, sizeof(dev.name)); | |
319 | ||
320 | temp2 = strsep(&temp, ":"); | |
321 | if (!temp2) { | |
322 | dbg("cannot parse line '%s'", line); | |
323 | continue; | |
324 | } | |
325 | strncpy(dev.owner, temp2, sizeof(dev.owner)); | |
326 | ||
327 | temp2 = strsep(&temp, ":"); | |
328 | if (!temp2) { | |
329 | dbg("cannot parse line '%s'", line); | |
330 | continue; | |
331 | } | |
eb7a964a | 332 | strncpy(dev.group, temp2, sizeof(dev.group)); |
19feb351 GKH |
333 | |
334 | if (!temp) { | |
335 | dbg("cannot parse line: %s", line); | |
336 | continue; | |
337 | } | |
338 | dev.mode = strtol(temp, NULL, 8); | |
339 | ||
340 | dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", | |
341 | dev.name, dev.owner, dev.group, | |
342 | dev.mode); | |
61219c75 | 343 | retval = add_perm_dev(&dev); |
19feb351 | 344 | if (retval) { |
3d150dfb | 345 | dbg("add_perm_dev returned with error %d", retval); |
19feb351 GKH |
346 | goto exit; |
347 | } | |
348 | } | |
349 | ||
350 | exit: | |
351 | fclose(fd); | |
352 | return retval; | |
267f534d | 353 | } |
19feb351 | 354 |