Commit | Line | Data |
---|---|---|
ccf10263 MD |
1 | /* |
2 | * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca> | |
3 | * Copyright (C) 2015 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License, version 2 only, | |
7 | * as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along | |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
17 | */ | |
18 | ||
ccf10263 MD |
19 | #define _LGPL_SOURCE |
20 | #include <ctype.h> | |
21 | #include <popt.h> | |
adce7589 | 22 | #include <stdbool.h> |
ccf10263 MD |
23 | #include <stdio.h> |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <sys/stat.h> | |
27 | #include <sys/types.h> | |
28 | #include <unistd.h> | |
3ecec76a | 29 | #include <assert.h> |
ccf10263 MD |
30 | |
31 | #include <urcu/list.h> | |
32 | ||
33 | #include <common/mi-lttng.h> | |
34 | ||
35 | #include "../command.h" | |
36 | ||
37 | enum cmd_type { | |
38 | CMD_TRACK, | |
39 | CMD_UNTRACK, | |
40 | }; | |
41 | ||
83d6d6c4 JR |
42 | enum tracker_type_state { |
43 | STATE_NONE = 0, | |
44 | STATE_PID, | |
45 | STATE_VPID, | |
46 | STATE_UID, | |
47 | STATE_VUID, | |
48 | STATE_GID, | |
49 | STATE_VGID, | |
50 | }; | |
51 | ||
52 | struct opt_type { | |
53 | int used; | |
54 | int all; | |
55 | char *string; | |
56 | }; | |
57 | ||
58 | struct id_list { | |
59 | size_t nr; | |
2d97a006 | 60 | struct lttng_tracker_id **array; |
83d6d6c4 JR |
61 | }; |
62 | ||
ccf10263 MD |
63 | static char *opt_session_name; |
64 | static int opt_kernel; | |
65 | static int opt_userspace; | |
83d6d6c4 JR |
66 | |
67 | static struct opt_type opt_pid, opt_vpid, opt_uid, opt_vuid, opt_gid, opt_vgid; | |
68 | ||
69 | static enum tracker_type_state type_state; | |
ccf10263 MD |
70 | |
71 | enum { | |
72 | OPT_HELP = 1, | |
73 | OPT_LIST_OPTIONS, | |
74 | OPT_SESSION, | |
75 | OPT_PID, | |
83d6d6c4 JR |
76 | OPT_VPID, |
77 | OPT_UID, | |
78 | OPT_VUID, | |
79 | OPT_GID, | |
80 | OPT_VGID, | |
81 | OPT_ALL, | |
ccf10263 MD |
82 | }; |
83 | ||
84 | static struct poptOption long_options[] = { | |
85 | /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */ | |
86 | { "help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, }, | |
87 | { "session", 's', POPT_ARG_STRING, &opt_session_name, OPT_SESSION, 0, 0, }, | |
88 | { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0, }, | |
89 | { "userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0, }, | |
83d6d6c4 JR |
90 | { "pid", 'p', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_pid.string, OPT_PID, 0, 0, }, |
91 | { "vpid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vpid.string, OPT_VPID, 0, 0, }, | |
92 | { "uid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_uid.string, OPT_UID, 0, 0, }, | |
93 | { "vuid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vuid.string, OPT_VUID, 0, 0, }, | |
94 | { "gid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_gid.string, OPT_GID, 0, 0, }, | |
95 | { "vgid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vgid.string, OPT_VGID, 0, 0, }, | |
96 | { "all", 'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0, }, | |
ccf10263 MD |
97 | { "list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, }, |
98 | { 0, 0, 0, 0, 0, 0, 0, }, | |
99 | }; | |
100 | ||
83d6d6c4 | 101 | static struct id_list *alloc_id_list(size_t nr_items) |
ccf10263 | 102 | { |
83d6d6c4 | 103 | struct id_list *id_list; |
2d97a006 | 104 | struct lttng_tracker_id **items; |
83d6d6c4 JR |
105 | |
106 | id_list = zmalloc(sizeof(*id_list)); | |
107 | if (!id_list) { | |
108 | goto error; | |
109 | } | |
110 | items = zmalloc(nr_items * sizeof(*items)); | |
111 | if (!items) { | |
112 | goto error; | |
113 | } | |
114 | id_list->nr = nr_items; | |
115 | id_list->array = items; | |
116 | return id_list; | |
117 | error: | |
118 | free(id_list); | |
119 | return NULL; | |
120 | } | |
121 | ||
122 | static void free_id_list(struct id_list *list) | |
123 | { | |
124 | size_t nr_items; | |
125 | int i; | |
126 | ||
127 | if (!list) { | |
128 | return; | |
129 | } | |
130 | nr_items = list->nr; | |
131 | for (i = 0; i < nr_items; i++) { | |
2d97a006 JR |
132 | struct lttng_tracker_id *item = list->array[i]; |
133 | lttng_tracker_id_destroy(item); | |
83d6d6c4 JR |
134 | } |
135 | free(list); | |
136 | } | |
137 | ||
2d97a006 JR |
138 | static int parse_id_string(const char *_id_string, |
139 | int all, | |
140 | struct id_list **_id_list, | |
141 | enum lttng_tracker_type tracker_type) | |
83d6d6c4 JR |
142 | { |
143 | const char *one_id_str; | |
ccf10263 MD |
144 | char *iter; |
145 | int retval = CMD_SUCCESS; | |
146 | int count = 0; | |
83d6d6c4 JR |
147 | struct id_list *id_list = NULL; |
148 | char *id_string = NULL; | |
44c1a903 | 149 | char *endptr; |
ccf10263 | 150 | |
83d6d6c4 JR |
151 | if (all && _id_string) { |
152 | ERR("An empty ID string is expected with --all"); | |
ccf10263 MD |
153 | retval = CMD_ERROR; |
154 | goto error; | |
155 | } | |
83d6d6c4 JR |
156 | if (!all && !_id_string) { |
157 | ERR("An ID string is expected"); | |
ccf10263 MD |
158 | retval = CMD_ERROR; |
159 | goto error; | |
160 | } | |
161 | if (all) { | |
2d97a006 JR |
162 | enum lttng_tracker_id_status status; |
163 | /* Empty `ID string means all IDs */ | |
83d6d6c4 JR |
164 | id_list = alloc_id_list(1); |
165 | if (!id_list) { | |
ccf10263 MD |
166 | ERR("Out of memory"); |
167 | retval = CMD_ERROR; | |
168 | goto error; | |
169 | } | |
2d97a006 JR |
170 | |
171 | id_list->array[0] = lttng_tracker_id_create(); | |
172 | if (id_list->array[0] == NULL) { | |
173 | ERR("Out of memory"); | |
174 | retval = CMD_ERROR; | |
175 | goto error; | |
176 | } | |
177 | ||
178 | status = lttng_tracker_id_set_all(id_list->array[0]); | |
179 | if (status != LTTNG_TRACKER_ID_STATUS_OK) { | |
180 | ERR("Invalid value for tracker id"); | |
181 | retval = CMD_ERROR; | |
182 | goto error; | |
183 | } | |
ccf10263 MD |
184 | goto assign; |
185 | } | |
186 | ||
83d6d6c4 JR |
187 | id_string = strdup(_id_string); |
188 | if (!id_string) { | |
ccf10263 MD |
189 | ERR("Out of memory"); |
190 | retval = CMD_ERROR; | |
191 | goto error; | |
192 | } | |
193 | ||
194 | /* Count */ | |
83d6d6c4 JR |
195 | one_id_str = strtok_r(id_string, ",", &iter); |
196 | while (one_id_str != NULL) { | |
ccf10263 MD |
197 | unsigned long v; |
198 | ||
83d6d6c4 JR |
199 | if (isdigit(one_id_str[0])) { |
200 | errno = 0; | |
201 | v = strtoul(one_id_str, &endptr, 10); | |
202 | if ((v == 0 && errno == EINVAL) || | |
203 | (v == ULONG_MAX && errno == ERANGE) || | |
204 | (*one_id_str != '\0' && | |
205 | *endptr != '\0')) { | |
206 | ERR("Error parsing ID %s", one_id_str); | |
207 | retval = CMD_ERROR; | |
208 | goto error; | |
209 | } | |
44c1a903 | 210 | |
83d6d6c4 JR |
211 | if ((long) v > INT_MAX || (int) v < 0) { |
212 | ERR("Invalid ID value %ld", (long) v); | |
213 | retval = CMD_ERROR; | |
214 | goto error; | |
215 | } | |
ccf10263 MD |
216 | } |
217 | count++; | |
218 | ||
219 | /* For next loop */ | |
83d6d6c4 | 220 | one_id_str = strtok_r(NULL, ",", &iter); |
ccf10263 | 221 | } |
dc1c9a44 JG |
222 | if (count == 0) { |
223 | ERR("Fatal error occurred when parsing pid string"); | |
224 | retval = CMD_ERROR; | |
225 | goto error; | |
226 | } | |
ccf10263 | 227 | |
83d6d6c4 | 228 | free(id_string); |
ccf10263 | 229 | /* Identity of delimiter has been lost in first pass. */ |
83d6d6c4 JR |
230 | id_string = strdup(_id_string); |
231 | if (!id_string) { | |
ccf10263 MD |
232 | ERR("Out of memory"); |
233 | retval = CMD_ERROR; | |
234 | goto error; | |
235 | } | |
236 | ||
237 | /* Allocate */ | |
83d6d6c4 JR |
238 | id_list = alloc_id_list(count); |
239 | if (!id_list) { | |
ccf10263 MD |
240 | ERR("Out of memory"); |
241 | retval = CMD_ERROR; | |
242 | goto error; | |
243 | } | |
244 | ||
83d6d6c4 | 245 | /* Reparse string and populate the id list. */ |
ccf10263 | 246 | count = 0; |
83d6d6c4 JR |
247 | one_id_str = strtok_r(id_string, ",", &iter); |
248 | while (one_id_str != NULL) { | |
2d97a006 | 249 | enum lttng_tracker_id_status status; |
83d6d6c4 | 250 | struct lttng_tracker_id *item; |
2d97a006 JR |
251 | item = lttng_tracker_id_create(); |
252 | if (item == NULL) { | |
253 | ERR("Out of memory"); | |
254 | retval = CMD_ERROR; | |
255 | goto error; | |
256 | } | |
ccf10263 | 257 | |
2d97a006 | 258 | id_list->array[count++] = item; |
83d6d6c4 JR |
259 | if (isdigit(one_id_str[0])) { |
260 | unsigned long v; | |
261 | ||
262 | v = strtoul(one_id_str, NULL, 10); | |
2d97a006 JR |
263 | status = lttng_tracker_id_set_value(item, (int) v); |
264 | if (status == LTTNG_TRACKER_ID_STATUS_INVALID) { | |
265 | ERR("Invalid value"); | |
266 | retval = CMD_ERROR; | |
267 | goto error; | |
268 | } | |
83d6d6c4 | 269 | } else { |
2d97a006 JR |
270 | status = lttng_tracker_id_set_string(item, one_id_str); |
271 | if (status == LTTNG_TRACKER_ID_STATUS_INVALID) { | |
272 | ERR("Failed to set ID string"); | |
83d6d6c4 JR |
273 | retval = CMD_ERROR; |
274 | goto error; | |
275 | } | |
276 | } | |
ccf10263 MD |
277 | |
278 | /* For next loop */ | |
83d6d6c4 | 279 | one_id_str = strtok_r(NULL, ",", &iter); |
ccf10263 MD |
280 | } |
281 | ||
282 | assign: | |
2d97a006 | 283 | /* SUCCESS */ |
83d6d6c4 | 284 | *_id_list = id_list; |
2d97a006 | 285 | goto end; |
ccf10263 | 286 | |
ccf10263 | 287 | error: |
2d97a006 | 288 | /* ERROR */ |
83d6d6c4 | 289 | free_id_list(id_list); |
ccf10263 | 290 | end: |
83d6d6c4 | 291 | free(id_string); |
ccf10263 MD |
292 | return retval; |
293 | } | |
294 | ||
83d6d6c4 JR |
295 | static const char *get_tracker_str(enum lttng_tracker_type tracker_type) |
296 | { | |
297 | switch (tracker_type) { | |
298 | case LTTNG_TRACKER_PID: | |
299 | return "PID"; | |
300 | case LTTNG_TRACKER_VPID: | |
301 | return "VPID"; | |
302 | case LTTNG_TRACKER_UID: | |
303 | return "UID"; | |
304 | case LTTNG_TRACKER_VUID: | |
305 | return "VUID"; | |
306 | case LTTNG_TRACKER_GID: | |
307 | return "GID"; | |
308 | case LTTNG_TRACKER_VGID: | |
309 | return "VGID"; | |
310 | default: | |
311 | return NULL; | |
312 | } | |
313 | return NULL; | |
314 | } | |
315 | ||
ef440343 JR |
316 | static int ust_tracker_type_support(enum lttng_tracker_type *tracker_type) |
317 | { | |
318 | int ret; | |
319 | ||
320 | switch (*tracker_type) { | |
321 | case LTTNG_TRACKER_PID: | |
322 | *tracker_type = LTTNG_TRACKER_VPID; | |
323 | ret = 0; | |
324 | break; | |
325 | case LTTNG_TRACKER_VPID: | |
326 | case LTTNG_TRACKER_VUID: | |
327 | case LTTNG_TRACKER_VGID: | |
328 | ret = 0; | |
329 | break; | |
330 | case LTTNG_TRACKER_UID: | |
331 | case LTTNG_TRACKER_GID: | |
332 | ERR("The %s tracker is invalid for UST domain.", | |
333 | get_tracker_str(*tracker_type)); | |
334 | ret = -1; | |
335 | break; | |
336 | default: | |
337 | ret = -1; | |
338 | break; | |
339 | } | |
340 | ||
341 | return ret; | |
342 | } | |
343 | ||
83d6d6c4 JR |
344 | static enum cmd_error_code track_untrack_id(enum cmd_type cmd_type, |
345 | const char *cmd_str, | |
346 | const char *session_name, | |
347 | const char *id_string, | |
348 | int all, | |
349 | struct mi_writer *writer, | |
350 | enum lttng_tracker_type tracker_type) | |
ccf10263 | 351 | { |
c51da673 JG |
352 | int ret, success = 1 , i; |
353 | enum cmd_error_code retval = CMD_SUCCESS; | |
83d6d6c4 | 354 | struct id_list *id_list = NULL; |
ccf10263 MD |
355 | struct lttng_domain dom; |
356 | struct lttng_handle *handle = NULL; | |
83d6d6c4 JR |
357 | int (*cmd_func)(struct lttng_handle *handle, |
358 | enum lttng_tracker_type tracker_type, | |
359 | const struct lttng_tracker_id *id); | |
360 | const char *tracker_str; | |
ccf10263 MD |
361 | |
362 | switch (cmd_type) { | |
363 | case CMD_TRACK: | |
83d6d6c4 | 364 | cmd_func = lttng_track_id; |
ccf10263 MD |
365 | break; |
366 | case CMD_UNTRACK: | |
83d6d6c4 | 367 | cmd_func = lttng_untrack_id; |
ccf10263 MD |
368 | break; |
369 | default: | |
370 | ERR("Unknown command"); | |
371 | retval = CMD_ERROR; | |
372 | goto end; | |
373 | } | |
ccf10263 MD |
374 | memset(&dom, 0, sizeof(dom)); |
375 | if (opt_kernel) { | |
376 | dom.type = LTTNG_DOMAIN_KERNEL; | |
377 | } else if (opt_userspace) { | |
378 | dom.type = LTTNG_DOMAIN_UST; | |
ef440343 JR |
379 | ret = ust_tracker_type_support(&tracker_type); |
380 | if (ret) { | |
381 | ERR("Invalid parameter"); | |
382 | retval = CMD_ERROR; | |
383 | goto end; | |
83d6d6c4 | 384 | } |
ccf10263 | 385 | } else { |
3ecec76a PP |
386 | /* Checked by the caller. */ |
387 | assert(0); | |
ccf10263 | 388 | } |
83d6d6c4 JR |
389 | tracker_str = get_tracker_str(tracker_type); |
390 | if (!tracker_str) { | |
391 | ERR("Unknown tracker type"); | |
392 | retval = CMD_ERROR; | |
393 | goto end; | |
394 | } | |
2d97a006 | 395 | ret = parse_id_string(id_string, all, &id_list, tracker_type); |
ccf10263 | 396 | if (ret != CMD_SUCCESS) { |
83d6d6c4 | 397 | ERR("Error parsing %s string", tracker_str); |
ccf10263 MD |
398 | retval = CMD_ERROR; |
399 | goto end; | |
400 | } | |
401 | ||
402 | handle = lttng_create_handle(session_name, &dom); | |
403 | if (handle == NULL) { | |
404 | retval = CMD_ERROR; | |
405 | goto end; | |
406 | } | |
407 | ||
408 | if (writer) { | |
83d6d6c4 JR |
409 | /* Open tracker_id and targets elements */ |
410 | ret = mi_lttng_id_tracker_open(writer, tracker_type); | |
ccf10263 | 411 | if (ret) { |
ccf10263 MD |
412 | goto end; |
413 | } | |
414 | } | |
415 | ||
83d6d6c4 | 416 | for (i = 0; i < id_list->nr; i++) { |
2d97a006 JR |
417 | struct lttng_tracker_id *item = id_list->array[i]; |
418 | enum lttng_tracker_id_type type = | |
419 | lttng_tracker_id_get_type(item); | |
420 | enum lttng_tracker_id_status status = | |
421 | LTTNG_TRACKER_ID_STATUS_OK; | |
422 | int value; | |
423 | const char *value_string; | |
424 | ||
425 | switch (type) { | |
426 | case LTTNG_ID_ALL: | |
427 | /* Nothing to check */ | |
428 | break; | |
429 | case LTTNG_ID_VALUE: | |
430 | status = lttng_tracker_id_get_value(item, &value); | |
431 | break; | |
432 | case LTTNG_ID_STRING: | |
433 | status = lttng_tracker_id_get_string( | |
434 | item, &value_string); | |
435 | break; | |
436 | default: | |
437 | retval = CMD_ERROR; | |
438 | goto end; | |
439 | } | |
83d6d6c4 | 440 | |
2d97a006 JR |
441 | if (status != LTTNG_TRACKER_ID_STATUS_OK) { |
442 | ERR("Tracker id object is in an invalid state"); | |
443 | retval = CMD_ERROR; | |
444 | goto end; | |
445 | } | |
446 | ||
447 | switch (type) { | |
83d6d6c4 JR |
448 | case LTTNG_ID_ALL: |
449 | DBG("%s all IDs", cmd_str); | |
450 | break; | |
451 | case LTTNG_ID_VALUE: | |
2d97a006 | 452 | DBG("%s ID %d", cmd_str, value); |
83d6d6c4 JR |
453 | break; |
454 | case LTTNG_ID_STRING: | |
2d97a006 | 455 | DBG("%s ID '%s'", cmd_str, value_string); |
83d6d6c4 JR |
456 | break; |
457 | default: | |
458 | retval = CMD_ERROR; | |
459 | goto end; | |
460 | } | |
2d97a006 | 461 | |
83d6d6c4 | 462 | ret = cmd_func(handle, tracker_type, item); |
ccf10263 | 463 | if (ret) { |
83d6d6c4 JR |
464 | char *msg = NULL; |
465 | ||
b93a4a13 | 466 | switch (-ret) { |
83d6d6c4 JR |
467 | case LTTNG_ERR_ID_TRACKED: |
468 | msg = "already tracked"; | |
b93a4a13 MJ |
469 | success = 1; |
470 | retval = CMD_SUCCESS; | |
471 | break; | |
83d6d6c4 JR |
472 | case LTTNG_ERR_ID_NOT_TRACKED: |
473 | msg = "already not tracked"; | |
b93a4a13 MJ |
474 | success = 1; |
475 | retval = CMD_SUCCESS; | |
476 | break; | |
477 | default: | |
478 | ERR("%s", lttng_strerror(ret)); | |
479 | success = 0; | |
480 | retval = CMD_ERROR; | |
481 | break; | |
482 | } | |
83d6d6c4 | 483 | if (msg) { |
2d97a006 | 484 | switch (type) { |
83d6d6c4 JR |
485 | case LTTNG_ID_ALL: |
486 | WARN("All %ss %s in session %s", | |
487 | tracker_str, msg, | |
488 | session_name); | |
489 | break; | |
490 | case LTTNG_ID_VALUE: | |
491 | WARN("%s %i %s in session %s", | |
2d97a006 | 492 | tracker_str, value, msg, |
83d6d6c4 JR |
493 | session_name); |
494 | break; | |
495 | case LTTNG_ID_STRING: | |
496 | WARN("%s '%s' %s in session %s", | |
497 | tracker_str, | |
2d97a006 | 498 | value_string, msg, |
83d6d6c4 JR |
499 | session_name); |
500 | break; | |
501 | default: | |
502 | retval = CMD_ERROR; | |
503 | goto end; | |
504 | } | |
505 | } | |
ebbf5ab7 | 506 | } else { |
2d97a006 | 507 | switch (type) { |
83d6d6c4 JR |
508 | case LTTNG_ID_ALL: |
509 | MSG("All %ss %sed in session %s", tracker_str, | |
efcbc78c | 510 | cmd_str, session_name); |
83d6d6c4 JR |
511 | break; |
512 | case LTTNG_ID_VALUE: | |
513 | MSG("%s %i %sed in session %s", tracker_str, | |
2d97a006 | 514 | value, cmd_str, session_name); |
83d6d6c4 JR |
515 | break; |
516 | case LTTNG_ID_STRING: | |
517 | MSG("%s '%s' %sed in session %s", tracker_str, | |
2d97a006 | 518 | value_string, cmd_str, |
83d6d6c4 JR |
519 | session_name); |
520 | break; | |
521 | default: | |
522 | retval = CMD_ERROR; | |
523 | goto end; | |
efcbc78c | 524 | } |
ebbf5ab7 JR |
525 | success = 1; |
526 | } | |
527 | ||
528 | /* Mi */ | |
529 | if (writer) { | |
83d6d6c4 | 530 | ret = mi_lttng_id_target(writer, tracker_type, item, 1); |
ebbf5ab7 JR |
531 | if (ret) { |
532 | retval = CMD_ERROR; | |
533 | goto end; | |
534 | } | |
535 | ||
536 | ret = mi_lttng_writer_write_element_bool(writer, | |
537 | mi_lttng_element_success, success); | |
538 | if (ret) { | |
539 | retval = CMD_ERROR; | |
540 | goto end; | |
541 | } | |
542 | ||
543 | ret = mi_lttng_writer_close_element(writer); | |
544 | if (ret) { | |
545 | retval = CMD_ERROR; | |
546 | goto end; | |
547 | } | |
ccf10263 MD |
548 | } |
549 | } | |
550 | ||
551 | if (writer) { | |
83d6d6c4 JR |
552 | /* Close targets and tracker_id elements */ |
553 | ret = mi_lttng_close_multi_element(writer, 2); | |
ccf10263 MD |
554 | if (ret) { |
555 | retval = CMD_ERROR; | |
556 | goto end; | |
557 | } | |
558 | } | |
559 | ||
ccf10263 MD |
560 | end: |
561 | if (handle) { | |
562 | lttng_destroy_handle(handle); | |
563 | } | |
83d6d6c4 | 564 | free_id_list(id_list); |
ccf10263 MD |
565 | return retval; |
566 | } | |
567 | ||
568 | static | |
569 | const char *get_mi_element_command(enum cmd_type cmd_type) | |
570 | { | |
571 | switch (cmd_type) { | |
572 | case CMD_TRACK: | |
573 | return mi_lttng_element_command_track; | |
574 | case CMD_UNTRACK: | |
575 | return mi_lttng_element_command_untrack; | |
576 | default: | |
577 | return NULL; | |
578 | } | |
579 | } | |
580 | ||
83d6d6c4 JR |
581 | static void print_err_duplicate(const char *type) |
582 | { | |
583 | ERR("The --%s option can only be used once. A list of comma-separated values can be specified.", | |
584 | type); | |
585 | } | |
586 | ||
ccf10263 MD |
587 | /* |
588 | * Add/remove tracker to/from session. | |
589 | */ | |
590 | static | |
591 | int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, | |
4fc83d94 | 592 | int argc, const char **argv, const char *help_msg) |
ccf10263 | 593 | { |
72aee8ec | 594 | int opt, ret = 0, success = 1; |
adce7589 | 595 | bool opt_all_present = false; |
c51da673 | 596 | enum cmd_error_code command_ret = CMD_SUCCESS; |
ccf10263 MD |
597 | static poptContext pc; |
598 | char *session_name = NULL; | |
c47a705b | 599 | const char *leftover = NULL; |
ccf10263 MD |
600 | struct mi_writer *writer = NULL; |
601 | ||
602 | if (argc < 1) { | |
c51da673 | 603 | command_ret = CMD_ERROR; |
ccf10263 MD |
604 | goto end; |
605 | } | |
606 | ||
607 | pc = poptGetContext(NULL, argc, argv, long_options, 0); | |
608 | poptReadDefaultConfig(pc, 0); | |
609 | ||
610 | while ((opt = poptGetNextOpt(pc)) != -1) { | |
611 | switch (opt) { | |
612 | case OPT_HELP: | |
4ba92f18 | 613 | SHOW_HELP(); |
ccf10263 MD |
614 | goto end; |
615 | case OPT_LIST_OPTIONS: | |
616 | list_cmd_options(stdout, long_options); | |
617 | goto end; | |
618 | case OPT_SESSION: | |
83d6d6c4 | 619 | break; |
ccf10263 | 620 | case OPT_PID: |
83d6d6c4 JR |
621 | if (opt_pid.used) { |
622 | print_err_duplicate("pid"); | |
623 | command_ret = CMD_ERROR; | |
624 | goto end; | |
625 | } | |
626 | opt_pid.used = 1; | |
627 | type_state = STATE_PID; | |
628 | break; | |
629 | case OPT_VPID: | |
630 | if (opt_vpid.used) { | |
631 | print_err_duplicate("vpid"); | |
632 | command_ret = CMD_ERROR; | |
633 | goto end; | |
634 | } | |
635 | opt_vpid.used = 1; | |
636 | type_state = STATE_VPID; | |
637 | break; | |
638 | case OPT_UID: | |
639 | if (opt_uid.used) { | |
640 | print_err_duplicate("uid"); | |
641 | command_ret = CMD_ERROR; | |
642 | goto end; | |
643 | } | |
644 | opt_uid.used = 1; | |
645 | type_state = STATE_UID; | |
646 | break; | |
647 | case OPT_VUID: | |
648 | if (opt_vuid.used) { | |
649 | print_err_duplicate("vuid"); | |
650 | command_ret = CMD_ERROR; | |
651 | goto end; | |
652 | } | |
653 | opt_vuid.used = 1; | |
654 | type_state = STATE_VUID; | |
655 | break; | |
656 | case OPT_GID: | |
657 | if (opt_gid.used) { | |
658 | print_err_duplicate("gid"); | |
659 | command_ret = CMD_ERROR; | |
660 | goto end; | |
661 | } | |
662 | opt_gid.used = 1; | |
663 | type_state = STATE_GID; | |
664 | break; | |
665 | case OPT_VGID: | |
666 | if (opt_vgid.used) { | |
667 | print_err_duplicate("vgid"); | |
668 | command_ret = CMD_ERROR; | |
669 | goto end; | |
670 | } | |
671 | opt_vgid.used = 1; | |
672 | type_state = STATE_VGID; | |
673 | break; | |
674 | case OPT_ALL: | |
adce7589 | 675 | opt_all_present = true; |
ccf10263 MD |
676 | break; |
677 | default: | |
c51da673 | 678 | command_ret = CMD_UNDEFINED; |
ccf10263 MD |
679 | goto end; |
680 | } | |
681 | } | |
682 | ||
3ecec76a PP |
683 | ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace); |
684 | if (ret) { | |
5061fb43 | 685 | command_ret = CMD_ERROR; |
ccf10263 MD |
686 | goto end; |
687 | } | |
688 | ||
adce7589 FD |
689 | /* |
690 | * If the `--all` option is present set the appropriate tracker's `all` | |
691 | * field. | |
692 | */ | |
693 | if (opt_all_present) { | |
694 | switch (type_state) { | |
695 | case STATE_PID: | |
696 | opt_pid.all = 1; | |
697 | break; | |
698 | case STATE_VPID: | |
699 | opt_vpid.all = 1; | |
700 | break; | |
701 | case STATE_UID: | |
702 | opt_uid.all = 1; | |
703 | break; | |
704 | case STATE_VUID: | |
705 | opt_vuid.all = 1; | |
706 | break; | |
707 | case STATE_GID: | |
708 | opt_gid.all = 1; | |
709 | break; | |
710 | case STATE_VGID: | |
711 | opt_vgid.all = 1; | |
712 | break; | |
713 | default: | |
714 | command_ret = CMD_ERROR; | |
715 | goto end; | |
716 | } | |
717 | } | |
718 | ||
ccf10263 MD |
719 | if (!opt_session_name) { |
720 | session_name = get_session_name(); | |
721 | if (session_name == NULL) { | |
c51da673 | 722 | command_ret = CMD_ERROR; |
ccf10263 MD |
723 | goto end; |
724 | } | |
725 | } else { | |
726 | session_name = opt_session_name; | |
727 | } | |
728 | ||
c47a705b FD |
729 | leftover = poptGetArg(pc); |
730 | if (leftover) { | |
731 | ERR("Unknown argument: %s", leftover); | |
732 | ret = CMD_ERROR; | |
733 | goto end; | |
734 | } | |
735 | ||
ccf10263 MD |
736 | /* Mi check */ |
737 | if (lttng_opt_mi) { | |
738 | writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); | |
739 | if (!writer) { | |
c51da673 | 740 | command_ret = CMD_ERROR; |
ccf10263 MD |
741 | goto end; |
742 | } | |
743 | } | |
744 | ||
745 | if (writer) { | |
746 | /* Open command element */ | |
747 | ret = mi_lttng_writer_command_open(writer, | |
748 | get_mi_element_command(cmd_type)); | |
749 | if (ret) { | |
c51da673 | 750 | command_ret = CMD_ERROR; |
ccf10263 MD |
751 | goto end; |
752 | } | |
753 | ||
754 | /* Open output element */ | |
755 | ret = mi_lttng_writer_open_element(writer, | |
756 | mi_lttng_element_command_output); | |
757 | if (ret) { | |
c51da673 | 758 | command_ret = CMD_ERROR; |
ccf10263 MD |
759 | goto end; |
760 | } | |
83d6d6c4 JR |
761 | |
762 | ret = mi_lttng_trackers_open(writer); | |
763 | if (ret) { | |
764 | goto end; | |
765 | } | |
ccf10263 MD |
766 | } |
767 | ||
83d6d6c4 JR |
768 | if (opt_pid.used) { |
769 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
770 | opt_pid.string, opt_pid.all, writer, | |
771 | LTTNG_TRACKER_PID); | |
772 | if (command_ret != CMD_SUCCESS) { | |
773 | success = 0; | |
774 | } | |
775 | } | |
776 | if (opt_vpid.used) { | |
777 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
778 | opt_vpid.string, opt_vpid.all, writer, | |
779 | LTTNG_TRACKER_VPID); | |
780 | if (command_ret != CMD_SUCCESS) { | |
781 | success = 0; | |
782 | } | |
783 | } | |
784 | if (opt_uid.used) { | |
785 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
786 | opt_uid.string, opt_uid.all, writer, | |
787 | LTTNG_TRACKER_UID); | |
788 | if (command_ret != CMD_SUCCESS) { | |
789 | success = 0; | |
790 | } | |
791 | } | |
792 | if (opt_vuid.used) { | |
793 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
794 | opt_vuid.string, opt_vuid.all, writer, | |
795 | LTTNG_TRACKER_VUID); | |
796 | if (command_ret != CMD_SUCCESS) { | |
797 | success = 0; | |
798 | } | |
799 | } | |
800 | if (opt_gid.used) { | |
801 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
802 | opt_gid.string, opt_gid.all, writer, | |
803 | LTTNG_TRACKER_GID); | |
804 | if (command_ret != CMD_SUCCESS) { | |
805 | success = 0; | |
806 | } | |
807 | } | |
808 | if (opt_vgid.used) { | |
809 | command_ret = track_untrack_id(cmd_type, cmd_str, session_name, | |
810 | opt_vgid.string, opt_vgid.all, writer, | |
811 | LTTNG_TRACKER_VGID); | |
812 | if (command_ret != CMD_SUCCESS) { | |
813 | success = 0; | |
814 | } | |
ccf10263 MD |
815 | } |
816 | ||
817 | /* Mi closing */ | |
818 | if (writer) { | |
83d6d6c4 JR |
819 | /* Close trackers and output elements */ |
820 | ret = mi_lttng_close_multi_element(writer, 2); | |
ccf10263 | 821 | if (ret) { |
c51da673 | 822 | command_ret = CMD_ERROR; |
ccf10263 MD |
823 | goto end; |
824 | } | |
825 | ||
826 | /* Success ? */ | |
827 | ret = mi_lttng_writer_write_element_bool(writer, | |
828 | mi_lttng_element_command_success, success); | |
829 | if (ret) { | |
c51da673 | 830 | command_ret = CMD_ERROR; |
ccf10263 MD |
831 | goto end; |
832 | } | |
833 | ||
834 | /* Command element close */ | |
835 | ret = mi_lttng_writer_command_close(writer); | |
836 | if (ret) { | |
c51da673 | 837 | command_ret = CMD_ERROR; |
ccf10263 MD |
838 | goto end; |
839 | } | |
840 | } | |
841 | ||
842 | end: | |
843 | if (!opt_session_name) { | |
844 | free(session_name); | |
845 | } | |
846 | ||
847 | /* Mi clean-up */ | |
848 | if (writer && mi_lttng_writer_destroy(writer)) { | |
849 | /* Preserve original error code */ | |
c51da673 | 850 | command_ret = CMD_ERROR; |
ccf10263 MD |
851 | } |
852 | ||
ccf10263 | 853 | poptFreeContext(pc); |
c51da673 | 854 | return (int) command_ret; |
ccf10263 MD |
855 | } |
856 | ||
857 | int cmd_track(int argc, const char **argv) | |
858 | { | |
4fc83d94 PP |
859 | static const char *help_msg = |
860 | #ifdef LTTNG_EMBED_HELP | |
861 | #include <lttng-track.1.h> | |
862 | #else | |
863 | NULL | |
864 | #endif | |
865 | ; | |
866 | ||
867 | return cmd_track_untrack(CMD_TRACK, "track", argc, argv, help_msg); | |
ccf10263 MD |
868 | } |
869 | ||
870 | int cmd_untrack(int argc, const char **argv) | |
871 | { | |
4fc83d94 PP |
872 | static const char *help_msg = |
873 | #ifdef LTTNG_EMBED_HELP | |
874 | #include <lttng-untrack.1.h> | |
875 | #else | |
876 | NULL | |
877 | #endif | |
878 | ; | |
879 | ||
880 | return cmd_track_untrack(CMD_UNTRACK, "untrack", argc, argv, help_msg); | |
ccf10263 | 881 | } |