namedev.c 19.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * namedev.c
 *
 * Userspace devfs
 *
 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
 *
 *
 *	This program is free software; you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the
 *	Free Software Foundation version 2 of the License.
 * 
 *	This program is distributed in the hope that it will be useful, but
 *	WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	General Public License for more details.
 * 
 *	You should have received a copy of the GNU General Public License along
 *	with this program; if not, write to the Free Software Foundation, Inc.,
 *	675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

24
25
/* define this to enable parsing debugging */
/* #define DEBUG_PARSER */
26

27
28
29
30
31
32
33
34
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
35
#include <sys/wait.h>
36
37
38
39
40

#include "list.h"
#include "udev.h"
#include "udev_version.h"
#include "namedev.h"
41
#include "libsysfs/libsysfs.h"
42
43
44
45
46

#define TYPE_LABEL	"LABEL"
#define TYPE_NUMBER	"NUMBER"
#define TYPE_TOPOLOGY	"TOPOLOGY"
#define TYPE_REPLACE	"REPLACE"
47
#define TYPE_CALLOUT	"CALLOUT"
48
49
50

static LIST_HEAD(config_device_list);

51
52
53
54
static void dump_dev(struct config_device *dev)
{
	switch (dev->type) {
	case KERNEL_NAME:
55
		dbg_parse("KERNEL name ='%s'"
56
			" owner = '%s', group = '%s', mode = '%#o'",
57
58
			dev->attr.name, 
			dev->attr.owner, dev->attr.group, dev->attr.mode);
59
60
		break;
	case LABEL:
61
		dbg_parse("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'"
62
			" owner = '%s', group = '%s', mode = '%#o'",
63
64
			dev->attr.name, dev->bus, dev->sysfs_file, dev->sysfs_value,
			dev->attr.owner, dev->attr.group, dev->attr.mode);
65
66
		break;
	case NUMBER:
67
		dbg_parse("NUMBER name = '%s', bus = '%s', id = '%s'"
68
			" owner = '%s', group = '%s', mode = '%#o'",
69
70
			dev->attr.name, dev->bus, dev->id,
			dev->attr.owner, dev->attr.group, dev->attr.mode);
71
72
		break;
	case TOPOLOGY:
73
		dbg_parse("TOPOLOGY name = '%s', bus = '%s', place = '%s'"
74
			" owner = '%s', group = '%s', mode = '%#o'",
75
76
			dev->attr.name, dev->bus, dev->place,
			dev->attr.owner, dev->attr.group, dev->attr.mode);
77
78
		break;
	case REPLACE:
79
		dbg_parse("REPLACE name = %s, kernel_name = %s"
80
			" owner = '%s', group = '%s', mode = '%#o'",
81
82
			dev->attr.name, dev->kernel_name,
			dev->attr.owner, dev->attr.group, dev->attr.mode);
83
		break;
84
	case CALLOUT:
85
		dbg_parse("CALLOUT name = '%s', program ='%s', bus = '%s', id = '%s'"
86
87
88
89
			" owner = '%s', group = '%s', mode = '%#o'",
			dev->attr.name, dev->exec_program, dev->bus, dev->id,
			dev->attr.owner, dev->attr.group, dev->attr.mode);
		break;
90
	default:
91
		dbg_parse("Unknown type of device!");
92
93
94
	}
}

95
96
#define copy_var(a, b, var)		\
	if (b->var)			\
97
		a->var = b->var;
98
99
100

#define copy_string(a, b, var)		\
	if (strlen(b->var))		\
101
		strcpy(a->var, b->var);
102
103
104
105
106
107
108
109
110
111

static int add_dev(struct config_device *new_dev)
{
	struct list_head *tmp;
	struct config_device *tmp_dev;

	/* loop through the whole list of devices to see if we already have
	 * this one... */
	list_for_each(tmp, &config_device_list) {
		struct config_device *dev = list_entry(tmp, struct config_device, node);
112
		if (strcmp(dev->attr.name, new_dev->attr.name) == 0) {
113
			/* the same, copy the new info into this structure */
114
			copy_var(dev, new_dev, type);
115
			copy_var(dev, new_dev, attr.mode);
116
117
118
119
120
121
			copy_string(dev, new_dev, bus);
			copy_string(dev, new_dev, sysfs_file);
			copy_string(dev, new_dev, sysfs_value);
			copy_string(dev, new_dev, id);
			copy_string(dev, new_dev, place);
			copy_string(dev, new_dev, kernel_name);
122
123
			copy_string(dev, new_dev, attr.owner);
			copy_string(dev, new_dev, attr.group);
124
125
126
127
128
129
130
131
132
133
			return 0;
		}
	}

	/* not found, lets create a new structure, and add it to the list */
	tmp_dev = malloc(sizeof(*tmp_dev));
	if (!tmp_dev)
		return -ENOMEM;
	memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
	list_add(&tmp_dev->node, &config_device_list);
134
	//dump_dev(tmp_dev);
135
136
137
	return 0;
}

138
139
140
141
142
143
144
145
146
147
static void dump_dev_list(void)
{
	struct list_head *tmp;

	list_for_each(tmp, &config_device_list) {
		struct config_device *dev = list_entry(tmp, struct config_device, node);
		dump_dev(dev);
	}
}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
static int get_value(const char *left, char **orig_string, char **ret_string)
{
	char *temp;
	char *string = *orig_string;

	/* eat any whitespace */
	while (isspace(*string))
		++string;

	/* split based on '=' */
	temp = strsep(&string, "=");
	if (strcasecmp(temp, left) == 0) {
		/* got it, now strip off the '"' */
		while (isspace(*string))
			++string;
		if (*string == '"')
			++string;
		temp = strsep(&string, "\"");
		*ret_string = temp;
		*orig_string = string;
		return 0;
	}
	return -ENODEV;
}
	
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
static int get_pair(char **orig_string, char **left, char **right)
{
	char *temp;
	char *string = *orig_string;

	/* eat any whitespace */
	while (isspace(*string))
		++string;

	/* split based on '=' */
	temp = strsep(&string, "=");
	*left = temp;

	/* take the right side and strip off the '"' */
	while (isspace(*string))
		++string;
	if (*string == '"')
		++string;
	temp = strsep(&string, "\"");
	*right = temp;
	*orig_string = string;
	
	return 0;
}
197
198
199
200
201
202
203
204
205
206
207

static int namedev_init_config(void)
{
	char line[255];
	char *temp;
	char *temp2;
	char *temp3;
	FILE *fd;
	int retval = 0;
	struct config_device dev;

208
	dbg("opening %s to read as config", udev_config_filename);
209
	fd = fopen(udev_config_filename, "r");
210
	if (fd == NULL) {
211
		dbg("Can't open %s", udev_config_filename);
212
213
214
215
216
217
218
219
220
221
		return -ENODEV;
	}

	/* loop through the whole file */
	while (1) {
		/* get a line */
		temp = fgets(line, sizeof(line), fd);
		if (temp == NULL)
			break;

222
		dbg_parse("read %s", temp);
223
224
225
226
227
228
229
230
231
232
233
234
235

		/* eat the whitespace at the beginning of the line */
		while (isspace(*temp))
			++temp;

		/* no more line? */
		if (*temp == 0x00)
			continue;

		/* see if this is a comment */
		if (*temp == COMMENT_CHARACTER)
			continue;

236
		memset(&dev, 0x00, sizeof(struct config_device));
237
238
239
240
241
242
243
244
245
246
247
248

		/* parse the line */
		temp2 = strsep(&temp, ",");
		if (strcasecmp(temp2, TYPE_LABEL) == 0) {
			/* label type */
			dev.type = LABEL;

			/* BUS="bus" */
			retval = get_value("BUS", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.bus, temp3);
249
250
251
252
253
254
255
256
257
258
259
260
261
262

			/* file="value" */
			temp2 = strsep(&temp, ",");
			retval = get_pair(&temp, &temp2, &temp3);
			if (retval)
				continue;
			strcpy(dev.sysfs_file, temp2);
			strcpy(dev.sysfs_value, temp3);

			/* NAME="new_name" */
			temp2 = strsep(&temp, ",");
			retval = get_value("NAME", &temp, &temp3);
			if (retval)
				continue;
263
			strcpy(dev.attr.name, temp3);
264

265
266
267
268
			dbg_parse("LABEL name = '%s', bus = '%s', "
				"sysfs_file = '%s', sysfs_value = '%s'", 
				dev.attr.name, dev.bus, dev.sysfs_file, 
				dev.sysfs_value);
269
270
271
272
273
274
275
276
277
278
279
		}

		if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
			/* number type */
			dev.type = NUMBER;

			/* BUS="bus" */
			retval = get_value("BUS", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.bus, temp3);
280
281
282
283
284
285
286
287
288
289
290
291
292

			/* ID="id" */
			temp2 = strsep(&temp, ",");
			retval = get_value("id", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.id, temp3);

			/* NAME="new_name" */
			temp2 = strsep(&temp, ",");
			retval = get_value("NAME", &temp, &temp3);
			if (retval)
				continue;
293
			strcpy(dev.attr.name, temp3);
294

295
296
			dbg_parse("NUMBER name = '%s', bus = '%s', id = '%s'",
					dev.attr.name, dev.bus, dev.id);
297
298
299
300
301
302
303
304
305
306
307
		}

		if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
			/* number type */
			dev.type = TOPOLOGY;

			/* BUS="bus" */
			retval = get_value("BUS", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.bus, temp3);
308
309
310
311
312
313
314
315
316
317
318
319
320

			/* PLACE="place" */
			temp2 = strsep(&temp, ",");
			retval = get_value("place", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.place, temp3);

			/* NAME="new_name" */
			temp2 = strsep(&temp, ",");
			retval = get_value("NAME", &temp, &temp3);
			if (retval)
				continue;
321
			strcpy(dev.attr.name, temp3);
322

323
324
			dbg_parse("TOPOLOGY name = '%s', bus = '%s', place = '%s'",
					dev.attr.name, dev.bus, dev.place);
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
		}

		if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
			/* number type */
			dev.type = REPLACE;

			/* KERNEL="kernel_name" */
			retval = get_value("KERNEL", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.kernel_name, temp3);

			/* NAME="new_name" */
			temp2 = strsep(&temp, ",");
			retval = get_value("NAME", &temp, &temp3);
			if (retval)
				continue;
342
			strcpy(dev.attr.name, temp3);
343
344
			dbg_parse("REPLACE name = %s, kernel_name = %s",
					dev.attr.name, dev.kernel_name);
345
		}
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
		if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
			/* number type */
			dev.type = CALLOUT;

			/* PROGRAM="executable" */
			retval = get_value("PROGRAM", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.exec_program, temp3);

			/* BUS="bus" */
			temp2 = strsep(&temp, ",");
			retval = get_value("BUS", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.bus, temp3);

			/* ID="id" */
			temp2 = strsep(&temp, ",");
			retval = get_value("ID", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.id, temp3);

			/* NAME="new_name" */
			temp2 = strsep(&temp, ",");
			retval = get_value("NAME", &temp, &temp3);
			if (retval)
				continue;
			strcpy(dev.attr.name, temp3);
376
377
			dbg_parse("CALLOUT name = %s, program = %s",
					dev.attr.name, dev.exec_program);
378
		}
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

		retval = add_dev(&dev);
		if (retval) {
			dbg("add_dev returned with error %d", retval);
			goto exit;
		}
	}

exit:
	fclose(fd);
	return retval;
}	


static int namedev_init_permissions(void)
{
	char line[255];
	char *temp;
	char *temp2;
	FILE *fd;
	int retval = 0;
	struct config_device dev;

402
403
	dbg("opening %s to read as permissions config", udev_config_permission_filename);
	fd = fopen(udev_config_permission_filename, "r");
404
	if (fd == NULL) {
405
		dbg("Can't open %s", udev_config_permission_filename);
406
407
408
409
410
411
412
413
414
415
		return -ENODEV;
	}

	/* loop through the whole file */
	while (1) {
		/* get a line */
		temp = fgets(line, sizeof(line), fd);
		if (temp == NULL)
			break;

416
		dbg_parse("read %s", temp);
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433

		/* eat the whitespace at the beginning of the line */
		while (isspace(*temp))
			++temp;

		/* no more line? */
		if (*temp == 0x00)
			continue;

		/* see if this is a comment */
		if (*temp == COMMENT_CHARACTER)
			continue;

		memset(&dev, 0x00, sizeof(dev));

		/* parse the line */
		temp2 = strsep(&temp, ":");
434
		strncpy(dev.attr.name, temp2, sizeof(dev.attr.name));
435
436

		temp2 = strsep(&temp, ":");
437
		strncpy(dev.attr.owner, temp2, sizeof(dev.attr.owner));
438
439

		temp2 = strsep(&temp, ":");
440
		strncpy(dev.attr.group, temp2, sizeof(dev.attr.owner));
441

442
		dev.attr.mode = strtol(temp, NULL, 8);
443

444
		dbg_parse("name = %s, owner = %s, group = %s, mode = %#o",
445
446
				dev.attr.name, dev.attr.owner, dev.attr.group,
				dev.attr.mode);
447
448
449
450
451
452
453
454
455
456
457
458
		retval = add_dev(&dev);
		if (retval) {
			dbg("add_dev returned with error %d", retval);
			goto exit;
		}
	}

exit:
	fclose(fd);
	return retval;
}	

459
static mode_t get_default_mode(struct sysfs_class_device *class_dev)
460
{
461
462
	/* just default everyone to rw for the world! */
	return 0666;
463
464
}

465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
static int exec_callout(struct config_device *dev, char *value, int len)
{
	int retval;
	int res;
	int status;
	int fds[2];
	pid_t pid;
	int value_set = 0;
	char buffer[256];

	dbg("callout to %s\n", dev->exec_program);
	retval = pipe(fds);
	if (retval != 0) {
		dbg("pipe failed");
		return -1;
	}
	pid = fork();
	if (pid == -1) {
		dbg("fork failed");
		return -1;
	}

	if (pid == 0) {
		/*
		 * child 
		 */
		close(STDOUT_FILENO);
		dup(fds[1]);	/* dup write side of pipe to STDOUT */
		retval = execve(dev->exec_program, main_argv, main_envp);
		if (retval != 0) {
			dbg("child execve failed");
			exit(1);
		}
		return -1; /* avoid compiler warning */
	} else {
		/*
		 * Parent reads from fds[0].
		 */
		close(fds[1]);
		retval = 0;
		while (1) {
			res = read(fds[0], buffer, sizeof(buffer) - 1);
			if (res <= 0)
				break;
			buffer[res] = '\0';
			if (res > len) {
				dbg("callout len %d too short\n", len);
				retval = -1;
			}
			if (value_set) {
				dbg("callout value already set");
				retval = -1;
			} else {
				value_set = 1;
				strncpy(value, buffer, len);
			}
		}
		close(fds[0]);
		res = wait(&status);
		if (res < 0) {
			dbg("wait failed result %d", res);
			retval = -1;
		}

		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
			dbg("callout program status 0x%x", status);
			retval = -1;
		}
	}
	return retval;
}

538
539
540
541
static int get_attr(struct sysfs_class_device *class_dev, struct device_attr *attr)
{
	struct list_head *tmp;
	int retval = 0;
542
	int found;
543

544
	attr->mode = 0;
545
	if (class_dev->sysdevice) {
546
		dbg_parse("class_dev->sysdevice->path = '%s'", class_dev->sysdevice->path);
547
		dbg_parse("class_dev->sysdevice->bus_id = '%s'", class_dev->sysdevice->bus_id);
548
	} else {
549
		dbg_parse("class_dev->name = '%s'", class_dev->name);
550
	}
551
552
	list_for_each(tmp, &config_device_list) {
		struct config_device *dev = list_entry(tmp, struct config_device, node);
553
554
		switch (dev->type) {
		case LABEL:
555
			{
556
557
558
			struct sysfs_attribute *tmpattr = NULL;
			struct sysfs_class_device *class_dev_parent = NULL;
			char *temp = NULL;
559

560
561
			dbg_parse("LABEL: match file '%s' with value '%s'",
					dev->sysfs_file, dev->sysfs_value);
562
			/* try to find the attribute in the class device directory */
563
564
			tmpattr = sysfs_get_classdev_attr(class_dev, dev->sysfs_file);
			if (tmpattr)
565
566
567
568
				goto label_found;

			/* look in the class device device directory if present */
			if (class_dev->sysdevice) {
569
570
				tmpattr = sysfs_get_classdev_attr(class_dev, dev->sysfs_file);
				if (tmpattr)
571
572
573
574
575
576
577
					goto label_found;
			}

			/* bah, let's go backwards up a level to see if the device is there,
			 * as block partitions don't point to the physical device.  Need to fix that
			 * up in the kernel...
			 */
578
			if (strstr(class_dev->path, "block")) {
579
				dbg_parse("looking at block device...");
580
				if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
581
582
					char path[SYSFS_PATH_MAX];

583
					dbg_parse("really is a partition...");
584
					strcpy(path, class_dev->path);
585
586
					temp = strrchr(path, '/');
					*temp = 0x00;
587
					dbg_parse("looking for a class device at '%s'", path);
588
589
					class_dev_parent = sysfs_open_class_device(path);
					if (class_dev_parent == NULL) {
590
						dbg("sysfs_open_class_device at '%s' failed", path);
591
592
						continue;
					}
593
					dbg_parse("class_dev_parent->name = %s", class_dev_parent->name);
594
595

					/* try to find the attribute in the class device directory */
596
597
					tmpattr = sysfs_get_classdev_attr(class_dev_parent, dev->sysfs_file);
					if (tmpattr) 
598
599
600
601
						goto label_found;

					/* look in the class device device directory if present */
					if (class_dev_parent->sysdevice) {
602
603
						tmpattr = sysfs_get_classdev_attr(class_dev_parent, dev->sysfs_file);
						if (tmpattr) 
604
605
606
607
608
							goto label_found;
					}
					
				}
			}
609
610
611
			if (class_dev_parent)
				sysfs_close_class_device(class_dev_parent);

612
			continue;
613

614
label_found:
615
616
617
618
619
			tmpattr->value[strlen(tmpattr->value)-1] = 0x00;
			dbg_parse("file '%s' found with value '%s' compare with '%s'", dev->sysfs_file, tmpattr->value, dev->sysfs_value);
			if (strcmp(dev->sysfs_value, tmpattr->value) != 0) {
				if (class_dev_parent) 
					sysfs_close_class_device(class_dev_parent);
620
				continue;
621
			}
622
623

			strcpy(attr->name, dev->attr.name);
624
625
			if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
				temp = &class_dev->path[strlen(class_dev->path)-1];
626
627
628
629
630
631
632
				strcat(attr->name, temp);
			}
			if (dev->attr.mode != 0) {
				attr->mode = dev->attr.mode;
				strcpy(attr->owner, dev->attr.owner);
				strcpy(attr->group, dev->attr.group);
			}
633
			dbg_parse("file '%s' with value '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
634
635
				dev->sysfs_file, dev->sysfs_value, attr->name, 
				dev->attr.owner, dev->attr.group, dev->attr.mode);
636
637
			if (class_dev_parent)
				sysfs_close_class_device(class_dev_parent);
638
			goto done;
639
			break;
640
			}
641
		case NUMBER:
642
643
644
645
			{
			char path[SYSFS_PATH_MAX];
			char *temp;

646
647
648
			found = 0;
			if (!class_dev->sysdevice)
				continue;
649
			strcpy(path, class_dev->sysdevice->path);
650
			temp = strrchr(path, '/');
651
652
			dbg_parse("NUMBER path = '%s'", path);
			dbg_parse("NUMBER temp = '%s' id = '%s'", temp, dev->id);
653
654
655
656
657
			if (strstr(temp, dev->id) != NULL) {
				found = 1;
			} else {
				*temp = 0x00;
				temp = strrchr(path, '/');
658
				dbg_parse("NUMBERY temp = '%s' id = '%s'", temp, dev->id);
659
660
661
662
663
664
665
				if (strstr(temp, dev->id) != NULL)
					found = 1;
			}
			if (!found)
				continue;

			strcpy(attr->name, dev->attr.name);
666
667
668
669
670
			if (dev->attr.mode != 0) {
				attr->mode = dev->attr.mode;
				strcpy(attr->owner, dev->attr.owner);
				strcpy(attr->group, dev->attr.group);
			}
671
			dbg_parse("device id '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
672
				dev->id, attr->name, 
673
				dev->attr.owner, dev->attr.group, dev->attr.mode);
674
			goto done;
675
			break;
676
			}
677
		case TOPOLOGY:
678
679
680
681
			{
			char path[SYSFS_PATH_MAX];
			char *temp;

682
683
			if (!class_dev->sysdevice)
				continue;
684
			found = 0;	
685
			strcpy(path, class_dev->sysdevice->path);
686
			temp = strrchr(path, '/');
687
688
			dbg_parse("TOPOLOGY path = '%s'", path);
			dbg_parse("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
689
690
691
692
693
			if (strstr(temp, dev->place) != NULL) {
				found = 1;
			} else {
				*temp = 0x00;
				temp = strrchr(path, '/');
694
				dbg_parse("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
695
696
697
698
699
700
701
				if (strstr(temp, dev->place) != NULL)
					found = 1;
			}
			if (!found)
				continue;

			strcpy(attr->name, dev->attr.name);
702
703
704
705
706
			if (dev->attr.mode != 0) {
				attr->mode = dev->attr.mode;
				strcpy(attr->owner, dev->attr.owner);
				strcpy(attr->group, dev->attr.group);
			}
707
			dbg_parse("device at '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
708
				dev->place, attr->name, 
709
				dev->attr.owner, dev->attr.group, dev->attr.mode);
710
			goto done;
711
			break;
712
			}
713
714
715
716
717
718
719
720
721
722
723
724
725
726
		case CALLOUT:
			{
			char value[ID_SIZE];

			if (exec_callout(dev, value, sizeof(value)))
				continue;
			if (strncmp(value, dev->id, sizeof(value)) != 0)
				continue;
			strcpy(attr->name, dev->attr.name);
			if (dev->attr.mode != 0) {
				attr->mode = dev->attr.mode;
				strcpy(attr->owner, dev->attr.owner);
				strcpy(attr->group, dev->attr.group);
			}
727
			dbg_parse("device callout '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
728
729
730
731
732
				dev->id, attr->name, 
				dev->attr.owner, dev->attr.group, dev->attr.mode);
			goto done;
			break;
			}
733
734
735
736
		case REPLACE:
			if (strcmp(dev->kernel_name, class_dev->name) != 0)
				continue;
			strcpy(attr->name, dev->attr.name);
737
738
739
740
741
			if (dev->attr.mode != 0) {
				attr->mode = dev->attr.mode;
				strcpy(attr->owner, dev->attr.owner);
				strcpy(attr->group, dev->attr.group);
			}
742
			dbg_parse("'%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
743
744
				dev->kernel_name, attr->name, 
				dev->attr.owner, dev->attr.group, dev->attr.mode);
745
			goto done;
746
			break;
747
748
		case KERNEL_NAME:
			break;
749
		default:
750
			dbg_parse("Unknown type of device '%d'", dev->type);
751
752
			break;
		}	
753
754
	}
	strcpy(attr->name, class_dev->name);
755

756
done:
757
758
	/* mode was never set above */
	if (!attr->mode) {
759
760
761
762
		attr->mode = get_default_mode(class_dev);
		attr->owner[0] = 0x00;
		attr->group[0] = 0x00;
	}
763
764
765
	return retval;
}

766
int namedev_name_device(struct sysfs_class_device *class_dev, struct device_attr *attr)
767
768
769
770
{
	int retval;

	retval = get_attr(class_dev, attr);
771
772
773
	if (retval)
		dbg("get_attr failed");

774
775
	return retval;
}
776
777
778
779

int namedev_init(void)
{
	int retval;
780
	
781
782
783
784
785
786
787
788
	retval = namedev_init_config();
	if (retval)
		return retval;

	retval = namedev_init_permissions();
	if (retval)
		return retval;

789
	dump_dev_list();
790
791
792
	return retval;
}

793