]>
Commit | Line | Data |
---|---|---|
2232cac8 GKH |
1 | /* |
2 | * namedev.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 | #include <stddef.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | #include <stdio.h> | |
28 | #include <fcntl.h> | |
29 | #include <ctype.h> | |
30 | #include <unistd.h> | |
31 | #include <errno.h> | |
32 | ||
33 | #include "list.h" | |
34 | #include "udev.h" | |
35 | #include "udev_version.h" | |
36 | #include "namedev.h" | |
37 | ||
38 | #define TYPE_LABEL "LABEL" | |
39 | #define TYPE_NUMBER "NUMBER" | |
40 | #define TYPE_TOPOLOGY "TOPOLOGY" | |
41 | #define TYPE_REPLACE "REPLACE" | |
42 | ||
43 | enum config_type { | |
44 | KERNEL_NAME = 0, /* must be 0 to let memset() default to this value */ | |
45 | LABEL = 1, | |
46 | NUMBER = 2, | |
47 | TOPOLOGY = 3, | |
48 | REPLACE = 4, | |
49 | }; | |
50 | ||
51 | #define BUS_SIZE 30 | |
52 | #define FILE_SIZE 50 | |
53 | #define VALUE_SIZE 100 | |
54 | #define ID_SIZE 50 | |
55 | #define PLACE_SIZE 50 | |
56 | #define NAME_SIZE 100 | |
57 | #define OWNER_SIZE 30 | |
58 | #define GROUP_SIZE 30 | |
59 | ||
60 | ||
61 | struct config_device { | |
62 | struct list_head node; | |
63 | ||
64 | enum config_type type; | |
65 | ||
66 | char bus[BUS_SIZE]; | |
67 | char sysfs_file[FILE_SIZE]; | |
68 | char sysfs_value[VALUE_SIZE]; | |
69 | char id[ID_SIZE]; | |
70 | char place[PLACE_SIZE]; | |
71 | char kernel_name[NAME_SIZE]; | |
72 | ||
73 | /* what to set the device to */ | |
74 | int mode; | |
75 | char name[NAME_SIZE]; | |
76 | char owner[OWNER_SIZE]; | |
77 | char group[GROUP_SIZE]; | |
78 | }; | |
79 | ||
80 | ||
81 | static LIST_HEAD(config_device_list); | |
82 | ||
469c7cff GKH |
83 | static void dump_dev(struct config_device *dev) |
84 | { | |
85 | switch (dev->type) { | |
86 | case KERNEL_NAME: | |
87 | dbg("KERNEL name ='%s'" | |
88 | " owner = '%s', group = '%s', mode = '%d'", | |
89 | dev->name, | |
90 | dev->owner, dev->group, dev->mode); | |
91 | break; | |
92 | case LABEL: | |
93 | dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'" | |
94 | " owner = '%s', group = '%s', mode = '%d'", | |
95 | dev->name, dev->bus, dev->sysfs_file, dev->sysfs_value, | |
96 | dev->owner, dev->group, dev->mode); | |
97 | break; | |
98 | case NUMBER: | |
99 | dbg("NUMBER name = '%s', bus = '%s', id = '%s'" | |
100 | " owner = '%s', group = '%s', mode = '%d'", | |
101 | dev->name, dev->bus, dev->id, | |
102 | dev->owner, dev->group, dev->mode); | |
103 | break; | |
104 | case TOPOLOGY: | |
105 | dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'" | |
106 | " owner = '%s', group = '%s', mode = '%d'", | |
107 | dev->name, dev->bus, dev->place, | |
108 | dev->owner, dev->group, dev->mode); | |
109 | break; | |
110 | case REPLACE: | |
111 | dbg("REPLACE name = %s, kernel_name = %s" | |
112 | " owner = '%s', group = '%s', mode = '%d'", | |
113 | dev->name, dev->kernel_name, | |
114 | dev->owner, dev->group, dev->mode); | |
115 | break; | |
116 | default: | |
117 | dbg("Unknown type of device!"); | |
118 | } | |
119 | } | |
120 | ||
2232cac8 GKH |
121 | #define copy_var(a, b, var) \ |
122 | if (b->var) \ | |
469c7cff | 123 | a->var = b->var; |
2232cac8 GKH |
124 | |
125 | #define copy_string(a, b, var) \ | |
126 | if (strlen(b->var)) \ | |
469c7cff | 127 | strcpy(a->var, b->var); |
2232cac8 GKH |
128 | |
129 | static int add_dev(struct config_device *new_dev) | |
130 | { | |
131 | struct list_head *tmp; | |
132 | struct config_device *tmp_dev; | |
133 | ||
134 | /* loop through the whole list of devices to see if we already have | |
135 | * this one... */ | |
136 | list_for_each(tmp, &config_device_list) { | |
137 | struct config_device *dev = list_entry(tmp, struct config_device, node); | |
138 | if (strcmp(dev->name, new_dev->name) == 0) { | |
139 | /* the same, copy the new info into this structure */ | |
469c7cff GKH |
140 | copy_var(dev, new_dev, type); |
141 | copy_var(dev, new_dev, mode); | |
142 | copy_string(dev, new_dev, bus); | |
143 | copy_string(dev, new_dev, sysfs_file); | |
144 | copy_string(dev, new_dev, sysfs_value); | |
145 | copy_string(dev, new_dev, id); | |
146 | copy_string(dev, new_dev, place); | |
147 | copy_string(dev, new_dev, kernel_name); | |
148 | copy_string(dev, new_dev, owner); | |
149 | copy_string(dev, new_dev, group); | |
2232cac8 GKH |
150 | return 0; |
151 | } | |
152 | } | |
153 | ||
154 | /* not found, lets create a new structure, and add it to the list */ | |
155 | tmp_dev = malloc(sizeof(*tmp_dev)); | |
156 | if (!tmp_dev) | |
157 | return -ENOMEM; | |
158 | memcpy(tmp_dev, new_dev, sizeof(*tmp_dev)); | |
159 | list_add(&tmp_dev->node, &config_device_list); | |
469c7cff | 160 | //dump_dev(tmp_dev); |
2232cac8 GKH |
161 | return 0; |
162 | } | |
163 | ||
469c7cff GKH |
164 | static void dump_dev_list(void) |
165 | { | |
166 | struct list_head *tmp; | |
167 | ||
168 | list_for_each(tmp, &config_device_list) { | |
169 | struct config_device *dev = list_entry(tmp, struct config_device, node); | |
170 | dump_dev(dev); | |
171 | } | |
172 | } | |
173 | ||
2232cac8 GKH |
174 | static int get_value(const char *left, char **orig_string, char **ret_string) |
175 | { | |
176 | char *temp; | |
177 | char *string = *orig_string; | |
178 | ||
179 | /* eat any whitespace */ | |
180 | while (isspace(*string)) | |
181 | ++string; | |
182 | ||
183 | /* split based on '=' */ | |
184 | temp = strsep(&string, "="); | |
185 | if (strcasecmp(temp, left) == 0) { | |
186 | /* got it, now strip off the '"' */ | |
187 | while (isspace(*string)) | |
188 | ++string; | |
189 | if (*string == '"') | |
190 | ++string; | |
191 | temp = strsep(&string, "\""); | |
192 | *ret_string = temp; | |
193 | *orig_string = string; | |
194 | return 0; | |
195 | } | |
196 | return -ENODEV; | |
197 | } | |
198 | ||
469c7cff GKH |
199 | static int get_pair(char **orig_string, char **left, char **right) |
200 | { | |
201 | char *temp; | |
202 | char *string = *orig_string; | |
203 | ||
204 | /* eat any whitespace */ | |
205 | while (isspace(*string)) | |
206 | ++string; | |
207 | ||
208 | /* split based on '=' */ | |
209 | temp = strsep(&string, "="); | |
210 | *left = temp; | |
211 | ||
212 | /* take the right side and strip off the '"' */ | |
213 | while (isspace(*string)) | |
214 | ++string; | |
215 | if (*string == '"') | |
216 | ++string; | |
217 | temp = strsep(&string, "\""); | |
218 | *right = temp; | |
219 | *orig_string = string; | |
220 | ||
221 | return 0; | |
222 | } | |
2232cac8 GKH |
223 | |
224 | static int namedev_init_config(void) | |
225 | { | |
226 | char filename[255]; | |
227 | char line[255]; | |
228 | char *temp; | |
229 | char *temp2; | |
230 | char *temp3; | |
231 | FILE *fd; | |
232 | int retval = 0; | |
233 | struct config_device dev; | |
234 | ||
235 | strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_FILE); | |
236 | dbg("opening %s to read as permissions config", filename); | |
237 | fd = fopen(filename, "r"); | |
238 | if (fd == NULL) { | |
239 | dbg("Can't open %s", filename); | |
240 | return -ENODEV; | |
241 | } | |
242 | ||
243 | /* loop through the whole file */ | |
244 | while (1) { | |
245 | /* get a line */ | |
246 | temp = fgets(line, sizeof(line), fd); | |
247 | if (temp == NULL) | |
248 | break; | |
249 | ||
250 | dbg("read %s", temp); | |
251 | ||
252 | /* eat the whitespace at the beginning of the line */ | |
253 | while (isspace(*temp)) | |
254 | ++temp; | |
255 | ||
256 | /* no more line? */ | |
257 | if (*temp == 0x00) | |
258 | continue; | |
259 | ||
260 | /* see if this is a comment */ | |
261 | if (*temp == COMMENT_CHARACTER) | |
262 | continue; | |
263 | ||
469c7cff | 264 | memset(&dev, 0x00, sizeof(struct config_device)); |
2232cac8 GKH |
265 | |
266 | /* parse the line */ | |
267 | temp2 = strsep(&temp, ","); | |
268 | if (strcasecmp(temp2, TYPE_LABEL) == 0) { | |
269 | /* label type */ | |
270 | dev.type = LABEL; | |
271 | ||
272 | /* BUS="bus" */ | |
273 | retval = get_value("BUS", &temp, &temp3); | |
274 | if (retval) | |
275 | continue; | |
276 | strcpy(dev.bus, temp3); | |
469c7cff GKH |
277 | |
278 | /* file="value" */ | |
279 | temp2 = strsep(&temp, ","); | |
280 | retval = get_pair(&temp, &temp2, &temp3); | |
281 | if (retval) | |
282 | continue; | |
283 | strcpy(dev.sysfs_file, temp2); | |
284 | strcpy(dev.sysfs_value, temp3); | |
285 | ||
286 | /* NAME="new_name" */ | |
287 | temp2 = strsep(&temp, ","); | |
288 | retval = get_value("NAME", &temp, &temp3); | |
289 | if (retval) | |
290 | continue; | |
291 | strcpy(dev.name, temp3); | |
292 | ||
293 | dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'", dev.name, dev.bus, dev.sysfs_file, dev.sysfs_value); | |
2232cac8 GKH |
294 | } |
295 | ||
296 | if (strcasecmp(temp2, TYPE_NUMBER) == 0) { | |
297 | /* number type */ | |
298 | dev.type = NUMBER; | |
299 | ||
300 | /* BUS="bus" */ | |
301 | retval = get_value("BUS", &temp, &temp3); | |
302 | if (retval) | |
303 | continue; | |
304 | strcpy(dev.bus, temp3); | |
469c7cff GKH |
305 | |
306 | /* ID="id" */ | |
307 | temp2 = strsep(&temp, ","); | |
308 | retval = get_value("id", &temp, &temp3); | |
309 | if (retval) | |
310 | continue; | |
311 | strcpy(dev.id, temp3); | |
312 | ||
313 | /* NAME="new_name" */ | |
314 | temp2 = strsep(&temp, ","); | |
315 | retval = get_value("NAME", &temp, &temp3); | |
316 | if (retval) | |
317 | continue; | |
318 | strcpy(dev.name, temp3); | |
319 | ||
320 | dbg("NUMBER name = '%s', bus = '%s', id = '%s'", dev.name, dev.bus, dev.id); | |
2232cac8 GKH |
321 | } |
322 | ||
323 | if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) { | |
324 | /* number type */ | |
325 | dev.type = TOPOLOGY; | |
326 | ||
327 | /* BUS="bus" */ | |
328 | retval = get_value("BUS", &temp, &temp3); | |
329 | if (retval) | |
330 | continue; | |
331 | strcpy(dev.bus, temp3); | |
469c7cff GKH |
332 | |
333 | /* PLACE="place" */ | |
334 | temp2 = strsep(&temp, ","); | |
335 | retval = get_value("place", &temp, &temp3); | |
336 | if (retval) | |
337 | continue; | |
338 | strcpy(dev.place, temp3); | |
339 | ||
340 | /* NAME="new_name" */ | |
341 | temp2 = strsep(&temp, ","); | |
342 | retval = get_value("NAME", &temp, &temp3); | |
343 | if (retval) | |
344 | continue; | |
345 | strcpy(dev.name, temp3); | |
346 | ||
347 | dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'", dev.name, dev.bus, dev.place); | |
2232cac8 GKH |
348 | } |
349 | ||
350 | if (strcasecmp(temp2, TYPE_REPLACE) == 0) { | |
351 | /* number type */ | |
352 | dev.type = REPLACE; | |
353 | ||
354 | /* KERNEL="kernel_name" */ | |
355 | retval = get_value("KERNEL", &temp, &temp3); | |
356 | if (retval) | |
357 | continue; | |
358 | strcpy(dev.kernel_name, temp3); | |
359 | ||
360 | /* NAME="new_name" */ | |
361 | temp2 = strsep(&temp, ","); | |
362 | retval = get_value("NAME", &temp, &temp3); | |
363 | if (retval) | |
364 | continue; | |
365 | strcpy(dev.name, temp3); | |
366 | dbg("REPLACE name = %s, kernel_name = %s", dev.name, dev.kernel_name); | |
367 | } | |
368 | ||
369 | retval = add_dev(&dev); | |
370 | if (retval) { | |
371 | dbg("add_dev returned with error %d", retval); | |
372 | goto exit; | |
373 | } | |
374 | } | |
375 | ||
376 | exit: | |
377 | fclose(fd); | |
378 | return retval; | |
379 | } | |
380 | ||
381 | ||
382 | static int namedev_init_permissions(void) | |
383 | { | |
384 | char filename[255]; | |
385 | char line[255]; | |
386 | char *temp; | |
387 | char *temp2; | |
388 | FILE *fd; | |
389 | int retval = 0; | |
390 | struct config_device dev; | |
391 | ||
392 | strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_PERMISSION_FILE); | |
393 | dbg("opening %s to read as permissions config", filename); | |
394 | fd = fopen(filename, "r"); | |
395 | if (fd == NULL) { | |
396 | dbg("Can't open %s", filename); | |
397 | return -ENODEV; | |
398 | } | |
399 | ||
400 | /* loop through the whole file */ | |
401 | while (1) { | |
402 | /* get a line */ | |
403 | temp = fgets(line, sizeof(line), fd); | |
404 | if (temp == NULL) | |
405 | break; | |
406 | ||
407 | dbg("read %s", temp); | |
408 | ||
409 | /* eat the whitespace at the beginning of the line */ | |
410 | while (isspace(*temp)) | |
411 | ++temp; | |
412 | ||
413 | /* no more line? */ | |
414 | if (*temp == 0x00) | |
415 | continue; | |
416 | ||
417 | /* see if this is a comment */ | |
418 | if (*temp == COMMENT_CHARACTER) | |
419 | continue; | |
420 | ||
421 | memset(&dev, 0x00, sizeof(dev)); | |
422 | ||
423 | /* parse the line */ | |
424 | temp2 = strsep(&temp, ":"); | |
425 | strncpy(dev.name, temp2, sizeof(dev.name)); | |
426 | ||
427 | temp2 = strsep(&temp, ":"); | |
428 | strncpy(dev.owner, temp2, sizeof(dev.owner)); | |
429 | ||
430 | temp2 = strsep(&temp, ":"); | |
431 | strncpy(dev.group, temp2, sizeof(dev.owner)); | |
432 | ||
433 | dev.mode = strtol(temp, NULL, 8); | |
434 | ||
435 | dbg("name = %s, owner = %s, group = %s, mode = %x", dev.name, dev.owner, dev.group, dev.mode); | |
436 | retval = add_dev(&dev); | |
437 | if (retval) { | |
438 | dbg("add_dev returned with error %d", retval); | |
439 | goto exit; | |
440 | } | |
441 | } | |
442 | ||
443 | exit: | |
444 | fclose(fd); | |
445 | return retval; | |
446 | } | |
447 | ||
448 | ||
449 | ||
450 | int namedev_init(void) | |
451 | { | |
452 | int retval; | |
453 | ||
454 | retval = namedev_init_config(); | |
455 | if (retval) | |
456 | return retval; | |
457 | ||
458 | retval = namedev_init_permissions(); | |
459 | if (retval) | |
460 | return retval; | |
461 | ||
469c7cff | 462 | dump_dev_list(); |
2232cac8 GKH |
463 | return retval; |
464 | } | |
465 |