chiark / gitweb /
[PATCH] spilt udev into pieces
[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 "logging.h"
38 #include "namedev.h"
39 #include "udevdb.h"
40 #include "libsysfs/libsysfs.h"
41
42 /* global variables */
43 char **main_argv;
44 char **main_envp;
45
46 static void sig_handler(int signum)
47 {
48         dbg("caught signal %d", signum);
49         switch (signum) {
50                 case SIGINT:
51                 case SIGTERM:
52                 case SIGKILL:
53                         sysbus_disconnect();
54                         udevdb_exit();
55                         exit(20 + signum);
56                         break;
57                 default:
58                         dbg("unhandled signal");
59         }
60 }
61
62 static inline char *get_action(void)
63 {
64         char *action;
65
66         action = getenv("ACTION");
67         return action;
68 }
69
70 static inline char *get_devpath(void)
71 {
72         char *devpath;
73
74         devpath = getenv("DEVPATH");
75         return devpath;
76 }
77
78 static inline char *get_seqnum(void)
79 {
80         char *seqnum;
81
82         seqnum = getenv("SEQNUM");
83         return seqnum;
84 }
85
86 /* callback for database dump */
87 static int print_record(char *path, struct udevice *dev)
88 {
89         printf("P: %s\n", path);
90         printf("N: %s\n", dev->name);
91         printf("S: %s\n", dev->symlink);
92         printf("O: %s\n", dev->owner);
93         printf("G: %s\n", dev->group);
94         printf("\n");
95         return 0;
96 }
97
98 enum query_type {
99         NONE,
100         NAME,
101         PATH,
102         SYMLINK,
103         OWNER,
104         GROUP
105 };
106
107 static inline int udev_user(int argc, char **argv)
108 {
109         static const char short_options[] = "dn:p:q:rVh";
110         int option;
111         int retval = -EINVAL;
112         struct udevice dev;
113         int root = 0;
114         enum query_type query = NONE;
115         char result[NAME_SIZE] = "";
116         char path[NAME_SIZE] = "";
117         char name[NAME_SIZE] = "";
118
119         /* get command line options */
120         while (1) {
121                 option = getopt(argc, argv, short_options);
122                 if (option == -1)
123                         break;
124
125                 dbg("option '%c'", option);
126                 switch (option) {
127                 case 'n':
128                         dbg("udev name: %s\n", optarg);
129                         strfieldcpy(name, optarg);
130                         break;
131
132                 case 'p':
133                         dbg("udev path: %s\n", optarg);
134                         strfieldcpy(path, optarg);
135                         break;
136
137                 case 'q':
138                         dbg("udev query: %s\n", optarg);
139
140                         if (strcmp(optarg, "name") == 0) {
141                                 query = NAME;
142                                 break;
143                         }
144
145                         if (strcmp(optarg, "symlink") == 0) {
146                                 query = SYMLINK;
147                                 break;
148                         }
149
150                         if (strcmp(optarg, "owner") == 0) {
151                                 query = OWNER;
152                                 break;
153                         }
154
155                         if (strcmp(optarg, "group") == 0) {
156                                 query = GROUP;
157                                 break;
158                         }
159
160                         if (strcmp(optarg, "path") == 0) {
161                                 query = PATH;
162                                 break;
163                         }
164
165                         printf("unknown query type\n");
166                         return -EINVAL;
167
168                 case 'r':
169                         root = 1;
170                         break;
171
172                 case 'd':
173                         retval = udevdb_open_ro();
174                         if (retval != 0) {
175                                 printf("unable to open udev database\n");
176                                 return -EACCES;
177                         }
178                         retval = udevdb_call_foreach(print_record);
179                         udevdb_exit();
180                         return retval;
181
182                 case 'V':
183                         printf("udev, version %s\n", UDEV_VERSION);
184                         return 0;
185
186                 case 'h':
187                         retval = 0;
188                 case '?':
189                 default:
190                         goto help;
191                 }
192         }
193
194         /* process options */
195         if (query != NONE) {
196                 retval = udevdb_open_ro();
197                 if (retval != 0) {
198                         printf("unable to open udev database\n");
199                         return -EACCES;
200                 }
201
202                 if (path[0] != '\0') {
203                         retval = udevdb_get_dev(path, &dev);
204                         if (retval != 0) {
205                                 printf("device not found in database\n");
206                                 goto exit;
207                         }
208                         goto print;
209                 }
210
211                 if (name[0] != '\0') {
212                         retval = udevdb_get_dev_byname(name, path, &dev);
213                         if (retval != 0) {
214                                 printf("device not found in database\n");
215                                 goto exit;
216                         }
217                         goto print;
218                 }
219
220                 printf("query needs device path(-p) or node name(-n) specified\n");
221                 goto exit;
222
223 print:
224                 switch(query) {
225                 case NAME:
226                         if (root)
227                                 strfieldcpy(result, udev_root);
228                         strncat(result, dev.name, sizeof(result));
229                         break;
230
231                 case SYMLINK:
232                         strfieldcpy(result, dev.symlink);
233                         break;
234
235                 case GROUP:
236                         strfieldcpy(result, dev.group);
237                         break;
238
239                 case OWNER:
240                         strfieldcpy(result, dev.owner);
241                         break;
242
243                 case PATH:
244                         strfieldcpy(result, path);
245                         break;
246
247                 default:
248                         goto exit;
249                 }
250                 printf("%s\n", result);
251
252 exit:
253                 udevdb_exit();
254                 return retval;
255         }
256
257         if (root) {
258                 printf("%s\n", udev_root);
259                 return 0;
260         }
261
262 help:
263         printf("Usage: [-npqrdVh]\n"
264                "  -q TYPE  query database for the specified value:\n"
265                "             'name'    name of device node\n"
266                "             'symlink' pointing to node\n"
267                "             'owner'   of node\n"
268                "             'group'   of node\n"
269                "             'path'    sysfs device path\n"
270                "  -p PATH  sysfs device path used for query\n"
271                "  -n NAME  node name used for query\n"
272                "\n"
273                "  -r       print udev root\n"
274                "  -d       dump whole database\n"
275                "  -V       print udev version\n"
276                "  -h       print this help text\n"
277                "\n");
278         return retval;
279 }
280
281 static char *subsystem_blacklist[] = {
282         "net",
283         "scsi_host",
284         "scsi_device",
285         "usb_host",
286         "pci_bus",
287         "",
288 };
289
290 static inline int udev_hotplug(int argc, char **argv)
291 {
292         char *action;
293         char *devpath;
294         char *subsystem;
295         int retval = -EINVAL;
296         int i;
297
298         subsystem = argv[1];
299
300         devpath = get_devpath();
301         if (!devpath) {
302                 dbg ("no devpath?");
303                 goto exit;
304         }
305         dbg("looking at '%s'", devpath);
306
307         /* we only care about class devices and block stuff */
308         if (!strstr(devpath, "class") &&
309             !strstr(devpath, "block")) {
310                 dbg("not a block or class device");
311                 goto exit;
312         }
313
314         /* skip blacklisted subsystems */
315         i = 0;
316         while (subsystem_blacklist[i][0] != '\0') {
317                 if (strcmp(subsystem, subsystem_blacklist[i]) == 0) {
318                         dbg("don't care about '%s' devices", subsystem);
319                         goto exit;
320                 }
321                 i++;
322         }
323
324         action = get_action();
325         if (!action) {
326                 dbg ("no action?");
327                 goto exit;
328         }
329
330         /* connect to the system message bus */
331         sysbus_connect();
332
333         /* initialize udev database */
334         retval = udevdb_init(UDEVDB_DEFAULT);
335         if (retval != 0) {
336                 dbg("unable to initialize database");
337                 goto exit_sysbus;
338         }
339
340         /* set up a default signal handler for now */
341         signal(SIGINT, sig_handler);
342         signal(SIGTERM, sig_handler);
343         signal(SIGKILL, sig_handler);
344
345         /* initialize the naming deamon */
346         namedev_init();
347
348         if (strcmp(action, "add") == 0)
349                 retval = udev_add_device(devpath, subsystem);
350
351         else if (strcmp(action, "remove") == 0)
352                 retval = udev_remove_device(devpath, subsystem);
353
354         else {
355                 dbg("unknown action '%s'", action);
356                 retval = -EINVAL;
357         }
358         udevdb_exit();
359
360 exit_sysbus:
361         /* disconnect from the system message bus */
362         sysbus_disconnect();
363
364 exit:
365         if (retval > 0)
366                 retval = 0;
367
368         return -retval;
369 }
370
371 int main(int argc, char **argv, char **envp)
372 {
373         int retval;
374         main_argv = argv;
375         main_envp = envp;
376
377         dbg("version %s", UDEV_VERSION);
378
379         /* initialize our configuration */
380         udev_init_config();
381
382         if (argc == 2 && argv[1][0] != '-') {
383                 dbg("called by hotplug");
384                 retval = udev_hotplug(argc, argv);
385         } else {
386                 dbg("called by user");
387                 retval = udev_user(argc, argv);
388         }
389
390         return retval;
391 }
392
393