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