Fix: statements with side-effects in assert statements
[lttng-tools.git] / src / bin / lttng / commands / remove_trigger.c
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"
10 #include "common/mi-lttng.h"
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,
23 OPT_OWNER_UID,
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 },
30 { OPT_OWNER_UID, '\0', "owner-uid", true },
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 {
62 enum lttng_error_code ret_code;
63 int ret;
64 struct argpar_parse_ret argpar_parse_ret = {};
65 const char *name = NULL;
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;
71 char *owner_uid = NULL;
72 long long uid;
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 }
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;
125 case OPT_OWNER_UID:
126 {
127 if (!assign_string(&owner_uid, item_opt->arg,
128 "--owner-uid")) {
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
140 if (name) {
141 ERR("Unexpected argument '%s'", item_non_opt->arg);
142 goto error;
143 }
144
145 name = item_non_opt->arg;
146 }
147 }
148
149 if (!name) {
150 ERR("Missing `name` argument.");
151 goto error;
152 }
153
154 if (owner_uid) {
155 char *end;
156
157 errno = 0;
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);
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);
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 }
191
192 trigger_status = lttng_trigger_get_owner_uid(
193 trigger, &trigger_uid);
194 assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
195
196 if (trigger_uid == uid && strcmp(trigger_name, name) == 0) {
197 trigger_to_remove = trigger;
198 break;
199 }
200 }
201
202 if (!trigger_to_remove) {
203 ERR("Couldn't find trigger with name `%s`.", name);
204 goto error;
205 }
206
207 ret = lttng_unregister_trigger(trigger_to_remove);
208 if (ret != 0) {
209 ERR("Failed to unregister trigger `%s`.", name);
210 goto error;
211 }
212
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 }
220 MSG("Removed trigger `%s`.", name);
221
222 ret = 0;
223 goto end;
224
225 error:
226 ret = 1;
227
228 end:
229 /* Mi closing. */
230 if (lttng_opt_mi && mi_writer) {
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:
254 argpar_parse_ret_fini(&argpar_parse_ret);
255 lttng_triggers_destroy(triggers);
256 free(owner_uid);
257
258 if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
259 /* Preserve original error code. */
260 ret = ret ? ret : CMD_ERROR;
261 }
262 return ret;
263 }
This page took 0.035955 seconds and 5 git commands to generate.