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