LCOV - code coverage report
Current view: top level - udev - udevadm-trigger.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 231 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 5 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 217 0.0 %

           Branch data     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