2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/types.h>
30 #include <common/utils.h>
31 #include <common/mi-lttng.h>
32 #include <lttng/snapshot.h>
34 #include "../command.h"
36 static const char *opt_session_name
;
37 static const char *opt_output_name
;
38 static const char *opt_data_url
;
39 static const char *opt_ctrl_url
;
40 static const char *current_session_name
;
41 static uint64_t opt_max_size
;
43 /* Stub for the cmd struct actions. */
44 static int cmd_add_output(int argc
, const char **argv
);
45 static int cmd_del_output(int argc
, const char **argv
);
46 static int cmd_list_output(int argc
, const char **argv
);
47 static int cmd_record(int argc
, const char **argv
);
49 static const char *indent4
= " ";
51 #ifdef LTTNG_EMBED_HELP
52 static const char help_msg
[] =
53 #include <lttng-snapshot.1.h>
64 static struct mi_writer
*writer
;
66 static struct poptOption snapshot_opts
[] = {
67 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
68 {"help", 'h', POPT_ARG_NONE
, 0, OPT_HELP
, 0, 0},
69 {"session", 's', POPT_ARG_STRING
, &opt_session_name
, 0, 0, 0},
70 {"ctrl-url", 'C', POPT_ARG_STRING
, &opt_ctrl_url
, 0, 0, 0},
71 {"data-url", 'D', POPT_ARG_STRING
, &opt_data_url
, 0, 0, 0},
72 {"name", 'n', POPT_ARG_STRING
, &opt_output_name
, 0, 0, 0},
73 {"max-size", 'm', POPT_ARG_STRING
, 0, OPT_MAX_SIZE
, 0, 0},
74 {"list-options", 0, POPT_ARG_NONE
, NULL
, OPT_LIST_OPTIONS
, NULL
, NULL
},
75 {"list-commands", 0, POPT_ARG_NONE
, NULL
, OPT_LIST_COMMANDS
},
79 static struct cmd_struct actions
[] = {
80 { "add-output", cmd_add_output
},
81 { "del-output", cmd_del_output
},
82 { "list-output", cmd_list_output
},
83 { "record", cmd_record
},
84 { NULL
, NULL
} /* Array closure */
88 * Count and return the number of arguments in argv.
90 static int count_arguments(const char **argv
)
96 while (argv
[i
] != NULL
) {
104 * Create a snapshot output object from arguments using the given URL.
106 * Return a newly allocated object or NULL on error.
108 static struct lttng_snapshot_output
*create_output_from_args(const char *url
)
111 struct lttng_snapshot_output
*output
= NULL
;
113 output
= lttng_snapshot_output_create();
119 ret
= lttng_snapshot_output_set_ctrl_url(url
, output
);
123 } else if (opt_ctrl_url
) {
124 ret
= lttng_snapshot_output_set_ctrl_url(opt_ctrl_url
, output
);
131 ret
= lttng_snapshot_output_set_data_url(opt_data_url
, output
);
138 ret
= lttng_snapshot_output_set_size(opt_max_size
, output
);
144 if (opt_output_name
) {
145 ret
= lttng_snapshot_output_set_name(opt_output_name
, output
);
154 lttng_snapshot_output_destroy(output
);
159 static int list_output(void)
161 int ret
, output_seen
= 0;
162 struct lttng_snapshot_output
*s_iter
;
163 struct lttng_snapshot_output_list
*list
;
165 ret
= lttng_snapshot_list_output(current_session_name
, &list
);
170 MSG("Snapshot output list for session %s", current_session_name
);
173 ret
= mi_lttng_snapshot_output_session_name(writer
,
174 current_session_name
);
181 while ((s_iter
= lttng_snapshot_output_list_get_next(list
)) != NULL
) {
182 if (lttng_snapshot_output_get_maxsize(s_iter
)) {
183 MSG("%s[%" PRIu32
"] %s: %s (max size: %" PRIu64
" bytes)", indent4
,
184 lttng_snapshot_output_get_id(s_iter
),
185 lttng_snapshot_output_get_name(s_iter
),
186 lttng_snapshot_output_get_ctrl_url(s_iter
),
187 lttng_snapshot_output_get_maxsize(s_iter
));
189 MSG("%s[%" PRIu32
"] %s: %s", indent4
,
190 lttng_snapshot_output_get_id(s_iter
),
191 lttng_snapshot_output_get_name(s_iter
),
192 lttng_snapshot_output_get_ctrl_url(s_iter
));
196 ret
= mi_lttng_snapshot_list_output(writer
, s_iter
);
205 /* Close snapshot snapshots element */
206 ret
= mi_lttng_writer_close_element(writer
);
212 /* Close snapshot session element */
213 ret
= mi_lttng_writer_close_element(writer
);
219 lttng_snapshot_output_list_destroy(list
);
222 MSG("%sNone", indent4
);
230 * Delete output by ID.
232 static int del_output(uint32_t id
, const char *name
)
235 struct lttng_snapshot_output
*output
= NULL
;
237 output
= lttng_snapshot_output_create();
244 ret
= lttng_snapshot_output_set_name(name
, output
);
245 } else if (id
!= UINT32_MAX
) {
246 ret
= lttng_snapshot_output_set_id(id
, output
);
256 ret
= lttng_snapshot_del_output(current_session_name
, output
);
261 if (id
!= UINT32_MAX
) {
262 MSG("Snapshot output id %" PRIu32
" successfully deleted for session %s",
263 id
, current_session_name
);
265 MSG("Snapshot output %s successfully deleted for session %s",
266 name
, current_session_name
);
270 ret
= mi_lttng_snapshot_del_output(writer
, id
, name
,
271 current_session_name
);
278 lttng_snapshot_output_destroy(output
);
283 * Add output from the user URL.
285 static int add_output(const char *url
)
288 struct lttng_snapshot_output
*output
= NULL
;
292 if (!url
&& (!opt_data_url
|| !opt_ctrl_url
)) {
297 output
= create_output_from_args(url
);
303 /* This call, if successful, populates the id of the output object. */
304 ret
= lttng_snapshot_add_output(current_session_name
, output
);
309 n_ptr
= lttng_snapshot_output_get_name(output
);
310 if (*n_ptr
== '\0') {
312 pret
= snprintf(name
, sizeof(name
), DEFAULT_SNAPSHOT_NAME
"-%" PRIu32
,
313 lttng_snapshot_output_get_id(output
));
315 PERROR("snprintf add output name");
320 MSG("Snapshot output successfully added for session %s",
321 current_session_name
);
323 MSG(" [%" PRIu32
"] %s: %s (max size: %" PRIu64
" bytes)",
324 lttng_snapshot_output_get_id(output
), n_ptr
,
325 lttng_snapshot_output_get_ctrl_url(output
),
326 lttng_snapshot_output_get_maxsize(output
));
328 MSG(" [%" PRIu32
"] %s: %s",
329 lttng_snapshot_output_get_id(output
), n_ptr
,
330 lttng_snapshot_output_get_ctrl_url(output
));
333 ret
= mi_lttng_snapshot_add_output(writer
, current_session_name
,
340 lttng_snapshot_output_destroy(output
);
344 static int cmd_add_output(int argc
, const char **argv
)
348 if (argc
< 2 && (!opt_data_url
|| !opt_ctrl_url
)) {
349 ERR("An output destination must be specified to add a snapshot output.");
354 ret
= add_output(argv
[1]);
357 case LTTNG_ERR_SNAPSHOT_UNSUPPORTED
:
358 ERR("Session \"%s\" contains a channel that is incompatible with the snapshot functionality.\nMake sure all channels are configured in 'mmap' output mode.",
359 current_session_name
);
371 static int cmd_del_output(int argc
, const char **argv
)
378 ERR("A snapshot output name or id must be provided to delete a snapshot output.");
384 id
= strtol(argv
[1], &name
, 10);
385 if (id
== 0 && (errno
== 0 || errno
== EINVAL
)) {
386 ret
= del_output(UINT32_MAX
, name
);
387 } else if (errno
== 0 && *name
== '\0') {
388 ret
= del_output(id
, NULL
);
390 ERR("Argument %s not recognized", argv
[1]);
399 static int cmd_list_output(int argc
, const char **argv
)
409 * Do a snapshot record with the URL if one is given.
411 static int record(const char *url
)
414 struct lttng_snapshot_output
*output
= NULL
;
416 output
= create_output_from_args(url
);
422 ret
= lttng_snapshot_record(current_session_name
, output
, 0);
424 if (ret
== -LTTNG_ERR_MAX_SIZE_INVALID
) {
425 ERR("Invalid snapshot size. Cannot fit at least one packet per stream.");
430 MSG("Snapshot recorded successfully for session %s", current_session_name
);
433 MSG("Snapshot written at: %s", url
);
434 } else if (opt_ctrl_url
) {
435 MSG("Snapshot written to ctrl: %s, data: %s", opt_ctrl_url
,
440 ret
= mi_lttng_snapshot_record(writer
, current_session_name
, url
,
441 opt_ctrl_url
, opt_data_url
);
448 lttng_snapshot_output_destroy(output
);
452 static int cmd_record(int argc
, const char **argv
)
457 ret
= record(argv
[1]);
465 static enum cmd_error_code
handle_command(const char **argv
)
467 int mi_ret
, i
= 0, argc
;
468 enum cmd_error_code cmd_ret
;
469 struct cmd_struct
*cmd
;
472 ERR("No action specified for snapshot command.");
477 if ((!opt_ctrl_url
&& opt_data_url
) ||
478 (opt_ctrl_url
&& !opt_data_url
)) {
479 ERR("URLs must be specified for both data and control");
484 argc
= count_arguments(argv
);
485 /* popt should have passed NULL if no arguments are present. */
489 while (cmd
->func
!= NULL
) {
491 if (strcmp(argv
[0], cmd
->name
) == 0) {
496 mi_ret
= mi_lttng_writer_open_element(writer
,
497 mi_lttng_element_command_action
);
503 /* Name of the action */
504 mi_ret
= mi_lttng_writer_write_element_string(writer
,
505 config_element_name
, argv
[0]);
511 /* Open output element */
512 mi_ret
= mi_lttng_writer_open_element(writer
,
513 mi_lttng_element_command_output
);
520 result
= cmd
->func(argc
, argv
);
527 case CMD_UNSUPPORTED
:
529 * Sub-commands mix lttng_error_codes
530 * and cmd_error_codes. This should be
531 * cleaned-up, but in the meantime this
532 * hack works since the values of the
533 * two enums do not intersect.
537 case -LTTNG_ERR_SNAPSHOT_NODATA
:
538 WARN("%s", lttng_strerror(result
));
540 /* A warning is fine since the user has no control on
541 * whether or not applications (or the kernel) have
542 * produced any event between the start of the tracing
543 * session and the recording of the snapshot. MI wise
544 * the command is not a success since nothing was
547 cmd_ret
= CMD_SUCCESS
;
550 ERR("%s", lttng_strerror(result
));
555 cmd_ret
= CMD_SUCCESS
;
560 /* Close output and action element */
561 mi_ret
= mi_lttng_close_multi_element(writer
, 2);
573 cmd_ret
= CMD_UNDEFINED
;
579 * The 'snapshot <cmd> <options>' first level command
581 int cmd_snapshot(int argc
, const char **argv
)
585 enum cmd_error_code cmd_ret
= CMD_SUCCESS
;
586 char *session_name
= NULL
;
587 static poptContext pc
;
589 pc
= poptGetContext(NULL
, argc
, argv
, snapshot_opts
, 0);
590 poptReadDefaultConfig(pc
, 0);
594 writer
= mi_lttng_writer_create(fileno(stdout
), lttng_opt_mi
);
600 /* Open command element */
601 mi_ret
= mi_lttng_writer_command_open(writer
,
602 mi_lttng_element_command_snapshot
);
608 /* Open output element */
609 mi_ret
= mi_lttng_writer_open_element(writer
,
610 mi_lttng_element_command_output
);
617 while ((opt
= poptGetNextOpt(pc
)) != -1) {
623 /* SHOW_HELP assigns to ret. */
628 case OPT_LIST_OPTIONS
:
629 list_cmd_options(stdout
, snapshot_opts
);
631 case OPT_LIST_COMMANDS
:
632 list_commands(actions
, stdout
);
637 const char *opt
= poptGetOptArg(pc
);
639 if (utils_parse_size_suffix((char *) opt
, &val
) < 0) {
640 ERR("Unable to handle max-size value %s", opt
);
650 cmd_ret
= CMD_UNDEFINED
;
655 if (!opt_session_name
) {
656 session_name
= get_session_name();
657 if (session_name
== NULL
) {
661 current_session_name
= session_name
;
663 current_session_name
= opt_session_name
;
666 cmd_ret
= handle_command(poptGetArgs(pc
));
669 /* Close output element */
670 mi_ret
= mi_lttng_writer_close_element(writer
);
677 mi_ret
= mi_lttng_writer_write_element_bool(writer
,
678 mi_lttng_element_command_success
,
679 cmd_ret
== CMD_SUCCESS
);
685 /* Command element close */
686 mi_ret
= mi_lttng_writer_command_close(writer
);
695 if (writer
&& mi_lttng_writer_destroy(writer
)) {
699 if (!opt_session_name
) {