]>
Commit | Line | Data |
---|---|---|
19feb351 GKH |
1 | /* |
2 | * namedev_parse.c | |
3 | * | |
4 | * Userspace devfs | |
5 | * | |
6 | * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> | |
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 | ||
24 | /* define this to enable parsing debugging */ | |
25 | /* #define DEBUG_PARSER */ | |
26 | ||
27 | #include <stddef.h> | |
28 | #include <stdlib.h> | |
29 | #include <string.h> | |
30 | #include <stdio.h> | |
31 | #include <fcntl.h> | |
32 | #include <ctype.h> | |
33 | #include <unistd.h> | |
34 | #include <errno.h> | |
35 | ||
36 | #include "udev.h" | |
37 | #include "namedev.h" | |
38 | ||
e8baccca | 39 | int get_pair(char **orig_string, char **left, char **right) |
19feb351 GKH |
40 | { |
41 | char *temp; | |
42 | char *string = *orig_string; | |
43 | ||
44 | if (!string) | |
45 | return -ENODEV; | |
46 | ||
47 | /* eat any whitespace */ | |
d94df232 | 48 | while (isspace(*string) || *string == ',') |
19feb351 GKH |
49 | ++string; |
50 | ||
51 | /* split based on '=' */ | |
52 | temp = strsep(&string, "="); | |
53 | *left = temp; | |
54 | if (!string) | |
55 | return -ENODEV; | |
56 | ||
57 | /* take the right side and strip off the '"' */ | |
58 | while (isspace(*string)) | |
59 | ++string; | |
60 | if (*string == '"') | |
61 | ++string; | |
62 | else | |
63 | return -ENODEV; | |
64 | ||
65 | temp = strsep(&string, "\""); | |
66 | if (!string || *temp == '\0') | |
67 | return -ENODEV; | |
68 | *right = temp; | |
69 | *orig_string = string; | |
70 | ||
71 | return 0; | |
72 | } | |
73 | ||
19feb351 GKH |
74 | void dump_config_dev(struct config_device *dev) |
75 | { | |
76 | switch (dev->type) { | |
77 | case KERNEL_NAME: | |
61219c75 | 78 | dbg_parse("KERNEL name='%s'", dev->name); |
19feb351 GKH |
79 | break; |
80 | case LABEL: | |
61219c75 GKH |
81 | dbg_parse("LABEL name='%s', bus='%s', sysfs_file='%s', sysfs_value='%s'", |
82 | dev->name, dev->bus, dev->sysfs_file, dev->sysfs_value); | |
19feb351 GKH |
83 | break; |
84 | case NUMBER: | |
61219c75 GKH |
85 | dbg_parse("NUMBER name='%s', bus='%s', id='%s'", |
86 | dev->name, dev->bus, dev->id); | |
19feb351 GKH |
87 | break; |
88 | case TOPOLOGY: | |
61219c75 GKH |
89 | dbg_parse("TOPOLOGY name='%s', bus='%s', place='%s'", |
90 | dev->name, dev->bus, dev->place); | |
19feb351 GKH |
91 | break; |
92 | case REPLACE: | |
61219c75 GKH |
93 | dbg_parse("REPLACE name=%s, kernel_name=%s", |
94 | dev->name, dev->kernel_name); | |
19feb351 GKH |
95 | break; |
96 | case CALLOUT: | |
61219c75 GKH |
97 | dbg_parse("CALLOUT name='%s', bus='%s', program='%s', id='%s'", |
98 | dev->name, dev->bus, dev->exec_program, dev->id); | |
19feb351 GKH |
99 | break; |
100 | default: | |
101 | dbg_parse("unknown type of method"); | |
102 | } | |
103 | } | |
104 | ||
105 | void dump_config_dev_list(void) | |
106 | { | |
107 | struct list_head *tmp; | |
108 | ||
109 | list_for_each(tmp, &config_device_list) { | |
110 | struct config_device *dev = list_entry(tmp, struct config_device, node); | |
111 | dump_config_dev(dev); | |
112 | } | |
113 | } | |
61219c75 GKH |
114 | |
115 | void dump_perm_dev(struct perm_device *dev) | |
116 | { | |
117 | dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", | |
118 | dev->name, dev->owner, dev->group, dev->mode); | |
119 | } | |
120 | ||
121 | void dump_perm_dev_list(void) | |
122 | { | |
123 | struct list_head *tmp; | |
124 | ||
125 | list_for_each(tmp, &perm_device_list) { | |
126 | struct perm_device *dev = list_entry(tmp, struct perm_device, node); | |
127 | dump_perm_dev(dev); | |
128 | } | |
129 | } | |
130 | ||
131 | ||
e8baccca | 132 | int namedev_init_rules(void) |
19feb351 GKH |
133 | { |
134 | char line[255]; | |
135 | int lineno; | |
136 | char *temp; | |
137 | char *temp2; | |
138 | char *temp3; | |
139 | FILE *fd; | |
140 | int retval = 0; | |
141 | struct config_device dev; | |
142 | ||
e8baccca GKH |
143 | fd = fopen(udev_rules_filename, "r"); |
144 | if (fd != NULL) { | |
145 | dbg("reading '%s' as rules file", udev_rules_filename); | |
146 | } else { | |
147 | dbg("can't open '%s' as a rules file", udev_rules_filename); | |
19feb351 GKH |
148 | return -ENODEV; |
149 | } | |
150 | ||
151 | /* loop through the whole file */ | |
152 | lineno = 0; | |
153 | while (1) { | |
154 | /* get a line */ | |
155 | temp = fgets(line, sizeof(line), fd); | |
156 | if (temp == NULL) | |
157 | goto exit; | |
158 | lineno++; | |
19feb351 GKH |
159 | dbg_parse("read '%s'", temp); |
160 | ||
19feb351 GKH |
161 | /* empty line? */ |
162 | if (*temp == 0x00) | |
163 | continue; | |
164 | ||
165 | /* see if this is a comment */ | |
166 | if (*temp == COMMENT_CHARACTER) | |
167 | continue; | |
168 | ||
d94df232 KS |
169 | /* eat the whitespace */ |
170 | while (isspace(*temp)) | |
171 | ++temp; | |
172 | ||
19feb351 GKH |
173 | memset(&dev, 0x00, sizeof(struct config_device)); |
174 | ||
d94df232 | 175 | /* get the method */ |
19feb351 | 176 | temp2 = strsep(&temp, ","); |
d94df232 | 177 | |
19feb351 | 178 | if (strcasecmp(temp2, TYPE_LABEL) == 0) { |
19feb351 | 179 | dev.type = LABEL; |
d94df232 | 180 | goto keys; |
19feb351 GKH |
181 | } |
182 | ||
183 | if (strcasecmp(temp2, TYPE_NUMBER) == 0) { | |
19feb351 | 184 | dev.type = NUMBER; |
d94df232 | 185 | goto keys; |
19feb351 GKH |
186 | } |
187 | ||
188 | if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) { | |
19feb351 | 189 | dev.type = TOPOLOGY; |
d94df232 | 190 | goto keys; |
19feb351 GKH |
191 | } |
192 | ||
193 | if (strcasecmp(temp2, TYPE_REPLACE) == 0) { | |
19feb351 | 194 | dev.type = REPLACE; |
d94df232 | 195 | goto keys; |
19feb351 | 196 | } |
3d150dfb | 197 | |
19feb351 | 198 | if (strcasecmp(temp2, TYPE_CALLOUT) == 0) { |
19feb351 | 199 | dev.type = CALLOUT; |
d94df232 KS |
200 | goto keys; |
201 | } | |
19feb351 | 202 | |
d94df232 KS |
203 | dbg_parse("unknown type of method '%s'", temp2); |
204 | goto error; | |
205 | keys: | |
206 | /* get all known keys */ | |
207 | while (1) { | |
208 | retval = get_pair(&temp, &temp2, &temp3); | |
19feb351 GKH |
209 | if (retval) |
210 | break; | |
3d150dfb | 211 | |
d94df232 KS |
212 | if (strcasecmp(temp2, FIELD_BUS) == 0) { |
213 | strfieldcpy(dev.bus, temp3); | |
214 | continue; | |
215 | } | |
216 | ||
217 | if (strcasecmp(temp2, FIELD_ID) == 0) { | |
218 | strfieldcpy(dev.id, temp3); | |
219 | continue; | |
220 | } | |
221 | ||
222 | if (strcasecmp(temp2, FIELD_PLACE) == 0) { | |
223 | strfieldcpy(dev.place, temp3); | |
224 | continue; | |
225 | } | |
226 | ||
227 | if (strncasecmp(temp2, FIELD_SYSFS, sizeof(FIELD_SYSFS)-1) == 0) { | |
228 | /* remove prepended 'SYSFS_' */ | |
229 | strfieldcpy(dev.sysfs_file, temp2 + sizeof(FIELD_SYSFS)-1); | |
230 | strfieldcpy(dev.sysfs_value, temp3); | |
231 | continue; | |
232 | } | |
233 | ||
234 | if (strcasecmp(temp2, FIELD_KERNEL) == 0) { | |
235 | strfieldcpy(dev.kernel_name, temp3); | |
236 | continue; | |
237 | } | |
238 | ||
239 | if (strcasecmp(temp2, FIELD_PROGRAM) == 0) { | |
240 | strfieldcpy(dev.exec_program, temp3); | |
241 | continue; | |
242 | } | |
243 | ||
244 | if (strcasecmp(temp2, FIELD_NAME) == 0) { | |
245 | strfieldcpy(dev.name, temp3); | |
246 | continue; | |
247 | } | |
248 | ||
249 | if (strcasecmp(temp2, FIELD_SYMLINK) == 0) { | |
3d150dfb | 250 | strfieldcpy(dev.symlink, temp3); |
d94df232 KS |
251 | continue; |
252 | } | |
3d150dfb | 253 | |
d94df232 KS |
254 | dbg_parse("unknown type of field '%s'", temp2); |
255 | } | |
256 | ||
257 | /* check presence of keys according to method type */ | |
258 | switch (dev.type) { | |
259 | case LABEL: | |
260 | dbg_parse("LABEL name='%s', bus='%s', " | |
261 | "sysfs_file='%s', sysfs_value='%s', symlink='%s'", | |
262 | dev.name, dev.bus, dev.sysfs_file, | |
263 | dev.sysfs_value, dev.symlink); | |
264 | if ((*dev.name == '\0') || | |
265 | (*dev.bus == '\0') || | |
266 | (*dev.sysfs_file == '\0') || | |
267 | (*dev.sysfs_value == '\0')) | |
268 | goto error; | |
269 | break; | |
270 | case NUMBER: | |
271 | dbg_parse("NUMBER name='%s', bus='%s', id='%s', symlink='%s'", | |
272 | dev.name, dev.bus, dev.id, dev.symlink); | |
273 | if ((*dev.name == '\0') || | |
274 | (*dev.bus == '\0') || | |
275 | (*dev.id == '\0')) | |
276 | goto error; | |
277 | break; | |
278 | case TOPOLOGY: | |
279 | dbg_parse("TOPOLOGY name='%s', bus='%s', " | |
280 | "place='%s', symlink='%s'", | |
281 | dev.name, dev.bus, dev.place, dev.symlink); | |
282 | if ((*dev.name == '\0') || | |
283 | (*dev.bus == '\0') || | |
284 | (*dev.place == '\0')) | |
285 | goto error; | |
286 | break; | |
287 | case REPLACE: | |
288 | dbg_parse("REPLACE name='%s', kernel_name='%s', symlink='%s'", | |
289 | dev.name, dev.kernel_name, dev.symlink); | |
290 | if ((*dev.name == '\0') || | |
291 | (*dev.kernel_name == '\0')) | |
292 | goto error; | |
293 | break; | |
294 | case CALLOUT: | |
3d150dfb KS |
295 | dbg_parse("CALLOUT name='%s', bus='%s', program='%s', " |
296 | "id='%s', symlink='%s'", | |
297 | dev.name, dev.bus, dev.exec_program, | |
298 | dev.id, dev.symlink); | |
d94df232 KS |
299 | if ((*dev.name == '\0') || |
300 | (*dev.bus == '\0') || | |
301 | (*dev.id == '\0') || | |
302 | (*dev.exec_program == '\0')) | |
303 | goto error; | |
304 | break; | |
305 | default: | |
306 | dbg_parse("xxx default method"); | |
307 | goto error; | |
19feb351 GKH |
308 | } |
309 | ||
310 | retval = add_config_dev(&dev); | |
311 | if (retval) { | |
312 | dbg("add_config_dev returned with error %d", retval); | |
d94df232 | 313 | continue; |
19feb351 GKH |
314 | } |
315 | } | |
d94df232 KS |
316 | error: |
317 | dbg_parse("%s:%d:%Zd: field missing or parse error", udev_rules_filename, | |
318 | lineno, temp - line); | |
19feb351 GKH |
319 | exit: |
320 | fclose(fd); | |
321 | return retval; | |
d94df232 | 322 | } |
19feb351 GKH |
323 | |
324 | int namedev_init_permissions(void) | |
325 | { | |
326 | char line[255]; | |
327 | char *temp; | |
328 | char *temp2; | |
329 | FILE *fd; | |
330 | int retval = 0; | |
61219c75 | 331 | struct perm_device dev; |
19feb351 | 332 | |
3836a3c4 | 333 | fd = fopen(udev_permissions_filename, "r"); |
e8baccca | 334 | if (fd != NULL) { |
3836a3c4 | 335 | dbg("reading '%s' as permissions file", udev_permissions_filename); |
e8baccca | 336 | } else { |
3836a3c4 | 337 | dbg("can't open '%s' as permissions file", udev_permissions_filename); |
19feb351 GKH |
338 | return -ENODEV; |
339 | } | |
340 | ||
341 | /* loop through the whole file */ | |
342 | while (1) { | |
343 | temp = fgets(line, sizeof(line), fd); | |
344 | if (temp == NULL) | |
345 | break; | |
346 | ||
347 | dbg_parse("read '%s'", temp); | |
348 | ||
349 | /* eat the whitespace at the beginning of the line */ | |
350 | while (isspace(*temp)) | |
351 | ++temp; | |
352 | ||
353 | /* empty line? */ | |
354 | if (*temp == 0x00) | |
355 | continue; | |
356 | ||
357 | /* see if this is a comment */ | |
358 | if (*temp == COMMENT_CHARACTER) | |
359 | continue; | |
360 | ||
361 | memset(&dev, 0x00, sizeof(dev)); | |
362 | ||
363 | /* parse the line */ | |
364 | temp2 = strsep(&temp, ":"); | |
365 | if (!temp2) { | |
366 | dbg("cannot parse line '%s'", line); | |
367 | continue; | |
368 | } | |
369 | strncpy(dev.name, temp2, sizeof(dev.name)); | |
370 | ||
371 | temp2 = strsep(&temp, ":"); | |
372 | if (!temp2) { | |
373 | dbg("cannot parse line '%s'", line); | |
374 | continue; | |
375 | } | |
376 | strncpy(dev.owner, temp2, sizeof(dev.owner)); | |
377 | ||
378 | temp2 = strsep(&temp, ":"); | |
379 | if (!temp2) { | |
380 | dbg("cannot parse line '%s'", line); | |
381 | continue; | |
382 | } | |
383 | strncpy(dev.group, temp2, sizeof(dev.owner)); | |
384 | ||
385 | if (!temp) { | |
386 | dbg("cannot parse line: %s", line); | |
387 | continue; | |
388 | } | |
389 | dev.mode = strtol(temp, NULL, 8); | |
390 | ||
391 | dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", | |
392 | dev.name, dev.owner, dev.group, | |
393 | dev.mode); | |
61219c75 | 394 | retval = add_perm_dev(&dev); |
19feb351 | 395 | if (retval) { |
3d150dfb | 396 | dbg("add_perm_dev returned with error %d", retval); |
19feb351 GKH |
397 | goto exit; |
398 | } | |
399 | } | |
400 | ||
401 | exit: | |
402 | fclose(fd); | |
403 | return retval; | |
404 | } | |
405 | ||
406 |