]>
Commit | Line | Data |
---|---|---|
e7145211 | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
bb051f66 | 2 | /* |
810adae9 | 3 | * Copyright © 2003-2004 Greg Kroah-Hartman <greg@kroah.com> |
bb051f66 GKH |
4 | */ |
5 | ||
bb051f66 | 6 | #include <errno.h> |
eff4a673 | 7 | #include <getopt.h> |
07630cea LP |
8 | #include <signal.h> |
9 | #include <stddef.h> | |
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
2181d30a | 12 | #include <sys/signalfd.h> |
07630cea | 13 | #include <unistd.h> |
bb051f66 | 14 | |
77ad202c YW |
15 | #include "sd-device.h" |
16 | ||
17 | #include "device-private.h" | |
18 | #include "device-util.h" | |
5ea78a39 | 19 | #include "libudev-util.h" |
07630cea | 20 | #include "string-util.h" |
5ea78a39 | 21 | #include "strxcpyx.h" |
07a26e42 | 22 | #include "udev-builtin.h" |
25de7aa7 | 23 | #include "udev-event.h" |
3d05193e | 24 | #include "udevadm.h" |
bb051f66 | 25 | |
89e94ad3 | 26 | static const char *arg_action = "add"; |
c4d44cba | 27 | static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY; |
89e94ad3 YW |
28 | static char arg_syspath[UTIL_PATH_SIZE] = {}; |
29 | ||
30 | static int help(void) { | |
5ac0162c | 31 | |
5639df9a YW |
32 | printf("%s test [OPTIONS] DEVPATH\n\n" |
33 | "Test an event run.\n\n" | |
5ac0162c | 34 | " -h --help Show this help\n" |
5639df9a | 35 | " -V --version Show package version\n" |
5ac0162c LP |
36 | " -a --action=ACTION Set action string\n" |
37 | " -N --resolve-names=early|late|never When to resolve names\n" | |
38 | , program_invocation_short_name); | |
5ac0162c | 39 | |
89e94ad3 YW |
40 | return 0; |
41 | } | |
912541b0 | 42 | |
89e94ad3 | 43 | static int parse_argv(int argc, char *argv[]) { |
912541b0 | 44 | static const struct option options[] = { |
5639df9a | 45 | { "action", required_argument, NULL, 'a' }, |
912541b0 | 46 | { "resolve-names", required_argument, NULL, 'N' }, |
5639df9a YW |
47 | { "version", no_argument, NULL, 'V' }, |
48 | { "help", no_argument, NULL, 'h' }, | |
912541b0 KS |
49 | {} |
50 | }; | |
51 | ||
89e94ad3 | 52 | int c; |
912541b0 | 53 | |
5639df9a | 54 | while ((c = getopt_long(argc, argv, "a:N:Vh", options, NULL)) >= 0) |
7643ac9a | 55 | switch (c) { |
a12b87f5 YW |
56 | case 'a': { |
57 | DeviceAction a; | |
58 | ||
59 | a = device_action_from_string(optarg); | |
60 | if (a < 0) | |
61 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
62 | "Invalid action '%s'", optarg); | |
63 | ||
89e94ad3 | 64 | arg_action = optarg; |
912541b0 | 65 | break; |
a12b87f5 | 66 | } |
912541b0 | 67 | case 'N': |
c4d44cba | 68 | arg_resolve_name_timing = resolve_name_timing_from_string(optarg); |
baaa35ad ZJS |
69 | if (arg_resolve_name_timing < 0) |
70 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
71 | "--resolve-names= must be early, late or never"); | |
912541b0 | 72 | break; |
5639df9a | 73 | case 'V': |
51b006e1 | 74 | return print_version(); |
912541b0 | 75 | case 'h': |
89e94ad3 | 76 | return help(); |
7643ac9a | 77 | case '?': |
89e94ad3 | 78 | return -EINVAL; |
7643ac9a ZJS |
79 | default: |
80 | assert_not_reached("Unknown option"); | |
912541b0 | 81 | } |
912541b0 | 82 | |
baaa35ad ZJS |
83 | if (!argv[optind]) |
84 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
85 | "syspath parameter missing."); | |
912541b0 | 86 | |
89e94ad3 YW |
87 | /* add /sys if needed */ |
88 | if (!startswith(argv[optind], "/sys")) | |
89 | strscpyl(arg_syspath, sizeof(arg_syspath), "/sys", argv[optind], NULL); | |
90 | else | |
91 | strscpy(arg_syspath, sizeof(arg_syspath), argv[optind]); | |
92 | ||
93 | return 1; | |
94 | } | |
95 | ||
96 | int test_main(int argc, char *argv[], void *userdata) { | |
9a07157d | 97 | _cleanup_(udev_rules_freep) UdevRules *rules = NULL; |
2e088715 | 98 | _cleanup_(udev_event_freep) UdevEvent *event = NULL; |
77ad202c YW |
99 | _cleanup_(sd_device_unrefp) sd_device *dev = NULL; |
100 | const char *cmd, *key, *value; | |
89e94ad3 | 101 | sigset_t mask, sigmask_orig; |
29448498 YW |
102 | Iterator i; |
103 | void *val; | |
89e94ad3 YW |
104 | int r; |
105 | ||
106 | log_set_max_level(LOG_DEBUG); | |
107 | ||
108 | r = parse_argv(argc, argv); | |
109 | if (r <= 0) | |
110 | return r; | |
111 | ||
baa30fbc | 112 | printf("This program is for debugging only, it does not run any program\n" |
912541b0 KS |
113 | "specified by a RUN key. It may show incorrect results, because\n" |
114 | "some values may be different, or not available at a simulation run.\n" | |
115 | "\n"); | |
116 | ||
babdf0d3 | 117 | assert_se(sigprocmask(SIG_SETMASK, NULL, &sigmask_orig) >= 0); |
912541b0 | 118 | |
2024ed61 | 119 | udev_builtin_init(); |
912541b0 | 120 | |
1d791281 ZJS |
121 | r = udev_rules_new(&rules, arg_resolve_name_timing); |
122 | if (r < 0) { | |
123 | log_error_errno(r, "Failed to read udev rules: %m"); | |
912541b0 KS |
124 | goto out; |
125 | } | |
126 | ||
77ad202c YW |
127 | r = device_new_from_synthetic_event(&dev, arg_syspath, arg_action); |
128 | if (r < 0) { | |
129 | log_error_errno(r, "Failed to open device '%s': %m", arg_syspath); | |
912541b0 KS |
130 | goto out; |
131 | } | |
132 | ||
bf0e00ec | 133 | /* don't read info from the db */ |
77ad202c | 134 | device_seal(dev); |
912541b0 | 135 | |
77ad202c | 136 | event = udev_event_new(dev, 0, NULL); |
912541b0 | 137 | |
a3ebe5eb YW |
138 | assert_se(sigfillset(&mask) >= 0); |
139 | assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0); | |
912541b0 | 140 | |
66f737b4 | 141 | udev_event_execute_rules(event, 60 * USEC_PER_SEC, NULL, rules); |
912541b0 | 142 | |
77ad202c YW |
143 | FOREACH_DEVICE_PROPERTY(dev, key, value) |
144 | printf("%s=%s\n", key, value); | |
912541b0 | 145 | |
39a15c8a | 146 | ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { |
1ea97217 | 147 | char program[UTIL_PATH_SIZE]; |
912541b0 | 148 | |
29448498 | 149 | udev_event_apply_format(event, cmd, program, sizeof(program), false); |
1ea97217 | 150 | printf("run: '%s'\n", program); |
912541b0 | 151 | } |
89e94ad3 YW |
152 | |
153 | r = 0; | |
2181d30a | 154 | out: |
2024ed61 | 155 | udev_builtin_exit(); |
89e94ad3 | 156 | return r; |
bb051f66 | 157 | } |