Add functions and command line for listing trace_events v3
[lttng-ust.git] / libustcmd / ustcmd.c
1 /* Copyright (C) 2009 Pierre-Marc Fournier, Philippe Proulx-Barrette
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <dirent.h>
26
27 #include "ustcomm.h"
28 #include "ust/ustcmd.h"
29 #include "usterr.h"
30
31 pid_t *ustcmd_get_online_pids(void)
32 {
33 struct dirent *dirent;
34 DIR *dir;
35 unsigned int ret_size = 1 * sizeof(pid_t), i = 0;
36
37 dir = opendir(SOCK_DIR);
38 if (!dir) {
39 return NULL;
40 }
41
42 pid_t *ret = (pid_t *) malloc(ret_size);
43
44 while ((dirent = readdir(dir))) {
45 if (!strcmp(dirent->d_name, ".") ||
46 !strcmp(dirent->d_name, "..")) {
47
48 continue;
49 }
50
51 if (dirent->d_type != DT_DIR &&
52 !!strcmp(dirent->d_name, "ustd")) {
53
54 sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]);
55 if (pid_is_online(ret[i])) {
56 ret_size += sizeof(pid_t);
57 ret = (pid_t *) realloc(ret, ret_size);
58 ++i;
59 }
60 }
61 }
62
63 ret[i] = 0; /* Array end */
64
65 if (ret[0] == 0) {
66 /* No PID at all */
67 free(ret);
68 return NULL;
69 }
70
71 closedir(dir);
72 return ret;
73 }
74
75 /**
76 * Sets marker state (USTCMD_MS_ON or USTCMD_MS_OFF).
77 *
78 * @param mn Marker name
79 * @param state Marker's new state
80 * @param pid Traced process ID
81 * @return 0 if successful, or errors {USTCMD_ERR_GEN, USTCMD_ERR_ARG}
82 */
83 int ustcmd_set_marker_state(const char *mn, int state, pid_t pid)
84 {
85 char *cmd_str [] = {"disable_marker", "enable_marker"};
86 char *cmd;
87 int result;
88
89 if (mn == NULL) {
90 return USTCMD_ERR_ARG;
91 }
92
93 if (asprintf(&cmd, "%s %s", cmd_str[state], mn) < 0) {
94 ERR("ustcmd_set_marker_state : asprintf failed (%s %s)",
95 cmd_str[state], mn);
96 return USTCMD_ERR_GEN;
97 }
98
99 result = ustcmd_send_cmd(cmd, pid, NULL);
100 if (result != 1) {
101 free(cmd);
102 return USTCMD_ERR_GEN;
103 }
104
105 free(cmd);
106 return 0;
107 }
108
109 /**
110 * Set subbuffer size.
111 *
112 * @param channel_size Channel name and size
113 * @param pid Traced process ID
114 * @return 0 if successful, or error
115 */
116 int ustcmd_set_subbuf_size(const char *channel_size, pid_t pid)
117 {
118 char *cmd;
119 int result;
120
121 if (asprintf(&cmd, "%s %s", "set_subbuf_size", channel_size) < 0) {
122 ERR("ustcmd_set_subbuf_size : asprintf failed (set_subbuf_size %s)",
123 channel_size);
124 return -1;
125 }
126
127 result = ustcmd_send_cmd(cmd, pid, NULL);
128 if (result != 1) {
129 free(cmd);
130 return 1;
131 }
132
133 free(cmd);
134 return 0;
135 }
136
137 /**
138 * Set subbuffer num.
139 *
140 * @param channel_num Channel name and num
141 * @param pid Traced process ID
142 * @return 0 if successful, or error
143 */
144 int ustcmd_set_subbuf_num(const char *channel_size, pid_t pid)
145 {
146 char *cmd;
147 int result;
148
149 if (asprintf(&cmd, "%s %s", "set_subbuf_num", channel_size) < 0) {
150 ERR("ustcmd_set_subbuf_num : asprintf failed (set_subbuf_num %s",
151 channel_size);
152 return -1;
153 }
154
155 result = ustcmd_send_cmd(cmd, pid, NULL);
156 if (result != 1) {
157 free(cmd);
158 return 1;
159 }
160
161 free(cmd);
162 return 0;
163 }
164
165 /**
166 * Get subbuffer size.
167 *
168 * @param channel Channel name
169 * @param pid Traced process ID
170 * @return subbuf size if successful, or error
171 */
172 int ustcmd_get_subbuf_size(const char *channel, pid_t pid)
173 {
174 char *cmd, *reply;
175 int result;
176
177 /* format: channel_cpu */
178 if (asprintf(&cmd, "%s %s_0", "get_subbuf_size", channel) < 0) {
179 ERR("ustcmd_get_subbuf_size : asprintf failed (get_subbuf_size, %s_0",
180 channel);
181 return -1;
182 }
183
184 result = ustcmd_send_cmd(cmd, pid, &reply);
185 if (result != 1) {
186 free(cmd);
187 return -1;
188 }
189
190 result = atoi(reply);
191 free(cmd);
192 free(reply);
193 return result;
194 }
195
196 /**
197 * Get subbuffer num.
198 *
199 * @param channel Channel name
200 * @param pid Traced process ID
201 * @return subbuf cnf if successful, or error
202 */
203 int ustcmd_get_subbuf_num(const char *channel, pid_t pid)
204 {
205 char *cmd, *reply;
206 int result;
207
208 /* format: channel_cpu */
209 if (asprintf(&cmd, "%s %s_0", "get_n_subbufs", channel) < 0) {
210 ERR("ustcmd_get_subbuf_num : asprintf failed (get_n_subbufs, %s_0",
211 channel);
212 return -1;
213 }
214
215 result = ustcmd_send_cmd(cmd, pid, &reply);
216 if (result != 1) {
217 free(cmd);
218 return -1;
219 }
220
221 result = atoi(reply);
222 free(cmd);
223 free(reply);
224 return result;
225 }
226
227 /**
228 * Destroys an UST trace according to a PID.
229 *
230 * @param pid Traced process ID
231 * @return 0 if successful, or error USTCMD_ERR_GEN
232 */
233 int ustcmd_destroy_trace(pid_t pid)
234 {
235 int result;
236
237 result = ustcmd_send_cmd("trace_destroy", pid, NULL);
238 if (result != 1) {
239 return USTCMD_ERR_GEN;
240 }
241
242 return 0;
243 }
244
245 /**
246 * Starts an UST trace (and setups it) according to a PID.
247 *
248 * @param pid Traced process ID
249 * @return 0 if successful, or error USTCMD_ERR_GEN
250 */
251 int ustcmd_setup_and_start(pid_t pid)
252 {
253 int result;
254
255 result = ustcmd_send_cmd("start", pid, NULL);
256 if (result != 1) {
257 return USTCMD_ERR_GEN;
258 }
259
260 return 0;
261 }
262
263 /**
264 * Creates an UST trace according to a PID.
265 *
266 * @param pid Traced process ID
267 * @return 0 if successful, or error USTCMD_ERR_GEN
268 */
269 int ustcmd_create_trace(pid_t pid)
270 {
271 int result;
272
273 result = ustcmd_send_cmd("trace_create", pid, NULL);
274 if (result != 1) {
275 return USTCMD_ERR_GEN;
276 }
277
278 return 0;
279 }
280
281 /**
282 * Starts an UST trace according to a PID.
283 *
284 * @param pid Traced process ID
285 * @return 0 if successful, or error USTCMD_ERR_GEN
286 */
287 int ustcmd_start_trace(pid_t pid)
288 {
289 int result;
290
291 result = ustcmd_send_cmd("trace_start", pid, NULL);
292 if (result != 1) {
293 return USTCMD_ERR_GEN;
294 }
295
296 return 0;
297 }
298
299 /**
300 * Alloc an UST trace according to a PID.
301 *
302 * @param pid Traced process ID
303 * @return 0 if successful, or error USTCMD_ERR_GEN
304 */
305 int ustcmd_alloc_trace(pid_t pid)
306 {
307 int result;
308
309 result = ustcmd_send_cmd("trace_alloc", pid, NULL);
310 if (result != 1) {
311 return USTCMD_ERR_GEN;
312 }
313
314 return 0;
315 }
316
317 /**
318 * Stops an UST trace according to a PID.
319 *
320 * @param pid Traced process ID
321 * @return 0 if successful, or error USTCMD_ERR_GEN
322 */
323 int ustcmd_stop_trace(pid_t pid)
324 {
325 int result;
326
327 result = ustcmd_send_cmd("trace_stop", pid, NULL);
328 if (result != 1) {
329 return USTCMD_ERR_GEN;
330 }
331
332 return 0;
333 }
334
335 /**
336 * Counts newlines ('\n') in a string.
337 *
338 * @param str String to search in
339 * @return Total newlines count
340 */
341 unsigned int ustcmd_count_nl(const char *str)
342 {
343 unsigned int i = 0, tot = 0;
344
345 while (str[i] != '\0') {
346 if (str[i] == '\n') {
347 ++tot;
348 }
349 ++i;
350 }
351
352 return tot;
353 }
354
355 /**
356 * Frees a CMSF array.
357 *
358 * @param cmsf CMSF array to free
359 * @return 0 if successful, or error USTCMD_ERR_ARG
360 */
361 int ustcmd_free_cmsf(struct marker_status *cmsf)
362 {
363 if (cmsf == NULL) {
364 return USTCMD_ERR_ARG;
365 }
366
367 unsigned int i = 0;
368 while (cmsf[i].channel != NULL) {
369 free(cmsf[i].channel);
370 free(cmsf[i].marker);
371 free(cmsf[i].fs);
372 ++i;
373 }
374 free(cmsf);
375
376 return 0;
377 }
378
379 /**
380 * Gets channel/marker/state/format string for a given PID.
381 *
382 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
383 * frees with `ustcmd_free_cmsf')
384 * @param pid Targeted PID
385 * @return 0 if successful, or -1 on error
386 */
387 int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid)
388 {
389 char *big_str = NULL;
390 int result;
391 struct marker_status *tmp_cmsf = NULL;
392 unsigned int i = 0, cmsf_ind = 0;
393
394 if (cmsf == NULL) {
395 return -1;
396 }
397 result = ustcmd_send_cmd("list_markers", pid, &big_str);
398 if (result != 1) {
399 return -1;
400 }
401
402 if (result != 1) {
403 ERR("error while getting markers list");
404 return -1;
405 }
406
407 tmp_cmsf = (struct marker_status *) malloc(sizeof(struct marker_status) *
408 (ustcmd_count_nl(big_str) + 1));
409 if (tmp_cmsf == NULL) {
410 return -1;
411 }
412
413 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
414 while (big_str[i] != '\0') {
415 char state;
416
417 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
418 &tmp_cmsf[cmsf_ind].channel,
419 &tmp_cmsf[cmsf_ind].marker,
420 &state,
421 &tmp_cmsf[cmsf_ind].fs);
422 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
423 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
424
425 while (big_str[i] != '\n') {
426 ++i; /* Go to next '\n' */
427 }
428 ++i; /* Skip current pointed '\n' */
429 ++cmsf_ind;
430 }
431 tmp_cmsf[cmsf_ind].channel = NULL;
432 tmp_cmsf[cmsf_ind].marker = NULL;
433 tmp_cmsf[cmsf_ind].fs = NULL;
434
435 *cmsf = tmp_cmsf;
436
437 free(big_str);
438 return 0;
439 }
440
441
442 /**
443 * Frees a TES array.
444 *
445 * @param tes TES array to free
446 * @return 0 if successful, or error USTCMD_ERR_ARG
447 */
448 int ustcmd_free_tes(struct trace_event_status *tes)
449 {
450 if (tes == NULL) {
451 return USTCMD_ERR_ARG;
452 }
453
454 unsigned int i = 0;
455 while (tes[i].name != NULL) {
456 free(tes[i].name);
457 ++i;
458 }
459 free(tes);
460
461 return 0;
462 }
463
464 /**
465 * Gets trace_events string for a given PID.
466 *
467 * @param tes Pointer to TES array to be filled (callee allocates, caller
468 * frees with `ustcmd_free_tes')
469 * @param pid Targeted PID
470 * @return 0 if successful, or -1 on error
471 */
472 int ustcmd_get_tes(struct trace_event_status **tes,
473 const pid_t pid)
474 {
475 char *big_str = NULL;
476 int result;
477 struct trace_event_status *tmp_tes = NULL;
478 unsigned int i = 0, tes_ind = 0;
479
480 if (tes == NULL) {
481 return -1;
482 }
483
484 result = ustcmd_send_cmd("list_trace_events", pid, &big_str);
485 if (result != 1) {
486 ERR("error while getting trace_event list");
487 return -1;
488 }
489
490 tmp_tes = (struct trace_event_status *)
491 zmalloc(sizeof(struct trace_event_status) *
492 (ustcmd_count_nl(big_str) + 1));
493 if (tmp_tes == NULL) {
494 ERR("Failed to allocate TES array");
495 return -1;
496 }
497
498 /* Parse received reply string (format: "[name]"): */
499 while (big_str[i] != '\0') {
500 char state;
501
502 sscanf(big_str + i, "trace_event: %a[^\n]",
503 &tmp_tes[tes_ind].name);
504 while (big_str[i] != '\n') {
505 ++i; /* Go to next '\n' */
506 }
507 ++i; /* Skip current pointed '\n' */
508 ++tes_ind;
509 }
510 tmp_tes[tes_ind].name = NULL;
511
512 *tes = tmp_tes;
513
514 free(big_str);
515 return 0;
516 }
517
518 /**
519 * Set socket path
520 *
521 * @param sock_path Socket path
522 * @param pid Traced process ID
523 * @return 0 if successful, or error
524 */
525 int ustcmd_set_sock_path(const char *sock_path, pid_t pid)
526 {
527 char *cmd;
528 int result;
529
530 if (asprintf(&cmd, "%s %s", "set_sock_path", sock_path) < 0) {
531 ERR("ustcmd_set_sock_path : asprintf failed (set_sock_path, %s",
532 sock_path);
533 return -1;
534 }
535
536 result = ustcmd_send_cmd(cmd, pid, NULL);
537 if (result != 1) {
538 free(cmd);
539 return USTCMD_ERR_GEN;
540 }
541
542 free(cmd);
543 return 0;
544 }
545
546 /**
547 * Get socket path
548 *
549 * @param sock_path Pointer to where the socket path will be returned
550 * @param pid Traced process ID
551 * @return 0 if successful, or error
552 */
553 int ustcmd_get_sock_path(char **sock_path, pid_t pid)
554 {
555 char *cmd, *reply;
556 int result;
557
558 if (asprintf(&cmd, "%s", "get_sock_path") < 0) {
559 ERR("ustcmd_get_sock_path : asprintf failed");
560 return USTCMD_ERR_GEN;
561 }
562
563 result = ustcmd_send_cmd(cmd, pid, &reply);
564 if (result != 1) {
565 free(cmd);
566 return USTCMD_ERR_GEN;
567 }
568
569 free(cmd);
570 *sock_path = reply;
571 return 0;
572 }
573
574 int ustcmd_force_switch(pid_t pid)
575 {
576 int result;
577
578 result = ustcmd_send_cmd("force_switch", pid, NULL);
579 if (result != 1) {
580 return USTCMD_ERR_GEN;
581 }
582
583 return 0;
584 }
585
586 /**
587 * Sends a given command to a traceable process
588 *
589 * @param cmd Null-terminated command to send
590 * @param pid Targeted PID
591 * @param reply Pointer to string to be filled with a reply string (must
592 * be NULL if no reply is needed for the given command).
593 * @return -1 if not successful, 0 on EOT, 1 on success
594 */
595
596 int ustcmd_send_cmd(const char *cmd, const pid_t pid, char **reply)
597 {
598 struct ustcomm_connection conn;
599 int retval;
600
601 if (ustcomm_connect_app(pid, &conn)) {
602 ERR("could not connect to PID %u", (unsigned int) pid);
603 return -1;
604 }
605
606 retval = ustcomm_send_request(&conn, cmd, reply);
607
608 ustcomm_close_app(&conn);
609
610 return retval;
611 }
This page took 0.041566 seconds and 5 git commands to generate.