Replace all casts of NULL to something with NULL.
[dragonfly.git] / usr.sbin / usbd / usbd.c
1 /*
2  * $NetBSD: usbd.c,v 1.4 1998/12/09 00:57:19 augustss Exp $
3  * $FreeBSD: src/usr.sbin/usbd/usbd.c,v 1.29 2003/10/25 22:03:10 jmg Exp $
4  * $DragonFly: src/usr.sbin/usbd/usbd.c,v 1.7 2005/12/05 01:23:23 swildner Exp $
5  */
6
7 /*
8  * Copyright (c) 1998 The NetBSD Foundation, Inc.
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to The NetBSD Foundation
12  * by Lennart Augustsson (augustss@netbsd.org).
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *        This product includes software developed by the NetBSD
25  *        Foundation, Inc. and its contributors.
26  * 4. Neither the name of The NetBSD Foundation nor the names of its
27  *    contributors may be used to endorse or promote products derived
28  *    from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42
43 /* USBD creates 'threads' in the kernel, used for doing discovery when a
44  * device has attached or detached. This functionality should be removed
45  * once kernel threads have been added to the kernel.
46  * It also handles the event queue, and executing commands based on those
47  * events.
48  *
49  * See usbd(8).
50  */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #include <paths.h>
60 #include <sys/param.h>
61 #include <sys/types.h>
62 #include <sys/errno.h>
63 #include <sys/ioctl.h>
64 #include <sys/linker.h>
65 #include <sys/module.h>
66 #include <sys/queue.h>
67 #include <sys/time.h>
68 #include <sys/wait.h>
69 #include <regex.h>
70
71 #include <bus/usb/usb.h>
72
73 /* default name of configuration file
74  */
75
76 #define CONFIGFILE      "/etc/usbd.conf"
77
78 /* the name of the device spitting out usb attach/detach events as well as
79  * the prefix for the individual busses (used as a semi kernel thread).
80  */
81 #define USBDEV          "/dev/usb"
82
83 /* Maximum number of USB busses expected to be in a system
84  * XXX should be replaced by dynamic allocation.
85  */
86 #define MAXUSBDEV       4
87
88 /* Sometimes a device does not respond in time for interrupt
89  * driven explore to find it.  Therefore we run an exploration
90  * at regular intervals to catch those.
91  */
92 #define TIMEOUT         30
93
94 /* The wildcard used in actions for strings and integers
95  */
96 #define WILDCARD_STRING NULL
97 #define WILDCARD_INT    -1
98
99
100 extern char *__progname;        /* name of program */
101
102 char *configfile = CONFIGFILE;  /* name of configuration file */
103
104 char *devs[MAXUSBDEV];          /* device names */
105 int fds[MAXUSBDEV];             /* file descriptors for USBDEV\d+ */
106 int ndevs = 0;                  /* number of entries in fds / devs */
107 int fd = -1;                    /* file descriptor for USBDEV */
108
109 int lineno;
110 int verbose = 0;                /* print message on what it is doing */
111
112 typedef struct event_name_s {
113         int     type;           /* event number (from usb.h) */
114         char    *name;
115 } event_name_t;
116
117 event_name_t event_names[] = {
118         {USB_EVENT_CTRLR_ATTACH, "ctrlr-attach"},
119         {USB_EVENT_CTRLR_DETACH, "ctrlr-detach"},
120         {USB_EVENT_DRIVER_ATTACH, "driver-attach"},
121         {USB_EVENT_DRIVER_DETACH, "driver-detach"},
122         {USB_EVENT_DEVICE_ATTACH, "device-attach"},
123         {USB_EVENT_DEVICE_DETACH, "device-detach"},
124         {0, NULL}                       /* NULL indicates end of list, not 0 */
125 };
126
127 #define DEVICE_FIELD            0       /* descriptive field */
128
129 #define VENDOR_FIELD            1       /* selective fields */
130 #define PRODUCT_FIELD           2
131 #define RELEASE_FIELD           3
132 #define CLASS_FIELD             4
133 #define SUBCLASS_FIELD          5
134 #define PROTOCOL_FIELD          6
135 #define DEVNAME_FIELD           7
136
137 #define ATTACH_FIELD            8       /* command fields */
138 #define DETACH_FIELD            9
139
140
141 typedef struct action_s {
142         char    *name;          /* descriptive string */
143
144         int     vendor; /* selection criteria */
145         int     product;
146         int     release;
147         int     class;
148         int     subclass;
149         int     protocol;
150         char    *devname;
151         regex_t devname_regex;
152
153         char    *attach;        /* commands to execute */
154         char    *detach;
155
156         STAILQ_ENTRY(action_s) next;
157 } action_t;
158
159 STAILQ_HEAD(action_list, action_s) actions = STAILQ_HEAD_INITIALIZER(actions);
160
161 typedef struct action_match_s {
162         action_t *action;
163         char    *devname;
164 } action_match_t;
165
166
167 /* the function returns 0 for failure, 1 for all arguments found and 2 for
168  * arguments left over in trail.
169  */
170 typedef int (*config_field_fn)(action_t *action, char *args, char **trail);
171
172 int set_device_field(action_t *action, char *args, char **trail);
173 int set_vendor_field(action_t *action, char *args, char **trail);
174 int set_product_field(action_t *action, char *args, char **trail);
175 int set_release_field(action_t *action, char *args, char **trail);
176 int set_class_field(action_t *action, char *args, char **trail);
177 int set_subclass_field(action_t *action, char *args, char **trail);
178 int set_protocol_field(action_t *action, char *args, char **trail);
179 int set_devname_field(action_t *action, char *args, char **trail);
180 int set_attach_field(action_t *action, char *args, char **trail);
181 int set_detach_field(action_t *action, char *args, char **trail);
182
183 /* the list of fields supported in an entry */
184 typedef struct config_field_s {
185         int     event;
186         char    *name;
187         config_field_fn function;
188 } config_field_t;
189
190 config_field_t config_fields[] = {
191         {DEVICE_FIELD,          "device",       set_device_field},
192
193         {VENDOR_FIELD,          "vendor",       set_vendor_field},
194         {PRODUCT_FIELD,         "product",      set_product_field},
195         {RELEASE_FIELD,         "release",      set_release_field},
196         {CLASS_FIELD,           "class",        set_class_field},
197         {SUBCLASS_FIELD,        "subclass",     set_subclass_field},
198         {PROTOCOL_FIELD,        "protocol",     set_protocol_field},
199         {DEVNAME_FIELD,         "devname",      set_devname_field},
200
201         {ATTACH_FIELD,          "attach",       set_attach_field},
202         {DETACH_FIELD,          "detach",       set_detach_field},
203
204         {0, NULL, NULL}         /* NULL is EOL marker, not the 0 */
205 };
206
207
208 /* prototypes for some functions */
209 void print_event(struct usb_event *event);
210 void print_action(action_t *action, int i);
211 void print_actions(void);
212 int  find_action(struct usb_device_info *devinfo, action_match_t *action_match);
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 %ld.%09ld, %s, %s:\n",
588                         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(void)
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         sigemptyset(&ign.sa_mask);
782         ign.sa_flags = 0;
783         sigaction(SIGINT, &ign, &intact);
784         sigaction(SIGQUIT, &ign, &quitact);
785         sigemptyset(&newsigblock);
786         sigaddset(&newsigblock, SIGCHLD);
787         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                 sigaction(SIGINT, &intact, NULL);
802                 sigaction(SIGQUIT,  &quitact, NULL);
803                 sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
804
805                 execl(_PATH_BSHELL, "sh", "-c", cmd, 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         sigaction(SIGINT, &intact, NULL);
816         sigaction(SIGQUIT,  &quitact, NULL);
817         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 event;
848         int error;
849         int len;
850         action_match_t action_match;
851
852         for (;;) {
853                 len = read(fd, &event, sizeof(event));
854                 if (len == -1) {
855                         if (errno == EWOULDBLOCK) {
856                                 /* no more events */
857                                 break;
858                         } else {
859                                 fprintf(stderr,"%s: Could not read event, %s\n",
860                                         __progname, strerror(errno));
861                                 exit(1);
862                         }
863                 }
864                 if (len == 0)
865                         break;
866                 if (len != sizeof(event)) {
867                         fprintf(stderr, "partial read on %s\n", USBDEV);
868                         exit(1);
869                 }
870
871                 /* we seem to have gotten a valid event */
872
873                 if (verbose)
874                         print_event(&event);
875
876                 /* handle the event appropriately */
877                 switch (event.ue_type) {
878                 case USB_EVENT_CTRLR_ATTACH:
879                         if (verbose)
880                                 printf("USB_EVENT_CTRLR_ATTACH\n");
881                         break;
882                 case USB_EVENT_CTRLR_DETACH:
883                         if (verbose)
884                                 printf("USB_EVENT_CTRLR_DETACH\n");
885                         break;
886                 case USB_EVENT_DEVICE_ATTACH:
887                 case USB_EVENT_DEVICE_DETACH:
888                         if (find_action(&event.u.ue_device, &action_match) == 0)
889                                 /* nothing found */
890                                 break;
891
892                         if (verbose >= 2)
893                                 print_action(action_match.action, 0);
894
895                         if (action_match.devname) {
896                                 if (verbose >= 2)
897                                         printf("%s: Setting DEVNAME='%s'\n",
898                                                 __progname, action_match.devname);
899
900                                 error = setenv("DEVNAME", action_match.devname, 1);
901                                 if (error)
902                                         fprintf(stderr, "%s: setenv(\"DEVNAME\", \"%s\",1) failed, %s\n",
903                                                 __progname, action_match.devname, strerror(errno));
904                         }
905
906                         if (USB_EVENT_IS_ATTACH(event.ue_type) &&
907                             action_match.action->attach) 
908                                 execute_command(action_match.action->attach);
909                         if (USB_EVENT_IS_DETACH(event.ue_type) &&
910                             action_match.action->detach)
911                                 execute_command(action_match.action->detach);
912                         break;
913                 case USB_EVENT_DRIVER_ATTACH:
914                         if (verbose)
915                                 printf("USB_EVENT_DRIVER_ATTACH\n");
916                         break;
917                 case USB_EVENT_DRIVER_DETACH:
918                         if (verbose)
919                                 printf("USB_EVENT_DRIVER_DETACH\n");
920                         break;
921                 default:
922                         printf("Unknown USB event %d\n", event.ue_type);
923                 }
924         }       
925 }
926
927
928 int
929 main(int argc, char **argv)
930 {
931         int error, i;
932         int ch;                 /* getopt option */
933         int debug = 0;          /* print debugging output */
934         int explore_once = 0;   /* don't do only explore */
935         int handle_events = 1;  /* do handle the event queue */
936         int maxfd;              /* maximum fd in use */
937         char buf[50];           /* for creation of the filename */
938         fd_set r,w;
939         int itimeout = TIMEOUT; /* timeout for select */
940         struct timeval tv;
941
942         if (modfind(USB_UHUB) < 0) {
943                 if (kldload(USB_KLD) < 0 || modfind(USB_UHUB) < 0) {
944                         perror(USB_KLD ": Kernel module not available");
945                         return 1;
946                 }
947         }
948
949         while ((ch = getopt(argc, argv, "c:def:nt:v")) != -1) {
950                 switch(ch) {
951                 case 'c':
952                         configfile = strdup(optarg);
953                         if (configfile == NULL) {
954                                 fprintf(stderr, "strdup returned NULL\n");
955                                 return 1;
956                         }
957                         break;
958                 case 'd':
959                         debug++;
960                         break;
961                 case 'e':
962                         explore_once = 1;
963                         break;
964                 case 'f':
965                         if (ndevs < MAXUSBDEV)
966                                 devs[ndevs++] = optarg;
967                         break;
968                 case 'n':
969                         handle_events = 0;
970                         break;
971                 case 't':
972                         itimeout = atoi(optarg);
973                         break;
974                 case 'v':
975                         verbose++;
976                         break;
977                 case '?':
978                 default:
979                         usage();
980                 }
981         }
982         argc -= optind;
983         argv += optind;
984
985         maxfd = 0;
986         if (ndevs == 0) {
987                 /* open all the USBDEVS\d+ devices */
988                 for (i = 0; i < MAXUSBDEV; i++) {
989                         sprintf(buf, "%s%d", USBDEV, i);
990                         fds[ndevs] = open(buf, O_RDWR);
991                         if (fds[ndevs] >= 0) {
992                                 devs[ndevs] = strdup(buf);
993                                 if (devs[ndevs] == NULL) {
994                                         fprintf(stderr, "strdup returned NULL\n");
995                                         return 1;
996                                 }
997                                 if (verbose)
998                                         printf("%s: opened %s\n", 
999                                                __progname, devs[ndevs]);
1000                                 if (fds[ndevs] > maxfd)
1001                                         maxfd = fds[ndevs];
1002                                 ndevs++;
1003                         } else if (errno != ENXIO && errno != ENOENT) {
1004                                 /* there was an error, on a device that does
1005                                  * exist (device is configured)
1006                                  */
1007                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1008                                         __progname, buf, strerror(errno));
1009                                 exit(1);
1010                         }
1011                 }
1012         } else {
1013                 /* open all the files specified with -f */
1014                 for (i = 0; i < ndevs; i++) {
1015                         fds[i] = open(devs[i], O_RDWR);
1016                         if (fds[i] < 0) {
1017                                 fprintf(stderr, "%s: Could not open %s, %s\n",
1018                                         __progname, devs[i], strerror(errno));
1019                                 exit(1);
1020                         } else {
1021                                 if (verbose)
1022                                         printf("%s: opened %s\n", 
1023                                                __progname, devs[i]);
1024                                 if (fds[i] > maxfd)
1025                                         maxfd = fds[i];
1026                         }
1027                 }
1028         }
1029
1030         if (ndevs == 0) {
1031                 fprintf(stderr, "No USB host controllers found\n");
1032                 exit(1);
1033         }
1034
1035
1036         /* Do the explore once and exit */
1037         if (explore_once) {
1038                 for (i = 0; i < ndevs; i++) {
1039                         error = ioctl(fds[i], USB_DISCOVER);
1040                         if (error < 0) {
1041                                 fprintf(stderr, "%s: ioctl(%s, USB_DISCOVER) "
1042                                         "failed, %s\n",
1043                                         __progname, devs[i], strerror(errno));
1044                                 exit(1);
1045                         }
1046                 }
1047                 exit(0);
1048         }
1049
1050         if (handle_events) {
1051                 if (verbose)
1052                         printf("%s: reading configuration file %s\n",
1053                                 __progname, configfile);
1054                 read_configuration();
1055
1056                 fd = open(USBDEV, O_RDONLY | O_NONBLOCK);
1057                 if (fd < 0) {
1058                         fprintf(stderr, "%s: Could not open %s, %s\n",
1059                                 __progname, USBDEV, strerror(errno));
1060                         exit(1);
1061                 }
1062                 if (verbose)
1063                         printf("%s: opened %s\n", __progname, USBDEV);
1064                 if (fd > maxfd)
1065                         maxfd = fd;
1066
1067                 process_event_queue(fd);        /* dequeue the initial events */
1068         }
1069
1070         /* move to the background */
1071         if (!debug)
1072                 daemon(0, 0);
1073
1074         /* start select on all the open file descriptors */
1075         for (;;) {
1076                 FD_ZERO(&r);
1077                 FD_ZERO(&w);
1078                 if (handle_events)
1079                         FD_SET(fd, &r);         /* device USBDEV */
1080                 for (i = 0; i < ndevs; i++)
1081                         FD_SET(fds[i], &w);     /* device USBDEV\d+ */
1082                 tv.tv_usec = 0;
1083                 tv.tv_sec = itimeout;
1084                 error = select(maxfd+1, &r, &w, 0, itimeout ? &tv : 0);
1085                 if (error < 0) {
1086                         fprintf(stderr, "%s: Select failed, %s\n",
1087                                 __progname, strerror(errno));
1088                         exit(1);
1089                 }
1090
1091                 /* USBDEV\d+ devices have signaled change, do a usb_discover */
1092                 for (i = 0; i < ndevs; i++) {
1093                         if (error == 0 || FD_ISSET(fds[i], &w)) {
1094                                 if (verbose >= 2)
1095                                         printf("%s: doing %sdiscovery on %s\n", 
1096                                                __progname,
1097                                                (error? "":"timeout "), devs[i]);
1098                                 if (ioctl(fds[i], USB_DISCOVER) < 0) {
1099                                         fprintf(stderr, "%s: ioctl(%s, "
1100                                                 "USB_DISCOVER) failed, %s\n",
1101                                                 __progname, devs[i],
1102                                                 strerror(errno));
1103                                         exit(1);
1104                                 }
1105                         }
1106                 }
1107
1108                 /* check the event queue */
1109                 if (handle_events && (FD_ISSET(fd, &r) || error == 0)) {
1110                         if (verbose >= 2)
1111                                 printf("%s: processing event queue %son %s\n",
1112                                         __progname,
1113                                        (error? "":"due to timeout "), USBDEV);
1114                         process_event_queue(fd);
1115                 }
1116         }
1117 }