Adapt libthread_xu to use the new lwp kernel functions.
[dragonfly.git] / usr.sbin / usbd / usbd.c
blobe7f79e1b56f24ee61515d85d78543371598619c0
1 /*
2 * $NetBSD: usbd.c,v 1.4 1998/12/09 00:57:19 augustss Exp $
3 * $FreeBSD: src/usr.sbin/usbd/usbd.c,v 1.29 2003/10/25 22:03:10 jmg Exp $
4 * $DragonFly: src/usr.sbin/usbd/usbd.c,v 1.7 2005/12/05 01:23:23 swildner Exp $
5 */
7 /*
8 * Copyright (c) 1998 The NetBSD Foundation, Inc.
9 * All rights reserved.
11 * This code is derived from software contributed to The NetBSD Foundation
12 * by Lennart Augustsson (augustss@netbsd.org).
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the NetBSD
25 * Foundation, Inc. and its contributors.
26 * 4. Neither the name of The NetBSD Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
43 /* USBD creates 'threads' in the kernel, used for doing discovery when a
44 * device has attached or detached. This functionality should be removed
45 * once kernel threads have been added to the kernel.
46 * It also handles the event queue, and executing commands based on those
47 * events.
49 * See usbd(8).
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <paths.h>
60 #include <sys/param.h>
61 #include <sys/types.h>
62 #include <sys/errno.h>
63 #include <sys/ioctl.h>
64 #include <sys/linker.h>
65 #include <sys/module.h>
66 #include <sys/queue.h>
67 #include <sys/time.h>
68 #include <sys/wait.h>
69 #include <regex.h>
71 #include <bus/usb/usb.h>
73 /* default name of configuration file
76 #define CONFIGFILE "/etc/usbd.conf"
78 /* the name of the device spitting out usb attach/detach events as well as
79 * the prefix for the individual busses (used as a semi kernel thread).
81 #define USBDEV "/dev/usb"
83 /* Maximum number of USB busses expected to be in a system
84 * XXX should be replaced by dynamic allocation.
86 #define MAXUSBDEV 4
88 /* Sometimes a device does not respond in time for interrupt
89 * driven explore to find it. Therefore we run an exploration
90 * at regular intervals to catch those.
92 #define TIMEOUT 30
94 /* The wildcard used in actions for strings and integers
96 #define WILDCARD_STRING NULL
97 #define WILDCARD_INT -1
100 extern char *__progname; /* name of program */
102 char *configfile = CONFIGFILE; /* name of configuration file */
104 char *devs[MAXUSBDEV]; /* device names */
105 int fds[MAXUSBDEV]; /* file descriptors for USBDEV\d+ */
106 int ndevs = 0; /* number of entries in fds / devs */
107 int fd = -1; /* file descriptor for USBDEV */
109 int lineno;
110 int verbose = 0; /* print message on what it is doing */
112 typedef struct event_name_s {
113 int type; /* event number (from usb.h) */
114 char *name;
115 } event_name_t;
117 event_name_t event_names[] = {
118 {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"},
119 {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"},
120 {USB_EVENT_DRIVER_ATTACH, "driver-attach"},
121 {USB_EVENT_DRIVER_DETACH, "driver-detach"},
122 {USB_EVENT_DEVICE_ATTACH, "device-attach"},
123 {USB_EVENT_DEVICE_DETACH, "device-detach"},
124 {0, NULL} /* NULL indicates end of list, not 0 */
127 #define DEVICE_FIELD 0 /* descriptive field */
129 #define VENDOR_FIELD 1 /* selective fields */
130 #define PRODUCT_FIELD 2
131 #define RELEASE_FIELD 3
132 #define CLASS_FIELD 4
133 #define SUBCLASS_FIELD 5
134 #define PROTOCOL_FIELD 6
135 #define DEVNAME_FIELD 7
137 #define ATTACH_FIELD 8 /* command fields */
138 #define DETACH_FIELD 9
141 typedef struct action_s {
142 char *name; /* descriptive string */
144 int vendor; /* selection criteria */
145 int product;
146 int release;
147 int class;
148 int subclass;
149 int protocol;
150 char *devname;
151 regex_t devname_regex;
153 char *attach; /* commands to execute */
154 char *detach;
156 STAILQ_ENTRY(action_s) next;
157 } action_t;
159 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
161 typedef struct action_match_s {
162 action_t *action;
163 char *devname;
164 } action_match_t;
167 /* the function returns 0 for failure, 1 for all arguments found and 2 for
168 * arguments left over in trail.
170 typedef int (*config_field_fn)(action_t *action, char *args, char **trail);
172 int set_device_field(action_t *action, char *args, char **trail);
173 int set_vendor_field(action_t *action, char *args, char **trail);
174 int set_product_field(action_t *action, char *args, char **trail);
175 int set_release_field(action_t *action, char *args, char **trail);
176 int set_class_field(action_t *action, char *args, char **trail);
177 int set_subclass_field(action_t *action, char *args, char **trail);
178 int set_protocol_field(action_t *action, char *args, char **trail);
179 int set_devname_field(action_t *action, char *args, char **trail);
180 int set_attach_field(action_t *action, char *args, char **trail);
181 int set_detach_field(action_t *action, char *args, char **trail);
183 /* the list of fields supported in an entry */
184 typedef struct config_field_s {
185 int event;
186 char *name;
187 config_field_fn function;
188 } config_field_t;
190 config_field_t config_fields[] = {
191 {DEVICE_FIELD, "device", set_device_field},
193 {VENDOR_FIELD, "vendor", set_vendor_field},
194 {PRODUCT_FIELD, "product", set_product_field},
195 {RELEASE_FIELD, "release", set_release_field},
196 {CLASS_FIELD, "class", set_class_field},
197 {SUBCLASS_FIELD, "subclass", set_subclass_field},
198 {PROTOCOL_FIELD, "protocol", set_protocol_field},
199 {DEVNAME_FIELD, "devname", set_devname_field},
201 {ATTACH_FIELD, "attach", set_attach_field},
202 {DETACH_FIELD, "detach", set_detach_field},
204 {0, NULL, NULL} /* NULL is EOL marker, not the 0 */
208 /* prototypes for some functions */
209 void print_event(struct usb_event *event);
210 void print_action(action_t *action, int i);
211 void print_actions(void);
212 int find_action(struct usb_device_info *devinfo, action_match_t *action_match);
215 void
216 usage(void)
218 fprintf(stderr, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
219 " [-n] [-c config]\n",
220 __progname);
221 exit(1);
225 /* generic helper functions for the functions to set the fields of actions */
227 get_string(char *src, char **rdst, char **rsrc)
229 /* Takes the first string from src, taking quoting into account.
230 * rsrc (if not NULL) is set to the first byte not included in the
231 * string returned in rdst.
233 * Input is:
234 * src = 'fir"st \'par"t second part';
235 * Returned is:
236 * *dst = 'hello \'world';
237 * if (rsrc != NULL)
238 * *rsrc = 'second part';
240 * Notice the fact that the single quote enclosed in double quotes is
241 * returned. Also notice that before second part there is more than
242 * one space, which is removed in rsrc.
244 * The string in src is not modified.
247 char *dst; /* destination string */
248 int i; /* index into src */
249 int j; /* index into dst */
250 int quoted = 0; /* 1 for single, 2 for double quoted */
252 dst = malloc(strlen(src)+1); /* XXX allocation is too big, realloc?*/
253 if (dst == NULL) { /* should not happen, really */
254 fprintf(stderr, "%s:%d: Out of memory\n", configfile, lineno);
255 exit(2);
258 /* find the end of the current string. If quotes are found the search
259 * continues until the corresponding quote is found.
260 * So,
261 * hel'lo" "wor'ld
262 * represents the string
263 * hello" "world
264 * and not (hello world).
266 for (i = 0, j = 0; i < strlen(src); i++) {
267 if (src[i] == '\'' && (quoted == 0 || quoted == 1)) {
268 quoted = (quoted? 0:1);
269 } else if (src[i] == '"' && (quoted == 0 || quoted == 2)) {
270 quoted = (quoted? 0:2);
271 } else if (isspace(src[i]) && !quoted) {
272 /* found a space outside quotes -> terminates src */
273 break;
274 } else {
275 dst[j++] = src[i]; /* copy character */
279 /* quotes being left open? */
280 if (quoted) {
281 fprintf(stderr, "%s:%d: Missing %s quote at end of '%s'\n",
282 configfile, lineno,
283 (quoted == 1? "single":"double"), src);
284 exit(2);
287 /* skip whitespace for second part */
288 for (/*i is set*/; i < strlen(src) && isspace(src[i]); i++)
289 ; /* nop */
291 dst[j] = '\0'; /* make sure it's NULL terminated */
293 *rdst = dst; /* and return the pointers */
294 if (rsrc != NULL) /* if info wanted */
295 *rsrc = &src[i];
297 if (*dst == '\0') { /* empty string */
298 return 0;
299 } else if (src[i] == '\0') { /* completely used (1 argument) */
300 return 1;
301 } else { /* 2 or more args, *rsrc is rest */
302 return 2;
307 get_integer(char *src, int *dst, char **rsrc)
309 char *endptr;
311 /* Converts str to a number. If one argument was found in
312 * str, 1 is returned and *dst is set to the value of the integer.
313 * If 2 or more arguments were presented, 2 is returned,
314 * *dst is set to the converted value and rsrc, if not null, points
315 * at the start of the next argument (whitespace skipped).
316 * Else 0 is returned and nothing else is valid.
319 if (src == NULL || *src == '\0') /* empty src */
320 return(0);
322 *dst = (int) strtol(src, &endptr, 0);
324 /* skip over whitespace of second argument */
325 while (isspace(*endptr))
326 endptr++;
328 if (rsrc)
329 *rsrc = endptr;
331 if (isspace(*endptr)) { /* partial match, 2 or more arguments */
332 return(2);
333 } else if (*endptr == '\0') { /* full match, 1 argument */
334 return(1);
335 } else { /* invalid src, no match */
336 return(0);
340 /* functions to set the fields of the actions appropriately */
342 set_device_field(action_t *action, char *args, char **trail)
344 return(get_string(args, &action->name, trail));
347 set_vendor_field(action_t *action, char *args, char **trail)
349 return(get_integer(args, &action->vendor, trail));
352 set_product_field(action_t *action, char *args, char **trail)
354 return(get_integer(args, &action->product, trail));
357 set_release_field(action_t *action, char *args, char **trail)
359 return(get_integer(args, &action->release, trail));
362 set_class_field(action_t *action, char *args, char **trail)
364 return(get_integer(args, &action->class, trail));
367 set_subclass_field(action_t *action, char *args, char **trail)
369 return(get_integer(args, &action->subclass, trail));
372 set_protocol_field(action_t *action, char *args, char **trail)
374 return(get_integer(args, &action->protocol, trail));
377 set_devname_field(action_t *action, char *args, char **trail)
379 int match = get_string(args, &action->devname, trail);
380 int len;
381 int error;
382 char *string;
383 # define ERRSTR_SIZE 100
384 char errstr[ERRSTR_SIZE];
386 if (match == 0)
387 return(0);
389 len = strlen(action->devname);
390 string = malloc(len + 15);
391 if (string == NULL)
392 return(0);
394 bcopy(action->devname, string+7, len); /* make some space for */
395 bcopy("[[:<:]]", string, 7); /* beginning of word */
396 bcopy("[[:>:]]", string+7+len, 7); /* and end of word */
397 string[len + 14] = '\0';
399 error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
400 if (error) {
401 errstr[0] = '\0';
402 regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
403 fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
404 return(0);
407 return(match);
410 set_attach_field(action_t *action, char *args, char **trail)
412 return(get_string(args, &action->attach, trail));
415 set_detach_field(action_t *action, char *args, char **trail)
417 return(get_string(args, &action->detach, trail));
421 void
422 read_configuration(void)
424 FILE *file; /* file descriptor */
425 char *line; /* current line */
426 char *linez; /* current line, NULL terminated */
427 char *field; /* first part, the field name */
428 char *args; /* second part, arguments */
429 char *trail; /* remaining part after parsing, should be '' */
430 size_t len; /* length of current line */
431 int i,j; /* loop counters */
432 action_t *action = NULL; /* current action */
434 file = fopen(configfile, "r");
435 if (file == NULL) {
436 fprintf(stderr, "%s: Could not open for reading, %s\n",
437 configfile, strerror(errno));
438 exit(2);
441 for (lineno = 1; /* nop */;lineno++) {
443 line = fgetln(file, &len);
444 if (line == NULL) {
445 if (feof(file)) /* EOF */
446 break;
447 if (ferror(file)) {
448 fprintf(stderr, "%s:%d: Could not read, %s\n",
449 configfile, lineno, strerror(errno));
450 exit(2);
454 /* skip initial spaces */
455 while (len > 0 && isspace(*line)) {
456 line++;
457 len--;
460 if (len == 0) /* empty line */
461 continue;
462 if (line[0] == '#') /* comment line */
463 continue;
465 /* make a NULL terminated copy of the string */
466 linez = malloc(len+1);
467 if (linez == NULL) {
468 fprintf(stderr, "%s:%d: Out of memory\n",
469 configfile, lineno);
470 exit(2);
472 strncpy(linez, line, len);
473 linez[len] = '\0';
475 /* find the end of the current word (is field), that's the
476 * start of the arguments
478 field = linez;
479 args = linez;
480 while (*args != '\0' && !isspace(*args))
481 args++;
483 /* If arguments is not the empty string, NULL terminate the
484 * field and move the argument pointer to the first character
485 * of the arguments.
486 * If arguments is the empty string field and arguments both
487 * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
489 if (*args != '\0') {
490 *args = '\0';
491 args++;
494 /* Skip initial spaces */
495 while (*args != '\0' && isspace(*args))
496 args++;
498 /* Cut off trailing whitespace */
499 for (i = 0, j = 0; args[i] != '\0'; i++)
500 if (!isspace(args[i]))
501 j = i+1;
502 args[j] = '\0';
504 /* We now have the field and the argument separated into
505 * two strings that are NULL terminated
508 /* If the field is 'device' we have to start a new action. */
509 if (strcmp(field, "device") == 0) {
510 /* Allocate a new action and set defaults */
511 action = malloc(sizeof(*action));
512 if (action == NULL) {
513 fprintf(stderr, "%s:%d: Out of memory\n",
514 configfile, lineno);
515 exit(2);
517 memset(action, 0, sizeof(*action));
518 action->product = WILDCARD_INT;
519 action->vendor = WILDCARD_INT;
520 action->release = WILDCARD_INT;
521 action->class = WILDCARD_INT;
522 action->subclass = WILDCARD_INT;
523 action->protocol = WILDCARD_INT;
524 action->devname = WILDCARD_STRING;
526 /* Add it to the end of the list to preserve order */
527 STAILQ_INSERT_TAIL(&actions, action, next);
530 if (action == NULL) {
531 line[len] = '\0'; /* XXX zero terminate */
532 fprintf(stderr, "%s:%d: Doesn't start with 'device' "
533 "but '%s'\n", configfile, lineno, field);
534 exit(2);
537 for (i = 0; config_fields[i].name ; i++) {
538 /* does the field name match? */
539 if (strcmp(config_fields[i].name, field) == 0) {
540 /* execute corresponding set-field function */
541 if ((config_fields[i].function)(action, args,
542 &trail)
543 != 1) {
544 fprintf(stderr,"%s:%d: "
545 "Syntax error in '%s'\n",
546 configfile, lineno, linez);
547 exit(2);
549 break;
552 if (config_fields[i].name == NULL) { /* Reached end of list*/
553 fprintf(stderr, "%s:%d: Unknown field '%s'\n",
554 configfile, lineno, field);
555 exit(2);
559 fclose(file);
561 if (verbose >= 2)
562 print_actions();
566 void
567 print_event(struct usb_event *event)
569 int i;
570 struct timespec *timespec = &event->ue_time;
571 struct usb_device_info *devinfo = &event->u.ue_device;
573 printf("%s: ", __progname);
574 for (i = 0; event_names[i].name != NULL; i++) {
575 if (event->ue_type == event_names[i].type) {
576 printf("%s event", event_names[i].name);
577 break;
580 if (event_names[i].name == NULL)
581 printf("unknown event %d", event->ue_type);
583 if (event->ue_type == USB_EVENT_DEVICE_ATTACH ||
584 event->ue_type == USB_EVENT_DEVICE_DETACH) {
585 devinfo = &event->u.ue_device;
587 printf(" at %ld.%09ld, %s, %s:\n",
588 timespec->tv_sec, timespec->tv_nsec,
589 devinfo->udi_product, devinfo->udi_vendor);
591 printf(" vndr=0x%04x prdct=0x%04x rlse=0x%04x "
592 "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n",
593 devinfo->udi_vendorNo, devinfo->udi_productNo,
594 devinfo->udi_releaseNo,
595 devinfo->udi_class, devinfo->udi_subclass, devinfo->udi_protocol);
597 if (devinfo->udi_devnames[0][0] != '\0') {
598 char c = ' ';
600 printf(" device names:");
601 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
602 if (devinfo->udi_devnames[i][0] == '\0')
603 break;
605 printf("%c%s", c, devinfo->udi_devnames[i]);
606 c = ',';
609 } else if (event->ue_type == USB_EVENT_CTRLR_ATTACH ||
610 event->ue_type == USB_EVENT_CTRLR_DETACH) {
611 printf(" bus=%d", &event->u.ue_ctrlr.ue_bus);
612 } else if (event->ue_type == USB_EVENT_DRIVER_ATTACH ||
613 event->ue_type == USB_EVENT_DRIVER_DETACH) {
614 printf(" cookie=%u devname=%s",
615 &event->u.ue_driver.ue_cookie.cookie,
616 &event->u.ue_driver.ue_devname);
618 printf("\n");
621 void
622 print_action(action_t *action, int i)
624 if (action == NULL)
625 return;
627 printf("%s: action %d: %s\n",
628 __progname, i,
629 (action->name? action->name:""));
630 if (action->product != WILDCARD_INT ||
631 action->vendor != WILDCARD_INT ||
632 action->release != WILDCARD_INT ||
633 action->class != WILDCARD_INT ||
634 action->subclass != WILDCARD_INT ||
635 action->protocol != WILDCARD_INT)
636 printf(" ");
637 if (action->vendor != WILDCARD_INT)
638 printf(" vndr=0x%04x", action->vendor);
639 if (action->product != WILDCARD_INT)
640 printf(" prdct=0x%04x", action->product);
641 if (action->release != WILDCARD_INT)
642 printf(" rlse=0x%04x", action->release);
643 if (action->class != WILDCARD_INT)
644 printf(" clss=0x%04x", action->class);
645 if (action->subclass != WILDCARD_INT)
646 printf(" subclss=0x%04x", action->subclass);
647 if (action->protocol != WILDCARD_INT)
648 printf(" prtcl=0x%04x", action->protocol);
649 if (action->vendor != WILDCARD_INT ||
650 action->product != WILDCARD_INT ||
651 action->release != WILDCARD_INT ||
652 action->class != WILDCARD_INT ||
653 action->subclass != WILDCARD_INT ||
654 action->protocol != WILDCARD_INT)
655 printf("\n");
656 if (action->devname != WILDCARD_STRING)
657 printf(" devname: %s\n", action->devname);
659 if (action->attach != NULL)
660 printf(" attach='%s'\n",
661 action->attach);
662 if (action->detach != NULL)
663 printf(" detach='%s'\n",
664 action->detach);
667 void
668 print_actions(void)
670 int i = 0;
671 action_t *action;
673 STAILQ_FOREACH(action, &actions, next)
674 print_action(action, ++i);
676 printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
681 match_devname(action_t *action, struct usb_device_info *devinfo)
683 int i;
684 regmatch_t match;
685 int error;
687 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
688 if (devinfo->udi_devnames[i][0] == '\0')
689 break;
691 error = regexec(&action->devname_regex, devinfo->udi_devnames[i],
692 1, &match, 0);
693 if (error == 0) {
694 if (verbose >= 2)
695 printf("%s: %s matches %s\n", __progname,
696 devinfo->udi_devnames[i], action->devname);
697 return(i);
701 return(-1);
706 find_action(struct usb_device_info *devinfo, action_match_t *action_match)
708 action_t *action;
709 char *devname = NULL;
710 int match = -1;
712 STAILQ_FOREACH(action, &actions, next) {
713 if ((action->vendor == WILDCARD_INT ||
714 action->vendor == devinfo->udi_vendorNo) &&
715 (action->product == WILDCARD_INT ||
716 action->product == devinfo->udi_productNo) &&
717 (action->release == WILDCARD_INT ||
718 action->release == devinfo->udi_releaseNo) &&
719 (action->class == WILDCARD_INT ||
720 action->class == devinfo->udi_class) &&
721 (action->subclass == WILDCARD_INT ||
722 action->subclass == devinfo->udi_subclass) &&
723 (action->protocol == WILDCARD_INT ||
724 action->protocol == devinfo->udi_protocol) &&
725 (action->devname == WILDCARD_STRING ||
726 (match = match_devname(action, devinfo)) != -1)) {
727 /* found match !*/
729 /* Find a devname for pretty printing. Either
730 * the matched one or otherwise, if there is only
731 * one devname for that device, use that.
733 if (match >= 0)
734 devname = devinfo->udi_devnames[match];
735 else if (devinfo->udi_devnames[0][0] != '\0' &&
736 devinfo->udi_devnames[1][0] == '\0')
737 /* if we have exactly 1 device name */
738 devname = devinfo->udi_devnames[0];
740 if (verbose) {
741 printf("%s: Found action '%s' for %s, %s",
742 __progname, action->name,
743 devinfo->udi_product, devinfo->udi_vendor);
744 if (devname)
745 printf(" at %s", devname);
746 printf("\n");
749 action_match->action = action;
750 action_match->devname = devname;
752 return(1);
756 return(0);
759 void
760 execute_command(char *cmd)
762 pid_t pid;
763 struct sigaction ign, intact, quitact;
764 sigset_t newsigblock, oldsigblock;
765 int status;
766 int i;
768 if (verbose)
769 printf("%s: Executing '%s'\n", __progname, cmd);
770 if (cmd == NULL)
771 return;
773 /* The code below is directly taken from the system(3) call.
774 * Added to it is the closing of open file descriptors.
777 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
778 * existing signal dispositions.
780 ign.sa_handler = SIG_IGN;
781 sigemptyset(&ign.sa_mask);
782 ign.sa_flags = 0;
783 sigaction(SIGINT, &ign, &intact);
784 sigaction(SIGQUIT, &ign, &quitact);
785 sigemptyset(&newsigblock);
786 sigaddset(&newsigblock, SIGCHLD);
787 sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
788 pid = fork();
789 if (pid == -1) {
790 fprintf(stderr, "%s: fork failed, %s\n",
791 __progname, strerror(errno));
792 } else if (pid == 0) {
793 /* child here */
795 /* close all open file handles for USBDEV\d* devices */
796 for (i = 0; i < ndevs; i++)
797 close(fds[i]); /* USBDEV\d+ */
798 close(fd); /* USBDEV */
800 /* Restore original signal dispositions and exec the command. */
801 sigaction(SIGINT, &intact, NULL);
802 sigaction(SIGQUIT, &quitact, NULL);
803 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
805 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
807 /* should only be reached in case of error */
808 exit(127);
809 } else {
810 /* parent here */
811 do {
812 pid = waitpid(pid, &status, 0);
813 } while (pid == -1 && errno == EINTR);
815 sigaction(SIGINT, &intact, NULL);
816 sigaction(SIGQUIT, &quitact, NULL);
817 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
819 if (pid == -1) {
820 fprintf(stderr, "%s: waitpid returned: %s\n",
821 __progname, strerror(errno));
822 } else if (pid == 0) {
823 fprintf(stderr, "%s: waitpid returned 0 ?!\n",
824 __progname);
825 } else {
826 if (status == -1) {
827 fprintf(stderr, "%s: Could not start '%s'\n",
828 __progname, cmd);
829 } else if (status == 127) {
830 fprintf(stderr, "%s: Shell failed for '%s'\n",
831 __progname, cmd);
832 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
833 fprintf(stderr, "%s: '%s' returned %d\n",
834 __progname, cmd, WEXITSTATUS(status));
835 } else if (WIFSIGNALED(status)) {
836 fprintf(stderr, "%s: '%s' caught signal %d\n",
837 __progname, cmd, WTERMSIG(status));
838 } else if (verbose >= 2) {
839 printf("%s: '%s' is ok\n", __progname, cmd);
844 void
845 process_event_queue(int fd)
847 struct usb_event event;
848 int error;
849 int len;
850 action_match_t action_match;
852 for (;;) {
853 len = read(fd, &event, sizeof(event));
854 if (len == -1) {
855 if (errno == EWOULDBLOCK) {
856 /* no more events */
857 break;
858 } else {
859 fprintf(stderr,"%s: Could not read event, %s\n",
860 __progname, strerror(errno));
861 exit(1);
864 if (len == 0)
865 break;
866 if (len != sizeof(event)) {
867 fprintf(stderr, "partial read on %s\n", USBDEV);
868 exit(1);
871 /* we seem to have gotten a valid event */
873 if (verbose)
874 print_event(&event);
876 /* handle the event appropriately */
877 switch (event.ue_type) {
878 case USB_EVENT_CTRLR_ATTACH:
879 if (verbose)
880 printf("USB_EVENT_CTRLR_ATTACH\n");
881 break;
882 case USB_EVENT_CTRLR_DETACH:
883 if (verbose)
884 printf("USB_EVENT_CTRLR_DETACH\n");
885 break;
886 case USB_EVENT_DEVICE_ATTACH:
887 case USB_EVENT_DEVICE_DETACH:
888 if (find_action(&event.u.ue_device, &action_match) == 0)
889 /* nothing found */
890 break;
892 if (verbose >= 2)
893 print_action(action_match.action, 0);
895 if (action_match.devname) {
896 if (verbose >= 2)
897 printf("%s: Setting DEVNAME='%s'\n",
898 __progname, action_match.devname);
900 error = setenv("DEVNAME", action_match.devname, 1);
901 if (error)
902 fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
903 __progname, action_match.devname, strerror(errno));
906 if (USB_EVENT_IS_ATTACH(event.ue_type) &&
907 action_match.action->attach)
908 execute_command(action_match.action->attach);
909 if (USB_EVENT_IS_DETACH(event.ue_type) &&
910 action_match.action->detach)
911 execute_command(action_match.action->detach);
912 break;
913 case USB_EVENT_DRIVER_ATTACH:
914 if (verbose)
915 printf("USB_EVENT_DRIVER_ATTACH\n");
916 break;
917 case USB_EVENT_DRIVER_DETACH:
918 if (verbose)
919 printf("USB_EVENT_DRIVER_DETACH\n");
920 break;
921 default:
922 printf("Unknown USB event %d\n", event.ue_type);
929 main(int argc, char **argv)
931 int error, i;
932 int ch; /* getopt option */
933 int debug = 0; /* print debugging output */
934 int explore_once = 0; /* don't do only explore */
935 int handle_events = 1; /* do handle the event queue */
936 int maxfd; /* maximum fd in use */
937 char buf[50]; /* for creation of the filename */
938 fd_set r,w;
939 int itimeout = TIMEOUT; /* timeout for select */
940 struct timeval tv;
942 if (modfind(USB_UHUB) < 0) {
943 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
944 perror(USB_KLD ": Kernel module not available");
945 return 1;
949 while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
950 switch(ch) {
951 case 'c':
952 configfile = strdup(optarg);
953 if (configfile == NULL) {
954 fprintf(stderr, "strdup returned NULL\n");
955 return 1;
957 break;
958 case 'd':
959 debug++;
960 break;
961 case 'e':
962 explore_once = 1;
963 break;
964 case 'f':
965 if (ndevs < MAXUSBDEV)
966 devs[ndevs++] = optarg;
967 break;
968 case 'n':
969 handle_events = 0;
970 break;
971 case 't':
972 itimeout = atoi(optarg);
973 break;
974 case 'v':
975 verbose++;
976 break;
977 case '?':
978 default:
979 usage();
982 argc -= optind;
983 argv += optind;
985 maxfd = 0;
986 if (ndevs == 0) {
987 /* open all the USBDEVS\d+ devices */
988 for (i = 0; i < MAXUSBDEV; i++) {
989 sprintf(buf, "%s%d", USBDEV, i);
990 fds[ndevs] = open(buf, O_RDWR);
991 if (fds[ndevs] >= 0) {
992 devs[ndevs] = strdup(buf);
993 if (devs[ndevs] == NULL) {
994 fprintf(stderr, "strdup returned NULL\n");
995 return 1;
997 if (verbose)
998 printf("%s: opened %s\n",
999 __progname, devs[ndevs]);
1000 if (fds[ndevs] > maxfd)
1001 maxfd = fds[ndevs];
1002 ndevs++;
1003 } else if (errno != ENXIO && errno != ENOENT) {
1004 /* there was an error, on a device that does
1005 * exist (device is configured)
1007 fprintf(stderr, "%s: Could not open %s, %s\n",
1008 __progname, buf, strerror(errno));
1009 exit(1);
1012 } else {
1013 /* open all the files specified with -f */
1014 for (i = 0; i < ndevs; i++) {
1015 fds[i] = open(devs[i], O_RDWR);
1016 if (fds[i] < 0) {
1017 fprintf(stderr, "%s: Could not open %s, %s\n",
1018 __progname, devs[i], strerror(errno));
1019 exit(1);
1020 } else {
1021 if (verbose)
1022 printf("%s: opened %s\n",
1023 __progname, devs[i]);
1024 if (fds[i] > maxfd)
1025 maxfd = fds[i];
1030 if (ndevs == 0) {
1031 fprintf(stderr, "No USB host controllers found\n");
1032 exit(1);
1036 /* Do the explore once and exit */
1037 if (explore_once) {
1038 for (i = 0; i < ndevs; i++) {
1039 error = ioctl(fds[i], USB_DISCOVER);
1040 if (error < 0) {
1041 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1042 "failed, %s\n",
1043 __progname, devs[i], strerror(errno));
1044 exit(1);
1047 exit(0);
1050 if (handle_events) {
1051 if (verbose)
1052 printf("%s: reading configuration file %s\n",
1053 __progname, configfile);
1054 read_configuration();
1056 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1057 if (fd < 0) {
1058 fprintf(stderr, "%s: Could not open %s, %s\n",
1059 __progname, USBDEV, strerror(errno));
1060 exit(1);
1062 if (verbose)
1063 printf("%s: opened %s\n", __progname, USBDEV);
1064 if (fd > maxfd)
1065 maxfd = fd;
1067 process_event_queue(fd); /* dequeue the initial events */
1070 /* move to the background */
1071 if (!debug)
1072 daemon(0, 0);
1074 /* start select on all the open file descriptors */
1075 for (;;) {
1076 FD_ZERO(&r);
1077 FD_ZERO(&w);
1078 if (handle_events)
1079 FD_SET(fd, &r); /* device USBDEV */
1080 for (i = 0; i < ndevs; i++)
1081 FD_SET(fds[i], &w); /* device USBDEV\d+ */
1082 tv.tv_usec = 0;
1083 tv.tv_sec = itimeout;
1084 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1085 if (error < 0) {
1086 fprintf(stderr, "%s: Select failed, %s\n",
1087 __progname, strerror(errno));
1088 exit(1);
1091 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1092 for (i = 0; i < ndevs; i++) {
1093 if (error == 0 || FD_ISSET(fds[i], &w)) {
1094 if (verbose >= 2)
1095 printf("%s: doing %sdiscovery on %s\n",
1096 __progname,
1097 (error? "":"timeout "), devs[i]);
1098 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1099 fprintf(stderr, "%s: ioctl(%s, "
1100 "USB_DISCOVER) failed, %s\n",
1101 __progname, devs[i],
1102 strerror(errno));
1103 exit(1);
1108 /* check the event queue */
1109 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1110 if (verbose >= 2)
1111 printf("%s: processing event queue %son %s\n",
1112 __progname,
1113 (error? "":"due to timeout "), USBDEV);
1114 process_event_queue(fd);