6 * Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
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.
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.
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.
25 /* define this to enable parsing debugging also */
26 /* #define DEBUG_PARSER */
46 static int add_config_dev(struct config_device
*new_dev
)
48 struct config_device
*tmp_dev
;
50 tmp_dev
= malloc(sizeof(*tmp_dev
));
53 memcpy(tmp_dev
, new_dev
, sizeof(*tmp_dev
));
54 list_add_tail(&tmp_dev
->node
, &config_device_list
);
55 //dump_config_dev(tmp_dev);
59 void dump_config_dev(struct config_device
*dev
)
61 /*FIXME dump all sysfs's */
62 dbg_parse("name='%s', symlink='%s', bus='%s', place='%s', id='%s', "
63 "sysfs_file[0]='%s', sysfs_value[0]='%s', "
64 "kernel='%s', program='%s', result='%s'",
65 dev
->name
, dev
->symlink
, dev
->bus
, dev
->place
, dev
->id
,
66 dev
->sysfs_pair
[0].file
, dev
->sysfs_pair
[0].value
,
67 dev
->kernel
, dev
->program
, dev
->result
);
70 void dump_config_dev_list(void)
72 struct config_device
*dev
;
74 list_for_each_entry(dev
, &config_device_list
, node
)
78 void dump_perm_dev(struct perm_device
*dev
)
80 dbg_parse("name='%s', owner='%s', group='%s', mode=%#o",
81 dev
->name
, dev
->owner
, dev
->group
, dev
->mode
);
84 void dump_perm_dev_list(void)
86 struct perm_device
*dev
;
88 list_for_each_entry(dev
, &perm_device_list
, node
)
92 /* extract possible KEY{attr} or KEY_attr */
93 static char *get_key_attribute(char *str
)
98 attr
= strchr(str
, '{');
101 pos
= strchr(attr
, '}');
103 dbg("missing closing brace for format");
107 dbg("attribute='%s'", attr
);
111 attr
= strchr(str
, '_');
114 dbg("attribute='%s'", attr
);
121 static int namedev_parse_rules(char *filename
)
130 int program_given
= 0;
132 struct config_device dev
;
134 fd
= fopen(filename
, "r");
136 dbg("reading '%s' as rules file", filename
);
138 dbg("can't open '%s' as a rules file", filename
);
142 /* loop through the whole file */
146 temp
= fgets(line
, sizeof(line
), fd
);
150 dbg_parse("read '%s'", temp
);
152 /* eat the whitespace */
153 while (isspace(*temp
))
157 if ((*temp
== '\0') || (*temp
== '\n'))
160 /* see if this is a comment */
161 if (*temp
== COMMENT_CHARACTER
)
164 memset(&dev
, 0x00, sizeof(struct config_device
));
166 /* get all known keys */
168 retval
= parse_get_pair(&temp
, &temp2
, &temp3
);
172 if (strcasecmp(temp2
, FIELD_BUS
) == 0) {
173 strfieldcpy(dev
.bus
, temp3
);
177 if (strcasecmp(temp2
, FIELD_ID
) == 0) {
178 strfieldcpy(dev
.id
, temp3
);
182 if (strcasecmp(temp2
, FIELD_PLACE
) == 0) {
183 strfieldcpy(dev
.place
, temp3
);
187 if (strncasecmp(temp2
, FIELD_SYSFS
, sizeof(FIELD_SYSFS
)-1) == 0) {
188 struct sysfs_pair
*pair
= &dev
.sysfs_pair
[0];
189 int sysfs_pair_num
= 0;
191 /* find first unused pair */
192 while (pair
->file
[0] != '\0') {
194 if (sysfs_pair_num
>= MAX_SYSFS_PAIRS
) {
201 attr
= get_key_attribute(temp2
+ sizeof(FIELD_SYSFS
)-1);
203 dbg("error parsing " FIELD_SYSFS
" attribute");
206 strfieldcpy(pair
->file
, attr
);
207 strfieldcpy(pair
->value
, temp3
);
212 if (strcasecmp(temp2
, FIELD_KERNEL
) == 0) {
213 strfieldcpy(dev
.kernel
, temp3
);
217 if (strcasecmp(temp2
, FIELD_PROGRAM
) == 0) {
219 strfieldcpy(dev
.program
, temp3
);
223 if (strcasecmp(temp2
, FIELD_RESULT
) == 0) {
224 strfieldcpy(dev
.result
, temp3
);
228 if (strncasecmp(temp2
, FIELD_NAME
, sizeof(FIELD_NAME
)-1) == 0) {
229 attr
= get_key_attribute(temp2
+ sizeof(FIELD_NAME
)-1);
231 if (strcasecmp(attr
, ATTR_PARTITIONS
) == 0) {
232 dbg_parse("creation of partition nodes requested");
233 dev
.partitions
= PARTITIONS_COUNT
;
235 strfieldcpy(dev
.name
, temp3
);
239 if (strcasecmp(temp2
, FIELD_SYMLINK
) == 0) {
240 strfieldcpy(dev
.symlink
, temp3
);
244 dbg("unknown type of field '%s'", temp2
);
245 dbg("You might be using a rules file in the old format, please fix.");
249 /* simple plausibility check for given keys */
250 if ((dev
.sysfs_pair
[0].file
[0] == '\0') ^
251 (dev
.sysfs_pair
[0].value
[0] == '\0')) {
252 dbg("inconsistency in " FIELD_SYSFS
" key");
256 if ((dev
.result
[0] != '\0') && (program_given
== 0)) {
257 dbg(FIELD_RESULT
" is only useful when "
258 FIELD_PROGRAM
" is called in any rule before");
262 dev
.config_line
= lineno
;
263 retval
= add_config_dev(&dev
);
265 dbg("add_config_dev returned with error %d", retval
);
268 dbg("%s:%d:%d: parse error, rule skipped",
269 filename
, lineno
, temp
- line
);
277 static int namedev_parse_permissions(char *filename
)
284 struct perm_device dev
;
286 fd
= fopen(filename
, "r");
288 dbg("reading '%s' as permissions file", filename
);
290 dbg("can't open '%s' as permissions file", filename
);
294 /* loop through the whole file */
296 temp
= fgets(line
, sizeof(line
), fd
);
300 dbg_parse("read '%s'", temp
);
302 /* eat the whitespace at the beginning of the line */
303 while (isspace(*temp
))
307 if ((*temp
== '\0') || (*temp
== '\n'))
310 /* see if this is a comment */
311 if (*temp
== COMMENT_CHARACTER
)
314 memset(&dev
, 0x00, sizeof(dev
));
317 temp2
= strsep(&temp
, ":");
319 dbg("cannot parse line '%s'", line
);
322 strfieldcpy(dev
.name
, temp2
);
324 temp2
= strsep(&temp
, ":");
326 dbg("cannot parse line '%s'", line
);
329 strfieldcpy(dev
.owner
, temp2
);
331 temp2
= strsep(&temp
, ":");
333 dbg("cannot parse line '%s'", line
);
336 strfieldcpy(dev
.group
, temp2
);
339 dbg("cannot parse line: %s", line
);
342 dev
.mode
= strtol(temp
, NULL
, 8);
344 dbg_parse("name='%s', owner='%s', group='%s', mode=%#o",
345 dev
.name
, dev
.owner
, dev
.group
,
347 retval
= add_perm_dev(&dev
);
349 dbg("add_perm_dev returned with error %d", retval
);
360 struct list_head list
;
361 char name
[NAME_SIZE
];
364 /* sort files in lexical order */
365 static int file_list_insert(char *filename
)
367 struct files
*loop_file
;
368 struct files
*new_file
;
370 list_for_each_entry(loop_file
, &file_list
, list
) {
371 if (strcmp(loop_file
->name
, filename
) > 0) {
376 new_file
= malloc(sizeof(struct files
));
377 if (new_file
== NULL
) {
382 strfieldcpy(new_file
->name
, filename
);
383 list_add_tail(&new_file
->list
, &loop_file
->list
);
387 /* calls function for file or every file found in directory */
388 static int call_foreach_file(int parser (char *f
) , char *filename
, char *extension
)
393 char file
[NAME_SIZE
];
395 struct files
*loop_file
;
396 struct files
*tmp_file
;
398 /* look if we have a plain file or a directory to scan */
399 stat(filename
, &stats
);
400 if ((stats
.st_mode
& S_IFMT
) != S_IFDIR
)
401 return parser(filename
);
403 /* sort matching filename into list */
404 dbg("open config as directory '%s'", filename
);
405 dir
= opendir(filename
);
408 if (ent
== NULL
|| ent
->d_name
[0] == '\0')
411 dbg("found file '%s'", ent
->d_name
);
412 ext
= strrchr(ent
->d_name
, '.');
416 if (strcmp(ext
, extension
) == 0) {
417 dbg("put file in list '%s'", ent
->d_name
);
418 file_list_insert(ent
->d_name
);
422 /* parse every file in the list */
423 list_for_each_entry_safe(loop_file
, tmp_file
, &file_list
, list
) {
424 strfieldcpy(file
, filename
);
425 strfieldcat(file
, loop_file
->name
);
427 list_del(&loop_file
->list
);
435 int namedev_init_rules()
437 return call_foreach_file(namedev_parse_rules
, udev_rules_filename
, RULEFILE_EXT
);
440 int namedev_init_permissions()
442 return call_foreach_file(namedev_parse_permissions
, udev_permissions_filename
, PERMFILE_EXT
);