chiark / gitweb /
839bfa6520299461e63d6261d01a2bc173df15d7
[elogind.git] / udev.c
1 /*
2  * udev.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
7  *
8  *      This program is free software; you can redistribute it and/or modify it
9  *      under the terms of the GNU General Public License as published by the
10  *      Free Software Foundation version 2 of the License.
11  * 
12  *      This program is distributed in the hope that it will be useful, but
13  *      WITHOUT ANY WARRANTY; without even the implied warranty of
14  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *      General Public License for more details.
16  * 
17  *      You should have received a copy of the GNU General Public License along
18  *      with this program; if not, write to the Free Software Foundation, Inc.,
19  *      675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define _KLIBC_HAS_ARCH_SIG_ATOMIC_T
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <unistd.h>
32
33 #include "libsysfs/sysfs/libsysfs.h"
34 #include "udev.h"
35 #include "udev_lib.h"
36 #include "udev_version.h"
37 #include "logging.h"
38 #include "namedev.h"
39 #include "udevdb.h"
40
41 /* timeout flag for udevdb */
42 extern sig_atomic_t gotalarm;
43
44 /* global variables */
45 char **main_argv;
46 char **main_envp;
47
48 #ifdef LOG
49 unsigned char logname[LOGNAME_SIZE];
50 void log_message(int level, const char *format, ...)
51 {
52         va_list args;
53
54         if (!udev_log)
55                 return;
56
57         va_start(args, format);
58         vsyslog(level, format, args);
59         va_end(args);
60 }
61 #endif
62
63 static void asmlinkage sig_handler(int signum)
64 {
65         switch (signum) {
66                 case SIGALRM:
67                         gotalarm = 1;
68                         info("error: timeout reached, event probably not handled correctly");
69                         break;
70                 case SIGINT:
71                 case SIGTERM:
72                         udevdb_exit();
73                         exit(20 + signum);
74                 default:
75                         dbg("unhandled signal %d", signum);
76         }
77 }
78
79 /* list of subsystems we don't care about. not listing such systems here
80  * is not critical, but it makes it faster as we don't look for the "dev" file
81  */
82 static int subsystem_without_dev(const char *subsystem)
83 {
84         char *subsystem_blacklist[] = {
85                 "scsi_host",
86                 "scsi_device",
87                 "usb_host",
88                 "pci_bus",
89                 "pcmcia_socket",
90                 "bluetooth",
91                 "i2c-adapter",
92                 "pci_bus",
93                 "ieee1394",
94                 "ieee1394_host",
95                 "ieee1394_node",
96                 NULL
97         };
98         char **subsys;
99
100         for (subsys = subsystem_blacklist; *subsys != NULL; subsys++) {
101                 if (strcmp(subsystem, *subsys) == 0)
102                         return 1;
103         }
104
105         return 0;
106 }
107
108 int main(int argc, char *argv[], char *envp[])
109 {
110         struct sigaction act;
111         struct sysfs_class_device *class_dev;
112         struct udevice udev;
113         char path[SYSFS_PATH_MAX];
114         int retval = -EINVAL;
115         enum {
116                 ADD,
117                 REMOVE,
118                 UDEVSTART,
119         } act_type;
120
121         dbg("version %s", UDEV_VERSION);
122
123         main_argv = argv;
124         main_envp = envp;
125
126         logging_init("udev");
127
128         udev_init_config();
129
130         if (strstr(argv[0], "udevstart")) {
131                 act_type = UDEVSTART;
132         } else {
133                 const char *action = get_action();
134                 const char *devpath = get_devpath();
135                 const char *subsystem = get_subsystem(main_argv[1]);
136
137                 if (!action) {
138                         dbg("no action?");
139                         goto exit;
140                 }
141                 if (strcmp(action, "add") == 0) {
142                         act_type = ADD;
143                 } else if (strcmp(action, "remove") == 0) {
144                         act_type = REMOVE;
145                 } else {
146                         dbg("no action '%s' for us", action);
147                         goto exit;
148                 }
149
150                 if (!devpath) {
151                         dbg("no devpath?");
152                         goto exit;
153                 }
154                 dbg("looking at '%s'", udev.devpath);
155
156                 /* we only care about class devices and block stuff */
157                 if (!strstr(devpath, "class") && !strstr(devpath, "block")) {
158                         dbg("not a block or class device");
159                         goto exit;
160                 }
161
162                 if (!subsystem) {
163                         dbg("no subsystem");
164                         goto exit;
165                 }
166
167                 /* skip blacklisted subsystems */
168                 if (subsystem_without_dev(subsystem)) {
169                         dbg("don't care about '%s' devices", subsystem);
170                         goto exit;
171                 };
172
173                 udev_set_values(&udev, devpath, subsystem);
174         }
175
176         /* set signal handlers */
177         act.sa_handler = (void (*) (int))sig_handler;
178         sigemptyset (&act.sa_mask);
179         /* alarm must not restart syscalls*/
180         sigaction(SIGALRM, &act, NULL);
181         sigaction(SIGINT, &act, NULL);
182         sigaction(SIGTERM, &act, NULL);
183
184         /* trigger timout to interrupt blocking syscalls */
185         alarm(ALARM_TIMEOUT);
186
187         /* initialize udev database */
188         if (udevdb_init(UDEVDB_DEFAULT) != 0)
189                 info("error: unable to initialize database, continuing without database");
190
191         switch(act_type) {
192         case UDEVSTART:
193                 dbg("udevstart");
194                 namedev_init();
195                 retval = udev_start();
196                 break;
197         case ADD:
198                 dbg("udev add");
199
200                 /* init rules */
201                 namedev_init();
202
203                 /* open the device */
204                 snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, udev.devpath);
205                 class_dev = sysfs_open_class_device_path(path);
206                 if (class_dev == NULL) {
207                         dbg ("sysfs_open_class_device_path failed");
208                         break;
209                 }
210                 dbg("opened class_dev->name='%s'", class_dev->name);
211
212                 /* name, create node, store in db */
213                 retval = udev_add_device(&udev, class_dev);
214
215                 /* run scripts */
216                 dev_d_execute(&udev);
217
218                 sysfs_close_class_device(class_dev);
219                 break;
220         case REMOVE:
221                 dbg("udev remove");
222
223                 /* get node from db, delete it*/
224                 retval = udev_remove_device(&udev);
225
226                 /* run scripts */
227                 dev_d_execute(&udev);
228         }
229
230         udevdb_exit();
231
232 exit:
233         logging_close();
234         return retval;
235 }