chiark / gitweb /
[PATCH] added libsysfs code from sysutils-0.1.1-071803 release
[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 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
121 #define copy_var(a, b, var)             \
122         if (b->var)                     \
123                 a->var = b->var;
124
125 #define copy_string(a, b, var)          \
126         if (strlen(b->var))             \
127                 strcpy(a->var, b->var);
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 */
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);
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);
160         //dump_dev(tmp_dev);
161         return 0;
162 }
163
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
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         
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 }
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
264                 memset(&dev, 0x00, sizeof(struct config_device));
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);
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);
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);
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);
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);
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);
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
462         dump_dev_list();
463         return retval;
464 }
465