LCOV - code coverage report
Current view: top level - udev - udevadm-trigger.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 231 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <getopt.h>
       5             : 
       6             : #include "sd-device.h"
       7             : #include "sd-event.h"
       8             : 
       9             : #include "device-enumerator-private.h"
      10             : #include "device-private.h"
      11             : #include "fd-util.h"
      12             : #include "fileio.h"
      13             : #include "path-util.h"
      14             : #include "process-util.h"
      15             : #include "set.h"
      16             : #include "string-util.h"
      17             : #include "strv.h"
      18             : #include "udevadm.h"
      19             : #include "udevadm-util.h"
      20             : #include "udev-ctrl.h"
      21             : #include "virt.h"
      22             : 
      23             : static bool arg_verbose = false;
      24             : static bool arg_dry_run = false;
      25             : 
      26           0 : static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_set) {
      27             :         sd_device *d;
      28           0 :         int r, ret = 0;
      29             : 
      30           0 :         FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
      31           0 :                 _cleanup_free_ char *filename = NULL;
      32             :                 const char *syspath;
      33             : 
      34           0 :                 if (sd_device_get_syspath(d, &syspath) < 0)
      35           0 :                         continue;
      36             : 
      37           0 :                 if (arg_verbose)
      38           0 :                         printf("%s\n", syspath);
      39           0 :                 if (arg_dry_run)
      40           0 :                         continue;
      41             : 
      42           0 :                 filename = path_join(syspath, "uevent");
      43           0 :                 if (!filename)
      44           0 :                         return log_oom();
      45             : 
      46           0 :                 r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER);
      47           0 :                 if (r < 0) {
      48           0 :                         log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
      49             :                                        "Failed to write '%s' to '%s': %m", action, filename);
      50           0 :                         if (ret == 0 && r != -ENOENT)
      51           0 :                                 ret = r;
      52           0 :                         continue;
      53             :                 }
      54             : 
      55           0 :                 if (settle_set) {
      56           0 :                         r = set_put_strdup(settle_set, syspath);
      57           0 :                         if (r < 0)
      58           0 :                                 return log_oom();
      59             :                 }
      60             :         }
      61             : 
      62           0 :         return ret;
      63             : }
      64             : 
      65           0 : static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) {
      66           0 :         _cleanup_free_ char *val = NULL;
      67           0 :         Set *settle_set = userdata;
      68             :         const char *syspath;
      69             : 
      70           0 :         assert(dev);
      71           0 :         assert(settle_set);
      72             : 
      73           0 :         if (sd_device_get_syspath(dev, &syspath) < 0)
      74           0 :                 return 0;
      75             : 
      76           0 :         if (arg_verbose)
      77           0 :                 printf("settle %s\n", syspath);
      78             : 
      79           0 :         val = set_remove(settle_set, syspath);
      80           0 :         if (!val)
      81           0 :                 log_debug("Got epoll event on syspath %s not present in syspath set", syspath);
      82             : 
      83           0 :         if (set_isempty(settle_set))
      84           0 :                 return sd_event_exit(sd_device_monitor_get_event(m), 0);
      85             : 
      86           0 :         return 0;
      87             : }
      88             : 
      89           0 : static char* keyval(const char *str, const char **key, const char **val) {
      90             :         char *buf, *pos;
      91             : 
      92           0 :         buf = strdup(str);
      93           0 :         if (!buf)
      94           0 :                 return NULL;
      95             : 
      96           0 :         pos = strchr(buf, '=');
      97           0 :         if (pos) {
      98           0 :                 pos[0] = 0;
      99           0 :                 pos++;
     100             :         }
     101             : 
     102           0 :         *key = buf;
     103           0 :         *val = pos;
     104             : 
     105           0 :         return buf;
     106             : }
     107             : 
     108           0 : static int help(void) {
     109           0 :         printf("%s trigger [OPTIONS] DEVPATH\n\n"
     110             :                "Request events from the kernel.\n\n"
     111             :                "  -h --help                         Show this help\n"
     112             :                "  -V --version                      Show package version\n"
     113             :                "  -v --verbose                      Print the list of devices while running\n"
     114             :                "  -n --dry-run                      Do not actually trigger the events\n"
     115             :                "  -t --type=                        Type of events to trigger\n"
     116             :                "          devices                     sysfs devices (default)\n"
     117             :                "          subsystems                  sysfs subsystems and drivers\n"
     118             :                "  -c --action=ACTION|help           Event action value, default is \"change\"\n"
     119             :                "  -s --subsystem-match=SUBSYSTEM    Trigger devices from a matching subsystem\n"
     120             :                "  -S --subsystem-nomatch=SUBSYSTEM  Exclude devices from a matching subsystem\n"
     121             :                "  -a --attr-match=FILE[=VALUE]      Trigger devices with a matching attribute\n"
     122             :                "  -A --attr-nomatch=FILE[=VALUE]    Exclude devices with a matching attribute\n"
     123             :                "  -p --property-match=KEY=VALUE     Trigger devices with a matching property\n"
     124             :                "  -g --tag-match=KEY=VALUE          Trigger devices with a matching property\n"
     125             :                "  -y --sysname-match=NAME           Trigger devices with this /sys path\n"
     126             :                "     --name-match=NAME              Trigger devices with this /dev name\n"
     127             :                "  -b --parent-match=NAME            Trigger devices with that parent device\n"
     128             :                "  -w --settle                       Wait for the triggered events to complete\n"
     129             :                "     --wait-daemon[=SECONDS]        Wait for udevd daemon to be initialized\n"
     130             :                "                                    before triggering uevents\n"
     131             :                , program_invocation_short_name);
     132             : 
     133           0 :         return 0;
     134             : }
     135             : 
     136           0 : int trigger_main(int argc, char *argv[], void *userdata) {
     137             :         enum {
     138             :                 ARG_NAME = 0x100,
     139             :                 ARG_PING,
     140             :         };
     141             : 
     142             :         static const struct option options[] = {
     143             :                 { "verbose",           no_argument,       NULL, 'v'      },
     144             :                 { "dry-run",           no_argument,       NULL, 'n'      },
     145             :                 { "type",              required_argument, NULL, 't'      },
     146             :                 { "action",            required_argument, NULL, 'c'      },
     147             :                 { "subsystem-match",   required_argument, NULL, 's'      },
     148             :                 { "subsystem-nomatch", required_argument, NULL, 'S'      },
     149             :                 { "attr-match",        required_argument, NULL, 'a'      },
     150             :                 { "attr-nomatch",      required_argument, NULL, 'A'      },
     151             :                 { "property-match",    required_argument, NULL, 'p'      },
     152             :                 { "tag-match",         required_argument, NULL, 'g'      },
     153             :                 { "sysname-match",     required_argument, NULL, 'y'      },
     154             :                 { "name-match",        required_argument, NULL, ARG_NAME },
     155             :                 { "parent-match",      required_argument, NULL, 'b'      },
     156             :                 { "settle",            no_argument,       NULL, 'w'      },
     157             :                 { "wait-daemon",       optional_argument, NULL, ARG_PING },
     158             :                 { "version",           no_argument,       NULL, 'V'      },
     159             :                 { "help",              no_argument,       NULL, 'h'      },
     160             :                 {}
     161             :         };
     162             :         enum {
     163             :                 TYPE_DEVICES,
     164             :                 TYPE_SUBSYSTEMS,
     165           0 :         } device_type = TYPE_DEVICES;
     166           0 :         const char *action = "change";
     167           0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
     168           0 :         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
     169           0 :         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
     170           0 :         _cleanup_set_free_free_ Set *settle_set = NULL;
     171           0 :         usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
     172           0 :         bool settle = false, ping = false;
     173             :         int c, r;
     174             : 
     175           0 :         if (running_in_chroot() > 0) {
     176           0 :                 log_info("Running in chroot, ignoring request.");
     177           0 :                 return 0;
     178             :         }
     179             : 
     180           0 :         r = sd_device_enumerator_new(&e);
     181           0 :         if (r < 0)
     182           0 :                 return r;
     183             : 
     184           0 :         r = sd_device_enumerator_allow_uninitialized(e);
     185           0 :         if (r < 0)
     186           0 :                 return r;
     187             : 
     188           0 :         while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) {
     189           0 :                 _cleanup_free_ char *buf = NULL;
     190             :                 const char *key, *val;
     191             : 
     192           0 :                 switch (c) {
     193           0 :                 case 'v':
     194           0 :                         arg_verbose = true;
     195           0 :                         break;
     196           0 :                 case 'n':
     197           0 :                         arg_dry_run = true;
     198           0 :                         break;
     199           0 :                 case 't':
     200           0 :                         if (streq(optarg, "devices"))
     201           0 :                                 device_type = TYPE_DEVICES;
     202           0 :                         else if (streq(optarg, "subsystems"))
     203           0 :                                 device_type = TYPE_SUBSYSTEMS;
     204             :                         else
     205           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg);
     206           0 :                         break;
     207           0 :                 case 'c':
     208           0 :                         if (streq(optarg, "help")) {
     209           0 :                                 dump_device_action_table();
     210           0 :                                 return 0;
     211             :                         }
     212           0 :                         if (device_action_from_string(optarg) < 0)
     213           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg);
     214             : 
     215           0 :                         action = optarg;
     216           0 :                         break;
     217           0 :                 case 's':
     218           0 :                         r = sd_device_enumerator_add_match_subsystem(e, optarg, true);
     219           0 :                         if (r < 0)
     220           0 :                                 return log_error_errno(r, "Failed to add subsystem match '%s': %m", optarg);
     221           0 :                         break;
     222           0 :                 case 'S':
     223           0 :                         r = sd_device_enumerator_add_match_subsystem(e, optarg, false);
     224           0 :                         if (r < 0)
     225           0 :                                 return log_error_errno(r, "Failed to add negative subsystem match '%s': %m", optarg);
     226           0 :                         break;
     227           0 :                 case 'a':
     228           0 :                         buf = keyval(optarg, &key, &val);
     229           0 :                         if (!buf)
     230           0 :                                 return log_oom();
     231           0 :                         r = sd_device_enumerator_add_match_sysattr(e, key, val, true);
     232           0 :                         if (r < 0)
     233           0 :                                 return log_error_errno(r, "Failed to add sysattr match '%s=%s': %m", key, val);
     234           0 :                         break;
     235           0 :                 case 'A':
     236           0 :                         buf = keyval(optarg, &key, &val);
     237           0 :                         if (!buf)
     238           0 :                                 return log_oom();
     239           0 :                         r = sd_device_enumerator_add_match_sysattr(e, key, val, false);
     240           0 :                         if (r < 0)
     241           0 :                                 return log_error_errno(r, "Failed to add negative sysattr match '%s=%s': %m", key, val);
     242           0 :                         break;
     243           0 :                 case 'p':
     244           0 :                         buf = keyval(optarg, &key, &val);
     245           0 :                         if (!buf)
     246           0 :                                 return log_oom();
     247           0 :                         r = sd_device_enumerator_add_match_property(e, key, val);
     248           0 :                         if (r < 0)
     249           0 :                                 return log_error_errno(r, "Failed to add property match '%s=%s': %m", key, val);
     250           0 :                         break;
     251           0 :                 case 'g':
     252           0 :                         r = sd_device_enumerator_add_match_tag(e, optarg);
     253           0 :                         if (r < 0)
     254           0 :                                 return log_error_errno(r, "Failed to add tag match '%s': %m", optarg);
     255           0 :                         break;
     256           0 :                 case 'y':
     257           0 :                         r = sd_device_enumerator_add_match_sysname(e, optarg);
     258           0 :                         if (r < 0)
     259           0 :                                 return log_error_errno(r, "Failed to add sysname match '%s': %m", optarg);
     260           0 :                         break;
     261           0 :                 case 'b': {
     262           0 :                         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
     263             : 
     264           0 :                         r = find_device(optarg, "/sys", &dev);
     265           0 :                         if (r < 0)
     266           0 :                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
     267             : 
     268           0 :                         r = device_enumerator_add_match_parent_incremental(e, dev);
     269           0 :                         if (r < 0)
     270           0 :                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
     271           0 :                         break;
     272             :                 }
     273           0 :                 case 'w':
     274           0 :                         settle = true;
     275           0 :                         break;
     276             : 
     277           0 :                 case ARG_NAME: {
     278           0 :                         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
     279             : 
     280           0 :                         r = find_device(optarg, "/dev/", &dev);
     281           0 :                         if (r < 0)
     282           0 :                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
     283             : 
     284           0 :                         r = device_enumerator_add_match_parent_incremental(e, dev);
     285           0 :                         if (r < 0)
     286           0 :                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
     287           0 :                         break;
     288             :                 }
     289             : 
     290           0 :                 case ARG_PING: {
     291           0 :                         ping = true;
     292           0 :                         if (optarg) {
     293           0 :                                 r = parse_sec(optarg, &ping_timeout_usec);
     294           0 :                                 if (r < 0)
     295           0 :                                         log_error_errno(r, "Failed to parse timeout value '%s', ignoring: %m", optarg);
     296             :                         }
     297           0 :                         break;
     298             :                 }
     299             : 
     300           0 :                 case 'V':
     301           0 :                         return print_version();
     302           0 :                 case 'h':
     303           0 :                         return help();
     304           0 :                 case '?':
     305           0 :                         return -EINVAL;
     306           0 :                 default:
     307           0 :                         assert_not_reached("Unknown option");
     308             :                 }
     309             :         }
     310             : 
     311           0 :         if (ping) {
     312           0 :                 _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
     313             : 
     314           0 :                 r = udev_ctrl_new(&uctrl);
     315           0 :                 if (r < 0)
     316           0 :                         return log_error_errno(r, "Failed to initialize udev control: %m");
     317             : 
     318           0 :                 r = udev_ctrl_send_ping(uctrl);
     319           0 :                 if (r < 0)
     320           0 :                         return log_error_errno(r, "Failed to connect to udev daemon: %m");
     321             : 
     322           0 :                 r = udev_ctrl_wait(uctrl, ping_timeout_usec);
     323           0 :                 if (r < 0)
     324           0 :                         return log_error_errno(r, "Failed to wait for daemon to reply: %m");
     325             :         }
     326             : 
     327           0 :         for (; optind < argc; optind++) {
     328           0 :                 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
     329             : 
     330           0 :                 r = find_device(argv[optind], NULL, &dev);
     331           0 :                 if (r < 0)
     332           0 :                         return log_error_errno(r, "Failed to open the device '%s': %m", argv[optind]);
     333             : 
     334           0 :                 r = device_enumerator_add_match_parent_incremental(e, dev);
     335           0 :                 if (r < 0)
     336           0 :                         return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]);
     337             :         }
     338             : 
     339           0 :         if (settle) {
     340           0 :                 settle_set = set_new(&string_hash_ops);
     341           0 :                 if (!settle_set)
     342           0 :                         return log_oom();
     343             : 
     344           0 :                 r = sd_event_default(&event);
     345           0 :                 if (r < 0)
     346           0 :                         return log_error_errno(r, "Failed to get default event: %m");
     347             : 
     348           0 :                 r = sd_device_monitor_new(&m);
     349           0 :                 if (r < 0)
     350           0 :                         return log_error_errno(r, "Failed to create device monitor object: %m");
     351             : 
     352           0 :                 r = sd_device_monitor_attach_event(m, event);
     353           0 :                 if (r < 0)
     354           0 :                         return log_error_errno(r, "Failed to attach event to device monitor: %m");
     355             : 
     356           0 :                 r = sd_device_monitor_start(m, device_monitor_handler, settle_set);
     357           0 :                 if (r < 0)
     358           0 :                         return log_error_errno(r, "Failed to start device monitor: %m");
     359             :         }
     360             : 
     361           0 :         switch (device_type) {
     362           0 :         case TYPE_SUBSYSTEMS:
     363           0 :                 r = device_enumerator_scan_subsystems(e);
     364           0 :                 if (r < 0)
     365           0 :                         return log_error_errno(r, "Failed to scan subsystems: %m");
     366           0 :                 break;
     367           0 :         case TYPE_DEVICES:
     368           0 :                 r = device_enumerator_scan_devices(e);
     369           0 :                 if (r < 0)
     370           0 :                         return log_error_errno(r, "Failed to scan devices: %m");
     371           0 :                 break;
     372           0 :         default:
     373           0 :                 assert_not_reached("Unknown device type");
     374             :         }
     375           0 :         r = exec_list(e, action, settle_set);
     376           0 :         if (r < 0)
     377           0 :                 return r;
     378             : 
     379           0 :         if (event && !set_isempty(settle_set)) {
     380           0 :                 r = sd_event_loop(event);
     381           0 :                 if (r < 0)
     382           0 :                         return log_error_errno(r, "Event loop failed: %m");
     383             :         }
     384             : 
     385           0 :         return 0;
     386             : }

Generated by: LCOV version 1.14