]>
Commit | Line | Data |
---|---|---|
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> |
7baada47 KS |
32 | #include <sys/stat.h> |
33 | #include <sys/types.h> | |
34 | ||
35 | #include "udev.h" | |
7baada47 | 36 | |
fc8ec932 | 37 | #define DEFAULT_TIMEOUT 180 |
7baada47 KS |
38 | #define LOOP_PER_SECOND 20 |
39 | ||
619b97ff | 40 | static volatile sig_atomic_t is_timeout; |
c2c24d4d | 41 | |
619b97ff | 42 | static void sig_handler(int signum) |
c2c24d4d KS |
43 | { |
44 | switch (signum) { | |
45 | case SIGALRM: | |
46 | is_timeout = 1; | |
bb38678e SJR |
47 | case SIGUSR1: |
48 | ; | |
c2c24d4d KS |
49 | } |
50 | } | |
51 | ||
7d563a17 | 52 | int udevadm_settle(struct udev *udev, int argc, char *argv[]) |
7baada47 | 53 | { |
c2666405 | 54 | static const struct option options[] = { |
98d3d517 KS |
55 | { "seq-start", required_argument, NULL, 's' }, |
56 | { "seq-end", required_argument, NULL, 'e' }, | |
033e9f8c | 57 | { "timeout", required_argument, NULL, 't' }, |
97f48a8c | 58 | { "exit-if-exists", required_argument, NULL, 'E' }, |
b76ad2e5 | 59 | { "quiet", no_argument, NULL, 'q' }, |
033e9f8c | 60 | { "help", no_argument, NULL, 'h' }, |
c2666405 KS |
61 | {} |
62 | }; | |
98d3d517 KS |
63 | unsigned long long start = 0; |
64 | unsigned long long end = 0; | |
b76ad2e5 | 65 | int quiet = 0; |
97f48a8c | 66 | const char *exists = NULL; |
9f894a33 | 67 | int timeout = DEFAULT_TIMEOUT; |
c2c24d4d | 68 | struct sigaction act; |
bc3ec7bd | 69 | sigset_t mask; |
f6bb9e98 | 70 | struct udev_queue *udev_queue = NULL; |
9f894a33 | 71 | int rc = 1; |
7baada47 | 72 | |
7d563a17 | 73 | dbg(udev, "version %s\n", VERSION); |
7baada47 | 74 | |
c2c24d4d KS |
75 | /* set signal handlers */ |
76 | memset(&act, 0x00, sizeof(act)); | |
619b97ff | 77 | act.sa_handler = sig_handler; |
c2c24d4d KS |
78 | sigemptyset (&act.sa_mask); |
79 | act.sa_flags = 0; | |
80 | sigaction(SIGALRM, &act, NULL); | |
bb38678e | 81 | sigaction(SIGUSR1, &act, NULL); |
bc3ec7bd KS |
82 | sigemptyset(&mask); |
83 | sigaddset(&mask, SIGUSR1); | |
84 | sigaddset(&mask, SIGALRM); | |
85 | sigprocmask(SIG_UNBLOCK, &mask, NULL); | |
c2c24d4d | 86 | |
88cbfb09 | 87 | for (;;) { |
8249e04e KS |
88 | int option; |
89 | int seconds; | |
90 | ||
97f48a8c | 91 | option = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL); |
c2666405 KS |
92 | if (option == -1) |
93 | break; | |
7baada47 | 94 | |
c2666405 | 95 | switch (option) { |
98d3d517 KS |
96 | case 's': |
97 | start = strtoull(optarg, NULL, 0); | |
98 | break; | |
99 | case 'e': | |
100 | end = strtoull(optarg, NULL, 0); | |
101 | break; | |
c2666405 KS |
102 | case 't': |
103 | seconds = atoi(optarg); | |
b76ad2e5 | 104 | if (seconds >= 0) |
e3396a2d KS |
105 | timeout = seconds; |
106 | else | |
107 | fprintf(stderr, "invalid timeout value\n"); | |
7d563a17 | 108 | dbg(udev, "timeout=%i\n", timeout); |
c2666405 | 109 | break; |
b76ad2e5 KS |
110 | case 'q': |
111 | quiet = 1; | |
112 | break; | |
97f48a8c KS |
113 | case 'E': |
114 | exists = optarg; | |
115 | break; | |
c2666405 | 116 | case 'h': |
f1e7e360 | 117 | printf("Usage: udevadm settle OPTIONS\n" |
97f48a8c KS |
118 | " --timeout=<seconds> maximum time to wait for events\n" |
119 | " --seq-start=<seqnum> first seqnum to wait for\n" | |
120 | " --seq-end=<seqnum> last seqnum to wait for\n" | |
121 | " --exit-if-exists=<file> stop waiting if file exists\n" | |
122 | " --quiet do not print list after timeout\n" | |
f1e7e360 | 123 | " --help\n\n"); |
9f894a33 | 124 | exit(0); |
7baada47 KS |
125 | } |
126 | } | |
127 | ||
c2c24d4d KS |
128 | if (timeout > 0) |
129 | alarm(timeout); | |
130 | else | |
9f894a33 | 131 | is_timeout = 1; |
c2c24d4d | 132 | |
8249e04e KS |
133 | udev_queue = udev_queue_new(udev); |
134 | if (udev_queue == NULL) | |
9f894a33 | 135 | exit(2); |
98d3d517 KS |
136 | |
137 | if (start > 0) { | |
138 | unsigned long long kernel_seq; | |
139 | ||
140 | kernel_seq = udev_queue_get_kernel_seqnum(udev_queue); | |
141 | ||
142 | /* unless specified, the last event is the current kernel seqnum */ | |
143 | if (end == 0) | |
144 | end = udev_queue_get_kernel_seqnum(udev_queue); | |
145 | ||
146 | if (start > end) { | |
147 | err(udev, "seq-start larger than seq-end, ignoring\n"); | |
98d3d517 KS |
148 | start = 0; |
149 | end = 0; | |
150 | } | |
151 | ||
152 | if (start > kernel_seq || end > kernel_seq) { | |
153 | err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n"); | |
98d3d517 KS |
154 | start = 0; |
155 | end = 0; | |
156 | } | |
157 | info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq); | |
158 | } else { | |
159 | if (end > 0) { | |
160 | err(udev, "seq-end needs seq-start parameter, ignoring\n"); | |
98d3d517 KS |
161 | end = 0; |
162 | } | |
163 | } | |
164 | ||
bb38678e SJR |
165 | /* guarantee that the udev daemon isn't pre-processing */ |
166 | if (getuid() == 0) { | |
167 | struct udev_ctrl *uctrl; | |
168 | ||
169 | uctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); | |
170 | if (uctrl != NULL) { | |
bc3ec7bd | 171 | sigset_t oldmask; |
bb38678e SJR |
172 | |
173 | sigemptyset(&mask); | |
174 | sigaddset(&mask, SIGUSR1); | |
175 | sigaddset(&mask, SIGALRM); | |
176 | sigprocmask(SIG_BLOCK, &mask, &oldmask); | |
177 | if (udev_ctrl_send_settle(uctrl) > 0) | |
178 | sigsuspend(&oldmask); | |
f58a9099 | 179 | sigprocmask(SIG_SETMASK, &oldmask, NULL); |
bb38678e SJR |
180 | udev_ctrl_unref(uctrl); |
181 | } | |
182 | } | |
183 | ||
88cbfb09 | 184 | for (;;) { |
97f48a8c | 185 | struct stat statbuf; |
959e8b5d | 186 | const struct timespec duration = { 0 , 1000 * 1000 * 1000 / LOOP_PER_SECOND }; |
97f48a8c KS |
187 | |
188 | if (exists != NULL && stat(exists, &statbuf) == 0) { | |
189 | rc = 0; | |
190 | break; | |
191 | } | |
192 | ||
98d3d517 | 193 | if (start > 0) { |
f503f6b2 | 194 | /* if asked for, wait for a specific sequence of events */ |
9f894a33 KS |
195 | if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) { |
196 | rc = 0; | |
f503f6b2 | 197 | break; |
9f894a33 | 198 | } |
f503f6b2 AJ |
199 | } else { |
200 | /* exit if queue is empty */ | |
9f894a33 KS |
201 | if (udev_queue_get_queue_is_empty(udev_queue)) { |
202 | rc = 0; | |
98d3d517 | 203 | break; |
9f894a33 | 204 | } |
98d3d517 | 205 | } |
f503f6b2 | 206 | |
9f894a33 KS |
207 | if (is_timeout) |
208 | break; | |
209 | ||
959e8b5d | 210 | nanosleep(&duration, NULL); |
7baada47 | 211 | } |
a402404f KS |
212 | |
213 | /* if we reached the timeout, print the list of remaining events */ | |
c2c24d4d | 214 | if (is_timeout) { |
8249e04e KS |
215 | struct udev_list_entry *list_entry; |
216 | ||
9f894a33 | 217 | if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) { |
b76ad2e5 | 218 | info(udev, "timeout waiting for udev queue\n"); |
c2de781e | 219 | printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout); |
b76ad2e5 KS |
220 | udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) |
221 | printf(" %s (%s)\n", | |
222 | udev_list_entry_get_name(list_entry), | |
223 | udev_list_entry_get_value(list_entry)); | |
224 | } | |
8249e04e | 225 | } |
9f894a33 | 226 | |
8249e04e | 227 | udev_queue_unref(udev_queue); |
7baada47 KS |
228 | return rc; |
229 | } |