Fix wrong message with lttng list
[lttng-tools.git] / lttng / commands / list.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; only version 2
7 * of the License.
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
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#define _GNU_SOURCE
20#include <inttypes.h>
21#include <popt.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "../cmd.h"
27
28static int opt_pid;
29static int opt_userspace;
30static int opt_kernel;
31static char *opt_channel;
32static int opt_domain;
33
34const char *indent4 = " ";
35const char *indent6 = " ";
36const char *indent8 = " ";
37
38enum {
39 OPT_HELP = 1,
40};
41
42static struct poptOption long_options[] = {
43 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
44 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
45 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
46 {"userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0},
47 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
48 {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
49 {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
50 {0, 0, 0, 0, 0, 0, 0}
51};
52
53/*
54 * usage
55 */
56static void usage(FILE *ofp)
57{
58 fprintf(ofp, "usage: lttng list [[-k] [-u] [-p PID] [SESSION [<options>]]]\n");
59 fprintf(ofp, "\n");
60 fprintf(ofp, "With no arguments, list available tracing session(s)\n");
61 fprintf(ofp, "\n");
62 fprintf(ofp, "With -k alone, list available kernel events\n");
63 fprintf(ofp, "With -u alone, list available userspace events\n");
64 fprintf(ofp, "\n");
65 fprintf(ofp, " -h, --help Show this help\n");
66 fprintf(ofp, " -k, --kernel Select kernel domain\n");
67 fprintf(ofp, " -u, --userspace Select user-space domain.\n");
68 fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
69 fprintf(ofp, "\n");
70 fprintf(ofp, "Options:\n");
71 fprintf(ofp, " -c, --channel NAME List details of a channel\n");
72 fprintf(ofp, " -d, --domain List available domain(s)\n");
73 fprintf(ofp, "\n");
74}
75
76/*
77 * Get command line from /proc for a specific pid.
78 *
79 * On success, return an allocated string pointer to the proc cmdline.
80 * On error, return NULL.
81 */
82#ifdef DISABLE
83static char *get_cmdline_by_pid(pid_t pid)
84{
85 int ret;
86 FILE *fp;
87 char *cmdline = NULL;
88 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
89
90 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
91 fp = fopen(path, "r");
92 if (fp == NULL) {
93 goto end;
94 }
95
96 /* Caller must free() *cmdline */
97 cmdline = malloc(PATH_MAX);
98 ret = fread(cmdline, 1, PATH_MAX, fp);
99 if (ret < 0) {
100 perror("fread proc list");
101 }
102 fclose(fp);
103
104end:
105 return cmdline;
106}
107#endif /* DISABLE */
108
109/*
110 * Ask for all trace events in the kernel and pretty print them.
111 */
112static int list_kernel_events(void)
113{
114 int i, size;
115 struct lttng_event *event_list;
116 struct lttng_domain dom;
117
118 DBG("Getting all tracing events");
119
120 dom.type = LTTNG_DOMAIN_KERNEL;
121
122 size = lttng_list_tracepoints(&dom, &event_list);
123 if (size < 0) {
124 ERR("Unable to list kernel events");
125 return size;
126 }
127
128 MSG("Kernel events:\n-------------");
129
130 for (i = 0; i < size; i++) {
131 MSG(" %s", event_list[i].name);
132 }
133
134 free(event_list);
135
136 return CMD_SUCCESS;
137}
138
139/*
140 * List events of channel of session and domain.
141 */
142static int list_events(struct lttng_domain *dom,
143 const char *session_name, const char *channel_name)
144{
145 int ret, count, i;
146 struct lttng_event *events = NULL;
147
148 count = lttng_list_events(dom, session_name, channel_name, &events);
149 if (count < 0) {
150 ret = count;
151 goto error;
152 }
153
154 MSG("\n%sEvents:", indent4);
155 if (count == 0) {
156 MSG("%sNone", indent6);
157 goto end;
158 }
159
160 for (i = 0; i < count; i++) {
161 switch (events[i].type) {
162 case LTTNG_EVENT_TRACEPOINT:
163 MSG("%s%s (type: tracepoint) [enabled: %d]", indent6,
164 events[i].name, events[i].enabled);
165 break;
166 case LTTNG_EVENT_PROBE:
167 MSG("%s%s (type: probe) [enabled: %d]", indent6,
168 events[i].name, events[i].enabled);
169 if (events[i].attr.probe.addr != 0) {
170 MSG("%saddr: 0x%" PRIx64, indent8, events[i].attr.probe.addr);
171 } else {
172 MSG("%soffset: 0x%" PRIx64, indent8, events[i].attr.probe.offset);
173 MSG("%ssymbol: %s", indent8, events[i].attr.probe.symbol_name);
174 }
175 break;
176 case LTTNG_EVENT_FUNCTION:
177 case LTTNG_EVENT_FUNCTION_ENTRY:
178 MSG("%s%s (type: function) [enabled: %d]", indent6,
179 events[i].name, events[i].enabled);
180 MSG("%ssymbol: \"%s\"", indent8, events[i].attr.ftrace.symbol_name);
181 break;
182 }
183 }
184
185 MSG("");
186
187end:
188 if (events) {
189 free(events);
190 }
191 ret = CMD_SUCCESS;
192
193error:
194 return ret;
195}
196
197/*
198 * Pretty print channel
199 */
200static void print_channel(struct lttng_channel *channel)
201{
202 MSG("- %s (enabled: %d):\n", channel->name, channel->enabled);
203
204 MSG("%sAttributes:", indent4);
205 MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite);
206 MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size);
207 MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf);
208 MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval);
209 MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval);
210 switch (channel->attr.output) {
211 case LTTNG_EVENT_SPLICE:
212 MSG("%soutput: splice()", indent6);
213 break;
214 case LTTNG_EVENT_MMAP:
215 MSG("%soutput: mmap()", indent6);
216 break;
217 }
218}
219
220/*
221 * List channel(s) of session and domain.
222 *
223 * If channel_name is NULL, all channels are listed.
224 */
225static int list_channels(struct lttng_domain *dom,
226 const char *session_name, const char *channel_name)
227{
228 int count, i, ret = CMD_SUCCESS;
229 unsigned int chan_found = 0;
230 struct lttng_channel *channels = NULL;
231
232 DBG("Listing channel(s) (%s)", channel_name);
233
234 count = lttng_list_channels(dom, session_name, &channels);
235 if (count < 0) {
236 ret = count;
237 goto error;
238 } else if (count == 0) {
239 MSG("No channel found");
240 goto end;
241 }
242
243 if (channel_name == NULL) {
244 MSG("Channels:\n-------------");
245 }
246
247 for (i = 0; i < count; i++) {
248 if (channel_name != NULL) {
249 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
250 chan_found = 1;
251 } else {
252 continue;
253 }
254 }
255 print_channel(&channels[i]);
256
257 /* Listing events per channel */
258 ret = list_events(dom, session_name, channels[i].name);
259 if (ret < 0) {
260 MSG("%s", lttng_get_readable_code(ret));
261 }
262
263 if (chan_found) {
264 break;
265 }
266 }
267
268 if (!chan_found && channel_name != NULL) {
269 MSG("Channel %s not found", channel_name);
270 }
271
272end:
273 free(channels);
274 ret = CMD_SUCCESS;
275
276error:
277 return ret;
278}
279
280/*
281 * List available tracing session. List only basic information.
282 *
283 * If session_name is NULL, all sessions are listed.
284 */
285static int list_sessions(const char *session_name)
286{
287 int ret, count, i;
288 unsigned int session_found = 0;
289 struct lttng_session *sessions;
290
291 count = lttng_list_sessions(&sessions);
292 DBG("Session count %d", count);
293 if (count < 0) {
294 ret = count;
295 goto error;
296 }
297
298 if (session_name == NULL) {
299 MSG("Available tracing sessions:");
300 }
301
302 for (i = 0; i < count; i++) {
303 if (session_name != NULL) {
304 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
305 session_found = 1;
306 MSG("Tracing session %s:", session_name);
307 MSG("%sTrace path: %s\n", indent4, sessions[i].path);
308 break;
309 }
310 }
311
312 MSG(" %d) %s (%s)", i + 1, sessions[i].name, sessions[i].path);
313
314 if (session_found) {
315 break;
316 }
317 }
318
319 free(sessions);
320
321 if (!session_found && session_name != NULL) {
322 MSG("Session %s not found", session_name);
323 }
324
325 if (session_name == NULL) {
326 MSG("\nUse lttng list <session_name> for more details");
327 }
328
329 return CMD_SUCCESS;
330
331error:
332 return ret;
333}
334
335/*
336 * List available domain(s) for a session.
337 */
338static int list_domains(const char *session_name)
339{
340 int i, count, ret = CMD_SUCCESS;
341 struct lttng_domain *domains = NULL;
342
343 MSG("Domains:\n-------------");
344
345 count = lttng_list_domains(session_name, &domains);
346 if (count < 0) {
347 ret = count;
348 goto error;
349 } else if (count == 0) {
350 MSG(" None");
351 goto end;
352 }
353
354 for (i = 0; i < count; i++) {
355 switch (domains[i].type) {
356 case LTTNG_DOMAIN_KERNEL:
357 MSG(" - Kernel");
358 default:
359 break;
360 }
361 }
362
363end:
364 free(domains);
365
366error:
367 return ret;
368}
369
370/*
371 * The 'list <options>' first level command
372 */
373int cmd_list(int argc, const char **argv)
374{
375 int opt, i, ret = CMD_SUCCESS;
376 const char *session_name;
377 static poptContext pc;
378 struct lttng_domain domain;
379 struct lttng_domain *domains = NULL;
380
381 if (argc < 1) {
382 usage(stderr);
383 goto end;
384 }
385
386 pc = poptGetContext(NULL, argc, argv, long_options, 0);
387 poptReadDefaultConfig(pc, 0);
388
389 while ((opt = poptGetNextOpt(pc)) != -1) {
390 switch (opt) {
391 case OPT_HELP:
392 usage(stderr);
393 goto end;
394 default:
395 usage(stderr);
396 ret = CMD_UNDEFINED;
397 goto end;
398 }
399 }
400
401 if (opt_userspace || opt_pid != 0) {
402 MSG("*** Userspace tracing not implemented ***\n");
403 }
404
405 /* Get session name (trailing argument) */
406 session_name = poptGetArg(pc);
407 DBG("Session name: %s", session_name);
408
409 if (session_name == NULL) {
410 if (opt_kernel) {
411 ret = list_kernel_events();
412 if (ret < 0) {
413 goto end;
414 }
415 } else {
416 ret = list_sessions(NULL);
417 if (ret < 0) {
418 goto end;
419 }
420 }
421 } else {
422 /* List session attributes */
423 ret = list_sessions(session_name);
424 if (ret < 0) {
425 goto end;
426 }
427
428 /* Domain listing */
429 if (opt_domain) {
430 ret = list_domains(session_name);
431 goto end;
432 }
433
434 if (opt_kernel) {
435 domain.type = LTTNG_DOMAIN_KERNEL;
436 /* Channel listing */
437 ret = list_channels(&domain, session_name, opt_channel);
438 if (ret < 0) {
439 goto end;
440 }
441 } else if (opt_userspace) {
442 /* TODO: Userspace domain */
443 } else {
444 /* We want all domain(s) */
445 ret = lttng_list_domains(session_name, &domains);
446 if (ret < 0) {
447 goto end;
448 }
449
450 for (i = 0; i < ret; i++) {
451 switch (domains[i].type) {
452 case LTTNG_DOMAIN_KERNEL:
453 MSG("=== Domain: Kernel ===\n");
454 break;
455 default:
456 MSG("=== Domain: Unimplemented ===\n");
457 break;
458 }
459
460 ret = list_channels(&domains[i], session_name, opt_channel);
461 if (ret < 0) {
462 goto end;
463 }
464 }
465 }
466 }
467
468end:
469 if (domains) {
470 free(domains);
471 }
472 return ret;
473}
This page took 0.024058 seconds and 4 git commands to generate.