chiark / gitweb /
[PATCH] udev - CALLOUT is PROGRAM now
[elogind.git] / udev.c
1 /*
2  * udev.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
7  *
8  *
9  *      This program is free software; you can redistribute it and/or modify it
10  *      under the terms of the GNU General Public License as published by the
11  *      Free Software Foundation version 2 of the License.
12  * 
13  *      This program is distributed in the hope that it will be useful, but
14  *      WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *      General Public License for more details.
17  * 
18  *      You should have received a copy of the GNU General Public License along
19  *      with this program; if not, write to the Free Software Foundation, Inc.,
20  *      675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <signal.h>
32 #include <stdarg.h>
33
34 #include "udev.h"
35 #include "udev_version.h"
36 #include "udev_dbus.h"
37 #include "namedev.h"
38 #include "udevdb.h"
39 #include "libsysfs/libsysfs.h"
40
41 /* global variables */
42 char **main_argv;
43 char **main_envp;
44
45 static void sig_handler(int signum)
46 {
47         dbg("caught signal %d", signum);
48         switch (signum) {
49                 case SIGINT:
50                 case SIGTERM:
51                 case SIGKILL:
52                         sysbus_disconnect();
53                         udevdb_exit();
54                         exit(20 + signum);
55                         break;
56                 default:
57                         dbg("unhandled signal");
58         }
59 }
60
61 static inline char *get_action(void)
62 {
63         char *action;
64
65         action = getenv("ACTION");
66         return action;
67 }
68
69 static inline char *get_devpath(void)
70 {
71         char *devpath;
72
73         devpath = getenv("DEVPATH");
74         return devpath;
75 }
76
77 static inline char *get_seqnum(void)
78 {
79         char *seqnum;
80
81         seqnum = getenv("SEQNUM");
82         return seqnum;
83 }
84
85 static void print_record(char *path, struct udevice *dev)
86 {
87         printf("P: %s\n", path);
88         printf("N: %s\n", dev->name);
89         printf("S: %s\n", dev->symlink);
90         printf("O: %s\n", dev->owner);
91         printf("G: %s\n\n", dev->group);
92 }
93
94 enum query_type {
95         NONE,
96         NAME,
97         SYMLINK,
98         OWNER,
99         GROUP
100 };
101
102 static inline int udev_user(int argc, char **argv)
103 {
104         static const char short_options[] = "dp:q:rVh";
105         int option;
106         int retval = -EINVAL;
107         struct udevice dev;
108         int root = 0;
109         enum query_type query = NONE;
110         char result[NAME_SIZE] = "";
111         char path[NAME_SIZE] = "";
112
113         /* get command line options */
114         while (1) {
115                 option = getopt(argc, argv, short_options);
116                 if (option == -1)
117                         break;
118
119                 dbg("option '%c'", option);
120                 switch (option) {
121                 case 'p':
122                         dbg("udev path: %s\n", optarg);
123                         strfieldcpy(path, optarg);
124                         break;
125
126                 case 'q':
127                         dbg("udev query: %s\n", optarg);
128
129                         if (strcmp(optarg, "name") == 0) {
130                                 query = NAME;
131                                 break;
132                         }
133
134                         if (strcmp(optarg, "symlink") == 0) {
135                                 query = SYMLINK;
136                                 break;
137                         }
138
139                         if (strcmp(optarg, "owner") == 0) {
140                                 query = OWNER;
141                                 break;
142                         }
143
144                         if (strcmp(optarg, "group") == 0) {
145                                 query = GROUP;
146                                 break;
147                         }
148
149                         printf("unknown query type\n");
150                         return -EINVAL;
151
152                 case 'r':
153                         root = 1;
154                         break;
155
156                 case 'd':
157                         retval = udevdb_open_ro();
158                         if (retval != 0) {
159                                 printf("unable to open udev database\n");
160                                 return -EACCES;
161                         }
162                         retval = udevdb_dump(print_record);
163                         udevdb_exit();
164                         return retval;
165
166                 case 'V':
167                         printf("udev, version %s\n", UDEV_VERSION);
168                         return 0;
169
170                 case 'h':
171                         retval = 0;
172                 case '?':
173                 default:
174                         goto help;
175                 }
176         }
177
178         /* process options */
179         if (query != NONE) {
180                 if (path[0] == '\0') {
181                         printf("query needs device path specified\n");
182                         return -EINVAL;
183                 }
184
185                 retval = udevdb_open_ro();
186                 if (retval != 0) {
187                         printf("unable to open udev database\n");
188                         return -EACCES;
189                 }
190                 retval = udevdb_get_dev(path, &dev);
191                 if (retval == 0) {
192                         switch(query) {
193                         case NAME:
194                                 if (root)
195                                 strfieldcpy(result, udev_root);
196                                 strncat(result, dev.name, sizeof(result));
197                                 break;
198
199                         case SYMLINK:
200                                 strfieldcpy(result, dev.symlink);
201                                 break;
202
203                         case GROUP:
204                                 strfieldcpy(result, dev.group);
205                                 break;
206
207                         case OWNER:
208                                 strfieldcpy(result, dev.owner);
209                                 break;
210
211                         default:
212                                 break;
213                         }
214                         printf("%s\n", result);
215                 } else {
216                         printf("device not found in udev database\n");
217                 }
218                 udevdb_exit();
219                 return retval;
220         }
221
222         if (root) {
223                 printf("%s\n", udev_root);
224                 return 0;
225         }
226
227 help:
228         printf("Usage: [-pqrdVh]\n"
229                "  -q TYPE  query database for the specified value:\n"
230                "             'name'    name of device node\n"
231                "             'symlink' pointing to node\n"
232                "             'owner'   of node\n"
233                "             'group'   of node\n"
234                "  -p PATH  sysfs device path used for query\n"
235                "  -r       print udev root\n"
236                "  -d       dump whole database\n"
237                "  -V       print udev version\n"
238                "  -h       print this help text\n"
239                "\n");
240         return retval;
241 }
242
243 static char *subsystem_blacklist[] = {
244         "net",
245         "scsi_host",
246         "scsi_device",
247         "",
248 };
249
250 static inline int udev_hotplug(int argc, char **argv)
251 {
252         char *action;
253         char *devpath;
254         char *subsystem;
255         int retval = -EINVAL;
256         int i;
257
258         subsystem = argv[1];
259
260         devpath = get_devpath();
261         if (!devpath) {
262                 dbg ("no devpath?");
263                 goto exit;
264         }
265         dbg("looking at '%s'", devpath);
266
267         /* we only care about class devices and block stuff */
268         if (!strstr(devpath, "class") &&
269             !strstr(devpath, "block")) {
270                 dbg("not a block or class device");
271                 goto exit;
272         }
273
274         /* skip blacklisted subsystems */
275         i = 0;
276         while (subsystem_blacklist[i][0] != '\0') {
277                 if (strcmp(subsystem, subsystem_blacklist[i]) == 0) {
278                         dbg("don't care about '%s' devices", subsystem);
279                         goto exit;
280                 }
281                 i++;
282         }
283
284         action = get_action();
285         if (!action) {
286                 dbg ("no action?");
287                 goto exit;
288         }
289
290         /* connect to the system message bus */
291         sysbus_connect();
292
293         /* initialize udev database */
294         retval = udevdb_init(UDEVDB_DEFAULT);
295         if (retval != 0) {
296                 dbg("unable to initialize database");
297                 goto exit_sysbus;
298         }
299
300         /* set up a default signal handler for now */
301         signal(SIGINT, sig_handler);
302         signal(SIGTERM, sig_handler);
303         signal(SIGKILL, sig_handler);
304
305         /* initialize the naming deamon */
306         namedev_init();
307
308         if (strcmp(action, "add") == 0)
309                 retval = udev_add_device(devpath, subsystem);
310
311         else if (strcmp(action, "remove") == 0)
312                 retval = udev_remove_device(devpath, subsystem);
313
314         else {
315                 dbg("unknown action '%s'", action);
316                 retval = -EINVAL;
317         }
318         udevdb_exit();
319
320 exit_sysbus:
321         /* disconnect from the system message bus */
322         sysbus_disconnect();
323
324 exit:
325         if (retval > 0)
326                 retval = 0;
327
328         return -retval;
329 }
330
331 int main(int argc, char **argv, char **envp)
332 {
333         int retval;
334         main_argv = argv;
335         main_envp = envp;
336
337         dbg("version %s", UDEV_VERSION);
338
339         /* initialize our configuration */
340         udev_init_config();
341
342         if (argc == 2 && argv[1][0] != '-') {
343                 dbg("called by hotplug");
344                 retval = udev_hotplug(argc, argv);
345         } else {
346                 dbg("called by user");
347                 retval = udev_user(argc, argv);
348         }
349
350         return retval;
351 }
352
353