chiark / gitweb /
[PATCH] Cset exclude: greg@kroah.com|ChangeSet|20040113010256|48515
[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         "",
249 };
250
251 static inline int udev_hotplug(int argc, char **argv)
252 {
253         char *action;
254         char *devpath;
255         char *subsystem;
256         int retval = -EINVAL;
257         int i;
258
259         subsystem = argv[1];
260
261         devpath = get_devpath();
262         if (!devpath) {
263                 dbg ("no devpath?");
264                 goto exit;
265         }
266         dbg("looking at '%s'", devpath);
267
268         /* we only care about class devices and block stuff */
269         if (!strstr(devpath, "class") &&
270             !strstr(devpath, "block")) {
271                 dbg("not a block or class device");
272                 goto exit;
273         }
274
275         /* skip blacklisted subsystems */
276         i = 0;
277         while (subsystem_blacklist[i][0] != '\0') {
278                 if (strcmp(subsystem, subsystem_blacklist[i]) == 0) {
279                         dbg("don't care about '%s' devices", subsystem);
280                         goto exit;
281                 }
282                 i++;
283         }
284
285         action = get_action();
286         if (!action) {
287                 dbg ("no action?");
288                 goto exit;
289         }
290
291         /* connect to the system message bus */
292         sysbus_connect();
293
294         /* initialize udev database */
295         retval = udevdb_init(UDEVDB_DEFAULT);
296         if (retval != 0) {
297                 dbg("unable to initialize database");
298                 goto exit_sysbus;
299         }
300
301         /* set up a default signal handler for now */
302         signal(SIGINT, sig_handler);
303         signal(SIGTERM, sig_handler);
304         signal(SIGKILL, sig_handler);
305
306         /* initialize the naming deamon */
307         namedev_init();
308
309         if (strcmp(action, "add") == 0)
310                 retval = udev_add_device(devpath, subsystem);
311
312         else if (strcmp(action, "remove") == 0)
313                 retval = udev_remove_device(devpath, subsystem);
314
315         else {
316                 dbg("unknown action '%s'", action);
317                 retval = -EINVAL;
318         }
319         udevdb_exit();
320
321 exit_sysbus:
322         /* disconnect from the system message bus */
323         sysbus_disconnect();
324
325 exit:
326         if (retval > 0)
327                 retval = 0;
328
329         return -retval;
330 }
331
332 int main(int argc, char **argv, char **envp)
333 {
334         int retval;
335         main_argv = argv;
336         main_envp = envp;
337
338         dbg("version %s", UDEV_VERSION);
339
340         /* initialize our configuration */
341         udev_init_config();
342
343         if (argc == 2 && argv[1][0] != '-') {
344                 dbg("called by hotplug");
345                 retval = udev_hotplug(argc, argv);
346         } else {
347                 dbg("called by user");
348                 retval = udev_user(argc, argv);
349         }
350
351         return retval;
352 }
353
354