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