1 /* $NetBSD: usbd.c,v 1.4 1998/12/09 00:57:19 augustss Exp $ */
2 /* $FreeBSD: src/usr.sbin/usbd/usbd.c,v 1.10.2.6 2002/12/31 09:05:27 maxim Exp $ */
3 /* $DragonFly: src/usr.sbin/usbd/usbd.c,v 1.3 2003/08/08 04:18:48 dillon Exp $ */
6 * Copyright (c) 1998 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Lennart Augustsson (augustss@netbsd.org).
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
41 /* USBD creates 'threads' in the kernel, used for doing discovery when a
42 * device has attached or detached. This functionality should be removed
43 * once kernel threads have been added to the kernel.
44 * It also handles the event queue, and executing commands based on those
58 #include <sys/types.h>
60 #include <sys/ioctl.h>
61 #include <sys/errno.h>
62 #include <sys/queue.h>
66 #include <bus/usb/usb.h>
68 /* default name of configuration file
71 #define CONFIGFILE "/etc/usbd.conf"
73 /* the name of the device spitting out usb attach/detach events as well as
74 * the prefix for the individual busses (used as a semi kernel thread).
76 #define USBDEV "/dev/usb"
78 /* Maximum number of USB busses expected to be in a system
79 * XXX should be replaced by dynamic allocation.
83 /* Sometimes a device does not respond in time for interrupt
84 * driven explore to find it. Therefore we run an exploration
85 * at regular intervals to catch those.
89 /* The wildcard used in actions for strings and integers
91 #define WILDCARD_STRING NULL
92 #define WILDCARD_INT -1
95 extern char *__progname; /* name of program */
97 char *configfile = CONFIGFILE; /* name of configuration file */
99 char *devs[MAXUSBDEV]; /* device names */
100 int fds[MAXUSBDEV]; /* file descriptors for USBDEV\d+ */
101 int ndevs = 0; /* number of entries in fds / devs */
102 int fd = -1; /* file descriptor for USBDEV */
105 int verbose = 0; /* print message on what it is doing */
107 typedef struct event_name_s {
108 int type; /* event number (from usb.h) */
112 event_name_t event_names[] = {
113 {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"},
114 {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"},
115 {USB_EVENT_DRIVER_ATTACH, "driver-attach"},
116 {USB_EVENT_DRIVER_DETACH, "driver-detach"},
117 {USB_EVENT_DEVICE_ATTACH, "device-attach"},
118 {USB_EVENT_DEVICE_DETACH, "device-detach"},
119 {0, NULL} /* NULL indicates end of list, not 0 */
122 #define DEVICE_FIELD 0 /* descriptive field */
124 #define VENDOR_FIELD 1 /* selective fields */
125 #define PRODUCT_FIELD 2
126 #define RELEASE_FIELD 3
127 #define CLASS_FIELD 4
128 #define SUBCLASS_FIELD 5
129 #define PROTOCOL_FIELD 6
130 #define DEVNAME_FIELD 7
132 #define ATTACH_FIELD 8 /* command fields */
133 #define DETACH_FIELD 9
136 typedef struct action_s {
137 char *name; /* descriptive string */
139 int vendor; /* selection criteria */
146 regex_t devname_regex;
148 char *attach; /* commands to execute */
151 STAILQ_ENTRY(action_s) next;
154 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
156 typedef struct action_match_s {
162 /* the function returns 0 for failure, 1 for all arguments found and 2 for
163 * arguments left over in trail.
165 typedef int (*config_field_fn) __P((action_t *action, char *args,
168 int set_device_field(action_t *action, char *args, char **trail);
169 int set_vendor_field(action_t *action, char *args, char **trail);
170 int set_product_field(action_t *action, char *args, char **trail);
171 int set_release_field(action_t *action, char *args, char **trail);
172 int set_class_field(action_t *action, char *args, char **trail);
173 int set_subclass_field(action_t *action, char *args, char **trail);
174 int set_protocol_field(action_t *action, char *args, char **trail);
175 int set_devname_field(action_t *action, char *args, char **trail);
176 int set_attach_field(action_t *action, char *args, char **trail);
177 int set_detach_field(action_t *action, char *args, char **trail);
179 /* the list of fields supported in an entry */
180 typedef struct config_field_s {
183 config_field_fn function;
186 config_field_t config_fields[] = {
187 {DEVICE_FIELD, "device", set_device_field},
189 {VENDOR_FIELD, "vendor", set_vendor_field},
190 {PRODUCT_FIELD, "product", set_product_field},
191 {RELEASE_FIELD, "release", set_release_field},
192 {CLASS_FIELD, "class", set_class_field},
193 {SUBCLASS_FIELD, "subclass", set_subclass_field},
194 {PROTOCOL_FIELD, "protocol", set_protocol_field},
195 {DEVNAME_FIELD, "devname", set_devname_field},
197 {ATTACH_FIELD, "attach", set_attach_field},
198 {DETACH_FIELD, "detach", set_detach_field},
200 {0, NULL, NULL} /* NULL is EOL marker, not the 0 */
204 /* prototypes for some functions */
205 void print_event __P((struct usb_event *event));
206 void print_action __P((action_t *action, int i));
207 void print_actions __P((void));
208 int find_action __P((struct usb_device_info *devinfo,
209 action_match_t *action_match));
215 fprintf(stderr, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
216 " [-n] [-c config]\n",
222 /* generic helper functions for the functions to set the fields of actions */
224 get_string(char *src, char **rdst, char **rsrc)
226 /* Takes the first string from src, taking quoting into account.
227 * rsrc (if not NULL) is set to the first byte not included in the
228 * string returned in rdst.
231 * src = 'fir"st \'par"t second part';
233 * *dst = 'hello \'world';
235 * *rsrc = 'second part';
237 * Notice the fact that the single quote enclosed in double quotes is
238 * returned. Also notice that before second part there is more than
239 * one space, which is removed in rsrc.
241 * The string in src is not modified.
244 char *dst; /* destination string */
245 int i; /* index into src */
246 int j; /* index into dst */
247 int quoted = 0; /* 1 for single, 2 for double quoted */
249 dst = malloc(strlen(src)+1); /* XXX allocation is too big, realloc?*/
250 if (dst == NULL) { /* should not happen, really */
251 fprintf(stderr, "%s:%d: Out of memory\n", configfile, lineno);
255 /* find the end of the current string. If quotes are found the search
256 * continues until the corresponding quote is found.
259 * represents the string
261 * and not (hello world).
263 for (i = 0, j = 0; i < strlen(src); i++) {
264 if (src[i] == '\'' && (quoted == 0 || quoted == 1)) {
265 quoted = (quoted? 0:1);
266 } else if (src[i] == '"' && (quoted == 0 || quoted == 2)) {
267 quoted = (quoted? 0:2);
268 } else if (isspace(src[i]) && !quoted) {
269 /* found a space outside quotes -> terminates src */
272 dst[j++] = src[i]; /* copy character */
276 /* quotes being left open? */
278 fprintf(stderr, "%s:%d: Missing %s quote at end of '%s'\n",
280 (quoted == 1? "single":"double"), src);
284 /* skip whitespace for second part */
285 for (/*i is set*/; i < strlen(src) && isspace(src[i]); i++)
288 dst[j] = '\0'; /* make sure it's NULL terminated */
290 *rdst = dst; /* and return the pointers */
291 if (rsrc != NULL) /* if info wanted */
294 if (*dst == '\0') { /* empty string */
296 } else if (src[i] == '\0') { /* completely used (1 argument) */
298 } else { /* 2 or more args, *rsrc is rest */
304 get_integer(char *src, int *dst, char **rsrc)
308 /* Converts str to a number. If one argument was found in
309 * str, 1 is returned and *dst is set to the value of the integer.
310 * If 2 or more arguments were presented, 2 is returned,
311 * *dst is set to the converted value and rsrc, if not null, points
312 * at the start of the next argument (whitespace skipped).
313 * Else 0 is returned and nothing else is valid.
316 if (src == NULL || *src == '\0') /* empty src */
319 *dst = (int) strtol(src, &endptr, 0);
321 /* skip over whitespace of second argument */
322 while (isspace(*endptr))
328 if (isspace(*endptr)) { /* partial match, 2 or more arguments */
330 } else if (*endptr == '\0') { /* full match, 1 argument */
332 } else { /* invalid src, no match */
337 /* functions to set the fields of the actions appropriately */
339 set_device_field(action_t *action, char *args, char **trail)
341 return(get_string(args, &action->name, trail));
344 set_vendor_field(action_t *action, char *args, char **trail)
346 return(get_integer(args, &action->vendor, trail));
349 set_product_field(action_t *action, char *args, char **trail)
351 return(get_integer(args, &action->product, trail));
354 set_release_field(action_t *action, char *args, char **trail)
356 return(get_integer(args, &action->release, trail));
359 set_class_field(action_t *action, char *args, char **trail)
361 return(get_integer(args, &action->class, trail));
364 set_subclass_field(action_t *action, char *args, char **trail)
366 return(get_integer(args, &action->subclass, trail));
369 set_protocol_field(action_t *action, char *args, char **trail)
371 return(get_integer(args, &action->protocol, trail));
374 set_devname_field(action_t *action, char *args, char **trail)
376 int match = get_string(args, &action->devname, trail);
380 # define ERRSTR_SIZE 100
381 char errstr[ERRSTR_SIZE];
386 len = strlen(action->devname);
387 string = malloc(len + 15);
391 bcopy(action->devname, string+7, len); /* make some space for */
392 bcopy("[[:<:]]", string, 7); /* beginning of word */
393 bcopy("[[:>:]]", string+7+len, 7); /* and end of word */
394 string[len + 14] = '\0';
396 error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
399 regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
400 fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
407 set_attach_field(action_t *action, char *args, char **trail)
409 return(get_string(args, &action->attach, trail));
412 set_detach_field(action_t *action, char *args, char **trail)
414 return(get_string(args, &action->detach, trail));
419 read_configuration(void)
421 FILE *file; /* file descriptor */
422 char *line; /* current line */
423 char *linez; /* current line, NULL terminated */
424 char *field; /* first part, the field name */
425 char *args; /* second part, arguments */
426 char *trail; /* remaining part after parsing, should be '' */
427 int len; /* length of current line */
428 int i,j; /* loop counters */
429 action_t *action = NULL; /* current action */
431 file = fopen(configfile, "r");
433 fprintf(stderr, "%s: Could not open for reading, %s\n",
434 configfile, strerror(errno));
438 for (lineno = 1; /* nop */;lineno++) {
440 line = fgetln(file, &len);
442 if (feof(file)) /* EOF */
445 fprintf(stderr, "%s:%d: Could not read, %s\n",
446 configfile, lineno, strerror(errno));
451 /* skip initial spaces */
452 while (len > 0 && isspace(*line)) {
457 if (len == 0) /* empty line */
459 if (line[0] == '#') /* comment line */
462 /* make a NULL terminated copy of the string */
463 linez = malloc(len+1);
465 fprintf(stderr, "%s:%d: Out of memory\n",
469 strncpy(linez, line, len);
472 /* find the end of the current word (is field), that's the
473 * start of the arguments
477 while (*args != '\0' && !isspace(*args))
480 /* If arguments is not the empty string, NULL terminate the
481 * field and move the argument pointer to the first character
483 * If arguments is the empty string field and arguments both
484 * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
491 /* Skip initial spaces */
492 while (*args != '\0' && isspace(*args))
495 /* Cut off trailing whitespace */
496 for (i = 0, j = 0; args[i] != '\0'; i++)
497 if (!isspace(args[i]))
501 /* We now have the field and the argument separated into
502 * two strings that are NULL terminated
505 /* If the field is 'device' we have to start a new action. */
506 if (strcmp(field, "device") == 0) {
507 /* Allocate a new action and set defaults */
508 action = malloc(sizeof(*action));
509 if (action == NULL) {
510 fprintf(stderr, "%s:%d: Out of memory\n",
514 memset(action, 0, sizeof(*action));
515 action->product = WILDCARD_INT;
516 action->vendor = WILDCARD_INT;
517 action->release = WILDCARD_INT;
518 action->class = WILDCARD_INT;
519 action->subclass = WILDCARD_INT;
520 action->protocol = WILDCARD_INT;
521 action->devname = WILDCARD_STRING;
523 /* Add it to the end of the list to preserve order */
524 STAILQ_INSERT_TAIL(&actions, action, next);
527 if (action == NULL) {
528 line[len] = '\0'; /* XXX zero terminate */
529 fprintf(stderr, "%s:%d: Doesn't start with 'device' "
530 "but '%s'\n", configfile, lineno, field);
534 for (i = 0; config_fields[i].name ; i++) {
535 /* does the field name match? */
536 if (strcmp(config_fields[i].name, field) == 0) {
537 /* execute corresponding set-field function */
538 if ((config_fields[i].function)(action, args,
541 fprintf(stderr,"%s:%d: "
542 "Syntax error in '%s'\n",
543 configfile, lineno, linez);
549 if (config_fields[i].name == NULL) { /* Reached end of list*/
550 fprintf(stderr, "%s:%d: Unknown field '%s'\n",
551 configfile, lineno, field);
564 print_event(struct usb_event *event)
567 struct timespec *timespec = &event->ue_time;
568 struct usb_device_info *devinfo = &event->u.ue_device;
570 printf("%s: ", __progname);
571 for (i = 0; event_names[i].name != NULL; i++) {
572 if (event->ue_type == event_names[i].type) {
573 printf("%s event", event_names[i].name);
577 if (event_names[i].name == NULL)
578 printf("unknown event %d", event->ue_type);
580 if (event->ue_type == USB_EVENT_DEVICE_ATTACH ||
581 event->ue_type == USB_EVENT_DEVICE_DETACH) {
582 devinfo = &event->u.ue_device;
584 printf(" at %ld.%09ld, %s, %s:\n",
585 timespec->tv_sec, timespec->tv_nsec,
586 devinfo->udi_product, devinfo->udi_vendor);
588 printf(" vndr=0x%04x prdct=0x%04x rlse=0x%04x "
589 "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n",
590 devinfo->udi_vendorNo, devinfo->udi_productNo,
591 devinfo->udi_releaseNo,
592 devinfo->udi_class, devinfo->udi_subclass, devinfo->udi_protocol);
594 if (devinfo->udi_devnames[0][0] != '\0') {
597 printf(" device names:");
598 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
599 if (devinfo->udi_devnames[i][0] == '\0')
602 printf("%c%s", c, devinfo->udi_devnames[i]);
606 } else if (event->ue_type == USB_EVENT_CTRLR_ATTACH ||
607 event->ue_type == USB_EVENT_CTRLR_DETACH) {
608 printf(" bus=%d", &event->u.ue_ctrlr.ue_bus);
609 } else if (event->ue_type == USB_EVENT_DRIVER_ATTACH ||
610 event->ue_type == USB_EVENT_DRIVER_DETACH) {
611 printf(" cookie=%u devname=%s",
612 &event->u.ue_driver.ue_cookie.cookie,
613 &event->u.ue_driver.ue_devname);
619 print_action(action_t *action, int i)
624 printf("%s: action %d: %s\n",
626 (action->name? action->name:""));
627 if (action->product != WILDCARD_INT ||
628 action->vendor != WILDCARD_INT ||
629 action->release != WILDCARD_INT ||
630 action->class != WILDCARD_INT ||
631 action->subclass != WILDCARD_INT ||
632 action->protocol != WILDCARD_INT)
634 if (action->vendor != WILDCARD_INT)
635 printf(" vndr=0x%04x", action->vendor);
636 if (action->product != WILDCARD_INT)
637 printf(" prdct=0x%04x", action->product);
638 if (action->release != WILDCARD_INT)
639 printf(" rlse=0x%04x", action->release);
640 if (action->class != WILDCARD_INT)
641 printf(" clss=0x%04x", action->class);
642 if (action->subclass != WILDCARD_INT)
643 printf(" subclss=0x%04x", action->subclass);
644 if (action->protocol != WILDCARD_INT)
645 printf(" prtcl=0x%04x", action->protocol);
646 if (action->vendor != WILDCARD_INT ||
647 action->product != WILDCARD_INT ||
648 action->release != WILDCARD_INT ||
649 action->class != WILDCARD_INT ||
650 action->subclass != WILDCARD_INT ||
651 action->protocol != WILDCARD_INT)
653 if (action->devname != WILDCARD_STRING)
654 printf(" devname: %s\n", action->devname);
656 if (action->attach != NULL)
657 printf(" attach='%s'\n",
659 if (action->detach != NULL)
660 printf(" detach='%s'\n",
670 STAILQ_FOREACH(action, &actions, next)
671 print_action(action, ++i);
673 printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
678 match_devname(action_t *action, struct usb_device_info *devinfo)
684 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
685 if (devinfo->udi_devnames[i][0] == '\0')
688 error = regexec(&action->devname_regex, devinfo->udi_devnames[i],
692 printf("%s: %s matches %s\n", __progname,
693 devinfo->udi_devnames[i], action->devname);
703 find_action(struct usb_device_info *devinfo, action_match_t *action_match)
706 char *devname = NULL;
709 STAILQ_FOREACH(action, &actions, next) {
710 if ((action->vendor == WILDCARD_INT ||
711 action->vendor == devinfo->udi_vendorNo) &&
712 (action->product == WILDCARD_INT ||
713 action->product == devinfo->udi_productNo) &&
714 (action->release == WILDCARD_INT ||
715 action->release == devinfo->udi_releaseNo) &&
716 (action->class == WILDCARD_INT ||
717 action->class == devinfo->udi_class) &&
718 (action->subclass == WILDCARD_INT ||
719 action->subclass == devinfo->udi_subclass) &&
720 (action->protocol == WILDCARD_INT ||
721 action->protocol == devinfo->udi_protocol) &&
722 (action->devname == WILDCARD_STRING ||
723 (match = match_devname(action, devinfo)) != -1)) {
726 /* Find a devname for pretty printing. Either
727 * the matched one or otherwise, if there is only
728 * one devname for that device, use that.
731 devname = devinfo->udi_devnames[match];
732 else if (devinfo->udi_devnames[0][0] != '\0' &&
733 devinfo->udi_devnames[1][0] == '\0')
734 /* if we have exactly 1 device name */
735 devname = devinfo->udi_devnames[0];
738 printf("%s: Found action '%s' for %s, %s",
739 __progname, action->name,
740 devinfo->udi_product, devinfo->udi_vendor);
742 printf(" at %s", devname);
746 action_match->action = action;
747 action_match->devname = devname;
757 execute_command(char *cmd)
760 struct sigaction ign, intact, quitact;
761 sigset_t newsigblock, oldsigblock;
766 printf("%s: Executing '%s'\n", __progname, cmd);
770 /* The code below is directly taken from the system(3) call.
771 * Added to it is the closing of open file descriptors.
774 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
775 * existing signal dispositions.
777 ign.sa_handler = SIG_IGN;
778 (void) sigemptyset(&ign.sa_mask);
780 (void) sigaction(SIGINT, &ign, &intact);
781 (void) sigaction(SIGQUIT, &ign, &quitact);
782 (void) sigemptyset(&newsigblock);
783 (void) sigaddset(&newsigblock, SIGCHLD);
784 (void) sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
787 fprintf(stderr, "%s: fork failed, %s\n",
788 __progname, strerror(errno));
789 } else if (pid == 0) {
792 /* close all open file handles for USBDEV\d* devices */
793 for (i = 0; i < ndevs; i++)
794 close(fds[i]); /* USBDEV\d+ */
795 close(fd); /* USBDEV */
797 /* Restore original signal dispositions and exec the command. */
798 (void) sigaction(SIGINT, &intact, NULL);
799 (void) sigaction(SIGQUIT, &quitact, NULL);
800 (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
802 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
804 /* should only be reached in case of error */
809 pid = waitpid(pid, &status, 0);
810 } while (pid == -1 && errno == EINTR);
812 (void) sigaction(SIGINT, &intact, NULL);
813 (void) sigaction(SIGQUIT, &quitact, NULL);
814 (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
817 fprintf(stderr, "%s: waitpid returned: %s\n",
818 __progname, strerror(errno));
819 } else if (pid == 0) {
820 fprintf(stderr, "%s: waitpid returned 0 ?!\n",
824 fprintf(stderr, "%s: Could not start '%s'\n",
826 } else if (status == 127) {
827 fprintf(stderr, "%s: Shell failed for '%s'\n",
829 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
830 fprintf(stderr, "%s: '%s' returned %d\n",
831 __progname, cmd, WEXITSTATUS(status));
832 } else if (WIFSIGNALED(status)) {
833 fprintf(stderr, "%s: '%s' caught signal %d\n",
834 __progname, cmd, WTERMSIG(status));
835 } else if (verbose >= 2) {
836 printf("%s: '%s' is ok\n", __progname, cmd);
842 process_event_queue(int fd)
844 struct usb_event event;
847 action_match_t action_match;
850 len = read(fd, &event, sizeof(event));
852 if (errno == EWOULDBLOCK) {
856 fprintf(stderr,"%s: Could not read event, %s\n",
857 __progname, strerror(errno));
863 if (len != sizeof(event)) {
864 fprintf(stderr, "partial read on %s\n", USBDEV);
868 /* we seem to have gotten a valid event */
873 /* handle the event appropriately */
874 switch (event.ue_type) {
875 case USB_EVENT_CTRLR_ATTACH:
877 printf("USB_EVENT_CTRLR_ATTACH\n");
879 case USB_EVENT_CTRLR_DETACH:
881 printf("USB_EVENT_CTRLR_DETACH\n");
883 case USB_EVENT_DEVICE_ATTACH:
884 case USB_EVENT_DEVICE_DETACH:
885 if (find_action(&event.u.ue_device, &action_match) == 0)
890 print_action(action_match.action, 0);
892 if (action_match.devname) {
894 printf("%s: Setting DEVNAME='%s'\n",
895 __progname, action_match.devname);
897 error = setenv("DEVNAME", action_match.devname, 1);
899 fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
900 __progname, action_match.devname, strerror(errno));
903 if (USB_EVENT_IS_ATTACH(event.ue_type) &&
904 action_match.action->attach)
905 execute_command(action_match.action->attach);
906 if (USB_EVENT_IS_DETACH(event.ue_type) &&
907 action_match.action->detach)
908 execute_command(action_match.action->detach);
910 case USB_EVENT_DRIVER_ATTACH:
912 printf("USB_EVENT_DRIVER_DETACH\n");
914 case USB_EVENT_DRIVER_DETACH:
916 printf("USB_EVENT_DRIVER_DETACH\n");
919 printf("Unknown USB event %d\n", event.ue_type);
926 main(int argc, char **argv)
929 int ch; /* getopt option */
930 extern char *optarg; /* from getopt */
931 extern int optind; /* from getopt */
932 int debug = 0; /* print debugging output */
933 int explore_once = 0; /* don't do only explore */
934 int handle_events = 1; /* do handle the event queue */
935 int maxfd; /* maximum fd in use */
936 char buf[50]; /* for creation of the filename */
938 int itimeout = TIMEOUT; /* timeout for select */
941 if (modfind(USB_UHUB) < 0) {
942 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
943 perror(USB_KLD ": Kernel module not available");
948 while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
951 configfile = strdup(optarg);
952 if (configfile == NULL) {
953 fprintf(stderr, "strdup returned NULL\n");
964 if (ndevs < MAXUSBDEV)
965 devs[ndevs++] = optarg;
971 itimeout = atoi(optarg);
986 /* open all the USBDEVS\d+ devices */
987 for (i = 0; i < MAXUSBDEV; i++) {
988 sprintf(buf, "%s%d", USBDEV, i);
989 fds[ndevs] = open(buf, O_RDWR);
990 if (fds[ndevs] >= 0) {
991 devs[ndevs] = strdup(buf);
992 if (devs[ndevs] == NULL) {
993 fprintf(stderr, "strdup returned NULL\n");
997 printf("%s: opened %s\n",
998 __progname, devs[ndevs]);
999 if (fds[ndevs] > maxfd)
1002 } else if (errno != ENXIO && errno != ENOENT) {
1003 /* there was an error, on a device that does
1004 * exist (device is configured)
1006 fprintf(stderr, "%s: Could not open %s, %s\n",
1007 __progname, buf, strerror(errno));
1012 /* open all the files specified with -f */
1013 for (i = 0; i < ndevs; i++) {
1014 fds[i] = open(devs[i], O_RDWR);
1016 fprintf(stderr, "%s: Could not open %s, %s\n",
1017 __progname, devs[i], strerror(errno));
1021 printf("%s: opened %s\n",
1022 __progname, devs[i]);
1030 fprintf(stderr, "No USB host controllers found\n");
1035 /* Do the explore once and exit */
1037 for (i = 0; i < ndevs; i++) {
1038 error = ioctl(fds[i], USB_DISCOVER);
1040 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1042 __progname, devs[i], strerror(errno));
1049 if (handle_events) {
1051 printf("%s: reading configuration file %s\n",
1052 __progname, configfile);
1053 read_configuration();
1055 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1057 fprintf(stderr, "%s: Could not open %s, %s\n",
1058 __progname, USBDEV, strerror(errno));
1062 printf("%s: opened %s\n", __progname, USBDEV);
1066 process_event_queue(fd); /* dequeue the initial events */
1069 /* move to the background */
1073 /* start select on all the open file descriptors */
1078 FD_SET(fd, &r); /* device USBDEV */
1079 for (i = 0; i < ndevs; i++)
1080 FD_SET(fds[i], &w); /* device USBDEV\d+ */
1082 tv.tv_sec = itimeout;
1083 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1085 fprintf(stderr, "%s: Select failed, %s\n",
1086 __progname, strerror(errno));
1090 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1091 for (i = 0; i < ndevs; i++) {
1092 if (error == 0 || FD_ISSET(fds[i], &w)) {
1094 printf("%s: doing %sdiscovery on %s\n",
1096 (error? "":"timeout "), devs[i]);
1097 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1098 fprintf(stderr, "%s: ioctl(%s, "
1099 "USB_DISCOVER) failed, %s\n",
1100 __progname, devs[i],
1107 /* check the event queue */
1108 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1110 printf("%s: processing event queue %son %s\n",
1112 (error? "":"due to timeout "), USBDEV);
1113 process_event_queue(fd);