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 $
8 * Copyright (c) 1998 The NetBSD Foundation, Inc.
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
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
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>
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.
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.
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 */
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) */
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 */
151 regex_t devname_regex
;
153 char *attach
; /* commands to execute */
156 STAILQ_ENTRY(action_s
) next
;
159 STAILQ_HEAD(action_list
, action_s
) actions
= STAILQ_HEAD_INITIALIZER(actions
);
161 typedef struct action_match_s
{
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
{
187 config_field_fn function
;
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
);
218 fprintf(stderr
, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
219 " [-n] [-c config]\n",
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.
234 * src = 'fir"st \'par"t second part';
236 * *dst = 'hello \'world';
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
);
258 /* find the end of the current string. If quotes are found the search
259 * continues until the corresponding quote is found.
262 * represents the string
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 */
275 dst
[j
++] = src
[i
]; /* copy character */
279 /* quotes being left open? */
281 fprintf(stderr
, "%s:%d: Missing %s quote at end of '%s'\n",
283 (quoted
== 1? "single":"double"), src
);
287 /* skip whitespace for second part */
288 for (/*i is set*/; i
< strlen(src
) && isspace(src
[i
]); i
++)
291 dst
[j
] = '\0'; /* make sure it's NULL terminated */
293 *rdst
= dst
; /* and return the pointers */
294 if (rsrc
!= NULL
) /* if info wanted */
297 if (*dst
== '\0') { /* empty string */
299 } else if (src
[i
] == '\0') { /* completely used (1 argument) */
301 } else { /* 2 or more args, *rsrc is rest */
307 get_integer(char *src
, int *dst
, char **rsrc
)
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 */
322 *dst
= (int) strtol(src
, &endptr
, 0);
324 /* skip over whitespace of second argument */
325 while (isspace(*endptr
))
331 if (isspace(*endptr
)) { /* partial match, 2 or more arguments */
333 } else if (*endptr
== '\0') { /* full match, 1 argument */
335 } else { /* invalid src, no match */
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
);
383 # define ERRSTR_SIZE 100
384 char errstr
[ERRSTR_SIZE
];
389 len
= strlen(action
->devname
);
390 string
= malloc(len
+ 15);
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
);
402 regerror(error
, &action
->devname_regex
, errstr
, ERRSTR_SIZE
);
403 fprintf(stderr
, "%s:%d: %s\n", configfile
, lineno
, errstr
);
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
));
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");
436 fprintf(stderr
, "%s: Could not open for reading, %s\n",
437 configfile
, strerror(errno
));
441 for (lineno
= 1; /* nop */;lineno
++) {
443 line
= fgetln(file
, &len
);
445 if (feof(file
)) /* EOF */
448 fprintf(stderr
, "%s:%d: Could not read, %s\n",
449 configfile
, lineno
, strerror(errno
));
454 /* skip initial spaces */
455 while (len
> 0 && isspace(*line
)) {
460 if (len
== 0) /* empty line */
462 if (line
[0] == '#') /* comment line */
465 /* make a NULL terminated copy of the string */
466 linez
= malloc(len
+1);
468 fprintf(stderr
, "%s:%d: Out of memory\n",
472 strncpy(linez
, line
, len
);
475 /* find the end of the current word (is field), that's the
476 * start of the arguments
480 while (*args
!= '\0' && !isspace(*args
))
483 /* If arguments is not the empty string, NULL terminate the
484 * field and move the argument pointer to the first character
486 * If arguments is the empty string field and arguments both
487 * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
494 /* Skip initial spaces */
495 while (*args
!= '\0' && isspace(*args
))
498 /* Cut off trailing whitespace */
499 for (i
= 0, j
= 0; args
[i
] != '\0'; i
++)
500 if (!isspace(args
[i
]))
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",
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
);
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
,
544 fprintf(stderr
,"%s:%d: "
545 "Syntax error in '%s'\n",
546 configfile
, lineno
, linez
);
552 if (config_fields
[i
].name
== NULL
) { /* Reached end of list*/
553 fprintf(stderr
, "%s:%d: Unknown field '%s'\n",
554 configfile
, lineno
, field
);
567 print_event(struct usb_event
*event
)
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
);
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') {
600 printf(" device names:");
601 for (i
= 0; i
< USB_MAX_DEVNAMES
; i
++) {
602 if (devinfo
->udi_devnames
[i
][0] == '\0')
605 printf("%c%s", c
, devinfo
->udi_devnames
[i
]);
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
);
622 print_action(action_t
*action
, int i
)
627 printf("%s: action %d: %s\n",
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
)
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
)
656 if (action
->devname
!= WILDCARD_STRING
)
657 printf(" devname: %s\n", action
->devname
);
659 if (action
->attach
!= NULL
)
660 printf(" attach='%s'\n",
662 if (action
->detach
!= NULL
)
663 printf(" detach='%s'\n",
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
)
687 for (i
= 0; i
< USB_MAX_DEVNAMES
; i
++) {
688 if (devinfo
->udi_devnames
[i
][0] == '\0')
691 error
= regexec(&action
->devname_regex
, devinfo
->udi_devnames
[i
],
695 printf("%s: %s matches %s\n", __progname
,
696 devinfo
->udi_devnames
[i
], action
->devname
);
706 find_action(struct usb_device_info
*devinfo
, action_match_t
*action_match
)
709 char *devname
= NULL
;
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)) {
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.
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];
741 printf("%s: Found action '%s' for %s, %s",
742 __progname
, action
->name
,
743 devinfo
->udi_product
, devinfo
->udi_vendor
);
745 printf(" at %s", devname
);
749 action_match
->action
= action
;
750 action_match
->devname
= devname
;
760 execute_command(char *cmd
)
763 struct sigaction ign
, intact
, quitact
;
764 sigset_t newsigblock
, oldsigblock
;
769 printf("%s: Executing '%s'\n", __progname
, cmd
);
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
);
783 sigaction(SIGINT
, &ign
, &intact
);
784 sigaction(SIGQUIT
, &ign
, &quitact
);
785 sigemptyset(&newsigblock
);
786 sigaddset(&newsigblock
, SIGCHLD
);
787 sigprocmask(SIG_BLOCK
, &newsigblock
, &oldsigblock
);
790 fprintf(stderr
, "%s: fork failed, %s\n",
791 __progname
, strerror(errno
));
792 } else if (pid
== 0) {
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 */
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
);
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",
827 fprintf(stderr
, "%s: Could not start '%s'\n",
829 } else if (status
== 127) {
830 fprintf(stderr
, "%s: Shell failed for '%s'\n",
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
);
845 process_event_queue(int fd
)
847 struct usb_event event
;
850 action_match_t action_match
;
853 len
= read(fd
, &event
, sizeof(event
));
855 if (errno
== EWOULDBLOCK
) {
859 fprintf(stderr
,"%s: Could not read event, %s\n",
860 __progname
, strerror(errno
));
866 if (len
!= sizeof(event
)) {
867 fprintf(stderr
, "partial read on %s\n", USBDEV
);
871 /* we seem to have gotten a valid event */
876 /* handle the event appropriately */
877 switch (event
.ue_type
) {
878 case USB_EVENT_CTRLR_ATTACH
:
880 printf("USB_EVENT_CTRLR_ATTACH\n");
882 case USB_EVENT_CTRLR_DETACH
:
884 printf("USB_EVENT_CTRLR_DETACH\n");
886 case USB_EVENT_DEVICE_ATTACH
:
887 case USB_EVENT_DEVICE_DETACH
:
888 if (find_action(&event
.u
.ue_device
, &action_match
) == 0)
893 print_action(action_match
.action
, 0);
895 if (action_match
.devname
) {
897 printf("%s: Setting DEVNAME='%s'\n",
898 __progname
, action_match
.devname
);
900 error
= setenv("DEVNAME", action_match
.devname
, 1);
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
);
913 case USB_EVENT_DRIVER_ATTACH
:
915 printf("USB_EVENT_DRIVER_ATTACH\n");
917 case USB_EVENT_DRIVER_DETACH
:
919 printf("USB_EVENT_DRIVER_DETACH\n");
922 printf("Unknown USB event %d\n", event
.ue_type
);
929 main(int argc
, char **argv
)
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 */
939 int itimeout
= TIMEOUT
; /* timeout for select */
942 if (modfind(USB_UHUB
) < 0) {
943 if (kldload(USB_KLD
) < 0 || modfind(USB_UHUB
) < 0) {
944 perror(USB_KLD
": Kernel module not available");
949 while ((ch
= getopt(argc
, argv
, "c:def:nt:v")) != -1) {
952 configfile
= strdup(optarg
);
953 if (configfile
== NULL
) {
954 fprintf(stderr
, "strdup returned NULL\n");
965 if (ndevs
< MAXUSBDEV
)
966 devs
[ndevs
++] = optarg
;
972 itimeout
= atoi(optarg
);
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");
998 printf("%s: opened %s\n",
999 __progname
, devs
[ndevs
]);
1000 if (fds
[ndevs
] > maxfd
)
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
));
1013 /* open all the files specified with -f */
1014 for (i
= 0; i
< ndevs
; i
++) {
1015 fds
[i
] = open(devs
[i
], O_RDWR
);
1017 fprintf(stderr
, "%s: Could not open %s, %s\n",
1018 __progname
, devs
[i
], strerror(errno
));
1022 printf("%s: opened %s\n",
1023 __progname
, devs
[i
]);
1031 fprintf(stderr
, "No USB host controllers found\n");
1036 /* Do the explore once and exit */
1038 for (i
= 0; i
< ndevs
; i
++) {
1039 error
= ioctl(fds
[i
], USB_DISCOVER
);
1041 fprintf(stderr
, "%s: ioctl(%s, USB_DISCOVER) "
1043 __progname
, devs
[i
], strerror(errno
));
1050 if (handle_events
) {
1052 printf("%s: reading configuration file %s\n",
1053 __progname
, configfile
);
1054 read_configuration();
1056 fd
= open(USBDEV
, O_RDONLY
| O_NONBLOCK
);
1058 fprintf(stderr
, "%s: Could not open %s, %s\n",
1059 __progname
, USBDEV
, strerror(errno
));
1063 printf("%s: opened %s\n", __progname
, USBDEV
);
1067 process_event_queue(fd
); /* dequeue the initial events */
1070 /* move to the background */
1074 /* start select on all the open file descriptors */
1079 FD_SET(fd
, &r
); /* device USBDEV */
1080 for (i
= 0; i
< ndevs
; i
++)
1081 FD_SET(fds
[i
], &w
); /* device USBDEV\d+ */
1083 tv
.tv_sec
= itimeout
;
1084 error
= select(maxfd
+1, &r
, &w
, 0, itimeout
? &tv
: 0);
1086 fprintf(stderr
, "%s: Select failed, %s\n",
1087 __progname
, strerror(errno
));
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
)) {
1095 printf("%s: doing %sdiscovery on %s\n",
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
],
1108 /* check the event queue */
1109 if (handle_events
&& (FD_ISSET(fd
, &r
) || error
== 0)) {
1111 printf("%s: processing event queue %son %s\n",
1113 (error
? "":"due to timeout "), USBDEV
);
1114 process_event_queue(fd
);