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; |
d50d200a SM |
65 | struct argpar_iter *argpar_iter = NULL; |
66 | const struct argpar_item *argpar_item = NULL; | |
e80b7150 | 67 | const char *name = NULL; |
b61776fb SM |
68 | int i; |
69 | struct lttng_triggers *triggers = NULL; | |
70 | unsigned int triggers_count; | |
71 | enum lttng_trigger_status trigger_status; | |
72 | const struct lttng_trigger *trigger_to_remove = NULL; | |
481c5310 | 73 | char *owner_uid = NULL; |
b61776fb | 74 | long long uid; |
523c4f8c JR |
75 | struct mi_writer *mi_writer = NULL; |
76 | ||
77 | if (lttng_opt_mi) { | |
28ab034a | 78 | mi_writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); |
523c4f8c JR |
79 | if (!mi_writer) { |
80 | ret = CMD_ERROR; | |
81 | goto error; | |
82 | } | |
83 | ||
84 | /* Open command element. */ | |
85 | ret = mi_lttng_writer_command_open(mi_writer, | |
28ab034a | 86 | mi_lttng_element_command_remove_trigger); |
523c4f8c JR |
87 | if (ret) { |
88 | ret = CMD_ERROR; | |
89 | goto error; | |
90 | } | |
91 | ||
92 | /* Open output element. */ | |
28ab034a | 93 | ret = mi_lttng_writer_open_element(mi_writer, mi_lttng_element_command_output); |
523c4f8c JR |
94 | if (ret) { |
95 | ret = CMD_ERROR; | |
96 | goto error; | |
97 | } | |
98 | } | |
b61776fb | 99 | |
d50d200a SM |
100 | argc--; |
101 | argv++; | |
102 | ||
103 | argpar_iter = argpar_iter_create(argc, argv, remove_trigger_options); | |
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 | ||
28ab034a | 112 | status = parse_next_item(argpar_iter, &argpar_item, 1, argv, true, NULL, NULL); |
ef9ff9cb | 113 | if (status == PARSE_NEXT_ITEM_STATUS_ERROR || |
28ab034a | 114 | status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) { |
d50d200a SM |
115 | goto error; |
116 | } else if (status == PARSE_NEXT_ITEM_STATUS_END) { | |
117 | break; | |
118 | } | |
119 | ||
120 | assert(status == PARSE_NEXT_ITEM_STATUS_OK); | |
b61776fb | 121 | |
d50d200a | 122 | if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) { |
28ab034a | 123 | const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item); |
d50d200a | 124 | const char *arg = argpar_item_opt_arg(argpar_item); |
b61776fb | 125 | |
d50d200a | 126 | switch (descr->id) { |
b61776fb SM |
127 | case OPT_HELP: |
128 | SHOW_HELP(); | |
129 | ret = 0; | |
130 | goto end; | |
131 | case OPT_LIST_OPTIONS: | |
28ab034a | 132 | list_cmd_options_argpar(stdout, remove_trigger_options); |
b61776fb SM |
133 | ret = 0; |
134 | goto end; | |
481c5310 | 135 | case OPT_OWNER_UID: |
b61776fb | 136 | { |
28ab034a | 137 | if (!assign_string(&owner_uid, arg, "--owner-uid")) { |
b61776fb SM |
138 | goto error; |
139 | } | |
140 | break; | |
141 | } | |
142 | default: | |
143 | abort(); | |
144 | } | |
145 | } else { | |
d50d200a | 146 | const char *arg = argpar_item_non_opt_arg(argpar_item); |
b61776fb | 147 | |
e80b7150 | 148 | if (name) { |
d50d200a | 149 | ERR("Unexpected argument '%s'", arg); |
b61776fb SM |
150 | goto error; |
151 | } | |
152 | ||
d50d200a | 153 | name = arg; |
b61776fb SM |
154 | } |
155 | } | |
156 | ||
e80b7150 SM |
157 | if (!name) { |
158 | ERR("Missing `name` argument."); | |
b61776fb SM |
159 | goto error; |
160 | } | |
161 | ||
481c5310 | 162 | if (owner_uid) { |
b61776fb SM |
163 | char *end; |
164 | ||
165 | errno = 0; | |
481c5310 SM |
166 | uid = strtol(owner_uid, &end, 10); |
167 | if (end == owner_uid || *end != '\0' || errno != 0) { | |
168 | ERR("Failed to parse `%s` as an integer.", owner_uid); | |
b61776fb SM |
169 | } |
170 | } else { | |
171 | uid = geteuid(); | |
172 | } | |
173 | ||
174 | ret = lttng_list_triggers(&triggers); | |
175 | if (ret != LTTNG_OK) { | |
176 | ERR("Failed to get the list of triggers."); | |
177 | goto error; | |
178 | } | |
179 | ||
180 | trigger_status = lttng_triggers_get_count(triggers, &triggers_count); | |
a0377dfe | 181 | LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); |
b61776fb SM |
182 | |
183 | for (i = 0; i < triggers_count; i++) { | |
184 | const struct lttng_trigger *trigger; | |
185 | const char *trigger_name; | |
186 | uid_t trigger_uid; | |
187 | ||
188 | trigger = lttng_triggers_get_at_index(triggers, i); | |
189 | trigger_status = lttng_trigger_get_name(trigger, &trigger_name); | |
0efb2ad7 JG |
190 | switch (trigger_status) { |
191 | case LTTNG_TRIGGER_STATUS_OK: | |
192 | break; | |
193 | case LTTNG_TRIGGER_STATUS_UNSET: | |
194 | /* Don't compare against anonymous triggers. */ | |
195 | continue; | |
196 | default: | |
197 | abort(); | |
198 | } | |
b61776fb | 199 | |
28ab034a | 200 | trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid); |
a0377dfe | 201 | LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK); |
b61776fb | 202 | |
e80b7150 | 203 | if (trigger_uid == uid && strcmp(trigger_name, name) == 0) { |
b61776fb SM |
204 | trigger_to_remove = trigger; |
205 | break; | |
206 | } | |
207 | } | |
208 | ||
209 | if (!trigger_to_remove) { | |
e80b7150 | 210 | ERR("Couldn't find trigger with name `%s`.", name); |
b61776fb SM |
211 | goto error; |
212 | } | |
213 | ||
214 | ret = lttng_unregister_trigger(trigger_to_remove); | |
215 | if (ret != 0) { | |
e80b7150 | 216 | ERR("Failed to unregister trigger `%s`.", name); |
b61776fb SM |
217 | goto error; |
218 | } | |
219 | ||
523c4f8c | 220 | if (lttng_opt_mi) { |
28ab034a | 221 | ret_code = lttng_trigger_mi_serialize(trigger_to_remove, mi_writer, NULL); |
523c4f8c JR |
222 | if (ret_code != LTTNG_OK) { |
223 | goto error; | |
224 | } | |
225 | } | |
e80b7150 | 226 | MSG("Removed trigger `%s`.", name); |
b61776fb SM |
227 | |
228 | ret = 0; | |
229 | goto end; | |
230 | ||
231 | error: | |
232 | ret = 1; | |
233 | ||
234 | end: | |
523c4f8c | 235 | /* Mi closing. */ |
fc63f82b | 236 | if (lttng_opt_mi && mi_writer) { |
523c4f8c JR |
237 | /* Close output element. */ |
238 | int mi_ret = mi_lttng_writer_close_element(mi_writer); | |
239 | if (mi_ret) { | |
240 | ret = 1; | |
241 | goto cleanup; | |
242 | } | |
243 | ||
28ab034a JG |
244 | mi_ret = mi_lttng_writer_write_element_bool( |
245 | mi_writer, mi_lttng_element_command_success, ret ? 0 : 1); | |
523c4f8c JR |
246 | if (mi_ret) { |
247 | ret = 1; | |
248 | goto cleanup; | |
249 | } | |
250 | ||
251 | /* Command element close. */ | |
252 | mi_ret = mi_lttng_writer_command_close(mi_writer); | |
253 | if (mi_ret) { | |
254 | ret = 1; | |
255 | goto cleanup; | |
256 | } | |
257 | } | |
258 | ||
259 | cleanup: | |
d50d200a SM |
260 | argpar_item_destroy(argpar_item); |
261 | argpar_iter_destroy(argpar_iter); | |
b61776fb | 262 | lttng_triggers_destroy(triggers); |
481c5310 | 263 | free(owner_uid); |
b61776fb | 264 | |
523c4f8c JR |
265 | if (mi_writer && mi_lttng_writer_destroy(mi_writer)) { |
266 | /* Preserve original error code. */ | |
267 | ret = ret ? ret : CMD_ERROR; | |
268 | } | |
b61776fb SM |
269 | return ret; |
270 | } |