]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udevadm-settle.c
add test/src to .gitignore
[thirdparty/systemd.git] / src / udevadm-settle.c
CommitLineData
7baada47 1/*
fc206fbe 2 * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>
bb38678e
SJR
3 * Copyright (C) 2009 Canonical Ltd.
4 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
7baada47 5 *
55e9959b
KS
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
7baada47 10 *
55e9959b
KS
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
7baada47
KS
18 */
19
20#include <stdlib.h>
21#include <stddef.h>
22#include <string.h>
23#include <stdio.h>
24#include <unistd.h>
25#include <errno.h>
26#include <dirent.h>
27#include <fcntl.h>
28#include <syslog.h>
c2666405 29#include <getopt.h>
c2c24d4d 30#include <signal.h>
959e8b5d 31#include <time.h>
a3eca08b
KS
32#include <sys/inotify.h>
33#include <sys/poll.h>
7baada47
KS
34#include <sys/stat.h>
35#include <sys/types.h>
36
37#include "udev.h"
7baada47 38
1985c76e 39static int adm_settle(struct udev *udev, int argc, char *argv[])
7baada47 40{
c2666405 41 static const struct option options[] = {
98d3d517
KS
42 { "seq-start", required_argument, NULL, 's' },
43 { "seq-end", required_argument, NULL, 'e' },
033e9f8c 44 { "timeout", required_argument, NULL, 't' },
97f48a8c 45 { "exit-if-exists", required_argument, NULL, 'E' },
b76ad2e5 46 { "quiet", no_argument, NULL, 'q' },
033e9f8c 47 { "help", no_argument, NULL, 'h' },
c2666405
KS
48 {}
49 };
ead7c62a 50 unsigned long long start_usec = now_usec();
98d3d517
KS
51 unsigned long long start = 0;
52 unsigned long long end = 0;
b76ad2e5 53 int quiet = 0;
97f48a8c 54 const char *exists = NULL;
d2f4a346 55 unsigned int timeout = 120;
a3eca08b 56 struct pollfd pfd[1];
f6bb9e98 57 struct udev_queue *udev_queue = NULL;
ead7c62a 58 int rc = EXIT_FAILURE;
7baada47 59
7d563a17 60 dbg(udev, "version %s\n", VERSION);
7baada47 61
88cbfb09 62 for (;;) {
8249e04e
KS
63 int option;
64 int seconds;
65
97f48a8c 66 option = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL);
c2666405
KS
67 if (option == -1)
68 break;
7baada47 69
c2666405 70 switch (option) {
98d3d517
KS
71 case 's':
72 start = strtoull(optarg, NULL, 0);
73 break;
74 case 'e':
75 end = strtoull(optarg, NULL, 0);
76 break;
c2666405
KS
77 case 't':
78 seconds = atoi(optarg);
b76ad2e5 79 if (seconds >= 0)
e3396a2d
KS
80 timeout = seconds;
81 else
82 fprintf(stderr, "invalid timeout value\n");
7d563a17 83 dbg(udev, "timeout=%i\n", timeout);
c2666405 84 break;
b76ad2e5
KS
85 case 'q':
86 quiet = 1;
87 break;
97f48a8c
KS
88 case 'E':
89 exists = optarg;
90 break;
c2666405 91 case 'h':
f1e7e360 92 printf("Usage: udevadm settle OPTIONS\n"
97f48a8c
KS
93 " --timeout=<seconds> maximum time to wait for events\n"
94 " --seq-start=<seqnum> first seqnum to wait for\n"
95 " --seq-end=<seqnum> last seqnum to wait for\n"
96 " --exit-if-exists=<file> stop waiting if file exists\n"
97 " --quiet do not print list after timeout\n"
f1e7e360 98 " --help\n\n");
d800e868
PU
99 exit(EXIT_SUCCESS);
100 default:
101 exit(EXIT_FAILURE);
7baada47
KS
102 }
103 }
104
8249e04e
KS
105 udev_queue = udev_queue_new(udev);
106 if (udev_queue == NULL)
9f894a33 107 exit(2);
98d3d517
KS
108
109 if (start > 0) {
110 unsigned long long kernel_seq;
111
112 kernel_seq = udev_queue_get_kernel_seqnum(udev_queue);
113
114 /* unless specified, the last event is the current kernel seqnum */
115 if (end == 0)
116 end = udev_queue_get_kernel_seqnum(udev_queue);
117
118 if (start > end) {
119 err(udev, "seq-start larger than seq-end, ignoring\n");
98d3d517
KS
120 start = 0;
121 end = 0;
122 }
123
124 if (start > kernel_seq || end > kernel_seq) {
125 err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n");
98d3d517
KS
126 start = 0;
127 end = 0;
128 }
129 info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq);
130 } else {
131 if (end > 0) {
132 err(udev, "seq-end needs seq-start parameter, ignoring\n");
98d3d517
KS
133 end = 0;
134 }
135 }
136
bb38678e
SJR
137 /* guarantee that the udev daemon isn't pre-processing */
138 if (getuid() == 0) {
139 struct udev_ctrl *uctrl;
140
5cc4112e 141 uctrl = udev_ctrl_new(udev);
bb38678e 142 if (uctrl != NULL) {
ff2c503d
KS
143 if (udev_ctrl_send_ping(uctrl, timeout) < 0) {
144 info(udev, "no connection to daemon\n");
145 udev_ctrl_unref(uctrl);
ead7c62a 146 rc = EXIT_SUCCESS;
ff2c503d
KS
147 goto out;
148 }
bb38678e
SJR
149 udev_ctrl_unref(uctrl);
150 }
151 }
152
a3eca08b
KS
153 pfd[0].events = POLLIN;
154 pfd[0].fd = inotify_init1(IN_CLOEXEC);
155 if (pfd[0].fd < 0) {
156 err(udev, "inotify_init failed: %m\n");
157 } else {
4b718be8 158 if (inotify_add_watch(pfd[0].fd, udev_get_run_path(udev), IN_MOVED_TO) < 0) {
a3eca08b
KS
159 err(udev, "watching '%s' failed\n", udev_get_run_path(udev));
160 close(pfd[0].fd);
161 pfd[0].fd = -1;
162 }
163 }
164
88cbfb09 165 for (;;) {
97f48a8c
KS
166 struct stat statbuf;
167
168 if (exists != NULL && stat(exists, &statbuf) == 0) {
ead7c62a 169 rc = EXIT_SUCCESS;
97f48a8c
KS
170 break;
171 }
172
98d3d517 173 if (start > 0) {
f503f6b2 174 /* if asked for, wait for a specific sequence of events */
9f894a33 175 if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) {
ead7c62a 176 rc = EXIT_SUCCESS;
f503f6b2 177 break;
9f894a33 178 }
f503f6b2
AJ
179 } else {
180 /* exit if queue is empty */
9f894a33 181 if (udev_queue_get_queue_is_empty(udev_queue)) {
ead7c62a 182 rc = EXIT_SUCCESS;
98d3d517 183 break;
9f894a33 184 }
98d3d517 185 }
f503f6b2 186
a3eca08b 187 if (pfd[0].fd >= 0) {
bd8e0e38
KS
188 int delay;
189
bd8e0e38
KS
190 if (exists != NULL || start > 0)
191 delay = 100;
192 else
193 delay = 1000;
2661ff21 194 /* wake up after delay, or immediately after the queue is rebuilt */
bd8e0e38 195 if (poll(pfd, 1, delay) > 0 && pfd[0].revents & POLLIN) {
a3eca08b
KS
196 char buf[sizeof(struct inotify_event) + PATH_MAX];
197
198 read(pfd[0].fd, buf, sizeof(buf));
199 }
200 } else {
ead7c62a 201 sleep(1);
a3eca08b 202 }
a402404f 203
ead7c62a
KS
204 if (timeout > 0) {
205 unsigned long long age_usec;
206
207 age_usec = now_usec() - start_usec;
208 if (age_usec / (1000 * 1000) >= timeout) {
209 struct udev_list_entry *list_entry;
210
211 if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) {
212 info(udev, "timeout waiting for udev queue\n");
213 printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout);
214 udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
215 printf(" %s (%s)\n",
216 udev_list_entry_get_name(list_entry),
217 udev_list_entry_get_value(list_entry));
218 }
219
220 break;
221 }
b76ad2e5 222 }
8249e04e 223 }
ff2c503d 224out:
a3eca08b
KS
225 if (pfd[0].fd >= 0)
226 close(pfd[0].fd);
8249e04e 227 udev_queue_unref(udev_queue);
7baada47
KS
228 return rc;
229}
1985c76e
KS
230
231const struct udevadm_cmd udevadm_settle = {
232 .name = "settle",
233 .cmd = adm_settle,
234 .help = "wait for the event queue to finish",
235};