kernel/mmc: Remove an unused variable.
[dragonfly.git] / usr.sbin / usbd / usbd.c
blob934d845defd3297194322b9d24c17a2c024bac71
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 */
6 /*
7 * Copyright (c) 1998 The NetBSD Foundation, Inc.
8 * All rights reserved.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Lennart Augustsson (augustss@netbsd.org).
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the NetBSD
24 * Foundation, Inc. and its contributors.
25 * 4. Neither the name of The NetBSD Foundation nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
42 /* USBD creates 'threads' in the kernel, used for doing discovery when a
43 * device has attached or detached. This functionality should be removed
44 * once kernel threads have been added to the kernel.
45 * It also handles the event queue, and executing commands based on those
46 * events.
48 * See usbd(8).
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56 #include <ctype.h>
57 #include <signal.h>
58 #include <paths.h>
59 #include <sys/param.h>
60 #include <sys/types.h>
61 #include <sys/errno.h>
62 #include <sys/ioctl.h>
63 #include <sys/linker.h>
64 #include <sys/module.h>
65 #include <sys/queue.h>
66 #include <sys/time.h>
67 #include <sys/wait.h>
68 #include <regex.h>
70 #include <bus/usb/usb.h>
72 /* default name of configuration file
75 #define CONFIGFILE "/etc/usbd.conf"
77 /* the name of the device spitting out usb attach/detach events as well as
78 * the prefix for the individual busses (used as a semi kernel thread).
80 #define USBDEV "/dev/usb"
82 /* Maximum number of USB busses expected to be in a system
83 * XXX should be replaced by dynamic allocation.
85 #define MAXUSBDEV 4
87 /* Sometimes a device does not respond in time for interrupt
88 * driven explore to find it. Therefore we run an exploration
89 * at regular intervals to catch those.
91 #define TIMEOUT 30
93 /* The wildcard used in actions for strings and integers
95 #define WILDCARD_STRING NULL
96 #define WILDCARD_INT -1
99 extern char *__progname; /* name of program */
101 const char *configfile = CONFIGFILE; /* name of configuration file */
103 char *devs[MAXUSBDEV]; /* device names */
104 int fds[MAXUSBDEV]; /* file descriptors for USBDEV\d+ */
105 int ndevs = 0; /* number of entries in fds / devs */
106 int fd = -1; /* file descriptor for USBDEV */
108 int lineno;
109 int verbose = 0; /* print message on what it is doing */
111 typedef struct event_name_s {
112 int type; /* event number (from usb.h) */
113 const char *name;
114 } event_name_t;
116 event_name_t event_names[] = {
117 {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"},
118 {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"},
119 {USB_EVENT_DRIVER_ATTACH, "driver-attach"},
120 {USB_EVENT_DRIVER_DETACH, "driver-detach"},
121 {USB_EVENT_DEVICE_ATTACH, "device-attach"},
122 {USB_EVENT_DEVICE_DETACH, "device-detach"},
123 {0, NULL} /* NULL indicates end of list, not 0 */
126 #define DEVICE_FIELD 0 /* descriptive field */
128 #define VENDOR_FIELD 1 /* selective fields */
129 #define PRODUCT_FIELD 2
130 #define RELEASE_FIELD 3
131 #define CLASS_FIELD 4
132 #define SUBCLASS_FIELD 5
133 #define PROTOCOL_FIELD 6
134 #define DEVNAME_FIELD 7
136 #define ATTACH_FIELD 8 /* command fields */
137 #define DETACH_FIELD 9
140 typedef struct action_s {
141 char *name; /* descriptive string */
143 int vendor; /* selection criteria */
144 int product;
145 int release;
146 int class;
147 int subclass;
148 int protocol;
149 char *devname;
150 regex_t devname_regex;
152 char *attach; /* commands to execute */
153 char *detach;
155 STAILQ_ENTRY(action_s) next;
156 } action_t;
158 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
160 typedef struct action_match_s {
161 action_t *action;
162 char *devname;
163 } action_match_t;
166 /* the function returns 0 for failure, 1 for all arguments found and 2 for
167 * arguments left over in trail.
169 typedef int (*config_field_fn)(action_t *action, char *args, char **trail);
171 static void execute_command(char *);
172 static int find_action(struct usb_device_info *, action_match_t *);
173 static int get_integer(char *, int *, char **);
174 static int get_string(char *, char **, char **);
175 static int match_devname(action_t *, struct usb_device_info *);
176 static void print_action(action_t *, int);
177 static void print_actions(void);
178 static void print_event(struct usb_event *);
179 static void process_event_queue(int);
180 static void read_configuration(void);
181 static int set_attach_field(action_t *, char *, char **);
182 static int set_class_field(action_t *, char *, char **);
183 static int set_detach_field(action_t *, char *, char **);
184 static int set_device_field(action_t *, char *, char **);
185 static int set_devname_field(action_t *, char *, char **);
186 static int set_product_field(action_t *, char *, char **);
187 static int set_protocol_field(action_t *, char *, char **);
188 static int set_release_field(action_t *, char *, char **);
189 static int set_subclass_field(action_t *, char *, char **);
190 static int set_vendor_field(action_t *, char *, char **);
191 static void usage(void);
194 /* the list of fields supported in an entry */
195 typedef struct config_field_s {
196 int event;
197 const char *name;
198 config_field_fn function;
199 } config_field_t;
201 config_field_t config_fields[] = {
202 {DEVICE_FIELD, "device", set_device_field},
204 {VENDOR_FIELD, "vendor", set_vendor_field},
205 {PRODUCT_FIELD, "product", set_product_field},
206 {RELEASE_FIELD, "release", set_release_field},
207 {CLASS_FIELD, "class", set_class_field},
208 {SUBCLASS_FIELD, "subclass", set_subclass_field},
209 {PROTOCOL_FIELD, "protocol", set_protocol_field},
210 {DEVNAME_FIELD, "devname", set_devname_field},
212 {ATTACH_FIELD, "attach", set_attach_field},
213 {DETACH_FIELD, "detach", set_detach_field},
215 {0, NULL, NULL} /* NULL is EOL marker, not the 0 */
218 static void
219 usage(void)
221 fprintf(stderr, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
222 " [-n] [-c config]\n",
223 __progname);
224 exit(1);
228 /* generic helper functions for the functions to set the fields of actions */
229 static int
230 get_string(char *src, char **rdst, char **rsrc)
232 /* Takes the first string from src, taking quoting into account.
233 * rsrc (if not NULL) is set to the first byte not included in the
234 * string returned in rdst.
236 * Input is:
237 * src = 'fir"st \'par"t second part';
238 * Returned is:
239 * *dst = 'hello \'world';
240 * if (rsrc != NULL)
241 * *rsrc = 'second part';
243 * Notice the fact that the single quote enclosed in double quotes is
244 * returned. Also notice that before second part there is more than
245 * one space, which is removed in rsrc.
247 * The string in src is not modified.
250 char *dst; /* destination string */
251 size_t i; /* index into src */
252 int j; /* index into dst */
253 int quoted = 0; /* 1 for single, 2 for double quoted */
255 dst = malloc(strlen(src)+1); /* XXX allocation is too big, realloc?*/
256 if (dst == NULL) { /* should not happen, really */
257 fprintf(stderr, "%s:%d: Out of memory\n", configfile, lineno);
258 exit(2);
261 /* find the end of the current string. If quotes are found the search
262 * continues until the corresponding quote is found.
263 * So,
264 * hel'lo" "wor'ld
265 * represents the string
266 * hello" "world
267 * and not (hello world).
269 for (i = 0, j = 0; i < strlen(src); i++) {
270 if (src[i] == '\'' && (quoted == 0 || quoted == 1)) {
271 quoted = (quoted? 0:1);
272 } else if (src[i] == '"' && (quoted == 0 || quoted == 2)) {
273 quoted = (quoted? 0:2);
274 } else if (isspace(src[i]) && !quoted) {
275 /* found a space outside quotes -> terminates src */
276 break;
277 } else {
278 dst[j++] = src[i]; /* copy character */
282 /* quotes being left open? */
283 if (quoted) {
284 fprintf(stderr, "%s:%d: Missing %s quote at end of '%s'\n",
285 configfile, lineno,
286 (quoted == 1? "single":"double"), src);
287 exit(2);
290 /* skip whitespace for second part */
291 for (/*i is set*/; i < strlen(src) && isspace(src[i]); i++)
292 ; /* nop */
294 dst[j] = '\0'; /* make sure it's NULL terminated */
296 *rdst = dst; /* and return the pointers */
297 if (rsrc != NULL) /* if info wanted */
298 *rsrc = &src[i];
300 if (*dst == '\0') { /* empty string */
301 return 0;
302 } else if (src[i] == '\0') { /* completely used (1 argument) */
303 return 1;
304 } else { /* 2 or more args, *rsrc is rest */
305 return 2;
309 static int
310 get_integer(char *src, int *dst, char **rsrc)
312 char *endptr;
314 /* Converts str to a number. If one argument was found in
315 * str, 1 is returned and *dst is set to the value of the integer.
316 * If 2 or more arguments were presented, 2 is returned,
317 * *dst is set to the converted value and rsrc, if not null, points
318 * at the start of the next argument (whitespace skipped).
319 * Else 0 is returned and nothing else is valid.
322 if (src == NULL || *src == '\0') /* empty src */
323 return(0);
325 *dst = (int) strtol(src, &endptr, 0);
327 /* skip over whitespace of second argument */
328 while (isspace(*endptr))
329 endptr++;
331 if (rsrc)
332 *rsrc = endptr;
334 if (isspace(*endptr)) { /* partial match, 2 or more arguments */
335 return(2);
336 } else if (*endptr == '\0') { /* full match, 1 argument */
337 return(1);
338 } else { /* invalid src, no match */
339 return(0);
343 /* functions to set the fields of the actions appropriately */
344 static int
345 set_device_field(action_t *action, char *args, char **trail)
347 return(get_string(args, &action->name, trail));
350 static int
351 set_vendor_field(action_t *action, char *args, char **trail)
353 return(get_integer(args, &action->vendor, trail));
356 static int
357 set_product_field(action_t *action, char *args, char **trail)
359 return(get_integer(args, &action->product, trail));
362 static int
363 set_release_field(action_t *action, char *args, char **trail)
365 return(get_integer(args, &action->release, trail));
368 static int
369 set_class_field(action_t *action, char *args, char **trail)
371 return(get_integer(args, &action->class, trail));
374 static int
375 set_subclass_field(action_t *action, char *args, char **trail)
377 return(get_integer(args, &action->subclass, trail));
380 static int
381 set_protocol_field(action_t *action, char *args, char **trail)
383 return(get_integer(args, &action->protocol, trail));
386 static int
387 set_devname_field(action_t *action, char *args, char **trail)
389 int match = get_string(args, &action->devname, trail);
390 int len;
391 int error;
392 char *string;
393 # define ERRSTR_SIZE 100
394 char errstr[ERRSTR_SIZE];
396 if (match == 0)
397 return(0);
399 len = strlen(action->devname);
400 string = malloc(len + 15);
401 if (string == NULL)
402 return(0);
404 bcopy(action->devname, string+7, len); /* make some space for */
405 bcopy("[[:<:]]", string, 7); /* beginning of word */
406 bcopy("[[:>:]]", string+7+len, 7); /* and end of word */
407 string[len + 14] = '\0';
409 error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
410 if (error) {
411 errstr[0] = '\0';
412 regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
413 fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
414 return(0);
417 return(match);
420 static int
421 set_attach_field(action_t *action, char *args, char **trail)
423 return(get_string(args, &action->attach, trail));
426 static int
427 set_detach_field(action_t *action, char *args, char **trail)
429 return(get_string(args, &action->detach, trail));
432 static void
433 read_configuration(void)
435 FILE *file; /* file descriptor */
436 char *line; /* current line */
437 char *linez; /* current line, NULL terminated */
438 char *field; /* first part, the field name */
439 char *args; /* second part, arguments */
440 char *trail; /* remaining part after parsing, should be '' */
441 size_t len; /* length of current line */
442 int i,j; /* loop counters */
443 action_t *action = NULL; /* current action */
445 file = fopen(configfile, "r");
446 if (file == NULL) {
447 fprintf(stderr, "%s: Could not open for reading, %s\n",
448 configfile, strerror(errno));
449 exit(2);
452 for (lineno = 1; /* nop */;lineno++) {
454 line = fgetln(file, &len);
455 if (line == NULL) {
456 if (feof(file)) /* EOF */
457 break;
458 if (ferror(file)) {
459 fprintf(stderr, "%s:%d: Could not read, %s\n",
460 configfile, lineno, strerror(errno));
461 exit(2);
465 /* skip initial spaces */
466 while (len > 0 && isspace(*line)) {
467 line++;
468 len--;
471 if (len == 0) /* empty line */
472 continue;
473 if (line[0] == '#') /* comment line */
474 continue;
476 /* make a NULL terminated copy of the string */
477 linez = malloc(len+1);
478 if (linez == NULL) {
479 fprintf(stderr, "%s:%d: Out of memory\n",
480 configfile, lineno);
481 exit(2);
483 strncpy(linez, line, len);
484 linez[len] = '\0';
486 /* find the end of the current word (is field), that's the
487 * start of the arguments
489 field = linez;
490 args = linez;
491 while (*args != '\0' && !isspace(*args))
492 args++;
494 /* If arguments is not the empty string, NULL terminate the
495 * field and move the argument pointer to the first character
496 * of the arguments.
497 * If arguments is the empty string field and arguments both
498 * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
500 if (*args != '\0') {
501 *args = '\0';
502 args++;
505 /* Skip initial spaces */
506 while (*args != '\0' && isspace(*args))
507 args++;
509 /* Cut off trailing whitespace */
510 for (i = 0, j = 0; args[i] != '\0'; i++)
511 if (!isspace(args[i]))
512 j = i+1;
513 args[j] = '\0';
515 /* We now have the field and the argument separated into
516 * two strings that are NULL terminated
519 /* If the field is 'device' we have to start a new action. */
520 if (strcmp(field, "device") == 0) {
521 /* Allocate a new action and set defaults */
522 action = malloc(sizeof(*action));
523 if (action == NULL) {
524 fprintf(stderr, "%s:%d: Out of memory\n",
525 configfile, lineno);
526 exit(2);
528 memset(action, 0, sizeof(*action));
529 action->product = WILDCARD_INT;
530 action->vendor = WILDCARD_INT;
531 action->release = WILDCARD_INT;
532 action->class = WILDCARD_INT;
533 action->subclass = WILDCARD_INT;
534 action->protocol = WILDCARD_INT;
535 action->devname = WILDCARD_STRING;
537 /* Add it to the end of the list to preserve order */
538 STAILQ_INSERT_TAIL(&actions, action, next);
541 if (action == NULL) {
542 line[len] = '\0'; /* XXX zero terminate */
543 fprintf(stderr, "%s:%d: Doesn't start with 'device' "
544 "but '%s'\n", configfile, lineno, field);
545 exit(2);
548 for (i = 0; config_fields[i].name ; i++) {
549 /* does the field name match? */
550 if (strcmp(config_fields[i].name, field) == 0) {
551 /* execute corresponding set-field function */
552 if ((config_fields[i].function)(action, args,
553 &trail)
554 != 1) {
555 fprintf(stderr,"%s:%d: "
556 "Syntax error in '%s'\n",
557 configfile, lineno, linez);
558 exit(2);
560 break;
563 if (config_fields[i].name == NULL) { /* Reached end of list*/
564 fprintf(stderr, "%s:%d: Unknown field '%s'\n",
565 configfile, lineno, field);
566 exit(2);
570 fclose(file);
572 if (verbose >= 2)
573 print_actions();
577 static void
578 print_event(struct usb_event *event)
580 int i;
581 struct timespec *timespec = &event->ue_time;
582 struct usb_device_info *devinfo = &event->u.ue_device;
584 printf("%s: ", __progname);
585 for (i = 0; event_names[i].name != NULL; i++) {
586 if (event->ue_type == event_names[i].type) {
587 printf("%s event", event_names[i].name);
588 break;
591 if (event_names[i].name == NULL)
592 printf("unknown event %d", event->ue_type);
594 if (event->ue_type == USB_EVENT_DEVICE_ATTACH ||
595 event->ue_type == USB_EVENT_DEVICE_DETACH) {
596 devinfo = &event->u.ue_device;
598 printf(" at %ld.%09ld, %s, %s:\n",
599 timespec->tv_sec, timespec->tv_nsec,
600 devinfo->udi_product, devinfo->udi_vendor);
602 printf(" vndr=0x%04x prdct=0x%04x rlse=0x%04x "
603 "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n",
604 devinfo->udi_vendorNo, devinfo->udi_productNo,
605 devinfo->udi_releaseNo,
606 devinfo->udi_class, devinfo->udi_subclass, devinfo->udi_protocol);
608 if (devinfo->udi_devnames[0][0] != '\0') {
609 char c = ' ';
611 printf(" device names:");
612 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
613 if (devinfo->udi_devnames[i][0] == '\0')
614 break;
616 printf("%c%s", c, devinfo->udi_devnames[i]);
617 c = ',';
620 } else if (event->ue_type == USB_EVENT_CTRLR_ATTACH ||
621 event->ue_type == USB_EVENT_CTRLR_DETACH) {
622 printf(" bus=%d", event->u.ue_ctrlr.ue_bus);
623 } else if (event->ue_type == USB_EVENT_DRIVER_ATTACH ||
624 event->ue_type == USB_EVENT_DRIVER_DETACH) {
625 printf(" cookie=%u devname=%s",
626 event->u.ue_driver.ue_cookie.cookie,
627 event->u.ue_driver.ue_devname);
629 printf("\n");
632 static void
633 print_action(action_t *action, int i)
635 if (action == NULL)
636 return;
638 printf("%s: action %d: %s\n",
639 __progname, i,
640 (action->name? action->name:""));
641 if (action->product != WILDCARD_INT ||
642 action->vendor != WILDCARD_INT ||
643 action->release != WILDCARD_INT ||
644 action->class != WILDCARD_INT ||
645 action->subclass != WILDCARD_INT ||
646 action->protocol != WILDCARD_INT)
647 printf(" ");
648 if (action->vendor != WILDCARD_INT)
649 printf(" vndr=0x%04x", action->vendor);
650 if (action->product != WILDCARD_INT)
651 printf(" prdct=0x%04x", action->product);
652 if (action->release != WILDCARD_INT)
653 printf(" rlse=0x%04x", action->release);
654 if (action->class != WILDCARD_INT)
655 printf(" clss=0x%04x", action->class);
656 if (action->subclass != WILDCARD_INT)
657 printf(" subclss=0x%04x", action->subclass);
658 if (action->protocol != WILDCARD_INT)
659 printf(" prtcl=0x%04x", action->protocol);
660 if (action->vendor != WILDCARD_INT ||
661 action->product != WILDCARD_INT ||
662 action->release != WILDCARD_INT ||
663 action->class != WILDCARD_INT ||
664 action->subclass != WILDCARD_INT ||
665 action->protocol != WILDCARD_INT)
666 printf("\n");
667 if (action->devname != WILDCARD_STRING)
668 printf(" devname: %s\n", action->devname);
670 if (action->attach != NULL)
671 printf(" attach='%s'\n",
672 action->attach);
673 if (action->detach != NULL)
674 printf(" detach='%s'\n",
675 action->detach);
678 static void
679 print_actions(void)
681 int i = 0;
682 action_t *action;
684 STAILQ_FOREACH(action, &actions, next)
685 print_action(action, ++i);
687 printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
691 static int
692 match_devname(action_t *action, struct usb_device_info *devinfo)
694 int i;
695 regmatch_t match;
696 int error;
698 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
699 if (devinfo->udi_devnames[i][0] == '\0')
700 break;
702 error = regexec(&action->devname_regex, devinfo->udi_devnames[i],
703 1, &match, 0);
704 if (error == 0) {
705 if (verbose >= 2)
706 printf("%s: %s matches %s\n", __progname,
707 devinfo->udi_devnames[i], action->devname);
708 return(i);
712 return(-1);
716 static int
717 find_action(struct usb_device_info *devinfo, action_match_t *action_match)
719 action_t *action;
720 char *_devname = NULL;
721 int match = -1;
723 STAILQ_FOREACH(action, &actions, next) {
724 if ((action->vendor == WILDCARD_INT ||
725 action->vendor == devinfo->udi_vendorNo) &&
726 (action->product == WILDCARD_INT ||
727 action->product == devinfo->udi_productNo) &&
728 (action->release == WILDCARD_INT ||
729 action->release == devinfo->udi_releaseNo) &&
730 (action->class == WILDCARD_INT ||
731 action->class == devinfo->udi_class) &&
732 (action->subclass == WILDCARD_INT ||
733 action->subclass == devinfo->udi_subclass) &&
734 (action->protocol == WILDCARD_INT ||
735 action->protocol == devinfo->udi_protocol) &&
736 (action->devname == WILDCARD_STRING ||
737 (match = match_devname(action, devinfo)) != -1)) {
738 /* found match !*/
740 /* Find a devname for pretty printing. Either
741 * the matched one or otherwise, if there is only
742 * one devname for that device, use that.
744 if (match >= 0)
745 _devname = devinfo->udi_devnames[match];
746 else if (devinfo->udi_devnames[0][0] != '\0' &&
747 devinfo->udi_devnames[1][0] == '\0')
748 /* if we have exactly 1 device name */
749 _devname = devinfo->udi_devnames[0];
751 if (verbose) {
752 printf("%s: Found action '%s' for %s, %s",
753 __progname, action->name,
754 devinfo->udi_product, devinfo->udi_vendor);
755 if (_devname)
756 printf(" at %s", _devname);
757 printf("\n");
760 action_match->action = action;
761 action_match->devname = _devname;
763 return(1);
767 return(0);
770 static void
771 execute_command(char *cmd)
773 pid_t pid;
774 struct sigaction ign, intact, quitact;
775 sigset_t newsigblock, oldsigblock;
776 int status;
777 int i;
779 if (verbose)
780 printf("%s: Executing '%s'\n", __progname, cmd);
781 if (cmd == NULL)
782 return;
784 /* The code below is directly taken from the system(3) call.
785 * Added to it is the closing of open file descriptors.
788 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
789 * existing signal dispositions.
791 ign.sa_handler = SIG_IGN;
792 sigemptyset(&ign.sa_mask);
793 ign.sa_flags = 0;
794 sigaction(SIGINT, &ign, &intact);
795 sigaction(SIGQUIT, &ign, &quitact);
796 sigemptyset(&newsigblock);
797 sigaddset(&newsigblock, SIGCHLD);
798 sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
799 pid = fork();
800 if (pid == -1) {
801 fprintf(stderr, "%s: fork failed, %s\n",
802 __progname, strerror(errno));
803 } else if (pid == 0) {
804 /* child here */
806 /* close all open file handles for USBDEV\d* devices */
807 for (i = 0; i < ndevs; i++)
808 close(fds[i]); /* USBDEV\d+ */
809 close(fd); /* USBDEV */
811 /* Restore original signal dispositions and exec the command. */
812 sigaction(SIGINT, &intact, NULL);
813 sigaction(SIGQUIT, &quitact, NULL);
814 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
816 execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
818 /* should only be reached in case of error */
819 exit(127);
820 } else {
821 /* parent here */
822 do {
823 pid = waitpid(pid, &status, 0);
824 } while (pid == -1 && errno == EINTR);
826 sigaction(SIGINT, &intact, NULL);
827 sigaction(SIGQUIT, &quitact, NULL);
828 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
830 if (pid == -1) {
831 fprintf(stderr, "%s: waitpid returned: %s\n",
832 __progname, strerror(errno));
833 } else if (pid == 0) {
834 fprintf(stderr, "%s: waitpid returned 0 ?!\n",
835 __progname);
836 } else {
837 if (status == -1) {
838 fprintf(stderr, "%s: Could not start '%s'\n",
839 __progname, cmd);
840 } else if (status == 127) {
841 fprintf(stderr, "%s: Shell failed for '%s'\n",
842 __progname, cmd);
843 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
844 fprintf(stderr, "%s: '%s' returned %d\n",
845 __progname, cmd, WEXITSTATUS(status));
846 } else if (WIFSIGNALED(status)) {
847 fprintf(stderr, "%s: '%s' caught signal %d\n",
848 __progname, cmd, WTERMSIG(status));
849 } else if (verbose >= 2) {
850 printf("%s: '%s' is ok\n", __progname, cmd);
855 static void
856 process_event_queue(int fdesc)
858 struct usb_event event;
859 int error;
860 int len;
861 action_match_t action_match;
863 for (;;) {
864 len = read(fdesc, &event, sizeof(event));
865 if (len == -1) {
866 if (errno == EWOULDBLOCK) {
867 /* no more events */
868 break;
869 } else {
870 fprintf(stderr,"%s: Could not read event, %s\n",
871 __progname, strerror(errno));
872 exit(1);
875 if (len == 0)
876 break;
877 if (len != sizeof(event)) {
878 fprintf(stderr, "partial read on %s\n", USBDEV);
879 exit(1);
882 /* we seem to have gotten a valid event */
884 if (verbose)
885 print_event(&event);
887 /* handle the event appropriately */
888 switch (event.ue_type) {
889 case USB_EVENT_CTRLR_ATTACH:
890 if (verbose)
891 printf("USB_EVENT_CTRLR_ATTACH\n");
892 break;
893 case USB_EVENT_CTRLR_DETACH:
894 if (verbose)
895 printf("USB_EVENT_CTRLR_DETACH\n");
896 break;
897 case USB_EVENT_DEVICE_ATTACH:
898 case USB_EVENT_DEVICE_DETACH:
899 if (find_action(&event.u.ue_device, &action_match) == 0)
900 /* nothing found */
901 break;
903 if (verbose >= 2)
904 print_action(action_match.action, 0);
906 if (action_match.devname) {
907 if (verbose >= 2)
908 printf("%s: Setting DEVNAME='%s'\n",
909 __progname, action_match.devname);
911 error = setenv("DEVNAME", action_match.devname, 1);
912 if (error)
913 fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
914 __progname, action_match.devname, strerror(errno));
917 if (USB_EVENT_IS_ATTACH(event.ue_type) &&
918 action_match.action->attach)
919 execute_command(action_match.action->attach);
920 if (USB_EVENT_IS_DETACH(event.ue_type) &&
921 action_match.action->detach)
922 execute_command(action_match.action->detach);
923 break;
924 case USB_EVENT_DRIVER_ATTACH:
925 if (verbose)
926 printf("USB_EVENT_DRIVER_ATTACH\n");
927 break;
928 case USB_EVENT_DRIVER_DETACH:
929 if (verbose)
930 printf("USB_EVENT_DRIVER_DETACH\n");
931 break;
932 default:
933 printf("Unknown USB event %d\n", event.ue_type);
940 main(int argc, char **argv)
942 int error, i;
943 int ch; /* getopt option */
944 int debug = 0; /* print debugging output */
945 int explore_once = 0; /* don't do only explore */
946 int handle_events = 1; /* do handle the event queue */
947 int maxfd; /* maximum fd in use */
948 char buf[50]; /* for creation of the filename */
949 fd_set r,w;
950 int itimeout = TIMEOUT; /* timeout for select */
951 struct timeval tv;
953 if (modfind(USB_UHUB) < 0) {
954 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
955 perror(USB_KLD ": Kernel module not available");
956 return 1;
960 while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
961 switch(ch) {
962 case 'c':
963 configfile = strdup(optarg);
964 if (configfile == NULL) {
965 fprintf(stderr, "strdup returned NULL\n");
966 return 1;
968 break;
969 case 'd':
970 debug++;
971 break;
972 case 'e':
973 explore_once = 1;
974 break;
975 case 'f':
976 if (ndevs < MAXUSBDEV)
977 devs[ndevs++] = optarg;
978 break;
979 case 'n':
980 handle_events = 0;
981 break;
982 case 't':
983 itimeout = atoi(optarg);
984 break;
985 case 'v':
986 verbose++;
987 break;
988 case '?':
989 default:
990 usage();
993 argc -= optind;
994 argv += optind;
996 maxfd = 0;
997 if (ndevs == 0) {
998 /* open all the USBDEVS\d+ devices */
999 for (i = 0; i < MAXUSBDEV; i++) {
1000 sprintf(buf, "%s%d", USBDEV, i);
1001 fds[ndevs] = open(buf, O_RDWR);
1002 if (fds[ndevs] >= 0) {
1003 devs[ndevs] = strdup(buf);
1004 if (devs[ndevs] == NULL) {
1005 fprintf(stderr, "strdup returned NULL\n");
1006 return 1;
1008 if (verbose)
1009 printf("%s: opened %s\n",
1010 __progname, devs[ndevs]);
1011 if (fds[ndevs] > maxfd)
1012 maxfd = fds[ndevs];
1013 ndevs++;
1014 } else if (errno != ENXIO && errno != ENOENT) {
1015 /* there was an error, on a device that does
1016 * exist (device is configured)
1018 fprintf(stderr, "%s: Could not open %s, %s\n",
1019 __progname, buf, strerror(errno));
1020 exit(1);
1023 } else {
1024 /* open all the files specified with -f */
1025 for (i = 0; i < ndevs; i++) {
1026 fds[i] = open(devs[i], O_RDWR);
1027 if (fds[i] < 0) {
1028 fprintf(stderr, "%s: Could not open %s, %s\n",
1029 __progname, devs[i], strerror(errno));
1030 exit(1);
1031 } else {
1032 if (verbose)
1033 printf("%s: opened %s\n",
1034 __progname, devs[i]);
1035 if (fds[i] > maxfd)
1036 maxfd = fds[i];
1041 if (ndevs == 0) {
1042 fprintf(stderr, "No USB host controllers found\n");
1043 exit(1);
1047 /* Do the explore once and exit */
1048 if (explore_once) {
1049 for (i = 0; i < ndevs; i++) {
1050 error = ioctl(fds[i], USB_DISCOVER);
1051 if (error < 0) {
1052 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1053 "failed, %s\n",
1054 __progname, devs[i], strerror(errno));
1055 exit(1);
1058 exit(0);
1061 if (handle_events) {
1062 if (verbose)
1063 printf("%s: reading configuration file %s\n",
1064 __progname, configfile);
1065 read_configuration();
1067 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1068 if (fd < 0) {
1069 fprintf(stderr, "%s: Could not open %s, %s\n",
1070 __progname, USBDEV, strerror(errno));
1071 exit(1);
1073 if (verbose)
1074 printf("%s: opened %s\n", __progname, USBDEV);
1075 if (fd > maxfd)
1076 maxfd = fd;
1078 process_event_queue(fd); /* dequeue the initial events */
1081 /* move to the background */
1082 if (!debug)
1083 daemon(0, 0);
1085 /* start select on all the open file descriptors */
1086 for (;;) {
1087 FD_ZERO(&r);
1088 FD_ZERO(&w);
1089 if (handle_events)
1090 FD_SET(fd, &r); /* device USBDEV */
1091 for (i = 0; i < ndevs; i++)
1092 FD_SET(fds[i], &w); /* device USBDEV\d+ */
1093 tv.tv_usec = 0;
1094 tv.tv_sec = itimeout;
1095 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1096 if (error < 0) {
1097 fprintf(stderr, "%s: Select failed, %s\n",
1098 __progname, strerror(errno));
1099 exit(1);
1102 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1103 for (i = 0; i < ndevs; i++) {
1104 if (error == 0 || FD_ISSET(fds[i], &w)) {
1105 if (verbose >= 2)
1106 printf("%s: doing %sdiscovery on %s\n",
1107 __progname,
1108 (error? "":"timeout "), devs[i]);
1109 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1110 fprintf(stderr, "%s: ioctl(%s, "
1111 "USB_DISCOVER) failed, %s\n",
1112 __progname, devs[i],
1113 strerror(errno));
1114 exit(1);
1119 /* check the event queue */
1120 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1121 if (verbose >= 2)
1122 printf("%s: processing event queue %son %s\n",
1123 __progname,
1124 (error? "":"due to timeout "), USBDEV);
1125 process_event_queue(fd);