chiark / gitweb /
[PATCH] Initial namedev parsing of config files
[elogind.git] / namedev.c
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
83 #define copy_var(a, b, var)             \
84         if (b->var)                     \
85                 b->var = a->var;
86
87 #define copy_string(a, b, var)          \
88         if (strlen(b->var))             \
89                 strcpy(b->var, a->var);
90
91 static int add_dev(struct config_device *new_dev)
92 {
93         struct list_head *tmp;
94         struct config_device *tmp_dev;
95
96         /* loop through the whole list of devices to see if we already have
97          * this one... */
98         list_for_each(tmp, &config_device_list) {
99                 struct config_device *dev = list_entry(tmp, struct config_device, node);
100                 if (strcmp(dev->name, new_dev->name) == 0) {
101                         /* the same, copy the new info into this structure */
102                         copy_var(new_dev, dev, type);
103                         copy_var(new_dev, dev, mode);
104                         copy_string(new_dev, dev, bus);
105                         copy_string(new_dev, dev, sysfs_file);
106                         copy_string(new_dev, dev, sysfs_value);
107                         copy_string(new_dev, dev, id);
108                         copy_string(new_dev, dev, place);
109                         copy_string(new_dev, dev, kernel_name);
110                         copy_string(new_dev, dev, owner);
111                         copy_string(new_dev, dev, group);
112                         return 0;
113                 }
114         }
115
116         /* not found, lets create a new structure, and add it to the list */
117         tmp_dev = malloc(sizeof(*tmp_dev));
118         if (!tmp_dev)
119                 return -ENOMEM;
120         memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
121         list_add(&tmp_dev->node, &config_device_list);
122         return 0;
123 }
124
125 static int get_value(const char *left, char **orig_string, char **ret_string)
126 {
127         char *temp;
128         char *string = *orig_string;
129
130         /* eat any whitespace */
131         while (isspace(*string))
132                 ++string;
133
134         /* split based on '=' */
135         temp = strsep(&string, "=");
136         if (strcasecmp(temp, left) == 0) {
137                 /* got it, now strip off the '"' */
138                 while (isspace(*string))
139                         ++string;
140                 if (*string == '"')
141                         ++string;
142                 temp = strsep(&string, "\"");
143                 *ret_string = temp;
144                 *orig_string = string;
145                 return 0;
146         }
147         return -ENODEV;
148 }
149         
150
151 static int namedev_init_config(void)
152 {
153         char filename[255];
154         char line[255];
155         char *temp;
156         char *temp2;
157         char *temp3;
158         FILE *fd;
159         int retval = 0;
160         struct config_device dev;
161
162         strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_FILE);
163         dbg("opening %s to read as permissions config", filename);
164         fd = fopen(filename, "r");
165         if (fd == NULL) {
166                 dbg("Can't open %s", filename);
167                 return -ENODEV;
168         }
169
170         /* loop through the whole file */
171         while (1) {
172                 /* get a line */
173                 temp = fgets(line, sizeof(line), fd);
174                 if (temp == NULL)
175                         break;
176
177                 dbg("read %s", temp);
178
179                 /* eat the whitespace at the beginning of the line */
180                 while (isspace(*temp))
181                         ++temp;
182
183                 /* no more line? */
184                 if (*temp == 0x00)
185                         continue;
186
187                 /* see if this is a comment */
188                 if (*temp == COMMENT_CHARACTER)
189                         continue;
190
191                 memset(&dev, 0x00, sizeof(dev));
192
193                 /* parse the line */
194                 temp2 = strsep(&temp, ",");
195                 if (strcasecmp(temp2, TYPE_LABEL) == 0) {
196                         /* label type */
197                         dev.type = LABEL;
198
199                         /* BUS="bus" */
200                         retval = get_value("BUS", &temp, &temp3);
201                         if (retval)
202                                 continue;
203                         strcpy(dev.bus, temp3);
204                         dbg("LABEL name = %s, bus = %s", dev.name, dev.bus);
205                 }
206
207                 if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
208                         /* number type */
209                         dev.type = NUMBER;
210
211                         /* BUS="bus" */
212                         retval = get_value("BUS", &temp, &temp3);
213                         if (retval)
214                                 continue;
215                         strcpy(dev.bus, temp3);
216                         dbg("NUMBER name = %s, bus = %s", dev.name, dev.bus);
217                 }
218
219                 if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
220                         /* number type */
221                         dev.type = TOPOLOGY;
222
223                         /* BUS="bus" */
224                         retval = get_value("BUS", &temp, &temp3);
225                         if (retval)
226                                 continue;
227                         strcpy(dev.bus, temp3);
228                         dbg("TOPOLOGY name = %s, bus = %s", dev.name, dev.bus);
229                 }
230
231                 if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
232                         /* number type */
233                         dev.type = REPLACE;
234
235                         /* KERNEL="kernel_name" */
236                         retval = get_value("KERNEL", &temp, &temp3);
237                         if (retval)
238                                 continue;
239                         strcpy(dev.kernel_name, temp3);
240
241                         /* NAME="new_name" */
242                         temp2 = strsep(&temp, ",");
243                         retval = get_value("NAME", &temp, &temp3);
244                         if (retval)
245                                 continue;
246                         strcpy(dev.name, temp3);
247                         dbg("REPLACE name = %s, kernel_name = %s", dev.name, dev.kernel_name);
248                 }
249
250                 retval = add_dev(&dev);
251                 if (retval) {
252                         dbg("add_dev returned with error %d", retval);
253                         goto exit;
254                 }
255         }
256
257 exit:
258         fclose(fd);
259         return retval;
260 }       
261
262
263 static int namedev_init_permissions(void)
264 {
265         char filename[255];
266         char line[255];
267         char *temp;
268         char *temp2;
269         FILE *fd;
270         int retval = 0;
271         struct config_device dev;
272
273         strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_PERMISSION_FILE);
274         dbg("opening %s to read as permissions config", filename);
275         fd = fopen(filename, "r");
276         if (fd == NULL) {
277                 dbg("Can't open %s", filename);
278                 return -ENODEV;
279         }
280
281         /* loop through the whole file */
282         while (1) {
283                 /* get a line */
284                 temp = fgets(line, sizeof(line), fd);
285                 if (temp == NULL)
286                         break;
287
288                 dbg("read %s", temp);
289
290                 /* eat the whitespace at the beginning of the line */
291                 while (isspace(*temp))
292                         ++temp;
293
294                 /* no more line? */
295                 if (*temp == 0x00)
296                         continue;
297
298                 /* see if this is a comment */
299                 if (*temp == COMMENT_CHARACTER)
300                         continue;
301
302                 memset(&dev, 0x00, sizeof(dev));
303
304                 /* parse the line */
305                 temp2 = strsep(&temp, ":");
306                 strncpy(dev.name, temp2, sizeof(dev.name));
307
308                 temp2 = strsep(&temp, ":");
309                 strncpy(dev.owner, temp2, sizeof(dev.owner));
310
311                 temp2 = strsep(&temp, ":");
312                 strncpy(dev.group, temp2, sizeof(dev.owner));
313
314                 dev.mode = strtol(temp, NULL, 8);
315
316                 dbg("name = %s, owner = %s, group = %s, mode = %x", dev.name, dev.owner, dev.group, dev.mode);
317                 retval = add_dev(&dev);
318                 if (retval) {
319                         dbg("add_dev returned with error %d", retval);
320                         goto exit;
321                 }
322         }
323
324 exit:
325         fclose(fd);
326         return retval;
327 }       
328
329
330
331 int namedev_init(void)
332 {
333         int retval;
334
335         retval = namedev_init_config();
336         if (retval)
337                 return retval;
338
339         retval = namedev_init_permissions();
340         if (retval)
341                 return retval;
342
343         return retval;
344 }
345