chiark / gitweb /
rules: fix md "change"/"remove" handling
[elogind.git] / udev / udevadm.c
1 /*
2  * Copyright (C) 2007-2008 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <getopt.h>
25
26 #include "udev.h"
27
28 static int debug;
29
30 static void log_fn(struct udev *udev, int priority,
31                    const char *file, int line, const char *fn,
32                    const char *format, va_list args)
33 {
34         if (debug) {
35                 fprintf(stderr, "%s: ", fn);
36                 vfprintf(stderr, format, args);
37         } else {
38                 vsyslog(priority, format, args);
39         }
40 }
41
42 struct command {
43         const char *name;
44         int (*cmd)(struct udev *udev, int argc, char *argv[]);
45         const char *help;
46         int debug;
47 };
48
49 static const struct command cmds[];
50
51 static int version(struct udev *udev, int argc, char *argv[])
52 {
53         printf("%s\n", VERSION);
54         return 0;
55 }
56
57 static int help(struct udev *udev, int argc, char *argv[])
58 {
59         const struct command *cmd;
60
61         printf("Usage: udevadm [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n");
62         for (cmd = cmds; cmd->name != NULL; cmd++)
63                 if (cmd->help != NULL)
64                         printf("  %-12s %s\n", cmd->name, cmd->help);
65         printf("\n");
66         return 0;
67 }
68
69 static const struct command cmds[] = {
70         {
71                 .name = "info",
72                 .cmd = udevadm_info,
73                 .help = "query sysfs or the udev database",
74         },
75         {
76                 .name = "trigger",
77                 .cmd = udevadm_trigger,
78                 .help = "request events from the kernel",
79         },
80         {
81                 .name = "settle",
82                 .cmd = udevadm_settle,
83                 .help = "wait for the event queue to finish",
84         },
85         {
86                 .name = "control",
87                 .cmd = udevadm_control,
88                 .help = "control the udev daemon",
89         },
90         {
91                 .name = "monitor",
92                 .cmd = udevadm_monitor,
93                 .help = "listen to kernel and udev events",
94         },
95         {
96                 .name = "test",
97                 .cmd = udevadm_test,
98                 .help = "simulation run",
99                 .debug = 1,
100         },
101         {
102                 .name = "version",
103                 .cmd = version,
104         },
105         {
106                 .name = "help",
107                 .cmd = help,
108         },
109         {}
110 };
111
112 static int run_command(struct udev *udev, const struct command *cmd, int argc, char *argv[])
113 {
114         if (cmd->debug) {
115                 debug = 1;
116                 if (udev_get_log_priority(udev) < LOG_INFO)
117                         udev_set_log_priority(udev, LOG_INFO);
118         }
119         info(udev, "calling: %s\n", cmd->name);
120         return cmd->cmd(udev, argc, argv);
121 }
122
123 int main(int argc, char *argv[])
124 {
125         struct udev *udev;
126         static const struct option options[] = {
127                 { "debug", no_argument, NULL, 'd' },
128                 { "help", no_argument, NULL, 'h' },
129                 { "version", no_argument, NULL, 'V' },
130                 {}
131         };
132         const char *command;
133         int i;
134         const char *pos;
135         int rc = 1;
136
137         udev = udev_new();
138         if (udev == NULL)
139                 goto out;
140
141         logging_init("udevadm");
142         udev_set_log_fn(udev, log_fn);
143         udev_selinux_init(udev);
144
145         /* see if we are a compat link, this will be removed in a future release */
146         command = argv[0];
147         pos = strrchr(command, '/');
148         if (pos != NULL)
149                 command = &pos[1];
150
151         /* the trailing part of the binary or link name is the command */
152         if (strncmp(command, "udev", 4) == 0)
153                 command = &command[4];
154
155         for (i = 0; cmds[i].cmd != NULL; i++) {
156                 if (strcmp(cmds[i].name, command) == 0) {
157                         char path[128];
158                         char prog[512];
159                         ssize_t len;
160
161                         snprintf(path, sizeof(path), "/proc/%lu/exe", (unsigned long) getppid());
162                         len = readlink(path, prog, sizeof(prog));
163                         if (len > 0) {
164                                 prog[len] = '\0';
165                                 fprintf(stderr, "the program '%s' called '%s', it should use 'udevadm %s <options>', "
166                                        "this will stop working in a future release\n", prog, argv[0], command);
167                                 err(udev, "the program '%s' called '%s', it should use 'udevadm %s <options>', "
168                                     "this will stop working in a future release\n", prog, argv[0], command);
169                         }
170                         rc = run_command(udev, &cmds[i], argc, argv);
171                         goto out;
172                 }
173         }
174
175         while (1) {
176                 int option;
177
178                 option = getopt_long(argc, argv, "+dhV", options, NULL);
179                 if (option == -1)
180                         break;
181
182                 switch (option) {
183                 case 'd':
184                         debug = 1;
185                         if (udev_get_log_priority(udev) < LOG_INFO)
186                                 udev_set_log_priority(udev, LOG_INFO);
187                         break;
188                 case 'h':
189                         rc = help(udev, argc, argv);
190                         goto out;
191                 case 'V':
192                         rc = version(udev, argc, argv);
193                         goto out;
194                 default:
195                         goto out;
196                 }
197         }
198         command = argv[optind];
199
200         if (command != NULL)
201                 for (i = 0; cmds[i].cmd != NULL; i++) {
202                         if (strcmp(cmds[i].name, command) == 0) {
203                                 argc -= optind;
204                                 argv += optind;
205                                 optind = 0;
206                                 rc = run_command(udev, &cmds[i], argc, argv);
207                                 goto out;
208                         }
209                 }
210
211         fprintf(stderr, "missing or unknown command\n\n");
212         help(udev, argc, argv);
213         rc = 2;
214 out:
215         udev_selinux_exit(udev);
216         udev_unref(udev);
217         logging_close();
218         return rc;
219 }