xref: /minix/minix/commands/devmand/main.c (revision fb9c64b2)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <getopt.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <lib.h>
7 #include <sys/stat.h>
8 #include <dirent.h>
9 #include <assert.h>
10 #include <signal.h>
11 #include <minix/dmap.h>
12 #include <minix/paths.h>
13 #include "usb_driver.h"
14 #include "proto.h"
15 
16 #define DEVMAN_TYPE_NAME "dev_type"
17 #define PATH_LEN 256
18 #define INVAL_MAJOR -1
19 #define MAX_CONFIG_DIRS 4
20 
21 static void main_loop();
22 static void handle_event();
23 static void cleanup();
24 static void parse_config();
25 static void display_usage();
26 static enum dev_type determine_type(char *path);
27 static int get_major();
28 static void create_pid_file();
29 static void put_major(int major);
30 static struct devmand_usb_driver* match_usb_driver(struct usb_device_id *id);
31 static struct devmand_driver_instance *find_instance(int dev_id);
32 
33 #define dbg(fmt, ... ) \
34 	if (args.verbose) \
35 	printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__,  ##__VA_ARGS__ )
36 
37 static LIST_HEAD(usb_driver_head, devmand_usb_driver) drivers =
38     LIST_HEAD_INITIALIZER(drivers);
39 static LIST_HEAD(usb_driver_inst_head, devmand_driver_instance) instances =
40     LIST_HEAD_INITIALIZER(instances);
41 
42 
43 static int _run = 1;
44 struct global_args {
45 	char *path;
46 	char *config_dirs[MAX_CONFIG_DIRS];
47 	int config_dir_count ;
48 	int major_offset;
49 	int verbose;
50 	int check_config;
51 };
52 
53 enum dev_type {
54 	DEV_TYPE_USB_DEVICE,
55 	DEV_TYPE_USB_INTF,
56 	DEV_TYPE_UNKOWN
57 };
58 
59 extern FILE *yyin;
60 
61 static struct global_args args = {
62 	.path = NULL,
63 	.config_dirs = {NULL,NULL,NULL,NULL},
64 	.config_dir_count = 0,
65 	.major_offset = USB_BASE_MAJOR,
66 	.verbose = 0,
67 	.check_config = 0};
68 
69 static struct option options[] =
70 {
71 	{"dir"   ,    required_argument, NULL, 'd'},
72 	{"path",      required_argument, NULL, 'p'},
73 	{"verbose",    required_argument, NULL, 'v'},
74 	{"check-config", no_argument,       NULL, 'x'},
75 	{0,0,0,0} /* terminating entry */
76 };
77 
78 static char major_bitmap[16]; /* can store up to 128 major number states */
79 
80 
81 /*===========================================================================*
82  *             run_upscript                                                  *
83  *===========================================================================*/
84 int run_upscript(struct devmand_driver_instance *inst)
85 {
86 	char cmdl[1024];
87 	cmdl[0] = 0;
88 	int ret;
89 
90 	assert(inst->drv->upscript);
91 	assert(inst->label);
92 
93 	snprintf(cmdl, 1024, "%s up %s %d %d",
94 	    inst->drv->upscript, inst->label, inst->major, inst->dev_id);
95 	dbg("Running Upscript:  \"%s\"", cmdl);
96 	ret = system(cmdl);
97 	if (ret != 0) {
98 		return EINVAL;
99 	}
100 	return 0;
101 }
102 
103 /*===========================================================================*
104  *             run_cleanscript                                               *
105  *===========================================================================*/
106 int run_cleanscript(struct devmand_usb_driver *drv)
107 {
108 	char cmdl[1024];
109 	cmdl[0] = 0;
110 	int ret;
111 
112 	assert(drv->upscript);
113 	assert(drv->devprefix);
114 
115 	snprintf(cmdl, 1024, "%s clean %s ",
116 		drv->upscript, drv->devprefix);
117 	dbg("Running Upscript:  \"%s\"", cmdl);
118 	ret = system(cmdl);
119 
120 	if (ret != 0) {
121 		return EINVAL;
122 	}
123 
124 	return 0;
125 }
126 
127 
128 /*===========================================================================*
129  *             run_downscript                                                *
130  *===========================================================================*/
131 int run_downscript(struct devmand_driver_instance *inst)
132 {
133 	char cmdl[1024];
134 	cmdl[0] = 0;
135 	int ret;
136 
137 	assert(inst->drv->downscript);
138 	assert(inst->label);
139 
140 	snprintf(cmdl, 1024, "%s down %s %d",
141 	    inst->drv->downscript, inst->label, inst->major);
142 
143 	dbg("Running Upscript:  \"%s\"", cmdl);
144 
145 	ret = system(cmdl);
146 
147 	if (ret != 0) {
148 		return EINVAL;
149 	}
150 
151 	return 0;
152 }
153 
154 
155 /*===========================================================================*
156  *             stop_driver                                                   *
157  *===========================================================================*/
158 int stop_driver(struct devmand_driver_instance *inst)
159 {
160 	char cmdl[1024];
161 	cmdl[0] = 0;
162 	int ret;
163 
164 	assert(inst->label);
165 
166 	snprintf(cmdl, 1024, "%s down %s %d",
167 	    _PATH_MINIX_SERVICE, inst->label, inst->dev_id);
168 	dbg("executing minix-service: \"%s\"", cmdl);
169 	ret = system(cmdl);
170 	if (ret != 0)
171 	{
172 		return EINVAL;
173 	}
174 	printf("Stopped driver %s with label %s for device %d.\n",
175 		inst->drv->binary, inst->label, inst->dev_id);
176 
177 	return 0;
178 }
179 
180 
181 /*===========================================================================*
182  *             start_driver                                                  *
183  *===========================================================================*/
184 int start_driver(struct devmand_driver_instance *inst)
185 {
186 	char cmdl[1024];
187 	cmdl[0] = 0;
188 	int ret;
189 
190 	/* generate label */
191 	ret = snprintf(inst->label, 32,  "%s%d", inst->drv->devprefix,
192 		inst->dev_id);
193 	if (ret < 0 || ret > DEVMAND_DRIVER_LABEL_LEN) {
194 		dbg("label too long");
195 		return ENOMEM;
196 	}
197 
198 	assert(inst->drv->binary);
199 	assert(inst->label);
200 
201 	snprintf(cmdl, 1024, "%s up %s  -major %d -devid %d -label %s",
202 	    _PATH_MINIX_SERVICE, inst->drv->binary, inst->major, inst->dev_id,
203 		inst->label);
204 	dbg("executing minix-service: \"%s\"", cmdl);
205 
206 	ret = system(cmdl);
207 
208 	if (ret != 0) {
209 		return EINVAL;
210 	}
211 
212 	printf("Started driver %s with label %s for device %d.\n",
213 		inst->drv->binary, inst->label, inst->dev_id);
214 
215 	return 0;
216 }
217 
218 /*===========================================================================*
219  *             find_instance                                                 *
220  *===========================================================================*/
221 static struct devmand_driver_instance *
222 find_instance(int dev_id)
223 {
224 	struct devmand_driver_instance *inst;
225 
226 	LIST_FOREACH(inst, &instances, list) {
227 		if (inst->dev_id == dev_id) {
228 			return inst;
229 		}
230 	}
231 	return NULL;
232 }
233 
234 /*===========================================================================*
235  *              match_usb_driver                                             *
236  *===========================================================================*/
237 static int
238 match_usb_id(struct devmand_usb_match_id *mid, struct usb_device_id *id)
239 {
240 	int res = 1;
241 	unsigned long match = mid->match_flags;
242 	struct usb_device_id *_id = &mid->match_id;
243 
244 	if (match & USB_MATCH_ID_VENDOR)
245 		if (id->idVendor != _id->idVendor) res = 0;
246 	if (match & USB_MATCH_ID_PRODUCT)
247 		if (id->idProduct != _id->idProduct) res = 0;
248 	if (match & USB_MATCH_BCD_DEVICE)
249 		if (id->bcdDevice != _id->bcdDevice) res = 0;
250 	if (match & USB_MATCH_DEVICE_PROTOCOL)
251 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
252 	if (match & USB_MATCH_DEVICE_SUBCLASS)
253 		if (id->bDeviceSubClass != _id->bDeviceSubClass) res = 0;
254 	if (match & USB_MATCH_DEVICE_PROTOCOL)
255 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
256 	if (match & USB_MATCH_INTERFACE_CLASS)
257 		if (id->bInterfaceClass != _id->bInterfaceClass) res = 0;
258 	if (match & USB_MATCH_INTERFACE_SUBCLASS)
259 		if (id->bInterfaceSubClass != _id->bInterfaceSubClass) res = 0;
260 	if (match & USB_MATCH_INTERFACE_PROTOCOL)
261 		if (id->bInterfaceProtocol != _id->bInterfaceProtocol) res = 0;
262 
263 	if (match == 0UL) {
264 		res = 0;
265 	}
266 
267 	return res;
268 }
269 
270 /*===========================================================================*
271  *              match_usb_driver                                             *
272  *===========================================================================*/
273 static struct devmand_usb_driver*
274 match_usb_driver(struct usb_device_id *id)
275 {
276 	struct devmand_usb_driver *driver;
277 	struct devmand_usb_match_id *mid;
278 
279 	LIST_FOREACH(driver, &drivers, list) {
280 		LIST_FOREACH(mid, &driver->ids, list) {
281 			if (match_usb_id(mid, id)) {
282 				return driver;
283 			}
284 		}
285 	}
286 	return NULL;
287 }
288 
289 /*===========================================================================*
290  *              add_usb_match_id                                             *
291  *===========================================================================*/
292 struct devmand_usb_driver * add_usb_driver(char *name)
293 {
294 	struct devmand_usb_driver *udrv = (struct devmand_usb_driver*)
295 	    malloc(sizeof(struct devmand_usb_driver));
296 
297 	LIST_INSERT_HEAD(&drivers, udrv, list);
298 	LIST_INIT(&udrv->ids);
299 
300 	udrv->name = name;
301 	return udrv;
302 }
303 
304 /*===========================================================================*
305  *              add_usb_match_id                                             *
306  *===========================================================================*/
307 struct devmand_usb_match_id *
308 add_usb_match_id
309 (struct devmand_usb_driver *drv)
310 {
311 	struct devmand_usb_match_id *id = (struct devmand_usb_match_id*)
312 	    malloc(sizeof(struct devmand_usb_match_id));
313 
314 	memset(id, 0, sizeof(struct devmand_usb_match_id));
315 
316 	LIST_INSERT_HEAD(&drv->ids, id, list);
317 
318 	return id;
319 }
320 
321 
322 /*===========================================================================*
323  *           parse_config                                                    *
324  *===========================================================================*/
325 static void parse_config()
326 {
327 	int i, status, error;
328 	struct stat stats;
329 	char * dirname;
330 
331 	DIR * dir;
332 	struct dirent entry;
333 	struct dirent *result;
334 	char config_file[PATH_MAX];
335 
336 	dbg("Parsing configuration directories... ");
337 	/* Next parse the configuration directories */
338 	for(i=0; i < args.config_dir_count; i++){
339 		dirname = args.config_dirs[i];
340 		dbg("Parsing config dir %s ", dirname);
341 		status = stat(dirname,&stats);
342 		if (status == -1){
343 			error = errno;
344 			dbg("Failed to read directory '%s':%s (skipping) \n",
345 			    dirname,strerror(error));
346 			continue;
347 		}
348 		if (!S_ISDIR(stats.st_mode)){
349 			dbg("Parse configuration skipping %s "
350 			    "(not a directory) \n",dirname);
351 			continue;
352 		}
353 		dir = opendir(dirname);
354 		if (dir == NULL){
355 			error = errno;
356 			dbg("Parse configuration failed to read dir '%s'"
357 			    "(skipping) :%s\n",dirname, strerror(error));
358 			continue;
359 		}
360 		while( (status = readdir_r(dir,&entry,&result)) == 0 ){
361 			if (result == NULL){ /* last entry */
362 				closedir(dir);
363 				break;
364 			}
365 
366 			/* concatenate dir and file name to open it */
367 			snprintf(config_file,PATH_MAX, "%s/%s",
368 				 dirname,entry.d_name);
369 			status = stat(config_file, &stats);
370 			if (status == -1){
371 				error = errno;
372 				dbg("Parse configuration Failed to stat file "
373 				    "'%s': %s (skipping)\n", config_file,
374 				    strerror(error));
375 			}
376 			if (S_ISREG(stats.st_mode)){
377 				dbg("Parsing file %s",config_file);
378 				yyin = fopen(config_file, "r");
379 
380 				if (yyin == NULL) {
381 					dbg("Can not open config file:"
382 				 	       " %d.\n", errno);
383 				}
384 				yyparse();
385 				dbg("Done.");
386 				fclose(yyin);
387 			}
388 		}
389 	}
390 	dbg("Parsing configuration directories done... ");
391 
392 }
393 
394 /*===========================================================================*
395  *           cleanup                                                        *
396  *===========================================================================*/
397 static void cleanup() {
398 	struct devmand_driver_instance *inst;
399 	/* destroy fifo */
400 	dbg("cleaning up... ");
401 	/* quit all running drivers */
402 	LIST_FOREACH(inst, &instances, list) {
403 		dbg("stopping driver %s", inst->label);
404 		if(inst->drv->downscript) {
405 			run_downscript (inst);
406 		}
407 		stop_driver(inst);
408 	}
409 	unlink("/var/run/devmand.pid");
410 }
411 
412 static void sig_int(int sig) {
413 	dbg("devman: Received SIGINT... cleaning up.");
414 	_run = 0;
415 }
416 
417 /*===========================================================================*
418  *           create_pid_file                                                 *
419  *===========================================================================*/
420 void create_pid_file()
421 {
422 	FILE *fd;
423 
424 	fd = fopen("/var/run/devmand.pid", "r");
425 	if(fd) {
426 		fprintf(stderr, "devmand: /var/run/devmand.pid exists... "
427 		                "another devmand running?\n");
428 		fclose(fd);
429 		exit(1);
430 	} else {
431 		fd = fopen("/var/run/devmand.pid","w");
432 		fprintf(fd, "%d", getpid());
433 		fclose(fd);
434 	}
435 }
436 
437 /*===========================================================================*
438  *           main                                                            *
439  *===========================================================================*/
440 int main(int argc, char *argv[])
441 {
442 	int opt, optindex;
443 	struct devmand_usb_driver *driver;
444 
445 
446 	/* get command line arguments */
447 	while ((opt = getopt_long(argc, argv, "d:p:vxh?", options, &optindex))
448 			!= -1) {
449 		switch (opt) {
450 			case 'd':/* config directory */
451 				if (args.config_dir_count >= MAX_CONFIG_DIRS){
452 				 	fprintf(stderr,"Parse arguments: Maximum"
453 					        " of %i configuration directories"
454 						" reached skipping directory '%s'\n"
455 						, MAX_CONFIG_DIRS, optarg);
456 				 	break;
457 				}
458 				args.config_dirs[args.config_dir_count] = optarg;
459 				args.config_dir_count++;
460 				break;
461 			case 'p': /* sysfs path */
462 				args.path = optarg;
463 				break;
464 			case 'v': /* verbose */
465 				args.verbose = 1;
466 				break;
467 			case 'x': /* check config */
468 				args.check_config = 1;
469 				break;
470 			case 'h': /* help */
471 			case '?': /* help */
472 			default:
473 				display_usage(argv[0]);
474 				return 0;
475 		}
476 	}
477 
478 
479 	/* is path set? */
480 	if (args.path == NULL) {
481 		args.path = "/sys/";
482 	}
483 
484 	/* is the configuration directory set? */
485 	if (args.config_dir_count == 0) {
486 		dbg("Using default configuration directory");
487 		args.config_dirs[0] = "/etc/devmand";
488 		args.config_dir_count = 1;
489 	}
490 
491 	/* If we only check the configuration run and exit imediately */
492 	if (args.check_config == 1){
493 		fprintf(stdout, "Only parsing configuration\n");
494 		parse_config();
495 		exit(0);
496 	}
497 
498 	create_pid_file();
499 
500 	parse_config();
501 	LIST_FOREACH(driver, &drivers, list) {
502 		if (driver->upscript) {
503 			run_cleanscript(driver);
504 		}
505 	}
506 
507 	signal(SIGINT, sig_int);
508 
509 	main_loop();
510 
511 	cleanup();
512 
513 	return 0;
514 }
515 
516 /*===========================================================================*
517  *           determine_type                                                  *
518  *===========================================================================*/
519 static enum dev_type determine_type (char *path)
520 {
521 	FILE * fd;
522 	char *mypath;
523 	char buf[256];
524 	int res;
525 
526 	mypath = (char *) calloc(1, strlen(path)+strlen(DEVMAN_TYPE_NAME)+1);
527 
528 	if (mypath == NULL) {
529 		fprintf(stderr, "ERROR: out of mem\n");
530 		cleanup();
531 		exit(1);
532 	}
533 
534 	strcat(mypath, path);
535 	strcat(mypath, DEVMAN_TYPE_NAME);
536 
537 	fd = fopen(mypath, "r");
538 	free(mypath);
539 
540 	if (fd == NULL) {
541 		fprintf(stderr, "WARN: could not open %s\n", mypath);
542 		return DEV_TYPE_UNKOWN;
543 	}
544 
545 	res = fscanf(fd , "%255s\n", buf);
546 	fclose(fd);
547 
548 	if (res != 1) {
549 		fprintf(stderr, "WARN: could not parse %s\n", mypath);
550 		return DEV_TYPE_UNKOWN;
551 	}
552 
553 	if (strcmp(buf, "USB_DEV") == 0) {
554 		return DEV_TYPE_USB_DEVICE;
555 	} else if (strcmp(buf, "USB_INTF") == 0) {
556 		return DEV_TYPE_USB_INTF;
557 	}
558 
559 	return  DEV_TYPE_UNKOWN;
560 }
561 
562 /*===========================================================================*
563  *           read_hex_uint                                                   *
564  *===========================================================================*/
565 static int read_hex_uint(char *base_path, char *name, unsigned int* val )
566 {
567 	char my_path[PATH_LEN];
568 	FILE *fd;
569 	memset(my_path,0,PATH_LEN);
570 	int ret = 0;
571 
572 	strcat(my_path, base_path);
573 	strcat(my_path, name);
574 
575 	fd = fopen(my_path, "r");
576 
577 	if (fd == NULL) {
578 		fprintf(stderr, "WARN: could not open %s\n", my_path);
579 		return EEXIST;
580 	} else	if (fscanf(fd, "0x%x\n", val ) != 1) {
581 		fprintf(stderr, "WARN: could not parse %s\n", my_path);
582 		ret = EINVAL;
583 	}
584 	fclose(fd);
585 
586 	return ret;
587 }
588 
589 /*===========================================================================*
590  *               get_major                                                   *
591  *===========================================================================*/
592 static int get_major() {
593 	int i, ret = args.major_offset;
594 
595 	for (i=0; i < 16; i++) {
596 		int j;
597 		for (j = 0; j < 8; j++ ) {
598 			if ((major_bitmap[i] & (1 << j))) {
599 				major_bitmap[i] &= !(1 << j);
600 				return ret;
601 			}
602 			ret++;
603 		}
604 	}
605 	return INVAL_MAJOR;
606 }
607 
608 /*===========================================================================*
609  *               put_major                                                   *
610  *===========================================================================*/
611 static void put_major(int major) {
612 	int i;
613 	major -= args.major_offset;
614 	assert(major >= 0);
615 
616 	for (i=0; i < 16; i++) {
617 		int j;
618 		for (j = 0; j < 8; j++ ) {
619 			if (major==0) {
620 				assert(!(major_bitmap[i] & (1 <<j)));
621 				major_bitmap[i] |= (1 << j);
622 				return;
623 			}
624 			major--;
625 		}
626 	}
627 }
628 
629 /*===========================================================================*
630  *          generate_usb_device_id                                           *
631  *===========================================================================*/
632 static struct usb_device_id *
633 generate_usb_device_id(char * path, int is_interface)
634 {
635 	struct usb_device_id *ret;
636 	int res;
637 	unsigned int val;
638 
639 	ret = (struct usb_device_id *)
640 	    calloc(1,sizeof (struct usb_device_id));
641 
642 	if (is_interface) {
643 
644 		res = read_hex_uint(path, "../idVendor", &val);
645 		if (res) goto err;
646 		ret->idVendor = val;
647 
648 		res = read_hex_uint(path, "../idProduct", &val);
649 		if (res) goto err;
650 		ret->idProduct = val;
651 #if 0
652 		res = read_hex_uint(path, "../bcdDevice", &val);
653 		if (res) goto err;
654 		ret->bcdDevice = val;
655 #endif
656 		res = read_hex_uint(path, "../bDeviceClass", &val);
657 		if (res) goto err;
658 		ret->bDeviceClass = val;
659 
660 		res = read_hex_uint(path, "../bDeviceSubClass", &val);
661 		if (res) goto err;
662 		ret->bDeviceSubClass = val;
663 
664 		res = read_hex_uint(path, "../bDeviceProtocol", &val);
665 		if (res) goto err;
666 		ret->bDeviceProtocol = val;
667 
668 		res = read_hex_uint(path, "/bInterfaceClass", &val);
669 		if (res) goto err;
670 		ret->bInterfaceClass = val;
671 
672 		res = read_hex_uint(path, "/bInterfaceSubClass", &val);
673 		if (res) goto err;
674 		ret->bInterfaceSubClass = val;
675 
676 		res = read_hex_uint(path, "/bInterfaceProtocol", &val);
677 		if (res) goto err;
678 		ret->bInterfaceProtocol = val;
679 	}
680 
681 	return ret;
682 
683 err:
684 	free(ret);
685 	return NULL;
686 }
687 
688 /*===========================================================================*
689  *            usb_intf_add_even                                              *
690  *===========================================================================*/
691 static void usb_intf_add_event(char *path, int dev_id)
692 {
693 	struct usb_device_id *id;
694 	struct devmand_usb_driver *drv;
695 	struct devmand_driver_instance *drv_inst;
696 	int major, ret;
697 
698 	/* generate usb_match_id */
699 	id = generate_usb_device_id(path,TRUE);
700 	if (id == NULL) {
701 		fprintf(stderr, "WARN: could not create usb_device id...\n"
702 		                "      ommiting event\n");
703 		free(id);
704 		return;
705 	}
706 
707 	/* find suitable driver */
708 	drv = match_usb_driver(id);
709 	free (id);
710 
711 	if (drv == NULL) {
712 		dbg("INFO: could not find a suitable driver for %s", path);
713 		return;
714 	}
715 
716 	/* create instance */
717 	drv_inst = (struct devmand_driver_instance *)
718 	    calloc(1,sizeof(struct devmand_driver_instance));
719 
720 	if (drv_inst == NULL) {
721 		fprintf(stderr, "ERROR: out of memory");
722 		return; /* maybe better quit here. */
723 	}
724 
725 
726 	/* allocate inode number, if device files needed */
727 	major = get_major();
728 	if (major == INVAL_MAJOR) {
729 		fprintf(stderr, "WARN: ran out of major numbers\n"
730 		                "      cannot start driver %s for %s\n",
731 							   drv->name, path);
732 		return;
733 	}
734 
735 	drv_inst->major  = major;
736 	drv_inst->drv    = drv;
737 	drv_inst->dev_id = dev_id;
738 
739 
740 	/* start driver (invoke minix-service) */
741 	start_driver(drv_inst);
742 
743 	/*
744 	 * run the up action
745 	 *
746 	 * An up action can be any executable. Before running it devmand
747 	 * will set certain environment variables so the script can configure
748 	 * the device (or generate device files, etc). See up_action() for that.
749 	 */
750 	if (drv->upscript) {
751 		ret = run_upscript(drv_inst);
752 		if (ret) {
753 			stop_driver(drv_inst);
754 			fprintf(stderr, "devmand: warning, could not run up_action\n");
755 			free(drv_inst);
756 			return;
757 		}
758 	}
759 
760 	LIST_INSERT_HEAD(&instances,drv_inst,list);
761 }
762 
763 /*===========================================================================*
764  *            usb_intf_remove_event                                          *
765  *===========================================================================*/
766 static void usb_intf_remove_event(char *path, int dev_id)
767 {
768 	struct devmand_driver_instance *inst;
769 	struct devmand_usb_driver *drv;
770 	int ret;
771 
772 	/* find the driver instance */
773 	inst = find_instance(dev_id);
774 
775 	if (inst == NULL) {
776 		dbg("No driver running for id: %d", dev_id);
777 		return;
778 	}
779 	drv = inst->drv;
780 
781 	/* run the down script */
782 	if (drv->downscript) {
783 		ret = run_downscript(inst);
784 		if (ret) {
785 			fprintf(stderr, "WARN: error running up_action");
786 		}
787 	}
788 
789 	/* stop the driver */
790 	stop_driver(inst);
791 
792 	/* free major */
793 	put_major(inst->major);
794 
795 	/* free instance */
796 	LIST_REMOVE(inst,list);
797 	free(inst);
798 }
799 
800 /*===========================================================================*
801  *           handle_event                                                    *
802  *===========================================================================*/
803 static void handle_event(char *event)
804 {
805 	enum dev_type type;
806 	char path[PATH_LEN];
807 	char tmp_path[PATH_LEN];
808 	int dev_id, res;
809 
810 	path[0]=0;
811 
812 	if (strncmp("ADD ", event, 4) == 0) {
813 
814 		/* read data from event */
815 		res = sscanf(event, "ADD %s 0x%x", tmp_path, &dev_id);
816 
817 		if (res != 2) {
818 			fprintf(stderr, "WARN: could not parse event: %s", event);
819 			fprintf(stderr, "WARN: omitting event: %s", event);
820 		}
821 
822 		strcpy(path, args.path);
823 		strcat(path, tmp_path);
824 
825 		/* what kind of device is added? */
826 		type = determine_type(path);
827 
828 		switch (type) {
829 			case DEV_TYPE_USB_DEVICE:
830 				dbg("USB device added: ommited....");
831 				/* ommit usb devices for now */
832 				break;
833 			case DEV_TYPE_USB_INTF:
834 				dbg("USB interface added: (%s, devid: = %d)",path, dev_id);
835 				usb_intf_add_event(path, dev_id);
836 				return;
837 			default:
838 				dbg("default");
839 				fprintf(stderr, "WARN: ommiting event\n");
840 		}
841 	} else if (strncmp("REMOVE ", event, 7) == 0) {
842 
843 		/* read data from event */
844 		res = sscanf(event,"REMOVE %s 0x%x", tmp_path, &dev_id);
845 
846 		if (res != 2) {
847 			fprintf(stderr, "WARN: could not parse event: %s", event);
848 			fprintf(stderr, "WARN: omitting event: %s", event);
849 		}
850 
851 		usb_intf_remove_event(path, dev_id);
852 
853 #if 0
854 		strcpy(path, args.path);
855 		strcat(path, tmp_path);
856 
857 		/* what kind of device is added? */
858 		type = determine_type(path);
859 
860 		switch (type) {
861 			case DEV_TYPE_USB_DEVICE:
862 				/* ommit usb devices for now */
863 				break;
864 			case DEV_TYPE_USB_INTF:
865 				usb_intf_remove_event(path, dev_id);
866 				return;
867 			default:
868 				fprintf(stderr, "WARN: ommiting event\n");
869 		}
870 #endif
871 
872 	}
873 }
874 
875 /*===========================================================================*
876  *           main_loop                                                       *
877  *===========================================================================*/
878 static void main_loop()
879 {
880 	char ev_path[128];
881 	char buf[256];
882 	int len;
883 	FILE* fd;
884 	len = strlen(args.path);
885 
886 	/* init major numbers */
887 
888 	memset(&major_bitmap, 0xff, 16);
889 
890 	if (len > 128 - 7 /*len of "events" */) {
891 		fprintf(stderr, "pathname to long\n");
892 		cleanup();
893 		exit(1);
894 	}
895 
896 	strcpy(ev_path, args.path);
897 	strcat(ev_path, "events");
898 
899 
900 	while (_run) {
901 
902 		char *res;
903 
904 		fd = fopen(ev_path, "r");
905 		if (fd == NULL) {
906 			/*
907 			 * ENFILE is a temporary failure, often caused by
908 			 * running the test set.  Don't die from that..
909 			 */
910 			if (errno == ENFILE) {
911 				usleep(50000);
912 				continue;
913 			}
914 
915 			fprintf(stderr,"devmand error: could not open event "
916 				"file %s bailing out\n", ev_path);
917 			cleanup();
918 			exit(1);
919 		}
920 
921 		res = fgets(buf, 256, fd);
922 		fclose(fd);
923 
924 		if (res == NULL) {
925 			usleep(50000);
926 			continue;
927 		}
928 		dbg("handle_event:  %s", buf);
929 		handle_event(buf);
930 	}
931 }
932 
933 /*===========================================================================*
934  *           display_usage                                                   *
935  *===========================================================================*/
936 static void display_usage(const char *name)
937 {
938 	printf("Usage: %s [{-p|--pathname} PATH_TO_SYS}"
939 	       " [{-d|--config-dir} CONFIG_DIR] [-v|--verbose]"
940 	       " [[x||--check-config]\n", name);
941 }
942 
943