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