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