]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/usbd/usbd.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / usr.sbin / usbd / usbd.c
1 /*      $NetBSD: usbd.c,v 1.4 1998/12/09 00:57:19 augustss Exp $        */
2 /*      $FreeBSD$       */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@netbsd.org).
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 /* USBD creates 'threads' in the kernel, used for doing discovery when a
41  * device has attached or detached. This functionality should be removed
42  * once kernel threads have been added to the kernel.
43  * It also handles the event queue, and executing commands based on those
44  * events.
45  *
46  * See usbd(8).
47  */
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54 #include <ctype.h>
55 #include <signal.h>
56 #include <paths.h>
57 #include <stdint.h>
58 #include <sys/param.h>
59 #include <sys/types.h>
60 #include <sys/errno.h>
61 #include <sys/ioctl.h>
62 #include <sys/linker.h>
63 #include <sys/module.h>
64 #include <sys/queue.h>
65 #include <sys/time.h>
66 #include <sys/wait.h>
67 #include <regex.h>
68
69 #include <dev/usb/usb.h>
70
71 /* default name of configuration file
72  */
73
74 #define CONFIGFILE      "/etc/usbd.conf"
75
76 /* the name of the device spitting out usb attach/detach events as well as
77  * the prefix for the individual busses (used as a semi kernel thread).
78  */
79 #define USBDEV          "/dev/usb"
80
81 /* Maximum number of USB busses expected to be in a system
82  * XXX should be replaced by dynamic allocation.
83  */
84 #define MAXUSBDEV       40
85
86 /* Sometimes a device does not respond in time for interrupt
87  * driven explore to find it.  Therefore we run an exploration
88  * at regular intervals to catch those.
89  */
90 #define TIMEOUT         30
91
92 /* The wildcard used in actions for strings and integers
93  */
94 #define WILDCARD_STRING NULL
95 #define WILDCARD_INT    -1
96
97
98 extern char *__progname;        /* name of program */
99
100 char *configfile = CONFIGFILE;  /* name of configuration file */
101
102 char *devs[MAXUSBDEV];          /* device names */
103 int fds[MAXUSBDEV];             /* file descriptors for USBDEV\d+ */
104 int ndevs = 0;                  /* number of entries in fds / devs */
105 int fd = -1;                    /* file descriptor for USBDEV */
106
107 int lineno;
108 int verbose = 0;                /* print message on what it is doing */
109
110 typedef struct event_name_s {
111         int     type;           /* event number (from usb.h) */
112         char    *name;
113 } event_name_t;
114
115 event_name_t event_names[] = {
116         {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"},
117         {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"},
118         {USB_EVENT_DRIVER_ATTACH, "driver-attach"},
119         {USB_EVENT_DRIVER_DETACH, "driver-detach"},
120         {USB_EVENT_DEVICE_ATTACH, "device-attach"},
121         {USB_EVENT_DEVICE_DETACH, "device-detach"},
122         {0, NULL}                       /* NULL indicates end of list, not 0 */
123 };
124
125 #define DEVICE_FIELD            0       /* descriptive field */
126
127 #define VENDOR_FIELD            1       /* selective fields */
128 #define PRODUCT_FIELD           2
129 #define RELEASE_FIELD           3
130 #define CLASS_FIELD             4
131 #define SUBCLASS_FIELD          5
132 #define PROTOCOL_FIELD          6
133 #define DEVNAME_FIELD           7
134
135 #define ATTACH_FIELD            8       /* command fields */
136 #define DETACH_FIELD            9
137
138
139 typedef struct action_s {
140         char    *name;          /* descriptive string */
141
142         int     vendor; /* selection criteria */
143         int     product;
144         int     release;
145         int     class;
146         int     subclass;
147         int     protocol;
148         char    *devname;
149         regex_t devname_regex;
150
151         char    *attach;        /* commands to execute */
152         char    *detach;
153
154         STAILQ_ENTRY(action_s) next;
155 } action_t;
156
157 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
158
159 typedef struct action_match_s {
160         action_t *action;
161         char    *devname;
162 } action_match_t;
163
164
165 /* the function returns 0 for failure, 1 for all arguments found and 2 for
166  * arguments left over in trail.
167  */
168 typedef int (*config_field_fn)  __P((action_t *action, char *args,
169                                         char **trail));
170
171 int set_device_field(action_t *action, char *args, char **trail);
172 int set_vendor_field(action_t *action, char *args, char **trail);
173 int set_product_field(action_t *action, char *args, char **trail);
174 int set_release_field(action_t *action, char *args, char **trail);
175 int set_class_field(action_t *action, char *args, char **trail);
176 int set_subclass_field(action_t *action, char *args, char **trail);
177 int set_protocol_field(action_t *action, char *args, char **trail);
178 int set_devname_field(action_t *action, char *args, char **trail);
179 int set_attach_field(action_t *action, char *args, char **trail);
180 int set_detach_field(action_t *action, char *args, char **trail);
181
182 /* the list of fields supported in an entry */
183 typedef struct config_field_s {
184         int     event;
185         char    *name;
186         config_field_fn function;
187 } config_field_t;
188
189 config_field_t config_fields[] = {
190         {DEVICE_FIELD,          "device",       set_device_field},
191
192         {VENDOR_FIELD,          "vendor",       set_vendor_field},
193         {PRODUCT_FIELD,         "product",      set_product_field},
194         {RELEASE_FIELD,         "release",      set_release_field},
195         {CLASS_FIELD,           "class",        set_class_field},
196         {SUBCLASS_FIELD,        "subclass",     set_subclass_field},
197         {PROTOCOL_FIELD,        "protocol",     set_protocol_field},
198         {DEVNAME_FIELD,         "devname",      set_devname_field},
199
200         {ATTACH_FIELD,          "attach",       set_attach_field},
201         {DETACH_FIELD,          "detach",       set_detach_field},
202
203         {0, NULL, NULL}         /* NULL is EOL marker, not the 0 */
204 };
205
206
207 /* prototypes for some functions */
208 void print_event        __P((struct usb_event *event));
209 void print_action       __P((action_t *action, int i));
210 void print_actions      __P((void));
211 int  find_action        __P((struct usb_device_info *devinfo,
212                         action_match_t *action_match));
213
214
215 void
216 usage(void)
217 {
218         fprintf(stderr, "usage: %s [-d] [-v] [-t timeout] [-e] [-f dev]\n"
219                         "           [-n] [-c config]\n",
220                 __progname);
221         exit(1);
222 }
223
224
225 /* generic helper functions for the functions to set the fields of actions */
226 int
227 get_string(char *src, char **rdst, char **rsrc)
228 {
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.
232          *
233          * Input is:
234          *   src = 'fir"st \'par"t       second part';
235          * Returned is:
236          *   *dst = 'hello \'world';
237          *   if (rsrc != NULL)
238          *     *rsrc = 'second part';
239          *
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.
243          *
244          * The string in src is not modified.
245          */
246
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 */
251
252         dst = malloc(strlen(src)+1);    /* XXX allocation is too big, realloc?*/
253         if (dst == NULL) {              /* should not happen, really */
254                 fprintf(stderr, "%s:%d: Out of memory\n", configfile, lineno);
255                 exit(2);
256         }
257
258         /* find the end of the current string. If quotes are found the search
259          * continues until the corresponding quote is found.
260          * So,
261          *   hel'lo" "wor'ld
262          * represents the string
263          *   hello" "world
264          * and not (hello world).
265          */
266         for (i = 0, j = 0; i < strlen(src); i++) {
267                 if (src[i] == '\'' && (quoted == 0 || quoted == 1)) {
268                         quoted = (quoted? 0:1);
269                 } else if (src[i] == '"' && (quoted == 0 || quoted == 2)) {
270                         quoted = (quoted? 0:2);
271                 } else if (isspace(src[i]) && !quoted) {
272                         /* found a space outside quotes -> terminates src */
273                         break;
274                 } else {
275                         dst[j++] = src[i];      /* copy character */
276                 }
277         }
278
279         /* quotes being left open? */
280         if (quoted) {
281                 fprintf(stderr, "%s:%d: Missing %s quote at end of '%s'\n",
282                         configfile, lineno,
283                         (quoted == 1? "single":"double"), src);
284                 exit(2);
285         }
286
287         /* skip whitespace for second part */
288         for (/*i is set*/; i < strlen(src) && isspace(src[i]); i++)
289                 ;       /* nop */
290
291         dst[j] = '\0';                  /* make sure it's NULL terminated */
292
293         *rdst = dst;                    /* and return the pointers */
294         if (rsrc != NULL)               /* if info wanted */
295                 *rsrc = &src[i];
296
297         if (*dst == '\0') {             /* empty string */
298                 return 0;
299         } else if (src[i] == '\0') {    /* completely used (1 argument) */
300                 return 1;
301         } else {                        /* 2 or more args, *rsrc is rest */
302                 return 2;
303         }
304 }
305
306 int
307 get_integer(char *src, int *dst, char **rsrc)
308 {
309         char *endptr;
310
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.
317          */
318
319         if (src == NULL || *src == '\0')        /* empty src */
320                 return(0);
321
322         *dst = (int) strtol(src, &endptr, 0);
323
324         /* skip over whitespace of second argument */
325         while (isspace(*endptr))
326                 endptr++;
327
328         if (rsrc)
329                 *rsrc = endptr;
330
331         if (isspace(*endptr)) {         /* partial match, 2 or more arguments */
332                 return(2);
333         } else if (*endptr == '\0') {   /* full match, 1 argument */
334                 return(1);
335         } else {                        /* invalid src, no match */
336                 return(0);
337         }
338 }
339
340 /* functions to set the fields of the actions appropriately */
341 int
342 set_device_field(action_t *action, char *args, char **trail)
343 {
344         return(get_string(args, &action->name, trail));
345 }
346 int
347 set_vendor_field(action_t *action, char *args, char **trail)
348 {
349         return(get_integer(args, &action->vendor, trail));
350 }
351 int
352 set_product_field(action_t *action, char *args, char **trail)
353 {
354         return(get_integer(args, &action->product, trail));
355 }
356 int
357 set_release_field(action_t *action, char *args, char **trail)
358 {
359         return(get_integer(args, &action->release, trail));
360 }
361 int
362 set_class_field(action_t *action, char *args, char **trail)
363 {
364         return(get_integer(args, &action->class, trail));
365 }
366 int
367 set_subclass_field(action_t *action, char *args, char **trail)
368 {
369         return(get_integer(args, &action->subclass, trail));
370 }
371 int
372 set_protocol_field(action_t *action, char *args, char **trail)
373 {
374         return(get_integer(args, &action->protocol, trail));
375 }
376 int
377 set_devname_field(action_t *action, char *args, char **trail)
378 {
379         int match = get_string(args, &action->devname, trail);
380         int len;
381         int error;
382         char *string;
383 #       define ERRSTR_SIZE      100
384         char errstr[ERRSTR_SIZE];
385
386         if (match == 0)
387                 return(0);
388
389         len = strlen(action->devname);
390         string = malloc(len + 15);
391         if (string == NULL)
392                 return(0);
393
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';
398
399         error = regcomp(&action->devname_regex, string, REG_NOSUB|REG_EXTENDED);
400         if (error) {
401                 errstr[0] = '\0';
402                 regerror(error, &action->devname_regex, errstr, ERRSTR_SIZE);
403                 fprintf(stderr, "%s:%d: %s\n", configfile, lineno, errstr);
404                 return(0);
405         }
406
407         return(match);
408 }
409 int
410 set_attach_field(action_t *action, char *args, char **trail)
411 {
412         return(get_string(args, &action->attach, trail));
413 }
414 int
415 set_detach_field(action_t *action, char *args, char **trail)
416 {
417         return(get_string(args, &action->detach, trail));
418 }
419
420
421 void
422 read_configuration(void)
423 {
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 */
433
434         file = fopen(configfile, "r");
435         if (file == NULL) {
436                 fprintf(stderr, "%s: Could not open for reading, %s\n",
437                         configfile, strerror(errno));
438                 exit(2);
439         }
440
441         for (lineno = 1; /* nop */;lineno++) {
442         
443                 line = fgetln(file, &len);
444                 if (line == NULL) {
445                         if (feof(file))                 /* EOF */
446                                 break;
447                         if (ferror(file)) {
448                                 fprintf(stderr, "%s:%d: Could not read, %s\n",
449                                         configfile, lineno, strerror(errno));
450                                 exit(2);
451                         }
452                 }
453
454                 /* skip initial spaces */
455                 while (len > 0 && isspace(*line)) {
456                         line++;
457                         len--;
458                 }
459
460                 if (len == 0)           /* empty line */
461                         continue;
462                 if (line[0] == '#')     /* comment line */
463                         continue;
464
465                 /* make a NULL terminated copy of the string */
466                 linez = malloc(len+1);
467                 if (linez == NULL) {
468                         fprintf(stderr, "%s:%d: Out of memory\n",
469                                 configfile, lineno);
470                         exit(2);
471                 }
472                 strncpy(linez, line, len);
473                 linez[len] = '\0';
474
475                 /* find the end of the current word (is field), that's the
476                  * start of the arguments
477                  */
478                 field = linez;
479                 args = linez;
480                 while (*args != '\0' && !isspace(*args))
481                         args++;
482
483                 /* If arguments is not the empty string, NULL terminate the
484                  * field and move the argument pointer to the first character
485                  * of the arguments.
486                  * If arguments is the empty string field and arguments both
487                  * are terminated (strlen(field) >= 0, strlen(arguments) == 0).
488                  */
489                 if (*args != '\0') {
490                         *args = '\0';
491                         args++;
492                 }
493
494                 /* Skip initial spaces */
495                 while (*args != '\0' && isspace(*args))
496                         args++;
497
498                 /* Cut off trailing whitespace */
499                 for (i = 0, j = 0; args[i] != '\0'; i++)
500                         if (!isspace(args[i]))
501                                 j = i+1;
502                 args[j] = '\0';
503
504                 /* We now have the field and the argument separated into
505                  * two strings that are NULL terminated
506                  */
507
508                 /* If the field is 'device' we have to start a new action. */
509                 if (strcmp(field, "device") == 0) {
510                         /* Allocate a new action and set defaults */
511                         action = malloc(sizeof(*action));
512                         if (action == NULL) {
513                                 fprintf(stderr, "%s:%d: Out of memory\n",
514                                         configfile, lineno);
515                                 exit(2);
516                         }
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;
525
526                         /* Add it to the end of the list to preserve order */
527                         STAILQ_INSERT_TAIL(&actions, action, next);
528                 }
529
530                 if (action == NULL) {
531                         line[len] = '\0';       /* XXX zero terminate */
532                         fprintf(stderr, "%s:%d: Doesn't start with 'device' "
533                                 "but '%s'\n", configfile, lineno, field);
534                         exit(2);
535                 }
536                 
537                 for (i = 0; config_fields[i].name  ; i++) {
538                         /* does the field name match? */
539                         if (strcmp(config_fields[i].name, field) == 0) {
540                                 /* execute corresponding set-field function */
541                                 if ((config_fields[i].function)(action, args,
542                                                                 &trail)
543                                     != 1) {
544                                         fprintf(stderr,"%s:%d: "
545                                                 "Syntax error in '%s'\n",
546                                                 configfile, lineno, linez);
547                                         exit(2);
548                                 }
549                                 break;
550                         }
551                 }
552                 if (config_fields[i].name == NULL) {    /* Reached end of list*/
553                         fprintf(stderr, "%s:%d: Unknown field '%s'\n",
554                                 configfile, lineno, field);
555                         exit(2);
556                 }
557         }
558
559         fclose(file);
560
561         if (verbose >= 2)
562                 print_actions();
563 }
564
565
566 void
567 print_event(struct usb_event *event)
568 {
569         int i;
570         struct timespec *timespec = &event->ue_time;
571         struct usb_device_info *devinfo = &event->u.ue_device;
572
573         printf("%s: ", __progname);
574         for (i = 0; event_names[i].name != NULL; i++) {
575                 if (event->ue_type == event_names[i].type) {
576                         printf("%s event", event_names[i].name);
577                         break;
578                 }
579         }
580         if (event_names[i].name == NULL)
581                 printf("unknown event %d", event->ue_type);
582
583         if (event->ue_type == USB_EVENT_DEVICE_ATTACH ||
584             event->ue_type == USB_EVENT_DEVICE_DETACH) {
585                 devinfo = &event->u.ue_device;
586
587                 printf(" at %jd.%09ld, %s, %s:\n",
588                         (intmax_t)timespec->tv_sec, timespec->tv_nsec,
589                         devinfo->udi_product, devinfo->udi_vendor);
590
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);
596
597                 if (devinfo->udi_devnames[0][0] != '\0') {
598                         char c = ' ';
599
600                         printf("  device names:");
601                         for (i = 0; i < USB_MAX_DEVNAMES; i++) {
602                                 if (devinfo->udi_devnames[i][0] == '\0')
603                                         break;
604
605                                 printf("%c%s", c, devinfo->udi_devnames[i]);
606                                 c = ',';
607                         }
608                 }
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);
617         }
618         printf("\n");
619 }
620
621 void
622 print_action(action_t *action, int i)
623 {
624         if (action == NULL)
625                 return;
626
627         printf("%s: action %d: %s\n",
628                 __progname, i,
629                 (action->name? action->name:""));
630         if (action->product != WILDCARD_INT ||
631             action->vendor != WILDCARD_INT ||
632             action->release != WILDCARD_INT ||
633             action->class != WILDCARD_INT ||
634             action->subclass != WILDCARD_INT ||
635             action->protocol != WILDCARD_INT)
636                 printf(" ");
637         if (action->vendor != WILDCARD_INT)
638                 printf(" vndr=0x%04x", action->vendor);
639         if (action->product != WILDCARD_INT)
640                 printf(" prdct=0x%04x", action->product);
641         if (action->release != WILDCARD_INT)
642                 printf(" rlse=0x%04x", action->release);
643         if (action->class != WILDCARD_INT)
644                 printf(" clss=0x%04x", action->class);
645         if (action->subclass != WILDCARD_INT)
646                 printf(" subclss=0x%04x", action->subclass);
647         if (action->protocol != WILDCARD_INT)
648                 printf(" prtcl=0x%04x", action->protocol);
649         if (action->vendor != WILDCARD_INT ||
650             action->product != WILDCARD_INT ||
651             action->release != WILDCARD_INT ||
652             action->class != WILDCARD_INT ||
653             action->subclass != WILDCARD_INT ||
654             action->protocol != WILDCARD_INT)
655                 printf("\n");
656         if (action->devname != WILDCARD_STRING)
657                 printf("  devname: %s\n", action->devname);
658
659         if (action->attach != NULL)
660                 printf("  attach='%s'\n",
661                         action->attach);
662         if (action->detach != NULL)
663                 printf("  detach='%s'\n",
664                         action->detach);
665 }
666
667 void
668 print_actions()
669 {
670         int i = 0;
671         action_t *action;
672
673         STAILQ_FOREACH(action, &actions, next)
674                 print_action(action, ++i);
675
676         printf("%s: %d action%s\n", __progname, i, (i == 1? "":"s"));
677 }
678
679
680 int
681 match_devname(action_t *action, struct usb_device_info *devinfo)
682 {
683         int i;
684         regmatch_t match;
685         int error;
686
687         for (i = 0; i < USB_MAX_DEVNAMES; i++) {
688                 if (devinfo->udi_devnames[i][0] == '\0')
689                         break;
690
691                 error = regexec(&action->devname_regex, devinfo->udi_devnames[i],
692                                 1, &match, 0);
693                 if (error == 0) {
694                         if (verbose >= 2)
695                                 printf("%s: %s matches %s\n", __progname,
696                                         devinfo->udi_devnames[i], action->devname);
697                         return(i);
698                 }
699         }
700         
701         return(-1);
702 }
703
704
705 int
706 find_action(struct usb_device_info *devinfo, action_match_t *action_match)
707 {
708         action_t *action;
709         char *devname = NULL;
710         int match = -1;
711
712         STAILQ_FOREACH(action, &actions, next) {
713                 if ((action->vendor == WILDCARD_INT ||
714                      action->vendor == devinfo->udi_vendorNo) &&
715                     (action->product == WILDCARD_INT ||
716                      action->product == devinfo->udi_productNo) &&
717                     (action->release == WILDCARD_INT ||
718                      action->release == devinfo->udi_releaseNo) &&
719                     (action->class == WILDCARD_INT ||
720                      action->class == devinfo->udi_class) &&
721                     (action->subclass == WILDCARD_INT ||
722                      action->subclass == devinfo->udi_subclass) &&
723                     (action->protocol == WILDCARD_INT ||
724                      action->protocol == devinfo->udi_protocol) &&
725                     (action->devname == WILDCARD_STRING ||
726                      (match = match_devname(action, devinfo)) != -1)) {
727                         /* found match !*/
728
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.
732                          */
733                         if (match >= 0)
734                                 devname = devinfo->udi_devnames[match];
735                         else if (devinfo->udi_devnames[0][0] != '\0' &&
736                                  devinfo->udi_devnames[1][0] == '\0')
737                                 /* if we have exactly 1 device name */
738                                 devname = devinfo->udi_devnames[0];
739
740                         if (verbose) {
741                                 printf("%s: Found action '%s' for %s, %s",
742                                         __progname, action->name,
743                                         devinfo->udi_product, devinfo->udi_vendor);
744                                 if (devname)
745                                         printf(" at %s", devname);
746                                 printf("\n");
747                         }
748
749                         action_match->action = action;
750                         action_match->devname = devname;
751
752                         return(1);
753                 }
754         }
755
756         return(0);
757 }
758
759 void
760 execute_command(char *cmd)
761 {
762         pid_t pid;
763         struct sigaction ign, intact, quitact;
764         sigset_t newsigblock, oldsigblock;
765         int status;
766         int i;
767
768         if (verbose)
769                 printf("%s: Executing '%s'\n", __progname, cmd);
770         if (cmd == NULL)
771                 return;
772
773         /* The code below is directly taken from the system(3) call.
774          * Added to it is the closing of open file descriptors.
775          */
776         /*
777          * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
778          * existing signal dispositions.
779          */
780         ign.sa_handler = SIG_IGN;
781         (void) sigemptyset(&ign.sa_mask);
782         ign.sa_flags = 0;
783         (void) sigaction(SIGINT, &ign, &intact);
784         (void) sigaction(SIGQUIT, &ign, &quitact);
785         (void) sigemptyset(&newsigblock);
786         (void) sigaddset(&newsigblock, SIGCHLD);
787         (void) sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
788         pid = fork();
789         if (pid == -1) {
790                 fprintf(stderr, "%s: fork failed, %s\n",
791                         __progname, strerror(errno));
792         } else if (pid == 0) {
793                 /* child here */
794
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 */
799
800                 /* Restore original signal dispositions and exec the command. */
801                 (void) sigaction(SIGINT, &intact, NULL);
802                 (void) sigaction(SIGQUIT,  &quitact, NULL);
803                 (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
804
805                 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
806
807                 /* should only be reached in case of error */
808                 exit(127);
809         } else {
810                 /* parent here */
811                 do {
812                         pid = waitpid(pid, &status, 0);
813                 } while (pid == -1 && errno == EINTR);
814         }
815         (void) sigaction(SIGINT, &intact, NULL);
816         (void) sigaction(SIGQUIT,  &quitact, NULL);
817         (void) sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
818
819         if (pid == -1) {
820                 fprintf(stderr, "%s: waitpid returned: %s\n",
821                         __progname, strerror(errno));
822         } else if (pid == 0) {
823                 fprintf(stderr, "%s: waitpid returned 0 ?!\n",
824                         __progname);
825         } else {
826                 if (status == -1) {
827                         fprintf(stderr, "%s: Could not start '%s'\n",
828                                 __progname, cmd);
829                 } else if (status == 127) {
830                         fprintf(stderr, "%s: Shell failed for '%s'\n",
831                                 __progname, cmd);
832                 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
833                         fprintf(stderr, "%s: '%s' returned %d\n",
834                                 __progname, cmd, WEXITSTATUS(status));
835                 } else if (WIFSIGNALED(status)) {
836                         fprintf(stderr, "%s: '%s' caught signal %d\n",
837                                 __progname, cmd, WTERMSIG(status));
838                 } else if (verbose >= 2) {
839                         printf("%s: '%s' is ok\n", __progname, cmd);
840                 }
841         }
842 }
843
844 void
845 process_event_queue(int fd)
846 {
847         struct usb_event events;
848         int error;
849         int len;
850         action_match_t action_match;
851         int i;
852         struct usb_event the_event;
853         struct usb_device_info* devinfo;
854         struct usb_device_info* the_devinfo;
855
856         for (;;) {
857                 len = read(fd, &events, sizeof(events));
858                 if (len == -1) {
859                         if (errno == EWOULDBLOCK) {
860                                 /* no more events */
861                                 break;
862                         } else {
863                                 fprintf(stderr,"%s: Could not read event, %s\n",
864                                                 __progname, strerror(errno));
865                                 exit(1);
866                         }
867                 }
868                 if (len == 0)
869                         break;
870                 if (len != sizeof(events)) {
871                         fprintf(stderr, "partial read on %s\n", USBDEV);
872                         exit(1);
873                 }
874
875                 /* we seem to have gotten a valid event */
876
877                 if (verbose)
878                         print_event(&events);
879
880                 devinfo = &events.u.ue_device;
881                 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
882                         if (devinfo->udi_devnames[i][0] == '\0')
883                                 break;
884
885                         memcpy(&the_event, &events, sizeof(the_event));
886                         the_devinfo = &the_event.u.ue_device;
887                         if (i > 0)
888                                 memcpy(the_devinfo->udi_devnames[0], the_devinfo->udi_devnames[i], USB_MAX_DEVNAMELEN);
889                         the_devinfo->udi_devnames[1][0] = '\0';
890
891                         if (verbose >=2) {
892                                 printf("  === match attempt: %s\n", the_devinfo->udi_devnames[0]);
893                         }
894
895                         /* handle the event appropriately */
896                         switch (the_event.ue_type) {
897                         case USB_EVENT_CTRLR_ATTACH:
898                                 if (verbose)
899                                         printf("USB_EVENT_CTRLR_ATTACH\n");
900                                 break;
901                         case USB_EVENT_CTRLR_DETACH:
902                                 if (verbose)
903                                         printf("USB_EVENT_CTRLR_DETACH\n");
904                                 break;
905                         case USB_EVENT_DEVICE_ATTACH:
906                         case USB_EVENT_DEVICE_DETACH:
907                                 if (find_action(&the_event.u.ue_device, &action_match) == 0)
908                                         /* nothing found */
909                                         break;
910
911                                 if (verbose >= 2)
912                                         print_action(action_match.action, 0);
913
914                                 if (action_match.devname) {
915                                         if (verbose >= 2)
916                                                 printf("%s: Setting DEVNAME='%s'\n",
917                                                            __progname, action_match.devname);
918
919                                         error = setenv("DEVNAME", action_match.devname, 1);
920                                         if (error)
921                                                 fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
922                                                                 __progname, action_match.devname, strerror(errno));
923                                 }
924
925                                 if (USB_EVENT_IS_ATTACH(the_event.ue_type) &&
926                                         action_match.action->attach) 
927                                         execute_command(action_match.action->attach);
928                                 if (USB_EVENT_IS_DETACH(the_event.ue_type) &&
929                                         action_match.action->detach)
930                                         execute_command(action_match.action->detach);
931                                 break;
932                         case USB_EVENT_DRIVER_ATTACH:
933                                 if (verbose)
934                                         printf("USB_EVENT_DRIVER_ATTACH\n");
935                                 break;
936                         case USB_EVENT_DRIVER_DETACH:
937                                 if (verbose)
938                                         printf("USB_EVENT_DRIVER_DETACH\n");
939                                 break;
940                         default:
941                                 printf("Unknown USB event %d\n", the_event.ue_type);
942                         }
943                 }
944         }
945 }
946
947
948 int
949 main(int argc, char **argv)
950 {
951         int error, i;
952         int ch;                 /* getopt option */
953         int debug = 0;          /* print debugging output */
954         int explore_once = 0;   /* don't do only explore */
955         int handle_events = 1;  /* do handle the event queue */
956         int maxfd;              /* maximum fd in use */
957         char buf[50];           /* for creation of the filename */
958         fd_set r,w;
959         int itimeout = TIMEOUT; /* timeout for select */
960         struct timeval tv;
961
962         if (modfind(USB_UHUB) < 0) {
963                 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
964                         perror(USB_KLD ": Kernel module not available");
965                         return 1;
966                 }
967         }
968
969         while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
970                 switch(ch) {
971                 case 'c':
972                         configfile = strdup(optarg);
973                         if (configfile == NULL) {
974                                 fprintf(stderr, "strdup returned NULL\n");
975                                 return 1;
976                         }
977                         break;
978                 case 'd':
979                         debug++;
980                         break;
981                 case 'e':
982                         explore_once = 1;
983                         break;
984                 case 'f':
985                         if (ndevs < MAXUSBDEV)
986                                 devs[ndevs++] = optarg;
987                         break;
988                 case 'n':
989                         handle_events = 0;
990                         break;
991                 case 't':
992                         itimeout = atoi(optarg);
993                         break;
994                 case 'v':
995                         verbose++;
996                         break;
997                 case '?':
998                 default:
999                         usage();
1000                 }
1001         }
1002         argc -= optind;
1003         argv += optind;
1004
1005         maxfd = 0;
1006         if (ndevs == 0) {
1007                 /* open all the USBDEVS\d+ devices */
1008                 for (i = 0; i < MAXUSBDEV; i++) {
1009                         sprintf(buf, "%s%d", USBDEV, i);
1010                         fds[ndevs] = open(buf, O_RDWR);
1011                         if (fds[ndevs] >= 0) {
1012                                 devs[ndevs] = strdup(buf);
1013                                 if (devs[ndevs] == NULL) {
1014                                         fprintf(stderr, "strdup returned NULL\n");
1015                                         return 1;
1016                                 }
1017                                 if (verbose)
1018                                         printf("%s: opened %s\n", 
1019                                                __progname, devs[ndevs]);
1020                                 if (fds[ndevs] > maxfd)
1021                                         maxfd = fds[ndevs];
1022                                 ndevs++;
1023                         } else if (errno != ENXIO && errno != ENOENT) {
1024                                 /* there was an error, on a device that does
1025                                  * exist (device is configured)
1026                                  */
1027                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1028                                         __progname, buf, strerror(errno));
1029                                 exit(1);
1030                         }
1031                 }
1032         } else {
1033                 /* open all the files specified with -f */
1034                 for (i = 0; i < ndevs; i++) {
1035                         fds[i] = open(devs[i], O_RDWR);
1036                         if (fds[i] < 0) {
1037                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1038                                         __progname, devs[i], strerror(errno));
1039                                 exit(1);
1040                         } else {
1041                                 if (verbose)
1042                                         printf("%s: opened %s\n", 
1043                                                __progname, devs[i]);
1044                                 if (fds[i] > maxfd)
1045                                         maxfd = fds[i];
1046                         }
1047                 }
1048         }
1049
1050         if (ndevs == 0) {
1051                 fprintf(stderr, "No USB host controllers found\n");
1052                 exit(1);
1053         }
1054
1055
1056         /* Do the explore once and exit */
1057         if (explore_once) {
1058                 for (i = 0; i < ndevs; i++) {
1059                         error = ioctl(fds[i], USB_DISCOVER);
1060                         if (error < 0) {
1061                                 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1062                                         "failed, %s\n",
1063                                         __progname, devs[i], strerror(errno));
1064                                 exit(1);
1065                         }
1066                 }
1067                 exit(0);
1068         }
1069
1070         if (handle_events) {
1071                 if (verbose)
1072                         printf("%s: reading configuration file %s\n",
1073                                 __progname, configfile);
1074                 read_configuration();
1075
1076                 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1077                 if (fd < 0) {
1078                         fprintf(stderr, "%s: Could not open %s, %s\n",
1079                                 __progname, USBDEV, strerror(errno));
1080                         exit(1);
1081                 }
1082                 if (verbose)
1083                         printf("%s: opened %s\n", __progname, USBDEV);
1084                 if (fd > maxfd)
1085                         maxfd = fd;
1086
1087                 process_event_queue(fd);        /* dequeue the initial events */
1088         }
1089
1090         /* move to the background */
1091         if (!debug)
1092                 daemon(0, 0);
1093
1094         /* start select on all the open file descriptors */
1095         for (;;) {
1096                 FD_ZERO(&r);
1097                 FD_ZERO(&w);
1098                 if (handle_events)
1099                         FD_SET(fd, &r);         /* device USBDEV */
1100                 for (i = 0; i < ndevs; i++)
1101                         FD_SET(fds[i], &w);     /* device USBDEV\d+ */
1102                 tv.tv_usec = 0;
1103                 tv.tv_sec = itimeout;
1104                 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1105                 if (error < 0) {
1106                         fprintf(stderr, "%s: Select failed, %s\n",
1107                                 __progname, strerror(errno));
1108                         exit(1);
1109                 }
1110
1111                 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1112                 for (i = 0; i < ndevs; i++) {
1113                         if (error == 0 || FD_ISSET(fds[i], &w)) {
1114                                 if (verbose >= 2)
1115                                         printf("%s: doing %sdiscovery on %s\n", 
1116                                                __progname,
1117                                                (error? "":"timeout "), devs[i]);
1118                                 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1119                                         fprintf(stderr, "%s: ioctl(%s, "
1120                                                 "USB_DISCOVER) failed, %s\n",
1121                                                 __progname, devs[i],
1122                                                 strerror(errno));
1123                                         exit(1);
1124                                 }
1125                         }
1126                 }
1127
1128                 /* check the event queue */
1129                 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1130                         if (verbose >= 2)
1131                                 printf("%s: processing event queue %son %s\n",
1132                                         __progname,
1133                                        (error? "":"due to timeout "), USBDEV);
1134                         process_event_queue(fd);
1135                 }
1136         }
1137 }