chiark / gitweb /
[PATCH] clean up some debugging stuff in namedev.c
[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 #undef DEBUG
25
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 #include "list.h"
36 #include "udev.h"
37 #include "udev_version.h"
38 #include "namedev.h"
39 #include "libsysfs/libsysfs.h"
40
41 #define TYPE_LABEL      "LABEL"
42 #define TYPE_NUMBER     "NUMBER"
43 #define TYPE_TOPOLOGY   "TOPOLOGY"
44 #define TYPE_REPLACE    "REPLACE"
45
46 static LIST_HEAD(config_device_list);
47
48 static void dump_dev(struct config_device *dev)
49 {
50         switch (dev->type) {
51         case KERNEL_NAME:
52                 dbg("KERNEL name ='%s'"
53                         " owner = '%s', group = '%s', mode = '%#o'",
54                         dev->attr.name, 
55                         dev->attr.owner, dev->attr.group, dev->attr.mode);
56                 break;
57         case LABEL:
58                 dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'"
59                         " owner = '%s', group = '%s', mode = '%#o'",
60                         dev->attr.name, dev->bus, dev->sysfs_file, dev->sysfs_value,
61                         dev->attr.owner, dev->attr.group, dev->attr.mode);
62                 break;
63         case NUMBER:
64                 dbg("NUMBER name = '%s', bus = '%s', id = '%s'"
65                         " owner = '%s', group = '%s', mode = '%#o'",
66                         dev->attr.name, dev->bus, dev->id,
67                         dev->attr.owner, dev->attr.group, dev->attr.mode);
68                 break;
69         case TOPOLOGY:
70                 dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'"
71                         " owner = '%s', group = '%s', mode = '%#o'",
72                         dev->attr.name, dev->bus, dev->place,
73                         dev->attr.owner, dev->attr.group, dev->attr.mode);
74                 break;
75         case REPLACE:
76                 dbg("REPLACE name = %s, kernel_name = %s"
77                         " owner = '%s', group = '%s', mode = '%#o'",
78                         dev->attr.name, dev->kernel_name,
79                         dev->attr.owner, dev->attr.group, dev->attr.mode);
80                 break;
81         default:
82                 dbg("Unknown type of device!");
83         }
84 }
85
86 #define copy_var(a, b, var)             \
87         if (b->var)                     \
88                 a->var = b->var;
89
90 #define copy_string(a, b, var)          \
91         if (strlen(b->var))             \
92                 strcpy(a->var, b->var);
93
94 static int add_dev(struct config_device *new_dev)
95 {
96         struct list_head *tmp;
97         struct config_device *tmp_dev;
98
99         /* loop through the whole list of devices to see if we already have
100          * this one... */
101         list_for_each(tmp, &config_device_list) {
102                 struct config_device *dev = list_entry(tmp, struct config_device, node);
103                 if (strcmp(dev->attr.name, new_dev->attr.name) == 0) {
104                         /* the same, copy the new info into this structure */
105                         copy_var(dev, new_dev, type);
106                         copy_var(dev, new_dev, attr.mode);
107                         copy_string(dev, new_dev, bus);
108                         copy_string(dev, new_dev, sysfs_file);
109                         copy_string(dev, new_dev, sysfs_value);
110                         copy_string(dev, new_dev, id);
111                         copy_string(dev, new_dev, place);
112                         copy_string(dev, new_dev, kernel_name);
113                         copy_string(dev, new_dev, attr.owner);
114                         copy_string(dev, new_dev, attr.group);
115                         return 0;
116                 }
117         }
118
119         /* not found, lets create a new structure, and add it to the list */
120         tmp_dev = malloc(sizeof(*tmp_dev));
121         if (!tmp_dev)
122                 return -ENOMEM;
123         memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
124         list_add(&tmp_dev->node, &config_device_list);
125         //dump_dev(tmp_dev);
126         return 0;
127 }
128
129 static void dump_dev_list(void)
130 {
131         struct list_head *tmp;
132
133         list_for_each(tmp, &config_device_list) {
134                 struct config_device *dev = list_entry(tmp, struct config_device, node);
135                 dump_dev(dev);
136         }
137 }
138
139 static int get_value(const char *left, char **orig_string, char **ret_string)
140 {
141         char *temp;
142         char *string = *orig_string;
143
144         /* eat any whitespace */
145         while (isspace(*string))
146                 ++string;
147
148         /* split based on '=' */
149         temp = strsep(&string, "=");
150         if (strcasecmp(temp, left) == 0) {
151                 /* got it, now strip off the '"' */
152                 while (isspace(*string))
153                         ++string;
154                 if (*string == '"')
155                         ++string;
156                 temp = strsep(&string, "\"");
157                 *ret_string = temp;
158                 *orig_string = string;
159                 return 0;
160         }
161         return -ENODEV;
162 }
163         
164 static int get_pair(char **orig_string, char **left, char **right)
165 {
166         char *temp;
167         char *string = *orig_string;
168
169         /* eat any whitespace */
170         while (isspace(*string))
171                 ++string;
172
173         /* split based on '=' */
174         temp = strsep(&string, "=");
175         *left = temp;
176
177         /* take the right side and strip off the '"' */
178         while (isspace(*string))
179                 ++string;
180         if (*string == '"')
181                 ++string;
182         temp = strsep(&string, "\"");
183         *right = temp;
184         *orig_string = string;
185         
186         return 0;
187 }
188
189 static int namedev_init_config(void)
190 {
191         char filename[255];
192         char line[255];
193         char *temp;
194         char *temp2;
195         char *temp3;
196         FILE *fd;
197         int retval = 0;
198         struct config_device dev;
199
200         strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_FILE);
201         dbg("opening %s to read as permissions config", filename);
202         fd = fopen(filename, "r");
203         if (fd == NULL) {
204                 dbg("Can't open %s", filename);
205                 return -ENODEV;
206         }
207
208         /* loop through the whole file */
209         while (1) {
210                 /* get a line */
211                 temp = fgets(line, sizeof(line), fd);
212                 if (temp == NULL)
213                         break;
214
215                 dbg("read %s", temp);
216
217                 /* eat the whitespace at the beginning of the line */
218                 while (isspace(*temp))
219                         ++temp;
220
221                 /* no more line? */
222                 if (*temp == 0x00)
223                         continue;
224
225                 /* see if this is a comment */
226                 if (*temp == COMMENT_CHARACTER)
227                         continue;
228
229                 memset(&dev, 0x00, sizeof(struct config_device));
230
231                 /* parse the line */
232                 temp2 = strsep(&temp, ",");
233                 if (strcasecmp(temp2, TYPE_LABEL) == 0) {
234                         /* label type */
235                         dev.type = LABEL;
236
237                         /* BUS="bus" */
238                         retval = get_value("BUS", &temp, &temp3);
239                         if (retval)
240                                 continue;
241                         strcpy(dev.bus, temp3);
242
243                         /* file="value" */
244                         temp2 = strsep(&temp, ",");
245                         retval = get_pair(&temp, &temp2, &temp3);
246                         if (retval)
247                                 continue;
248                         strcpy(dev.sysfs_file, temp2);
249                         strcpy(dev.sysfs_value, temp3);
250
251                         /* NAME="new_name" */
252                         temp2 = strsep(&temp, ",");
253                         retval = get_value("NAME", &temp, &temp3);
254                         if (retval)
255                                 continue;
256                         strcpy(dev.attr.name, temp3);
257
258                         dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'", dev.attr.name, dev.bus, dev.sysfs_file, dev.sysfs_value);
259                 }
260
261                 if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
262                         /* number type */
263                         dev.type = NUMBER;
264
265                         /* BUS="bus" */
266                         retval = get_value("BUS", &temp, &temp3);
267                         if (retval)
268                                 continue;
269                         strcpy(dev.bus, temp3);
270
271                         /* ID="id" */
272                         temp2 = strsep(&temp, ",");
273                         retval = get_value("id", &temp, &temp3);
274                         if (retval)
275                                 continue;
276                         strcpy(dev.id, temp3);
277
278                         /* NAME="new_name" */
279                         temp2 = strsep(&temp, ",");
280                         retval = get_value("NAME", &temp, &temp3);
281                         if (retval)
282                                 continue;
283                         strcpy(dev.attr.name, temp3);
284
285                         dbg("NUMBER name = '%s', bus = '%s', id = '%s'", dev.attr.name, dev.bus, dev.id);
286                 }
287
288                 if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
289                         /* number type */
290                         dev.type = TOPOLOGY;
291
292                         /* BUS="bus" */
293                         retval = get_value("BUS", &temp, &temp3);
294                         if (retval)
295                                 continue;
296                         strcpy(dev.bus, temp3);
297
298                         /* PLACE="place" */
299                         temp2 = strsep(&temp, ",");
300                         retval = get_value("place", &temp, &temp3);
301                         if (retval)
302                                 continue;
303                         strcpy(dev.place, temp3);
304
305                         /* NAME="new_name" */
306                         temp2 = strsep(&temp, ",");
307                         retval = get_value("NAME", &temp, &temp3);
308                         if (retval)
309                                 continue;
310                         strcpy(dev.attr.name, temp3);
311
312                         dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'", dev.attr.name, dev.bus, dev.place);
313                 }
314
315                 if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
316                         /* number type */
317                         dev.type = REPLACE;
318
319                         /* KERNEL="kernel_name" */
320                         retval = get_value("KERNEL", &temp, &temp3);
321                         if (retval)
322                                 continue;
323                         strcpy(dev.kernel_name, temp3);
324
325                         /* NAME="new_name" */
326                         temp2 = strsep(&temp, ",");
327                         retval = get_value("NAME", &temp, &temp3);
328                         if (retval)
329                                 continue;
330                         strcpy(dev.attr.name, temp3);
331                         dbg("REPLACE name = %s, kernel_name = %s", dev.attr.name, dev.kernel_name);
332                 }
333
334                 retval = add_dev(&dev);
335                 if (retval) {
336                         dbg("add_dev returned with error %d", retval);
337                         goto exit;
338                 }
339         }
340
341 exit:
342         fclose(fd);
343         return retval;
344 }       
345
346
347 static int namedev_init_permissions(void)
348 {
349         char filename[255];
350         char line[255];
351         char *temp;
352         char *temp2;
353         FILE *fd;
354         int retval = 0;
355         struct config_device dev;
356
357         strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_PERMISSION_FILE);
358         dbg("opening %s to read as permissions config", filename);
359         fd = fopen(filename, "r");
360         if (fd == NULL) {
361                 dbg("Can't open %s", filename);
362                 return -ENODEV;
363         }
364
365         /* loop through the whole file */
366         while (1) {
367                 /* get a line */
368                 temp = fgets(line, sizeof(line), fd);
369                 if (temp == NULL)
370                         break;
371
372                 dbg("read %s", temp);
373
374                 /* eat the whitespace at the beginning of the line */
375                 while (isspace(*temp))
376                         ++temp;
377
378                 /* no more line? */
379                 if (*temp == 0x00)
380                         continue;
381
382                 /* see if this is a comment */
383                 if (*temp == COMMENT_CHARACTER)
384                         continue;
385
386                 memset(&dev, 0x00, sizeof(dev));
387
388                 /* parse the line */
389                 temp2 = strsep(&temp, ":");
390                 strncpy(dev.attr.name, temp2, sizeof(dev.attr.name));
391
392                 temp2 = strsep(&temp, ":");
393                 strncpy(dev.attr.owner, temp2, sizeof(dev.attr.owner));
394
395                 temp2 = strsep(&temp, ":");
396                 strncpy(dev.attr.group, temp2, sizeof(dev.attr.owner));
397
398                 dev.attr.mode = strtol(temp, NULL, 8);
399
400                 dbg("name = %s, owner = %s, group = %s, mode = %#o", dev.attr.name, dev.attr.owner, dev.attr.group, dev.attr.mode);
401                 retval = add_dev(&dev);
402                 if (retval) {
403                         dbg("add_dev returned with error %d", retval);
404                         goto exit;
405                 }
406         }
407
408 exit:
409         fclose(fd);
410         return retval;
411 }       
412
413 static int get_default_mode(struct sysfs_class_device *class_dev)
414 {
415         /* just default everyone to rw for the world! */
416         return 0666;
417 }
418
419
420 static int get_attr(struct sysfs_class_device *class_dev, struct device_attr *attr)
421 {
422         struct list_head *tmp;
423         int retval = 0;
424         int found;
425
426         attr->mode = -1;
427         if (class_dev->sysdevice) {
428                 dbg("class_dev->sysdevice->directory->path = '%s'", class_dev->sysdevice->directory->path);
429                 dbg("class_dev->sysdevice->bus_id = '%s'", class_dev->sysdevice->bus_id);
430         } else {
431                 dbg("class_dev->name = '%s'", class_dev->name);
432         }
433         list_for_each(tmp, &config_device_list) {
434                 struct config_device *dev = list_entry(tmp, struct config_device, node);
435                 switch (dev->type) {
436                 case LABEL:
437                         {
438                         char *temp;
439
440                         dbg("LABEL: match file '%s' with value '%s'", dev->sysfs_file, dev->sysfs_value);
441                         /* try to find the attribute in the class device directory */
442                         temp = sysfs_get_value_from_attributes(class_dev->directory->attributes, dev->sysfs_file);
443                         if (temp)
444                                 goto label_found;
445
446                         /* look in the class device device directory if present */
447                         if (class_dev->sysdevice) {
448                                 temp = sysfs_get_value_from_attributes(class_dev->sysdevice->directory->attributes, dev->sysfs_file);
449                                 if (temp)
450                                         goto label_found;
451                         }
452
453                         /* bah, let's go backwards up a level to see if the device is there,
454                          * as block partitions don't point to the physical device.  Need to fix that
455                          * up in the kernel...
456                          */
457                         if (strstr(class_dev->directory->path, "block")) {
458                                 dbg("looking at block device...");
459                                 if (isdigit(class_dev->directory->path[strlen(class_dev->directory->path)-1])) {
460                                         char path[SYSFS_PATH_MAX];
461                                         struct sysfs_class_device *class_dev_parent;
462
463                                         dbg("really is a partition...");
464                                         strcpy(path, class_dev->directory->path);
465                                         temp = strrchr(path, '/');
466                                         *temp = 0x00;
467                                         dbg("looking for a class device at '%s'", path);
468                                         class_dev_parent = sysfs_open_class_device(path);
469                                         if (class_dev_parent == NULL) {
470                                                 dbg ("sysfs_open_class_device failed");
471                                                 continue;
472                                         }
473                                         dbg("class_dev_parent->name = %s", class_dev_parent->name);
474
475                                         /* try to find the attribute in the class device directory */
476                                         temp = sysfs_get_value_from_attributes(class_dev_parent->directory->attributes, dev->sysfs_file);
477                                         if (temp) {
478                                                 //sysfs_close_class_device(class_dev_parent);
479                                                 goto label_found;
480                                         }
481
482                                         /* look in the class device device directory if present */
483                                         if (class_dev_parent->sysdevice) {
484                                                 temp = sysfs_get_value_from_attributes(class_dev_parent->sysdevice->directory->attributes, dev->sysfs_file);
485                                                 if (temp) {
486                                                         // sysfs_close_class_device(class_dev_parent);
487                                                         goto label_found;
488                                                 }
489                                         }
490                                         
491                                 }
492                         }
493                         continue;
494
495 label_found:
496                         temp[strlen(temp)-1] = 0x00;
497                         dbg("file '%s' found with value '%s' compare with '%s'", dev->sysfs_file, temp, dev->sysfs_value);
498                         if (strcmp(dev->sysfs_value, temp) != 0)
499                                 continue;
500
501                         strcpy(attr->name, dev->attr.name);
502                         if (isdigit(class_dev->directory->path[strlen(class_dev->directory->path)-1])) {
503                                 temp[0] = class_dev->directory->path[strlen(class_dev->directory->path)-1];
504                                 temp[1] = 0x00;
505                                 strcat(attr->name, temp);
506                         }
507                         if (dev->attr.mode != 0) {
508                                 attr->mode = dev->attr.mode;
509                                 strcpy(attr->owner, dev->attr.owner);
510                                 strcpy(attr->group, dev->attr.group);
511                         }
512                         dbg("file '%s' with value '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
513                                 dev->sysfs_file, dev->sysfs_value, attr->name, 
514                                 dev->attr.owner, dev->attr.group, dev->attr.mode);
515                         goto done;
516                         break;
517                         }
518                 case NUMBER:
519                         {
520                         char path[SYSFS_PATH_MAX];
521                         char *temp;
522
523                         found = 0;
524                         if (!class_dev->sysdevice)
525                                 continue;
526                         strcpy(path, class_dev->sysdevice->directory->path);
527                         temp = strrchr(path, '/');
528                         dbg("NUMBER path = '%s'", path);
529                         dbg("NUMBER temp = '%s' id = '%s'", temp, dev->id);
530                         if (strstr(temp, dev->id) != NULL) {
531                                 found = 1;
532                         } else {
533                                 *temp = 0x00;
534                                 temp = strrchr(path, '/');
535                                 dbg("NUMBERY temp = '%s' id = '%s'", temp, dev->id);
536                                 if (strstr(temp, dev->id) != NULL)
537                                         found = 1;
538                         }
539                         if (!found)
540                                 continue;
541
542                         strcpy(attr->name, dev->attr.name);
543                         if (dev->attr.mode != 0) {
544                                 attr->mode = dev->attr.mode;
545                                 strcpy(attr->owner, dev->attr.owner);
546                                 strcpy(attr->group, dev->attr.group);
547                         }
548                         dbg("device id '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
549                                 dev->id, attr->name, 
550                                 dev->attr.owner, dev->attr.group, dev->attr.mode);
551                         goto done;
552                         break;
553                         }
554                 case TOPOLOGY:
555                         {
556                         char path[SYSFS_PATH_MAX];
557                         char *temp;
558
559                         if (!class_dev->sysdevice)
560                                 continue;
561                         found = 0;      
562                         strcpy(path, class_dev->sysdevice->directory->path);
563                         temp = strrchr(path, '/');
564                         dbg("TOPOLOGY path = '%s'", path);
565                         dbg("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
566                         if (strstr(temp, dev->place) != NULL) {
567                                 found = 1;
568                         } else {
569                                 *temp = 0x00;
570                                 temp = strrchr(path, '/');
571                                 dbg("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
572                                 if (strstr(temp, dev->place) != NULL)
573                                         found = 1;
574                         }
575                         if (!found)
576                                 continue;
577
578                         strcpy(attr->name, dev->attr.name);
579                         if (dev->attr.mode != 0) {
580                                 attr->mode = dev->attr.mode;
581                                 strcpy(attr->owner, dev->attr.owner);
582                                 strcpy(attr->group, dev->attr.group);
583                         }
584                         dbg("device at '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
585                                 dev->place, attr->name, 
586                                 dev->attr.owner, dev->attr.group, dev->attr.mode);
587                         goto done;
588                         break;
589                         }
590                 case REPLACE:
591                         if (strcmp(dev->kernel_name, class_dev->name) != 0)
592                                 continue;
593                         strcpy(attr->name, dev->attr.name);
594                         if (dev->attr.mode != 0) {
595                                 attr->mode = dev->attr.mode;
596                                 strcpy(attr->owner, dev->attr.owner);
597                                 strcpy(attr->group, dev->attr.group);
598                         }
599                         dbg("'%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
600                                 dev->kernel_name, attr->name, 
601                                 dev->attr.owner, dev->attr.group, dev->attr.mode);
602                         goto done;
603                         break;
604                 case KERNEL_NAME:
605                         break;
606                 default:
607                         dbg("Unknown type of device '%d'", dev->type);
608                         break;
609                 }       
610         }
611         strcpy(attr->name, class_dev->name);
612         
613 done:
614         if (attr->mode == -1) { 
615                 attr->mode = get_default_mode(class_dev);
616                 attr->owner[0] = 0x00;
617                 attr->group[0] = 0x00;
618         }
619         return retval;
620 }
621
622 int namedev_name_device(struct sysfs_class_device *class_dev, struct device_attr *attr)
623 {
624         int retval;
625
626         retval = get_attr(class_dev, attr);
627         if (retval)
628                 dbg("get_attr failed");
629
630         return retval;
631 }
632
633 int namedev_init(void)
634 {
635         int retval;
636         
637         retval = namedev_init_config();
638         if (retval)
639                 return retval;
640
641         retval = namedev_init_permissions();
642         if (retval)
643                 return retval;
644
645         dump_dev_list();
646         return retval;
647 }
648
649