Commit | Line | Data |
---|---|---|
b61776fb SM |
1 | /* |
2 | * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0-only | |
5 | * | |
6 | */ | |
7 | ||
c9e313bc | 8 | #include "../command.hpp" |
c9e313bc | 9 | #include "common/argpar-utils/argpar-utils.hpp" |
28ab034a | 10 | #include "common/argpar/argpar.h" |
c9e313bc | 11 | #include "common/mi-lttng.hpp" |
28ab034a | 12 | |
b61776fb | 13 | #include <lttng/lttng.h> |
28ab034a | 14 | |
b61776fb SM |
15 | #include <stdio.h> |
16 | ||
17 | #ifdef LTTNG_EMBED_HELP | |
18 | static const char help_msg[] = | |
19 | #include <lttng-remove-trigger.1.h> | |
28ab034a | 20 | ; |
b61776fb SM |
21 | #endif |
22 | ||
23 | enum { | |
24 | OPT_HELP, | |
25 | OPT_LIST_OPTIONS, | |
481c5310 | 26 | OPT_OWNER_UID, |
b61776fb SM |
27 | }; |
28 | ||
28ab034a | 29 | static const struct argpar_opt_descr remove_trigger_options[] = { |
b61776fb SM |
30 | { OPT_HELP, 'h', "help", false }, |
31 | { OPT_LIST_OPTIONS, '\0', "list-options", false }, | |
481c5310 | 32 | { OPT_OWNER_UID, '\0', "owner-uid", true }, |
b61776fb SM |
33 | ARGPAR_OPT_DESCR_SENTINEL, |
34 | }; | |
35 | ||
28ab034a | 36 | static bool assign_string(char **dest, const char *src, const char *opt_name) |
b61776fb SM |
37 | { |
38 | bool ret; | |
39 | ||
40 | if (*dest) { | |
41 | ERR("Duplicate option '%s' given.", opt_name); | |
42 | goto error; | |
43 | } | |
44 | ||
45 | *dest = strdup(src); | |
46 | if (!*dest) { | |
47 | ERR("Failed to allocate '%s' string.", opt_name); | |
48 | goto error; | |
49 | } | |
50 | ||
51 | ret = true; | |
52 | goto end; | |
53 | ||
54 | error: | |
55 | ret = false; | |
56 | ||
57 | end: | |
58 | return ret; | |
59 | } | |
60 | ||
61 | int cmd_remove_trigger(int argc, const char **argv) | |
62 | { | |
523c4f8c | 63 | enum lttng_error_code ret_code; |
b61776fb | 64 | int ret; |
cd9adb8b JG |
65 | struct argpar_iter *argpar_iter = nullptr; |
66 | const struct argpar_item *argpar_item = nullptr; | |
67 | const char *name = nullptr; | |
b61776fb | 68 | int i; |
cd9adb8b | 69 | struct lttng_triggers *triggers = nullptr; |
b61776fb SM |
70 | unsigned int triggers_count; |
71 | enum lttng_trigger_status trigger_status; | |
cd9adb8b JG |
72 | const struct lttng_trigger *trigger_to_remove = nullptr; |
73 | char *owner_uid = nullptr; | |
b61776fb | 74 | long long uid; |
cd9adb8b | 75 | struct mi_writer *mi_writer = nullptr; |
5ba02fff | 76 | const char **args; |
523c4f8c JR |
77 | |
78 | if (lttng_opt_mi) { | |
28ab034a | 79 | mi_writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); |
523c4f8c JR |
80 | if (!mi_writer) { |
81 | ret = CMD_ERROR; | |
82 | goto error; | |
83 | } | |
84 | ||
85 | /* Open command element. */ | |
86 | ret = mi_lttng_writer_command_open(mi_writer, | |
28ab034a | 87 | mi_lttng_element_command_remove_trigger); |
523c4f8c JR |
88 | if (ret) { |
89 | ret = CMD_ERROR; | |
90 | goto error; | |
91 | } | |
92 | ||
93 | /* Open output element. */ | |
28ab034a | 94 | ret = mi_lttng_writer_open_element(mi_writer, mi_lttng_element_command_output); |
523c4f8c JR |
95 | if (ret) { |
96 | ret = CMD_ERROR; | |
97 | goto error; | |
98 | } | |
99 | } | |
b61776fb | 100 | |
5ba02fff | 101 | args = argv + 1; |
d50d200a | 102 | |
5ba02fff | 103 | argpar_iter = argpar_iter_create(argc - 1, args, remove_trigger_options); |
d50d200a SM |
104 | if (!argpar_iter) { |
105 | ERR("Failed to allocate an argpar iter."); | |
b61776fb SM |
106 | goto error; |
107 | } | |
108 | ||
d50d200a SM |
109 | while (true) { |
110 | enum parse_next_item_status status; | |
111 | ||
cd9adb8b | 112 | status = |
5ba02fff | 113 | parse_next_item(argpar_iter, &argpar_item, 1, args, true, nullptr, nullptr); |
ef9ff9cb | 114 | if (status == PARSE_NEXT_ITEM_STATUS_ERROR || |
28ab034a | 115 | status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) { |
d50d200a SM |
116 | goto error; |
117 | } else if (status == PARSE_NEXT_ITEM_STATUS_END) { | |
118 | break; | |
119 | } | |
120 | ||
121 | assert(status == PARSE_NEXT_ITEM_STATUS_OK); | |
b61776fb | 122 | |
d50d200a | 123 | if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { |
28ab034a | 124 | const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item); |
d50d200a | 125 | const char *arg = argpar_item_opt_arg(argpar_item); |
b61776fb | 126 | |
d50d200a | 127 | switch (descr->id) { |
b61776fb SM |
128 | case OPT_HELP: |
129 | SHOW_HELP(); | |
130 | ret = 0; | |
131 | goto end; | |
132 | case OPT_LIST_OPTIONS: | |
28ab034a | 133 | list_cmd_options_argpar(stdout, remove_trigger_options); |
b61776fb SM |
134 | ret = 0; |
135 | goto end; | |
481c5310 | 136 | case OPT_OWNER_UID: |
b61776fb | 137 | { |
28ab034a | 138 | if (!assign_string(&owner_uid, arg, "--owner-uid")) { |
b61776fb SM |
139 | goto error; |
140 | } | |
141 | break; | |
142 | } | |
143 | default: | |
144 | abort(); | |
145 | } | |
146 | } else { | |
d50d200a | 147 | const char *arg = argpar_item_non_opt_arg(argpar_item); |
b61776fb | 148 | |
e80b7150 | 149 | if (name) { |
d50d200a | 150 | ERR("Unexpected argument '%s'", arg); |
b61776fb SM |
151 | goto error; |
152 | } | |
153 | ||
d50d200a | 154 | name = arg; |
b61776fb SM |
155 | } |
156 | } | |
157 | ||
e80b7150 SM |
158 | if (!name) { |
159 | ERR("Missing `name` argument."); | |
b61776fb SM |
160 | goto error; |
161 | } | |
162 | ||
481c5310 | 163 | if (owner_uid) { |
b61776fb SM |
164 | char *end; |
165 | ||
166 | errno = 0; | |
481c5310 SM |
167 | uid = strtol(owner_uid, &end, 10); |
168 | if (end == owner_uid || *end != '\0' || errno != 0) { | |
169 | ERR("Failed to parse `%s` as an integer.", owner_uid); | |
b61776fb SM |
170 | } |
171 | } else { | |
172 | uid = geteuid(); | |
173 | } | |
174 | ||
175 | ret = lttng_list_triggers(&triggers); | |
176 | if (ret != LTTNG_OK) { | |
177 | ERR("Failed to get the list of triggers."); | |
178 | goto error; | |
179 | } | |
180 | ||
181 | trigger_status = lttng_triggers_get_count(triggers, &triggers_count); | |
a0377dfe | 182 | LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); |
b61776fb SM |
183 | |
184 | for (i = 0; i < triggers_count; i++) { | |
185 | const struct lttng_trigger *trigger; | |
186 | const char *trigger_name; | |
187 | uid_t trigger_uid; | |
188 | ||
189 | trigger = lttng_triggers_get_at_index(triggers, i); | |
190 | trigger_status = lttng_trigger_get_name(trigger, &trigger_name); | |
0efb2ad7 JG |
191 | switch (trigger_status) { |
192 | case LTTNG_TRIGGER_STATUS_OK: | |
193 | break; | |
194 | case LTTNG_TRIGGER_STATUS_UNSET: | |
195 | /* Don't compare against anonymous triggers. */ | |
196 | continue; | |
197 | default: | |
198 | abort(); | |
199 | } | |
b61776fb | 200 | |
28ab034a | 201 | trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid); |
a0377dfe | 202 | LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); |
b61776fb | 203 | |
e80b7150 | 204 | if (trigger_uid == uid && strcmp(trigger_name, name) == 0) { |
b61776fb SM |
205 | trigger_to_remove = trigger; |
206 | break; | |
207 | } | |
208 | } | |
209 | ||
210 | if (!trigger_to_remove) { | |
e80b7150 | 211 | ERR("Couldn't find trigger with name `%s`.", name); |
b61776fb SM |
212 | goto error; |
213 | } | |
214 | ||
215 | ret = lttng_unregister_trigger(trigger_to_remove); | |
216 | if (ret != 0) { | |
e80b7150 | 217 | ERR("Failed to unregister trigger `%s`.", name); |
b61776fb SM |
218 | goto error; |
219 | } | |
220 | ||
523c4f8c | 221 | if (lttng_opt_mi) { |
cd9adb8b | 222 | ret_code = lttng_trigger_mi_serialize(trigger_to_remove, mi_writer, nullptr); |
523c4f8c JR |
223 | if (ret_code != LTTNG_OK) { |
224 | goto error; | |
225 | } | |
226 | } | |
e80b7150 | 227 | MSG("Removed trigger `%s`.", name); |
b61776fb SM |
228 | |
229 | ret = 0; | |
230 | goto end; | |
231 | ||
232 | error: | |
233 | ret = 1; | |
234 | ||
235 | end: | |
523c4f8c | 236 | /* Mi closing. */ |
fc63f82b | 237 | if (lttng_opt_mi && mi_writer) { |
523c4f8c JR |
238 | /* Close output element. */ |
239 | int mi_ret = mi_lttng_writer_close_element(mi_writer); | |
240 | if (mi_ret) { | |
241 | ret = 1; | |
242 | goto cleanup; | |
243 | } | |
244 | ||
28ab034a JG |
245 | mi_ret = mi_lttng_writer_write_element_bool( |
246 | mi_writer, mi_lttng_element_command_success, ret ? 0 : 1); | |
523c4f8c JR |
247 | if (mi_ret) { |
248 | ret = 1; | |
249 | goto cleanup; | |
250 | } | |
251 | ||
252 | /* Command element close. */ | |
253 | mi_ret = mi_lttng_writer_command_close(mi_writer); | |
254 | if (mi_ret) { | |
255 | ret = 1; | |
256 | goto cleanup; | |
257 | } | |
258 | } | |
259 | ||
260 | cleanup: | |
d50d200a SM |
261 | argpar_item_destroy(argpar_item); |
262 | argpar_iter_destroy(argpar_iter); | |
b61776fb | 263 | lttng_triggers_destroy(triggers); |
481c5310 | 264 | free(owner_uid); |
b61776fb | 265 | |
523c4f8c JR |
266 | if (mi_writer && mi_lttng_writer_destroy(mi_writer)) { |
267 | /* Preserve original error code. */ | |
268 | ret = ret ? ret : CMD_ERROR; | |
269 | } | |
b61776fb SM |
270 | return ret; |
271 | } |