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