Clean (void) casts from usr.sbin
[dragonfly.git] / usr.sbin / usbd / usbd.c
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.6 2004/12/18 22:48:14 swildner Exp $
5  */
6
7 /*
8  * Copyright (c) 1998 The NetBSD Foundation, Inc.
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to The NetBSD Foundation
12  * by Lennart Augustsson (augustss@netbsd.org).
13  *
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.
29  *
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.
41  */
42
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.
48  *
49  * See usbd(8).
50  */
51
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>
70
71 #include <bus/usb/usb.h>
72
73 /* default name of configuration file
74  */
75
76 #define CONFIGFILE      "/etc/usbd.conf"
77
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).
80  */
81 #define USBDEV          "/dev/usb"
82
83 /* Maximum number of USB busses expected to be in a system
84  * XXX should be replaced by dynamic allocation.
85  */
86 #define MAXUSBDEV       4
87
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.
91  */
92 #define TIMEOUT         30
93
94 /* The wildcard used in actions for strings and integers
95  */
96 #define WILDCARD_STRING NULL
97 #define WILDCARD_INT    -1
98
99
100 extern char *__progname;        /* name of program */
101
102 char *configfile = CONFIGFILE;  /* name of configuration file */
103
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 */
108
109 int lineno;
110 int verbose = 0;                /* print message on what it is doing */
111
112 typedef struct event_name_s {
113         int     type;           /* event number (from usb.h) */
114         char    *name;
115 } event_name_t;
116
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 */
125 };
126
127 #define DEVICE_FIELD            0       /* descriptive field */
128
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
136
137 #define ATTACH_FIELD            8       /* command fields */
138 #define DETACH_FIELD            9
139
140
141 typedef struct action_s {
142         char    *name;          /* descriptive string */
143
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;
152
153         char    *attach;        /* commands to execute */
154         char    *detach;
155
156         STAILQ_ENTRY(action_s) next;
157 } action_t;
158
159 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
160
161 typedef struct action_match_s {
162         action_t *action;
163         char    *devname;
164 } action_match_t;
165
166
167 /* the function returns 0 for failure, 1 for all arguments found and 2 for
168  * arguments left over in trail.
169  */
170 typedef int (*config_field_fn)  __P((action_t *action, char *args,
171                                         char **trail));
172
173 int set_device_field(action_t *action, char *args, char **trail);
174 int set_vendor_field(action_t *action, char *args, char **trail);
175 int set_product_field(action_t *action, char *args, char **trail);
176 int set_release_field(action_t *action, char *args, char **trail);
177 int set_class_field(action_t *action, char *args, char **trail);
178 int set_subclass_field(action_t *action, char *args, char **trail);
179 int set_protocol_field(action_t *action, char *args, char **trail);
180 int set_devname_field(action_t *action, char *args, char **trail);
181 int set_attach_field(action_t *action, char *args, char **trail);
182 int set_detach_field(action_t *action, char *args, char **trail);
183
184 /* the list of fields supported in an entry */
185 typedef struct config_field_s {
186         int     event;
187         char    *name;
188         config_field_fn function;
189 } config_field_t;
190
191 config_field_t config_fields[] = {
192         {DEVICE_FIELD,          "device",       set_device_field},
193
194         {VENDOR_FIELD,          "vendor",       set_vendor_field},
195         {PRODUCT_FIELD,         "product",      set_product_field},
196         {RELEASE_FIELD,         "release",      set_release_field},
197         {CLASS_FIELD,           "class",        set_class_field},
198         {SUBCLASS_FIELD,        "subclass",     set_subclass_field},
199         {PROTOCOL_FIELD,        "protocol",     set_protocol_field},
200         {DEVNAME_FIELD,         "devname",      set_devname_field},
201
202         {ATTACH_FIELD,          "attach",       set_attach_field},
203         {DETACH_FIELD,          "detach",       set_detach_field},
204
205         {0, NULL, NULL}         /* NULL is EOL marker, not the 0 */
206 };
207
208
209 /* prototypes for some functions */
210 void print_event        __P((struct usb_event *event));
211 void print_action       __P((action_t *action, int i));
212 void print_actions      __P((void));
213 int  find_action        __P((struct usb_device_info *devinfo,
214                         action_match_t *action_match));
215
216
217 void
218 usage(void)
219 {
220         fprintf(stderr, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
221                         "           [-n] [-c config]\n",
222                 __progname);
223         exit(1);
224 }
225
226
227 /* generic helper functions for the functions to set the fields of actions */
228 int
229 get_string(char *src, char **rdst, char **rsrc)
230 {
231         /* Takes the first string from src, taking quoting into account.
232          * rsrc (if not NULL) is set to the first byte not included in the
233          * string returned in rdst.
234          *
235          * Input is:
236          *   src = 'fir"st \'par"t       second part';
237          * Returned is:
238          *   *dst = 'hello \'world';
239          *   if (rsrc != NULL)
240          *     *rsrc = 'second part';
241          *
242          * Notice the fact that the single quote enclosed in double quotes is
243          * returned. Also notice that before second part there is more than
244          * one space, which is removed in rsrc.
245          *
246          * The string in src is not modified.
247          */
248
249         char *dst;              /* destination string */
250         int i;                  /* index into src */
251         int j;                  /* index into dst */
252         int quoted = 0;         /* 1 for single, 2 for double quoted */
253
254         dst = malloc(strlen(src)+1);    /* XXX allocation is too big, realloc?*/
255         if (dst == NULL) {              /* should not happen, really */
256                 fprintf(stderr, "%s:%d: Out of memory\n", configfile, lineno);
257                 exit(2);
258         }
259
260         /* find the end of the current string. If quotes are found the search
261          * continues until the corresponding quote is found.
262          * So,
263          *   hel'lo" "wor'ld
264          * represents the string
265          *   hello" "world
266          * and not (hello world).
267          */
268         for (i = 0, j = 0; i < strlen(src); i++) {
269                 if (src[i] == '\'' && (quoted == 0 || quoted == 1)) {
270                         quoted = (quoted? 0:1);
271                 } else if (src[i] == '"' && (quoted == 0 || quoted == 2)) {
272                         quoted = (quoted? 0:2);
273                 } else if (isspace(src[i]) && !quoted) {
274                         /* found a space outside quotes -> terminates src */
275                         break;
276                 } else {
277                         dst[j++] = src[i];      /* copy character */
278                 }
279         }
280
281         /* quotes being left open? */
282         if (quoted) {
283                 fprintf(stderr, "%s:%d: Missing %s quote at end of '%s'\n",
284                         configfile, lineno,
285                         (quoted == 1? "single":"double"), src);
286                 exit(2);
287         }
288
289         /* skip whitespace for second part */
290         for (/*i is set*/; i < strlen(src) && isspace(src[i]); i++)
291                 ;       /* nop */
292
293         dst[j] = '\0';                  /* make sure it's NULL terminated */
294
295         *rdst = dst;                    /* and return the pointers */
296         if (rsrc != NULL)               /* if info wanted */
297                 *rsrc = &src[i];
298
299         if (*dst == '\0') {             /* empty string */
300                 return 0;
301         } else if (src[i] == '\0') {    /* completely used (1 argument) */
302                 return 1;
303         } else {                        /* 2 or more args, *rsrc is rest */
304                 return 2;
305         }
306 }
307
308 int
309 get_integer(char *src, int *dst, char **rsrc)
310 {
311         char *endptr;
312
313         /* Converts str to a number. If one argument was found in
314          * str, 1 is returned and *dst is set to the value of the integer.
315          * If 2 or more arguments were presented, 2 is returned,
316          * *dst is set to the converted value and rsrc, if not null, points
317          * at the start of the next argument (whitespace skipped).
318          * Else 0 is returned and nothing else is valid.
319          */
320
321         if (src == NULL || *src == '\0')        /* empty src */
322                 return(0);
323
324         *dst = (int) strtol(src, &endptr, 0);
325
326         /* skip over whitespace of second argument */
327         while (isspace(*endptr))
328                 endptr++;
329
330         if (rsrc)
331                 *rsrc = endptr;
332
333         if (isspace(*endptr)) {         /* partial match, 2 or more arguments */
334                 return(2);
335         } else if (*endptr == '\0') {   /* full match, 1 argument */
336                 return(1);
337         } else {                        /* invalid src, no match */
338                 return(0);
339         }
340 }
341
342 /* functions to set the fields of the actions appropriately */
343 int
344 set_device_field(action_t *action, char *args, char **trail)
345 {
346         return(get_string(args, &action->name, trail));
347 }
348 int
349 set_vendor_field(action_t *action, char *args, char **trail)
350 {
351         return(get_integer(args, &action->vendor, trail));
352 }
353 int
354 set_product_field(action_t *action, char *args, char **trail)
355 {
356         return(get_integer(args, &action->product, trail));
357 }
358 int
359 set_release_field(action_t *action, char *args, char **trail)
360 {
361         return(get_integer(args, &action->release, trail));
362 }
363 int
364 set_class_field(action_t *action, char *args, char **trail)
365 {
366         return(get_integer(args, &action->class, trail));
367 }
368 int
369 set_subclass_field(action_t *action, char *args, char **trail)
370 {
371         return(get_integer(args, &action->subclass, trail));
372 }
373 int
374 set_protocol_field(action_t *action, char *args, char **trail)
375 {
376         return(get_integer(args, &action->protocol, trail));
377 }
378 int
379 set_devname_field(action_t *action, char *args, char **trail)
380 {
381         int match = get_string(args, &action->devname, trail);
382         int len;
383         int error;
384         char *string;
385 #       define ERRSTR_SIZE      100
386         char errstr[ERRSTR_SIZE];
387
388         if (match == 0)
389                 return(0);
390
391         len = strlen(action->devname);
392         string = malloc(len + 15);
393         if (string == NULL)
394                 return(0);
395
396         bcopy(action->devname, string+7, len);  /* make some space for */
397         bcopy("[[:<:]]", string, 7);            /*   beginning of word */
398         bcopy("[[:>:]]", string+7+len, 7);      /*   and end of word   */
399         string[len + 14] = '\0';
400
401         error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
402         if (error) {
403                 errstr[0] = '\0';
404                 regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
405                 fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
406                 return(0);
407         }
408
409         return(match);
410 }
411 int
412 set_attach_field(action_t *action, char *args, char **trail)
413 {
414         return(get_string(args, &action->attach, trail));
415 }
416 int
417 set_detach_field(action_t *action, char *args, char **trail)
418 {
419         return(get_string(args, &action->detach, trail));
420 }
421
422
423 void
424 read_configuration(void)
425 {
426         FILE *file;             /* file descriptor */
427         char *line;             /* current line */
428         char *linez;            /* current line, NULL terminated */
429         char *field;            /* first part, the field name */
430         char *args;             /* second part, arguments */
431         char *trail;            /* remaining part after parsing, should be '' */
432         size_t len;             /* length of current line */
433         int i,j;                /* loop counters */
434         action_t *action = NULL;        /* current action */
435
436         file = fopen(configfile, "r");
437         if (file == NULL) {
438                 fprintf(stderr, "%s: Could not open for reading, %s\n",
439                         configfile, strerror(errno));
440                 exit(2);
441         }
442
443         for (lineno = 1; /* nop */;lineno++) {
444         
445                 line = fgetln(file, &len);
446                 if (line == NULL) {
447                         if (feof(file))                 /* EOF */
448                                 break;
449                         if (ferror(file)) {
450                                 fprintf(stderr, "%s:%d: Could not read, %s\n",
451                                         configfile, lineno, strerror(errno));
452                                 exit(2);
453                         }
454                 }
455
456                 /* skip initial spaces */
457                 while (len > 0 && isspace(*line)) {
458                         line++;
459                         len--;
460                 }
461
462                 if (len == 0)           /* empty line */
463                         continue;
464                 if (line[0] == '#')     /* comment line */
465                         continue;
466
467                 /* make a NULL terminated copy of the string */
468                 linez = malloc(len+1);
469                 if (linez == NULL) {
470                         fprintf(stderr, "%s:%d: Out of memory\n",
471                                 configfile, lineno);
472                         exit(2);
473                 }
474                 strncpy(linez, line, len);
475                 linez[len] = '\0';
476
477                 /* find the end of the current word (is field), that's the
478                  * start of the arguments
479                  */
480                 field = linez;
481                 args = linez;
482                 while (*args != '\0' && !isspace(*args))
483                         args++;
484
485                 /* If arguments is not the empty string, NULL terminate the
486                  * field and move the argument pointer to the first character
487                  * of the arguments.
488                  * If arguments is the empty string field and arguments both
489                  * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
490                  */
491                 if (*args != '\0') {
492                         *args = '\0';
493                         args++;
494                 }
495
496                 /* Skip initial spaces */
497                 while (*args != '\0' && isspace(*args))
498                         args++;
499
500                 /* Cut off trailing whitespace */
501                 for (i = 0, j = 0; args[i] != '\0'; i++)
502                         if (!isspace(args[i]))
503                                 j = i+1;
504                 args[j] = '\0';
505
506                 /* We now have the field and the argument separated into
507                  * two strings that are NULL terminated
508                  */
509
510                 /* If the field is 'device' we have to start a new action. */
511                 if (strcmp(field, "device") == 0) {
512                         /* Allocate a new action and set defaults */
513                         action = malloc(sizeof(*action));
514                         if (action == NULL) {
515                                 fprintf(stderr, "%s:%d: Out of memory\n",
516                                         configfile, lineno);
517                                 exit(2);
518                         }
519                         memset(action, 0, sizeof(*action));
520                         action->product = WILDCARD_INT;
521                         action->vendor = WILDCARD_INT;
522                         action->release = WILDCARD_INT;
523                         action->class = WILDCARD_INT;
524                         action->subclass = WILDCARD_INT;
525                         action->protocol = WILDCARD_INT;
526                         action->devname = WILDCARD_STRING;
527
528                         /* Add it to the end of the list to preserve order */
529                         STAILQ_INSERT_TAIL(&actions, action, next);
530                 }
531
532                 if (action == NULL) {
533                         line[len] = '\0';       /* XXX zero terminate */
534                         fprintf(stderr, "%s:%d: Doesn't start with 'device' "
535                                 "but '%s'\n", configfile, lineno, field);
536                         exit(2);
537                 }
538                 
539                 for (i = 0; config_fields[i].name  ; i++) {
540                         /* does the field name match? */
541                         if (strcmp(config_fields[i].name, field) == 0) {
542                                 /* execute corresponding set-field function */
543                                 if ((config_fields[i].function)(action, args,
544                                                                 &trail)
545                                     != 1) {
546                                         fprintf(stderr,"%s:%d: "
547                                                 "Syntax error in '%s'\n",
548                                                 configfile, lineno, linez);
549                                         exit(2);
550                                 }
551                                 break;
552                         }
553                 }
554                 if (config_fields[i].name == NULL) {    /* Reached end of list*/
555                         fprintf(stderr, "%s:%d: Unknown field '%s'\n",
556                                 configfile, lineno, field);
557                         exit(2);
558                 }
559         }
560
561         fclose(file);
562
563         if (verbose >= 2)
564                 print_actions();
565 }
566
567
568 void
569 print_event(struct usb_event *event)
570 {
571         int i;
572         struct timespec *timespec = &event->ue_time;
573         struct usb_device_info *devinfo = &event->u.ue_device;
574
575         printf("%s: ", __progname);
576         for (i = 0; event_names[i].name != NULL; i++) {
577                 if (event->ue_type == event_names[i].type) {
578                         printf("%s event", event_names[i].name);
579                         break;
580                 }
581         }
582         if (event_names[i].name == NULL)
583                 printf("unknown event %d", event->ue_type);
584
585         if (event->ue_type == USB_EVENT_DEVICE_ATTACH ||
586             event->ue_type == USB_EVENT_DEVICE_DETACH) {
587                 devinfo = &event->u.ue_device;
588
589                 printf(" at %ld.%09ld, %s, %s:\n",
590                         timespec->tv_sec, timespec->tv_nsec,
591                         devinfo->udi_product, devinfo->udi_vendor);
592
593                 printf("  vndr=0x%04x prdct=0x%04x rlse=0x%04x "
594                        "clss=0x%04x subclss=0x%04x prtcl=0x%04x\n",
595                        devinfo->udi_vendorNo, devinfo->udi_productNo,
596                        devinfo->udi_releaseNo,
597                        devinfo->udi_class, devinfo->udi_subclass, devinfo->udi_protocol);
598
599                 if (devinfo->udi_devnames[0][0] != '\0') {
600                         char c = ' ';
601
602                         printf("  device names:");
603                         for (i = 0; i < USB_MAX_DEVNAMES; i++) {
604                                 if (devinfo->udi_devnames[i][0] == '\0')
605                                         break;
606
607                                 printf("%c%s", c, devinfo->udi_devnames[i]);
608                                 c = ',';
609                         }
610                 }
611         } else if (event->ue_type == USB_EVENT_CTRLR_ATTACH ||
612             event->ue_type == USB_EVENT_CTRLR_DETACH) {
613                 printf(" bus=%d", &event->u.ue_ctrlr.ue_bus);
614         } else if (event->ue_type == USB_EVENT_DRIVER_ATTACH ||
615             event->ue_type == USB_EVENT_DRIVER_DETACH) {
616                 printf(" cookie=%u devname=%s",
617                     &event->u.ue_driver.ue_cookie.cookie,
618                     &event->u.ue_driver.ue_devname);
619         }
620         printf("\n");
621 }
622
623 void
624 print_action(action_t *action, int i)
625 {
626         if (action == NULL)
627                 return;
628
629         printf("%s: action %d: %s\n",
630                 __progname, i,
631                 (action->name? action->name:""));
632         if (action->product != WILDCARD_INT ||
633             action->vendor != WILDCARD_INT ||
634             action->release != WILDCARD_INT ||
635             action->class != WILDCARD_INT ||
636             action->subclass != WILDCARD_INT ||
637             action->protocol != WILDCARD_INT)
638                 printf(" ");
639         if (action->vendor != WILDCARD_INT)
640                 printf(" vndr=0x%04x", action->vendor);
641         if (action->product != WILDCARD_INT)
642                 printf(" prdct=0x%04x", action->product);
643         if (action->release != WILDCARD_INT)
644                 printf(" rlse=0x%04x", action->release);
645         if (action->class != WILDCARD_INT)
646                 printf(" clss=0x%04x", action->class);
647         if (action->subclass != WILDCARD_INT)
648                 printf(" subclss=0x%04x", action->subclass);
649         if (action->protocol != WILDCARD_INT)
650                 printf(" prtcl=0x%04x", action->protocol);
651         if (action->vendor != WILDCARD_INT ||
652             action->product != WILDCARD_INT ||
653             action->release != WILDCARD_INT ||
654             action->class != WILDCARD_INT ||
655             action->subclass != WILDCARD_INT ||
656             action->protocol != WILDCARD_INT)
657                 printf("\n");
658         if (action->devname != WILDCARD_STRING)
659                 printf("  devname: %s\n", action->devname);
660
661         if (action->attach != NULL)
662                 printf("  attach='%s'\n",
663                         action->attach);
664         if (action->detach != NULL)
665                 printf("  detach='%s'\n",
666                         action->detach);
667 }
668
669 void
670 print_actions()
671 {
672         int i = 0;
673         action_t *action;
674
675         STAILQ_FOREACH(action, &actions, next)
676                 print_action(action, ++i);
677
678         printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
679 }
680
681
682 int
683 match_devname(action_t *action, struct usb_device_info *devinfo)
684 {
685         int i;
686         regmatch_t match;
687         int error;
688
689         for (i = 0; i < USB_MAX_DEVNAMES; i++) {
690                 if (devinfo->udi_devnames[i][0] == '\0')
691                         break;
692
693                 error = regexec(&action->devname_regex, devinfo->udi_devnames[i],
694                                 1, &match, 0);
695                 if (error == 0) {
696                         if (verbose >= 2)
697                                 printf("%s: %s matches %s\n", __progname,
698                                         devinfo->udi_devnames[i], action->devname);
699                         return(i);
700                 }
701         }
702         
703         return(-1);
704 }
705
706
707 int
708 find_action(struct usb_device_info *devinfo, action_match_t *action_match)
709 {
710         action_t *action;
711         char *devname = NULL;
712         int match = -1;
713
714         STAILQ_FOREACH(action, &actions, next) {
715                 if ((action->vendor == WILDCARD_INT ||
716                      action->vendor == devinfo->udi_vendorNo) &&
717                     (action->product == WILDCARD_INT ||
718                      action->product == devinfo->udi_productNo) &&
719                     (action->release == WILDCARD_INT ||
720                      action->release == devinfo->udi_releaseNo) &&
721                     (action->class == WILDCARD_INT ||
722                      action->class == devinfo->udi_class) &&
723                     (action->subclass == WILDCARD_INT ||
724                      action->subclass == devinfo->udi_subclass) &&
725                     (action->protocol == WILDCARD_INT ||
726                      action->protocol == devinfo->udi_protocol) &&
727                     (action->devname == WILDCARD_STRING ||
728                      (match = match_devname(action, devinfo)) != -1)) {
729                         /* found match !*/
730
731                         /* Find a devname for pretty printing. Either
732                          * the matched one or otherwise, if there is only
733                          * one devname for that device, use that.
734                          */
735                         if (match >= 0)
736                                 devname = devinfo->udi_devnames[match];
737                         else if (devinfo->udi_devnames[0][0] != '\0' &&
738                                  devinfo->udi_devnames[1][0] == '\0')
739                                 /* if we have exactly 1 device name */
740                                 devname = devinfo->udi_devnames[0];
741
742                         if (verbose) {
743                                 printf("%s: Found action '%s' for %s, %s",
744                                         __progname, action->name,
745                                         devinfo->udi_product, devinfo->udi_vendor);
746                                 if (devname)
747                                         printf(" at %s", devname);
748                                 printf("\n");
749                         }
750
751                         action_match->action = action;
752                         action_match->devname = devname;
753
754                         return(1);
755                 }
756         }
757
758         return(0);
759 }
760
761 void
762 execute_command(char *cmd)
763 {
764         pid_t pid;
765         struct sigaction ign, intact, quitact;
766         sigset_t newsigblock, oldsigblock;
767         int status;
768         int i;
769
770         if (verbose)
771                 printf("%s: Executing '%s'\n", __progname, cmd);
772         if (cmd == NULL)
773                 return;
774
775         /* The code below is directly taken from the system(3) call.
776          * Added to it is the closing of open file descriptors.
777          */
778         /*
779          * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
780          * existing signal dispositions.
781          */
782         ign.sa_handler = SIG_IGN;
783         sigemptyset(&ign.sa_mask);
784         ign.sa_flags = 0;
785         sigaction(SIGINT, &ign, &intact);
786         sigaction(SIGQUIT, &ign, &quitact);
787         sigemptyset(&newsigblock);
788         sigaddset(&newsigblock, SIGCHLD);
789         sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
790         pid = fork();
791         if (pid == -1) {
792                 fprintf(stderr, "%s: fork failed, %s\n",
793                         __progname, strerror(errno));
794         } else if (pid == 0) {
795                 /* child here */
796
797                 /* close all open file handles for USBDEV\d* devices */
798                 for (i = 0; i < ndevs; i++)
799                         close(fds[i]);          /* USBDEV\d+ */
800                 close(fd);                      /* USBDEV */
801
802                 /* Restore original signal dispositions and exec the command. */
803                 sigaction(SIGINT, &intact, NULL);
804                 sigaction(SIGQUIT,  &quitact, NULL);
805                 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
806
807                 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
808
809                 /* should only be reached in case of error */
810                 exit(127);
811         } else {
812                 /* parent here */
813                 do {
814                         pid = waitpid(pid, &status, 0);
815                 } while (pid == -1 && errno == EINTR);
816         }
817         sigaction(SIGINT, &intact, NULL);
818         sigaction(SIGQUIT,  &quitact, NULL);
819         sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
820
821         if (pid == -1) {
822                 fprintf(stderr, "%s: waitpid returned: %s\n",
823                         __progname, strerror(errno));
824         } else if (pid == 0) {
825                 fprintf(stderr, "%s: waitpid returned 0 ?!\n",
826                         __progname);
827         } else {
828                 if (status == -1) {
829                         fprintf(stderr, "%s: Could not start '%s'\n",
830                                 __progname, cmd);
831                 } else if (status == 127) {
832                         fprintf(stderr, "%s: Shell failed for '%s'\n",
833                                 __progname, cmd);
834                 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
835                         fprintf(stderr, "%s: '%s' returned %d\n",
836                                 __progname, cmd, WEXITSTATUS(status));
837                 } else if (WIFSIGNALED(status)) {
838                         fprintf(stderr, "%s: '%s' caught signal %d\n",
839                                 __progname, cmd, WTERMSIG(status));
840                 } else if (verbose >= 2) {
841                         printf("%s: '%s' is ok\n", __progname, cmd);
842                 }
843         }
844 }
845
846 void
847 process_event_queue(int fd)
848 {
849         struct usb_event event;
850         int error;
851         int len;
852         action_match_t action_match;
853
854         for (;;) {
855                 len = read(fd, &event, sizeof(event));
856                 if (len == -1) {
857                         if (errno == EWOULDBLOCK) {
858                                 /* no more events */
859                                 break;
860                         } else {
861                                 fprintf(stderr,"%s: Could not read event, %s\n",
862                                         __progname, strerror(errno));
863                                 exit(1);
864                         }
865                 }
866                 if (len == 0)
867                         break;
868                 if (len != sizeof(event)) {
869                         fprintf(stderr, "partial read on %s\n", USBDEV);
870                         exit(1);
871                 }
872
873                 /* we seem to have gotten a valid event */
874
875                 if (verbose)
876                         print_event(&event);
877
878                 /* handle the event appropriately */
879                 switch (event.ue_type) {
880                 case USB_EVENT_CTRLR_ATTACH:
881                         if (verbose)
882                                 printf("USB_EVENT_CTRLR_ATTACH\n");
883                         break;
884                 case USB_EVENT_CTRLR_DETACH:
885                         if (verbose)
886                                 printf("USB_EVENT_CTRLR_DETACH\n");
887                         break;
888                 case USB_EVENT_DEVICE_ATTACH:
889                 case USB_EVENT_DEVICE_DETACH:
890                         if (find_action(&event.u.ue_device, &action_match) == 0)
891                                 /* nothing found */
892                                 break;
893
894                         if (verbose >= 2)
895                                 print_action(action_match.action, 0);
896
897                         if (action_match.devname) {
898                                 if (verbose >= 2)
899                                         printf("%s: Setting DEVNAME='%s'\n",
900                                                 __progname, action_match.devname);
901
902                                 error = setenv("DEVNAME", action_match.devname, 1);
903                                 if (error)
904                                         fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
905                                                 __progname, action_match.devname, strerror(errno));
906                         }
907
908                         if (USB_EVENT_IS_ATTACH(event.ue_type) &&
909                             action_match.action->attach) 
910                                 execute_command(action_match.action->attach);
911                         if (USB_EVENT_IS_DETACH(event.ue_type) &&
912                             action_match.action->detach)
913                                 execute_command(action_match.action->detach);
914                         break;
915                 case USB_EVENT_DRIVER_ATTACH:
916                         if (verbose)
917                                 printf("USB_EVENT_DRIVER_ATTACH\n");
918                         break;
919                 case USB_EVENT_DRIVER_DETACH:
920                         if (verbose)
921                                 printf("USB_EVENT_DRIVER_DETACH\n");
922                         break;
923                 default:
924                         printf("Unknown USB event %d\n", event.ue_type);
925                 }
926         }       
927 }
928
929
930 int
931 main(int argc, char **argv)
932 {
933         int error, i;
934         int ch;                 /* getopt option */
935         int debug = 0;          /* print debugging output */
936         int explore_once = 0;   /* don't do only explore */
937         int handle_events = 1;  /* do handle the event queue */
938         int maxfd;              /* maximum fd in use */
939         char buf[50];           /* for creation of the filename */
940         fd_set r,w;
941         int itimeout = TIMEOUT; /* timeout for select */
942         struct timeval tv;
943
944         if (modfind(USB_UHUB) < 0) {
945                 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
946                         perror(USB_KLD ": Kernel module not available");
947                         return 1;
948                 }
949         }
950
951         while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
952                 switch(ch) {
953                 case 'c':
954                         configfile = strdup(optarg);
955                         if (configfile == NULL) {
956                                 fprintf(stderr, "strdup returned NULL\n");
957                                 return 1;
958                         }
959                         break;
960                 case 'd':
961                         debug++;
962                         break;
963                 case 'e':
964                         explore_once = 1;
965                         break;
966                 case 'f':
967                         if (ndevs < MAXUSBDEV)
968                                 devs[ndevs++] = optarg;
969                         break;
970                 case 'n':
971                         handle_events = 0;
972                         break;
973                 case 't':
974                         itimeout = atoi(optarg);
975                         break;
976                 case 'v':
977                         verbose++;
978                         break;
979                 case '?':
980                 default:
981                         usage();
982                 }
983         }
984         argc -= optind;
985         argv += optind;
986
987         maxfd = 0;
988         if (ndevs == 0) {
989                 /* open all the USBDEVS\d+ devices */
990                 for (i = 0; i < MAXUSBDEV; i++) {
991                         sprintf(buf, "%s%d", USBDEV, i);
992                         fds[ndevs] = open(buf, O_RDWR);
993                         if (fds[ndevs] >= 0) {
994                                 devs[ndevs] = strdup(buf);
995                                 if (devs[ndevs] == NULL) {
996                                         fprintf(stderr, "strdup returned NULL\n");
997                                         return 1;
998                                 }
999                                 if (verbose)
1000                                         printf("%s: opened %s\n", 
1001                                                __progname, devs[ndevs]);
1002                                 if (fds[ndevs] > maxfd)
1003                                         maxfd = fds[ndevs];
1004                                 ndevs++;
1005                         } else if (errno != ENXIO && errno != ENOENT) {
1006                                 /* there was an error, on a device that does
1007                                  * exist (device is configured)
1008                                  */
1009                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1010                                         __progname, buf, strerror(errno));
1011                                 exit(1);
1012                         }
1013                 }
1014         } else {
1015                 /* open all the files specified with -f */
1016                 for (i = 0; i < ndevs; i++) {
1017                         fds[i] = open(devs[i], O_RDWR);
1018                         if (fds[i] < 0) {
1019                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1020                                         __progname, devs[i], strerror(errno));
1021                                 exit(1);
1022                         } else {
1023                                 if (verbose)
1024                                         printf("%s: opened %s\n", 
1025                                                __progname, devs[i]);
1026                                 if (fds[i] > maxfd)
1027                                         maxfd = fds[i];
1028                         }
1029                 }
1030         }
1031
1032         if (ndevs == 0) {
1033                 fprintf(stderr, "No USB host controllers found\n");
1034                 exit(1);
1035         }
1036
1037
1038         /* Do the explore once and exit */
1039         if (explore_once) {
1040                 for (i = 0; i < ndevs; i++) {
1041                         error = ioctl(fds[i], USB_DISCOVER);
1042                         if (error < 0) {
1043                                 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1044                                         "failed, %s\n",
1045                                         __progname, devs[i], strerror(errno));
1046                                 exit(1);
1047                         }
1048                 }
1049                 exit(0);
1050         }
1051
1052         if (handle_events) {
1053                 if (verbose)
1054                         printf("%s: reading configuration file %s\n",
1055                                 __progname, configfile);
1056                 read_configuration();
1057
1058                 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1059                 if (fd < 0) {
1060                         fprintf(stderr, "%s: Could not open %s, %s\n",
1061                                 __progname, USBDEV, strerror(errno));
1062                         exit(1);
1063                 }
1064                 if (verbose)
1065                         printf("%s: opened %s\n", __progname, USBDEV);
1066                 if (fd > maxfd)
1067                         maxfd = fd;
1068
1069                 process_event_queue(fd);        /* dequeue the initial events */
1070         }
1071
1072         /* move to the background */
1073         if (!debug)
1074                 daemon(0, 0);
1075
1076         /* start select on all the open file descriptors */
1077         for (;;) {
1078                 FD_ZERO(&r);
1079                 FD_ZERO(&w);
1080                 if (handle_events)
1081                         FD_SET(fd, &r);         /* device USBDEV */
1082                 for (i = 0; i < ndevs; i++)
1083                         FD_SET(fds[i], &w);     /* device USBDEV\d+ */
1084                 tv.tv_usec = 0;
1085                 tv.tv_sec = itimeout;
1086                 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1087                 if (error < 0) {
1088                         fprintf(stderr, "%s: Select failed, %s\n",
1089                                 __progname, strerror(errno));
1090                         exit(1);
1091                 }
1092
1093                 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1094                 for (i = 0; i < ndevs; i++) {
1095                         if (error == 0 || FD_ISSET(fds[i], &w)) {
1096                                 if (verbose >= 2)
1097                                         printf("%s: doing %sdiscovery on %s\n", 
1098                                                __progname,
1099                                                (error? "":"timeout "), devs[i]);
1100                                 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1101                                         fprintf(stderr, "%s: ioctl(%s, "
1102                                                 "USB_DISCOVER) failed, %s\n",
1103                                                 __progname, devs[i],
1104                                                 strerror(errno));
1105                                         exit(1);
1106                                 }
1107                         }
1108                 }
1109
1110                 /* check the event queue */
1111                 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1112                         if (verbose >= 2)
1113                                 printf("%s: processing event queue %son %s\n",
1114                                         __progname,
1115                                        (error? "":"due to timeout "), USBDEV);
1116                         process_event_queue(fd);
1117                 }
1118         }
1119 }