]> git.ipfire.org Git - thirdparty/systemd.git/blame - namedev_parse.c
[PATCH] udev_volume_id: volume_id version 034
[thirdparty/systemd.git] / namedev_parse.c
CommitLineData
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>
19feb351
GKH
33#include <ctype.h>
34#include <unistd.h>
e41245cb 35#include <sys/stat.h>
19feb351
GKH
36#include <errno.h>
37
38#include "udev.h"
9af5bb2f 39#include "udev_utils.h"
54988802 40#include "logging.h"
19feb351
GKH
41#include "namedev.h"
42
8b36cc0f 43LIST_HEAD(config_device_list);
e41016d3 44
a8b01705
GKH
45static int add_config_dev(struct config_device *new_dev)
46{
47 struct config_device *tmp_dev;
48
49 tmp_dev = malloc(sizeof(*tmp_dev));
50 if (tmp_dev == NULL)
51 return -ENOMEM;
52 memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
53 list_add_tail(&tmp_dev->node, &config_device_list);
54 //dump_config_dev(tmp_dev);
55 return 0;
56}
57
19feb351
GKH
58void dump_config_dev(struct config_device *dev)
59{
ac28b86d
KS
60 dbg_parse("name='%s', symlink='%s', bus='%s', place='%s', id='%s', "
61 "sysfs_file[0]='%s', sysfs_value[0]='%s', "
3e441450 62 "kernel='%s', program='%s', result='%s'"
e41016d3 63 "owner='%s', group='%s', mode=%#o",
ac28b86d
KS
64 dev->name, dev->symlink, dev->bus, dev->place, dev->id,
65 dev->sysfs_pair[0].file, dev->sysfs_pair[0].value,
2731fd98 66 dev->kernel, dev->program, dev->result,
e41016d3 67 dev->owner, dev->group, dev->mode);
19feb351
GKH
68}
69
70void dump_config_dev_list(void)
71{
843d1a84 72 struct config_device *dev;
19feb351 73
843d1a84 74 list_for_each_entry(dev, &config_device_list, node)
19feb351 75 dump_config_dev(dev);
19feb351 76}
61219c75 77
d4a32aa2 78/* extract possible KEY{attr} */
bb738647
KS
79static char *get_key_attribute(char *str)
80{
81 char *pos;
82 char *attr;
83
bb738647
KS
84 attr = strchr(str, '{');
85 if (attr != NULL) {
86 attr++;
87 pos = strchr(attr, '}');
88 if (pos == NULL) {
89 dbg("missing closing brace for format");
90 return NULL;
91 }
92 pos[0] = '\0';
93 dbg("attribute='%s'", attr);
94 return attr;
95 }
96
97 return NULL;
98}
99
8b36cc0f 100static int namedev_parse(const char *filename, void *data)
19feb351 101{
3e441450 102 char line[LINE_SIZE];
103 char *bufline;
19feb351
GKH
104 int lineno;
105 char *temp;
106 char *temp2;
107 char *temp3;
bb738647 108 char *attr;
c81b35c0
KS
109 char *buf;
110 size_t bufsize;
111 size_t cur;
112 size_t count;
ac28b86d 113 int program_given = 0;
3e441450 114 int valid;
19feb351
GKH
115 int retval = 0;
116 struct config_device dev;
117
c81b35c0 118 if (file_map(filename, &buf, &bufsize) == 0) {
e41245cb 119 dbg("reading '%s' as rules file", filename);
e8baccca 120 } else {
c81b35c0
KS
121 dbg("can't open '%s' as rules file", filename);
122 return -1;
19feb351
GKH
123 }
124
125 /* loop through the whole file */
c81b35c0 126 cur = 0;
19feb351 127 lineno = 0;
3e441450 128 while (cur < bufsize) {
1134a81b 129 unsigned int i, j;
9f8dfa19 130
c81b35c0 131 count = buf_get_line(buf, bufsize, cur);
3e441450 132 bufline = &buf[cur];
c81b35c0 133 cur += count+1;
3e441450 134 lineno++;
19feb351 135
3e441450 136 if (count >= LINE_SIZE) {
9f8dfa19 137 info("line too long, rule skipped %s, line %d", filename, lineno);
3e441450 138 continue;
139 }
093bf8f4 140
3e441450 141 /* eat the whitespace */
3db7fa27 142 while ((count > 0) && isspace(bufline[0])) {
3e441450 143 bufline++;
144 count--;
145 }
3db7fa27
KS
146 if (count == 0)
147 continue;
3e441450 148
19feb351 149 /* see if this is a comment */
3e441450 150 if (bufline[0] == COMMENT_CHARACTER)
19feb351
GKH
151 continue;
152
9f8dfa19
KS
153 /* skip backslash and newline from multi line rules */
154 for (i = j = 0; i < count; i++) {
155 if (bufline[i] == '\\' || bufline[i] == '\n')
156 continue;
157
158 line[j++] = bufline[i];
159 }
160 line[j] = '\0';
3e441450 161 dbg_parse("read '%s'", line);
19feb351 162
d94df232 163 /* get all known keys */
3e441450 164 memset(&dev, 0x00, sizeof(struct config_device));
165 temp = line;
166 valid = 0;
167
d94df232 168 while (1) {
274812b5 169 retval = parse_get_pair(&temp, &temp2, &temp3);
19feb351
GKH
170 if (retval)
171 break;
3d150dfb 172
d94df232
KS
173 if (strcasecmp(temp2, FIELD_BUS) == 0) {
174 strfieldcpy(dev.bus, temp3);
3e441450 175 valid = 1;
d94df232
KS
176 continue;
177 }
178
179 if (strcasecmp(temp2, FIELD_ID) == 0) {
180 strfieldcpy(dev.id, temp3);
3e441450 181 valid = 1;
d94df232
KS
182 continue;
183 }
184
185 if (strcasecmp(temp2, FIELD_PLACE) == 0) {
186 strfieldcpy(dev.place, temp3);
3e441450 187 valid = 1;
d94df232
KS
188 continue;
189 }
190
191 if (strncasecmp(temp2, FIELD_SYSFS, sizeof(FIELD_SYSFS)-1) == 0) {
a8b01705
GKH
192 struct sysfs_pair *pair = &dev.sysfs_pair[0];
193 int sysfs_pair_num = 0;
194
195 /* find first unused pair */
196 while (pair->file[0] != '\0') {
197 ++sysfs_pair_num;
198 if (sysfs_pair_num >= MAX_SYSFS_PAIRS) {
199 pair = NULL;
200 break;
201 }
202 ++pair;
203 }
204 if (pair) {
bb738647
KS
205 attr = get_key_attribute(temp2 + sizeof(FIELD_SYSFS)-1);
206 if (attr == NULL) {
207 dbg("error parsing " FIELD_SYSFS " attribute");
208 continue;
209 }
210 strfieldcpy(pair->file, attr);
a8b01705 211 strfieldcpy(pair->value, temp3);
3e441450 212 valid = 1;
a8b01705 213 }
d94df232
KS
214 continue;
215 }
216
217 if (strcasecmp(temp2, FIELD_KERNEL) == 0) {
ac28b86d 218 strfieldcpy(dev.kernel, temp3);
3e441450 219 valid = 1;
d94df232
KS
220 continue;
221 }
222
6818c51d
KS
223 if (strcasecmp(temp2, FIELD_SUBSYSTEM) == 0) {
224 strfieldcpy(dev.subsystem, temp3);
225 valid = 1;
226 continue;
227 }
228
2092fbcd
KS
229 if (strcasecmp(temp2, FIELD_DRIVER) == 0) {
230 strfieldcpy(dev.driver, temp3);
231 valid = 1;
232 continue;
233 }
234
d94df232 235 if (strcasecmp(temp2, FIELD_PROGRAM) == 0) {
ac28b86d
KS
236 program_given = 1;
237 strfieldcpy(dev.program, temp3);
3e441450 238 valid = 1;
ac28b86d
KS
239 continue;
240 }
241
242 if (strcasecmp(temp2, FIELD_RESULT) == 0) {
243 strfieldcpy(dev.result, temp3);
3e441450 244 valid = 1;
d94df232
KS
245 continue;
246 }
247
50e5de03
KS
248 if (strncasecmp(temp2, FIELD_NAME, sizeof(FIELD_NAME)-1) == 0) {
249 attr = get_key_attribute(temp2 + sizeof(FIELD_NAME)-1);
7efa217d
KS
250 if (attr != NULL) {
251 if (strstr(attr, ATTR_PARTITIONS) != NULL) {
50e5de03
KS
252 dbg_parse("creation of partition nodes requested");
253 dev.partitions = PARTITIONS_COUNT;
254 }
7efa217d
KS
255 if (strstr(attr, ATTR_IGNORE_REMOVE) != NULL) {
256 dbg_parse("remove event should be ignored");
257 dev.ignore_remove = 1;
258 }
259 }
d94df232 260 strfieldcpy(dev.name, temp3);
3e441450 261 valid = 1;
d94df232
KS
262 continue;
263 }
264
265 if (strcasecmp(temp2, FIELD_SYMLINK) == 0) {
3d150dfb 266 strfieldcpy(dev.symlink, temp3);
3e441450 267 valid = 1;
d94df232
KS
268 continue;
269 }
3d150dfb 270
e41016d3
KS
271 if (strcasecmp(temp2, FIELD_OWNER) == 0) {
272 strfieldcpy(dev.owner, temp3);
3e441450 273 valid = 1;
e41016d3
KS
274 continue;
275 }
276
277 if (strcasecmp(temp2, FIELD_GROUP) == 0) {
278 strfieldcpy(dev.group, temp3);
3e441450 279 valid = 1;
e41016d3
KS
280 continue;
281 }
282
283 if (strcasecmp(temp2, FIELD_MODE) == 0) {
284 dev.mode = strtol(temp3, NULL, 8);
3e441450 285 valid = 1;
e41016d3
KS
286 continue;
287 }
288
851cd18d 289 dbg("unknown type of field '%s'", temp2);
851cd18d 290 goto error;
d94df232
KS
291 }
292
3e441450 293 /* skip line if not any valid key was found */
294 if (!valid)
295 goto error;
296
e41016d3 297 /* simple plausibility checks for given keys */
ac28b86d
KS
298 if ((dev.sysfs_pair[0].file[0] == '\0') ^
299 (dev.sysfs_pair[0].value[0] == '\0')) {
3e441450 300 info("inconsistency in " FIELD_SYSFS " key");
ac28b86d
KS
301 goto error;
302 }
303
304 if ((dev.result[0] != '\0') && (program_given == 0)) {
3e441450 305 info(FIELD_RESULT " is only useful when "
306 FIELD_PROGRAM " is called in any rule before");
d94df232 307 goto error;
19feb351
GKH
308 }
309
54988802 310 dev.config_line = lineno;
bd5f8e7c 311 strfieldcpy(dev.config_file, filename);
19feb351
GKH
312 retval = add_config_dev(&dev);
313 if (retval) {
314 dbg("add_config_dev returned with error %d", retval);
d94df232 315 continue;
ac28b86d 316error:
3e441450 317 info("parse error %s, line %d:%d, rule skipped",
318 filename, lineno, temp - line);
19feb351
GKH
319 }
320 }
c81b35c0
KS
321
322 file_unmap(buf, bufsize);
19feb351 323 return retval;
d94df232 324}
19feb351 325
8b36cc0f 326int namedev_init(void)
19feb351 327{
8b36cc0f
KS
328 struct stat stats;
329 int retval;
19feb351 330
8b36cc0f 331 if (stat(udev_rules_filename, &stats) != 0)
c81b35c0 332 return -1;
19feb351 333
e41245cb 334 if ((stats.st_mode & S_IFMT) != S_IFDIR)
8b36cc0f 335 retval = namedev_parse(udev_rules_filename, NULL);
4a539daf 336 else
8b36cc0f 337 retval = call_foreach_file(namedev_parse, udev_rules_filename, RULEFILE_SUFFIX, NULL);
e41245cb 338
8b36cc0f 339 return retval;
e41245cb 340}