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