chiark / gitweb /
udevadm: settle - use timeout signal, instead of loop counter
[elogind.git] / udev / udevadm-settle.c
1 /*
2  * Copyright (C) 2006-2008 Kay Sievers <kay@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 <stdlib.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <syslog.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 #include "udev.h"
33
34 #define DEFAULT_TIMEOUT                 180
35 #define LOOP_PER_SECOND                 20
36
37 static int volatile is_timeout;
38
39 static void asmlinkage sig_handler(int signum)
40 {
41         switch (signum) {
42                 case SIGALRM:
43                         is_timeout = 1;
44         }
45 }
46
47 int udevadm_settle(struct udev *udev, int argc, char *argv[])
48 {
49         static const struct option options[] = {
50                 { "seq-start", required_argument, NULL, 's' },
51                 { "seq-end", required_argument, NULL, 'e' },
52                 { "timeout", required_argument, NULL, 't' },
53                 { "quiet", no_argument, NULL, 'q' },
54                 { "help", no_argument, NULL, 'h' },
55                 {}
56         };
57         unsigned long long start = 0;
58         unsigned long long end = 0;
59         int quiet = 0;
60         int timeout = 0;
61         struct sigaction act;
62         struct udev_queue *udev_queue = NULL;
63         int rc = 0;
64
65         dbg(udev, "version %s\n", VERSION);
66
67         /* set signal handlers */
68         memset(&act, 0x00, sizeof(act));
69         act.sa_handler = (void (*)(int)) sig_handler;
70         sigemptyset (&act.sa_mask);
71         act.sa_flags = 0;
72         sigaction(SIGALRM, &act, NULL);
73
74         while (1) {
75                 int option;
76                 int seconds;
77
78                 option = getopt_long(argc, argv, "s:e:t:qh", options, NULL);
79                 if (option == -1)
80                         break;
81
82                 switch (option) {
83                 case 's':
84                         start = strtoull(optarg, NULL, 0);
85                         break;
86                 case 'e':
87                         end = strtoull(optarg, NULL, 0);
88                         break;
89                 case 't':
90                         seconds = atoi(optarg);
91                         if (seconds >= 0)
92                                 timeout = seconds;
93                         else
94                                 fprintf(stderr, "invalid timeout value\n");
95                         dbg(udev, "timeout=%i\n", timeout);
96                         break;
97                 case 'q':
98                         quiet = 1;
99                         break;
100                 case 'h':
101                         printf("Usage: udevadm settle OPTIONS\n"
102                                "  --timeout=<seconds>   maximum time to wait for events\n"
103                                "  --seq-start=<seqnum>  first seqnum to wait for\n"
104                                "  --seq-end=<seqnum>    last seqnum to wait for\n"
105                                "  --quiet               do not print list after timeout\n"
106                                "  --help\n\n");
107                         goto exit;
108                 }
109         }
110
111         if (timeout > 0)
112                 alarm(timeout);
113         else
114                 alarm(DEFAULT_TIMEOUT);
115
116         udev_queue = udev_queue_new(udev);
117         if (udev_queue == NULL)
118                 goto exit;
119
120         if (start > 0) {
121                 unsigned long long kernel_seq;
122
123                 kernel_seq = udev_queue_get_kernel_seqnum(udev_queue);
124
125                 /* unless specified, the last event is the current kernel seqnum */
126                 if (end == 0)
127                         end = udev_queue_get_kernel_seqnum(udev_queue);
128
129                 if (start > end) {
130                         err(udev, "seq-start larger than seq-end, ignoring\n");
131                         fprintf(stderr, "seq-start larger than seq-end, ignoring\n");
132                         start = 0;
133                         end = 0;
134                 }
135
136                 if (start > kernel_seq || end > kernel_seq) {
137                         err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n");
138                         fprintf(stderr, "seq-start or seq-end larger than current kernel value, ignoring\n");
139                         start = 0;
140                         end = 0;
141                 }
142                 info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq);
143         } else {
144                 if (end > 0) {
145                         err(udev, "seq-end needs seq-start parameter, ignoring\n");
146                         fprintf(stderr, "seq-end needs seq-start parameter, ignoring\n");
147                         end = 0;
148                 }
149         }
150
151         while (!is_timeout) {
152                 /* exit if queue is empty */
153                 if (udev_queue_get_queue_is_empty(udev_queue))
154                         break;
155
156                 /* if asked for, wait for a specific sequence of events */
157                 if (start > 0) {
158                         unsigned long long seq;
159                         int finished;
160
161                         finished = 0;
162                         for (seq = start; seq <= end; seq++) {
163                                 finished  = udev_queue_get_seqnum_is_finished(udev_queue, seq);
164                                 if (!finished)
165                                         break;
166                         }
167                         if (finished)
168                                 break;
169                 }
170                 usleep(1000 * 1000 / LOOP_PER_SECOND);
171         }
172
173         /* if we reached the timeout, print the list of remaining events */
174         if (is_timeout) {
175                 struct udev_list_entry *list_entry;
176
177                 if (!quiet) {
178                         info(udev, "timeout waiting for udev queue\n");
179                         printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout);
180                         udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
181                                 printf("  %s (%s)\n",
182                                        udev_list_entry_get_name(list_entry),
183                                        udev_list_entry_get_value(list_entry));
184                 }
185                 rc = 1;
186         }
187 exit:
188         udev_queue_unref(udev_queue);
189         return rc;
190 }