199ca880aSopenharmony_ci/* 299ca880aSopenharmony_ci * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org> 399ca880aSopenharmony_ci * Copyright (C) 2009 Canonical Ltd. 499ca880aSopenharmony_ci * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com> 599ca880aSopenharmony_ci * 699ca880aSopenharmony_ci * This program is free software: you can redistribute it and/or modify 799ca880aSopenharmony_ci * it under the terms of the GNU General Public License as published by 899ca880aSopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 999ca880aSopenharmony_ci * (at your option) any later version. 1099ca880aSopenharmony_ci * 1199ca880aSopenharmony_ci * This program is distributed in the hope that it will be useful, 1299ca880aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1399ca880aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1499ca880aSopenharmony_ci * GNU General Public License for more details. 1599ca880aSopenharmony_ci * 1699ca880aSopenharmony_ci * You should have received a copy of the GNU General Public License 1799ca880aSopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 1899ca880aSopenharmony_ci */ 1999ca880aSopenharmony_ci 2099ca880aSopenharmony_ci#include <stdlib.h> 2199ca880aSopenharmony_ci#include <stddef.h> 2299ca880aSopenharmony_ci#include <string.h> 2399ca880aSopenharmony_ci#include <stdio.h> 2499ca880aSopenharmony_ci#include <unistd.h> 2599ca880aSopenharmony_ci#include <errno.h> 2699ca880aSopenharmony_ci#include <dirent.h> 2799ca880aSopenharmony_ci#include <fcntl.h> 2899ca880aSopenharmony_ci#include <getopt.h> 2999ca880aSopenharmony_ci#include <signal.h> 3099ca880aSopenharmony_ci#include <time.h> 3199ca880aSopenharmony_ci#include <poll.h> 3299ca880aSopenharmony_ci#include <sys/stat.h> 3399ca880aSopenharmony_ci#include <sys/types.h> 3499ca880aSopenharmony_ci 3599ca880aSopenharmony_ci#include "udev.h" 3699ca880aSopenharmony_ci#include "udev-util.h" 3799ca880aSopenharmony_ci#include "util.h" 3899ca880aSopenharmony_ci 3999ca880aSopenharmony_cistatic void help(void) { 4099ca880aSopenharmony_ci printf("%s settle OPTIONS\n\n" 4199ca880aSopenharmony_ci "Wait for pending udev events.\n\n" 4299ca880aSopenharmony_ci " -h --help Show this help\n" 4399ca880aSopenharmony_ci " --version Show package version\n" 4499ca880aSopenharmony_ci " -t --timeout=SECONDS Maximum time to wait for events\n" 4599ca880aSopenharmony_ci " -E --exit-if-exists=FILE Stop waiting if file exists\n" 4699ca880aSopenharmony_ci , program_invocation_short_name); 4799ca880aSopenharmony_ci} 4899ca880aSopenharmony_ci 4999ca880aSopenharmony_cistatic int adm_settle(struct udev *udev, int argc, char *argv[]) { 5099ca880aSopenharmony_ci static const struct option options[] = { 5199ca880aSopenharmony_ci { "timeout", required_argument, NULL, 't' }, 5299ca880aSopenharmony_ci { "exit-if-exists", required_argument, NULL, 'E' }, 5399ca880aSopenharmony_ci { "help", no_argument, NULL, 'h' }, 5499ca880aSopenharmony_ci { "seq-start", required_argument, NULL, 's' }, /* removed */ 5599ca880aSopenharmony_ci { "seq-end", required_argument, NULL, 'e' }, /* removed */ 5699ca880aSopenharmony_ci { "quiet", no_argument, NULL, 'q' }, /* removed */ 5799ca880aSopenharmony_ci {} 5899ca880aSopenharmony_ci }; 5999ca880aSopenharmony_ci usec_t deadline; 6099ca880aSopenharmony_ci const char *exists = NULL; 6199ca880aSopenharmony_ci unsigned int timeout = 120; 6299ca880aSopenharmony_ci struct pollfd pfd[1] = { {.fd = -1}, }; 6399ca880aSopenharmony_ci int c; 6499ca880aSopenharmony_ci struct udev_queue *queue; 6599ca880aSopenharmony_ci int rc = EXIT_FAILURE; 6699ca880aSopenharmony_ci 6799ca880aSopenharmony_ci while ((c = getopt_long(argc, argv, "t:E:hs:e:q", options, NULL)) >= 0) { 6899ca880aSopenharmony_ci switch (c) { 6999ca880aSopenharmony_ci 7099ca880aSopenharmony_ci case 't': { 7199ca880aSopenharmony_ci int r; 7299ca880aSopenharmony_ci 7399ca880aSopenharmony_ci r = safe_atou(optarg, &timeout); 7499ca880aSopenharmony_ci if (r < 0) { 7599ca880aSopenharmony_ci fprintf(stderr, "Invalid timeout value '%s': %s\n", 7699ca880aSopenharmony_ci optarg, strerror(-r)); 7799ca880aSopenharmony_ci exit(EXIT_FAILURE); 7899ca880aSopenharmony_ci }; 7999ca880aSopenharmony_ci break; 8099ca880aSopenharmony_ci } 8199ca880aSopenharmony_ci 8299ca880aSopenharmony_ci case 'E': 8399ca880aSopenharmony_ci exists = optarg; 8499ca880aSopenharmony_ci break; 8599ca880aSopenharmony_ci 8699ca880aSopenharmony_ci case 'h': 8799ca880aSopenharmony_ci help(); 8899ca880aSopenharmony_ci return EXIT_SUCCESS; 8999ca880aSopenharmony_ci 9099ca880aSopenharmony_ci case 's': 9199ca880aSopenharmony_ci case 'e': 9299ca880aSopenharmony_ci case 'q': 9399ca880aSopenharmony_ci log_info("Option -%c no longer supported.", c); 9499ca880aSopenharmony_ci return EXIT_FAILURE; 9599ca880aSopenharmony_ci 9699ca880aSopenharmony_ci case '?': 9799ca880aSopenharmony_ci return EXIT_FAILURE; 9899ca880aSopenharmony_ci 9999ca880aSopenharmony_ci default: 10099ca880aSopenharmony_ci assert_not_reached("Unknown argument"); 10199ca880aSopenharmony_ci } 10299ca880aSopenharmony_ci } 10399ca880aSopenharmony_ci 10499ca880aSopenharmony_ci if (optind < argc) { 10599ca880aSopenharmony_ci fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]); 10699ca880aSopenharmony_ci return EXIT_FAILURE; 10799ca880aSopenharmony_ci } 10899ca880aSopenharmony_ci 10999ca880aSopenharmony_ci deadline = now(CLOCK_MONOTONIC) + timeout * USEC_PER_SEC; 11099ca880aSopenharmony_ci 11199ca880aSopenharmony_ci /* guarantee that the udev daemon isn't pre-processing */ 11299ca880aSopenharmony_ci if (getuid() == 0) { 11399ca880aSopenharmony_ci struct udev_ctrl *uctrl; 11499ca880aSopenharmony_ci 11599ca880aSopenharmony_ci uctrl = udev_ctrl_new(udev); 11699ca880aSopenharmony_ci if (uctrl != NULL) { 11799ca880aSopenharmony_ci if (udev_ctrl_send_ping(uctrl, MAX(5U, timeout)) < 0) { 11899ca880aSopenharmony_ci log_debug("no connection to daemon"); 11999ca880aSopenharmony_ci udev_ctrl_unref(uctrl); 12099ca880aSopenharmony_ci return EXIT_SUCCESS; 12199ca880aSopenharmony_ci } 12299ca880aSopenharmony_ci udev_ctrl_unref(uctrl); 12399ca880aSopenharmony_ci } 12499ca880aSopenharmony_ci } 12599ca880aSopenharmony_ci 12699ca880aSopenharmony_ci queue = udev_queue_new(udev); 12799ca880aSopenharmony_ci if (!queue) { 12899ca880aSopenharmony_ci log_error("unable to get udev queue"); 12999ca880aSopenharmony_ci return EXIT_FAILURE; 13099ca880aSopenharmony_ci } 13199ca880aSopenharmony_ci 13299ca880aSopenharmony_ci pfd[0].events = POLLIN; 13399ca880aSopenharmony_ci pfd[0].fd = udev_queue_get_fd(queue); 13499ca880aSopenharmony_ci if (pfd[0].fd < 0) { 13599ca880aSopenharmony_ci log_debug("queue is empty, nothing to watch"); 13699ca880aSopenharmony_ci rc = EXIT_SUCCESS; 13799ca880aSopenharmony_ci goto out; 13899ca880aSopenharmony_ci } 13999ca880aSopenharmony_ci 14099ca880aSopenharmony_ci for (;;) { 14199ca880aSopenharmony_ci if (exists && access(exists, F_OK) >= 0) { 14299ca880aSopenharmony_ci rc = EXIT_SUCCESS; 14399ca880aSopenharmony_ci break; 14499ca880aSopenharmony_ci } 14599ca880aSopenharmony_ci 14699ca880aSopenharmony_ci /* exit if queue is empty */ 14799ca880aSopenharmony_ci if (udev_queue_get_queue_is_empty(queue)) { 14899ca880aSopenharmony_ci rc = EXIT_SUCCESS; 14999ca880aSopenharmony_ci break; 15099ca880aSopenharmony_ci } 15199ca880aSopenharmony_ci 15299ca880aSopenharmony_ci if (now(CLOCK_MONOTONIC) >= deadline) 15399ca880aSopenharmony_ci break; 15499ca880aSopenharmony_ci 15599ca880aSopenharmony_ci /* wake up when queue is empty */ 15699ca880aSopenharmony_ci if (poll(pfd, 1, MSEC_PER_SEC) > 0 && pfd[0].revents & POLLIN) 15799ca880aSopenharmony_ci udev_queue_flush(queue); 15899ca880aSopenharmony_ci } 15999ca880aSopenharmony_ci 16099ca880aSopenharmony_ciout: 16199ca880aSopenharmony_ci udev_queue_unref(queue); 16299ca880aSopenharmony_ci return rc; 16399ca880aSopenharmony_ci} 16499ca880aSopenharmony_ci 16599ca880aSopenharmony_ciconst struct udevadm_cmd udevadm_settle = { 16699ca880aSopenharmony_ci .name = "settle", 16799ca880aSopenharmony_ci .cmd = adm_settle, 16899ca880aSopenharmony_ci .help = "Wait for pending udev events", 16999ca880aSopenharmony_ci}; 170