chiark / gitweb /
b395be2abb15e362457a875ba4620900295c1ba5
[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", dev->group);
92         printf("\n");
93 }
94
95 enum query_type {
96         NONE,
97         NAME,
98         SYMLINK,
99         OWNER,
100         GROUP
101 };
102
103 static inline int udev_user(int argc, char **argv)
104 {
105         static const char short_options[] = "dp:q:rVh";
106         int option;
107         int retval = -EINVAL;
108         struct udevice dev;
109         int root = 0;
110         enum query_type query = NONE;
111         char result[NAME_SIZE] = "";
112         char path[NAME_SIZE] = "";
113
114         /* get command line options */
115         while (1) {
116                 option = getopt(argc, argv, short_options);
117                 if (option == -1)
118                         break;
119
120                 dbg("option '%c'", option);
121                 switch (option) {
122                 case 'p':
123                         dbg("udev path: %s\n", optarg);
124                         strfieldcpy(path, optarg);
125                         break;
126
127                 case 'q':
128                         dbg("udev query: %s\n", optarg);
129
130                         if (strcmp(optarg, "name") == 0) {
131                                 query = NAME;
132                                 break;
133                         }
134
135                         if (strcmp(optarg, "symlink") == 0) {
136                                 query = SYMLINK;
137                                 break;
138                         }
139
140                         if (strcmp(optarg, "owner") == 0) {
141                                 query = OWNER;
142                                 break;
143                         }
144
145                         if (strcmp(optarg, "group") == 0) {
146                                 query = GROUP;
147                                 break;
148                         }
149
150                         printf("unknown query type\n");
151                         return -EINVAL;
152
153                 case 'r':
154                         root = 1;
155                         break;
156
157                 case 'd':
158                         retval = udevdb_open_ro();
159                         if (retval != 0) {
160                                 printf("unable to open udev database\n");
161                                 return -EACCES;
162                         }
163                         retval = udevdb_dump(print_record);
164                         udevdb_exit();
165                         return retval;
166
167                 case 'V':
168                         printf("udev, version %s\n", UDEV_VERSION);
169                         return 0;
170
171                 case 'h':
172                         retval = 0;
173                 case '?':
174                 default:
175                         goto help;
176                 }
177         }
178
179         /* process options */
180         if (query != NONE) {
181                 if (path[0] == '\0') {
182                         printf("query needs device path specified\n");
183                         return -EINVAL;
184                 }
185
186                 retval = udevdb_open_ro();
187                 if (retval != 0) {
188                         printf("unable to open udev database\n");
189                         return -EACCES;
190                 }
191                 retval = udevdb_get_dev(path, &dev);
192                 if (retval == 0) {
193                         switch(query) {
194                         case NAME:
195                                 if (root)
196                                 strfieldcpy(result, udev_root);
197                                 strncat(result, dev.name, sizeof(result));
198                                 break;
199
200                         case SYMLINK:
201                                 strfieldcpy(result, dev.symlink);
202                                 break;
203
204                         case GROUP:
205                                 strfieldcpy(result, dev.group);
206                                 break;
207
208                         case OWNER:
209                                 strfieldcpy(result, dev.owner);
210                                 break;
211
212                         default:
213                                 break;
214                         }
215                         printf("%s\n", result);
216                 } else {
217                         printf("device not found in udev database\n");
218                 }
219                 udevdb_exit();
220                 return retval;
221         }
222
223         if (root) {
224                 printf("%s\n", udev_root);
225                 return 0;
226         }
227
228 help:
229         printf("Usage: [-pqrdVh]\n"
230                "  -q TYPE  query database for the specified value:\n"
231                "             'name'    name of device node\n"
232                "             'symlink' pointing to node\n"
233                "             'owner'   of node\n"
234                "             'group'   of node\n"
235                "  -p PATH  sysfs device path used for query\n"
236                "  -r       print udev root\n"
237                "  -d       dump whole database\n"
238                "  -V       print udev version\n"
239                "  -h       print this help text\n"
240                "\n");
241         return retval;
242 }
243
244 static char *subsystem_blacklist[] = {
245         "net",
246         "scsi_host",
247         "scsi_device",
248         "usb_host",
249         "pci_bus",
250         "",
251 };
252
253 static inline int udev_hotplug(int argc, char **argv)
254 {
255         char *action;
256         char *devpath;
257         char *subsystem;
258         int retval = -EINVAL;
259         int i;
260
261         subsystem = argv[1];
262
263         devpath = get_devpath();
264         if (!devpath) {
265                 dbg ("no devpath?");
266                 goto exit;
267         }
268         dbg("looking at '%s'", devpath);
269
270         /* we only care about class devices and block stuff */
271         if (!strstr(devpath, "class") &&
272             !strstr(devpath, "block")) {
273                 dbg("not a block or class device");
274                 goto exit;
275         }
276
277         /* skip blacklisted subsystems */
278         i = 0;
279         while (subsystem_blacklist[i][0] != '\0') {
280                 if (strcmp(subsystem, subsystem_blacklist[i]) == 0) {
281                         dbg("don't care about '%s' devices", subsystem);
282                         goto exit;
283                 }
284                 i++;
285         }
286
287         action = get_action();
288         if (!action) {
289                 dbg ("no action?");
290                 goto exit;
291         }
292
293         /* connect to the system message bus */
294         sysbus_connect();
295
296         /* initialize udev database */
297         retval = udevdb_init(UDEVDB_DEFAULT);
298         if (retval != 0) {
299                 dbg("unable to initialize database");
300                 goto exit_sysbus;
301         }
302
303         /* set up a default signal handler for now */
304         signal(SIGINT, sig_handler);
305         signal(SIGTERM, sig_handler);
306         signal(SIGKILL, sig_handler);
307
308         /* initialize the naming deamon */
309         namedev_init();
310
311         if (strcmp(action, "add") == 0)
312                 retval = udev_add_device(devpath, subsystem);
313
314         else if (strcmp(action, "remove") == 0)
315                 retval = udev_remove_device(devpath, subsystem);
316
317         else {
318                 dbg("unknown action '%s'", action);
319                 retval = -EINVAL;
320         }
321         udevdb_exit();
322
323 exit_sysbus:
324         /* disconnect from the system message bus */
325         sysbus_disconnect();
326
327 exit:
328         if (retval > 0)
329                 retval = 0;
330
331         return -retval;
332 }
333
334 int main(int argc, char **argv, char **envp)
335 {
336         int retval;
337         main_argv = argv;
338         main_envp = envp;
339
340         dbg("version %s", UDEV_VERSION);
341
342         /* initialize our configuration */
343         udev_init_config();
344
345         if (argc == 2 && argv[1][0] != '-') {
346                 dbg("called by hotplug");
347                 retval = udev_hotplug(argc, argv);
348         } else {
349                 dbg("called by user");
350                 retval = udev_user(argc, argv);
351         }
352
353         return retval;
354 }
355
356