Rename libustcmd to libustctl
[ust.git] / libustctl / libustctl.c
CommitLineData
ab33e65c
PP
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
ef290fca 18#define _GNU_SOURCE
ab33e65c
PP
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>
ab33e65c
PP
26
27#include "ustcomm.h"
2298f329 28#include "ust/ustctl.h"
2a79ceeb 29#include "usterr.h"
ab33e65c 30
72098143
NC
31static int do_cmd(const pid_t pid,
32 const struct ustcomm_header *req_header,
33 const char *req_data,
34 struct ustcomm_header *res_header,
35 char **res_data)
36{
37 int app_fd, result, saved_errno = 0;
38 char *recv_buf;
39
40 if (ustcomm_connect_app(pid, &app_fd)) {
41 ERR("could not connect to PID %u", (unsigned int) pid);
42 errno = ENOTCONN;
43 return -1;
44 }
45
46 recv_buf = zmalloc(USTCOMM_BUFFER_SIZE);
47 if (!recv_buf) {
48 saved_errno = ENOMEM;
49 goto close_app_fd;
50 }
51
52 result = ustcomm_req(app_fd, req_header, req_data, res_header, recv_buf);
53 if (result > 0) {
54 saved_errno = -res_header->result;
55 if (res_header->size == 0 || saved_errno > 0) {
56 free(recv_buf);
57 } else {
58 if (res_data) {
59 *res_data = recv_buf;
60 } else {
61 free(recv_buf);
62 }
63 }
64 } else {
65 ERR("ustcomm req failed");
66 if (result == 0) {
67 saved_errno = ENOTCONN;
68 } else {
69 saved_errno = -result;
70 }
71 free(recv_buf);
72 }
73
74close_app_fd:
75 close(app_fd);
76
77 errno = saved_errno;
78
79 if (errno) {
80 return -1;
81 }
82
83 return 0;
84}
85
2298f329 86pid_t *ustctl_get_online_pids(void)
772030fe 87{
08230db7
PMF
88 struct dirent *dirent;
89 DIR *dir;
ef290fca 90 unsigned int ret_size = 1 * sizeof(pid_t), i = 0;
ab33e65c
PP
91
92 dir = opendir(SOCK_DIR);
93 if (!dir) {
94 return NULL;
95 }
96
08230db7 97 pid_t *ret = (pid_t *) malloc(ret_size);
ab33e65c 98
772030fe 99 while ((dirent = readdir(dir))) {
ab33e65c 100 if (!strcmp(dirent->d_name, ".") ||
72098143 101 !strcmp(dirent->d_name, "..")) {
ab33e65c
PP
102
103 continue;
104 }
105
106 if (dirent->d_type != DT_DIR &&
9dc7b7ff 107 !!strcmp(dirent->d_name, "ust-consumer")) {
ab33e65c 108
08230db7 109 sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]);
4723ca09
NC
110 /* FIXME: Here we previously called pid_is_online, which
111 * always returned 1, now I replaced it with just 1.
112 * We need to figure out an intelligent way of solving
113 * this, maybe connect-disconnect.
114 */
115 if (1) {
ab33e65c 116 ret_size += sizeof(pid_t);
08230db7 117 ret = (pid_t *) realloc(ret, ret_size);
ab33e65c
PP
118 ++i;
119 }
120 }
121 }
122
77957c95 123 ret[i] = 0; /* Array end */
ab33e65c 124
08230db7 125 if (ret[0] == 0) {
72098143 126 /* No PID at all */
ab33e65c
PP
127 free(ret);
128 return NULL;
129 }
130
131 closedir(dir);
132 return ret;
133}
134
135/**
2298f329 136 * Sets marker state (USTCTL_MS_ON or USTCTL_MS_OFF).
ab33e65c
PP
137 *
138 * @param mn Marker name
139 * @param state Marker's new state
140 * @param pid Traced process ID
2298f329 141 * @return 0 if successful, or errors {USTCTL_ERR_GEN, USTCTL_ERR_ARG}
ab33e65c 142 */
2298f329 143int ustctl_set_marker_state(const char *trace, const char *channel,
d89b8191 144 const char *marker, int state, pid_t pid)
ef290fca 145{
72098143
NC
146 struct ustcomm_header req_header, res_header;
147 struct ustcomm_marker_info marker_inf;
ef290fca
PMF
148 int result;
149
72098143
NC
150 result = ustcomm_pack_marker_info(&req_header,
151 &marker_inf,
d89b8191 152 trace,
72098143
NC
153 channel,
154 marker);
155 if (result < 0) {
156 errno = -result;
157 return -1;
08b8805e 158 }
ab33e65c 159
72098143 160 req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER;
ab33e65c 161
72098143
NC
162 return do_cmd(pid, &req_header, (char *)&marker_inf,
163 &res_header, NULL);
ab33e65c
PP
164}
165
763f41e5
DS
166/**
167 * Set subbuffer size.
168 *
169 * @param channel_size Channel name and size
170 * @param pid Traced process ID
171 * @return 0 if successful, or error
172 */
2298f329 173int ustctl_set_subbuf_size(const char *trace, const char *channel,
d89b8191 174 unsigned int subbuf_size, pid_t pid)
763f41e5 175{
72098143
NC
176 struct ustcomm_header req_header, res_header;
177 struct ustcomm_channel_info ch_inf;
763f41e5
DS
178 int result;
179
72098143
NC
180 result = ustcomm_pack_channel_info(&req_header,
181 &ch_inf,
d89b8191 182 trace,
72098143
NC
183 channel);
184 if (result < 0) {
185 errno = -result;
08b8805e
DG
186 return -1;
187 }
763f41e5 188
72098143
NC
189 req_header.command = SET_SUBBUF_SIZE;
190 ch_inf.subbuf_size = subbuf_size;
763f41e5 191
72098143
NC
192 return do_cmd(pid, &req_header, (char *)&ch_inf,
193 &res_header, NULL);
763f41e5
DS
194}
195
196/**
197 * Set subbuffer num.
198 *
199 * @param channel_num Channel name and num
200 * @param pid Traced process ID
201 * @return 0 if successful, or error
202 */
2298f329 203int ustctl_set_subbuf_num(const char *trace, const char *channel,
d89b8191 204 unsigned int num, pid_t pid)
763f41e5 205{
72098143
NC
206 struct ustcomm_header req_header, res_header;
207 struct ustcomm_channel_info ch_inf;
763f41e5
DS
208 int result;
209
72098143
NC
210 result = ustcomm_pack_channel_info(&req_header,
211 &ch_inf,
d89b8191 212 trace,
72098143
NC
213 channel);
214 if (result < 0) {
215 errno = -result;
08b8805e
DG
216 return -1;
217 }
763f41e5 218
72098143
NC
219 req_header.command = SET_SUBBUF_NUM;
220 ch_inf.subbuf_num = num;
221
222 return do_cmd(pid, &req_header, (char *)&ch_inf,
223 &res_header, NULL);
763f41e5 224
763f41e5
DS
225}
226
2298f329 227static int ustctl_get_subbuf_num_size(const char *trace, const char *channel,
d89b8191 228 pid_t pid, int *num, int *size)
e77b8e8e 229{
72098143
NC
230 struct ustcomm_header req_header, res_header;
231 struct ustcomm_channel_info ch_inf, *ch_inf_res;
e77b8e8e
DS
232 int result;
233
72098143
NC
234
235 result = ustcomm_pack_channel_info(&req_header,
236 &ch_inf,
d89b8191 237 trace,
72098143
NC
238 channel);
239 if (result < 0) {
240 errno = -result;
08b8805e
DG
241 return -1;
242 }
e77b8e8e 243
72098143
NC
244 req_header.command = GET_SUBBUF_NUM_SIZE;
245
246 result = do_cmd(pid, &req_header, (char *)&ch_inf,
247 &res_header, (char **)&ch_inf_res);
248 if (result < 0) {
e77b8e8e
DS
249 return -1;
250 }
251
72098143
NC
252 *num = ch_inf_res->subbuf_num;
253 *size = ch_inf_res->subbuf_size;
254
255 free(ch_inf_res);
256
257 return 0;
e77b8e8e
DS
258}
259
260/**
261 * Get subbuffer num.
262 *
263 * @param channel Channel name
264 * @param pid Traced process ID
265 * @return subbuf cnf if successful, or error
266 */
2298f329 267int ustctl_get_subbuf_num(const char *trace, const char *channel, pid_t pid)
e77b8e8e 268{
72098143 269 int num, size, result;
e77b8e8e 270
2298f329 271 result = ustctl_get_subbuf_num_size(trace, channel, pid,
72098143
NC
272 &num, &size);
273 if (result < 0) {
274 errno = -result;
08b8805e
DG
275 return -1;
276 }
e77b8e8e 277
72098143
NC
278 return num;
279}
280
281/**
282 * Get subbuffer size.
283 *
284 * @param channel Channel name
285 * @param pid Traced process ID
286 * @return subbuf size if successful, or error
287 */
2298f329 288int ustctl_get_subbuf_size(const char *trace, const char *channel, pid_t pid)
72098143
NC
289{
290 int num, size, result;
291
2298f329 292 result = ustctl_get_subbuf_num_size(trace, channel, pid,
72098143
NC
293 &num, &size);
294 if (result < 0) {
295 errno = -result;
e77b8e8e
DS
296 return -1;
297 }
298
72098143 299 return size;
e77b8e8e 300}
763f41e5 301
d89b8191
NC
302
303static int do_trace_cmd(const char *trace, pid_t pid, int command)
304{
305 struct ustcomm_header req_header, res_header;
28c1bb40 306 struct ustcomm_single_field trace_inf;
d89b8191
NC
307 int result;
308
28c1bb40
NC
309 result = ustcomm_pack_single_field(&req_header,
310 &trace_inf,
311 trace);
d89b8191
NC
312 if (result < 0) {
313 errno = -result;
314 return -1;
315 }
316
317 req_header.command = command;
318
319 return do_cmd(pid, &req_header, (char *)&trace_inf, &res_header, NULL);
320}
321
ab33e65c
PP
322/**
323 * Destroys an UST trace according to a PID.
324 *
325 * @param pid Traced process ID
2298f329 326 * @return 0 if successful, or error USTCTL_ERR_GEN
ab33e65c 327 */
2298f329 328int ustctl_destroy_trace(const char *trace, pid_t pid)
772030fe 329{
d89b8191 330 return do_trace_cmd(trace, pid, DESTROY_TRACE);
ab33e65c
PP
331}
332
333/**
334 * Starts an UST trace (and setups it) according to a PID.
335 *
336 * @param pid Traced process ID
2298f329 337 * @return 0 if successful, or error USTCTL_ERR_GEN
ab33e65c 338 */
2298f329 339int ustctl_setup_and_start(const char *trace, pid_t pid)
772030fe 340{
d89b8191 341 return do_trace_cmd(trace, pid, START);
ab33e65c
PP
342}
343
62ec620f
PMF
344/**
345 * Creates an UST trace according to a PID.
346 *
347 * @param pid Traced process ID
2298f329 348 * @return 0 if successful, or error USTCTL_ERR_GEN
62ec620f 349 */
2298f329 350int ustctl_create_trace(const char *trace, pid_t pid)
62ec620f 351{
d89b8191 352 return do_trace_cmd(trace, pid, CREATE_TRACE);
62ec620f
PMF
353}
354
ab33e65c
PP
355/**
356 * Starts an UST trace according to a PID.
357 *
358 * @param pid Traced process ID
2298f329 359 * @return 0 if successful, or error USTCTL_ERR_GEN
ab33e65c 360 */
2298f329 361int ustctl_start_trace(const char *trace, pid_t pid)
772030fe 362{
d89b8191 363 return do_trace_cmd(trace, pid, START_TRACE);
ab33e65c
PP
364}
365
763f41e5
DS
366/**
367 * Alloc an UST trace according to a PID.
368 *
369 * @param pid Traced process ID
2298f329 370 * @return 0 if successful, or error USTCTL_ERR_GEN
763f41e5 371 */
2298f329 372int ustctl_alloc_trace(const char *trace, pid_t pid)
763f41e5 373{
d89b8191 374 return do_trace_cmd(trace, pid, ALLOC_TRACE);
763f41e5
DS
375}
376
ab33e65c
PP
377/**
378 * Stops an UST trace according to a PID.
379 *
380 * @param pid Traced process ID
2298f329 381 * @return 0 if successful, or error USTCTL_ERR_GEN
ab33e65c 382 */
2298f329 383int ustctl_stop_trace(const char *trace, pid_t pid)
772030fe 384{
d89b8191 385 return do_trace_cmd(trace, pid, STOP_TRACE);
ab33e65c
PP
386}
387
388/**
389 * Counts newlines ('\n') in a string.
390 *
391 * @param str String to search in
392 * @return Total newlines count
393 */
2298f329 394unsigned int ustctl_count_nl(const char *str)
772030fe 395{
ab33e65c
PP
396 unsigned int i = 0, tot = 0;
397
398 while (str[i] != '\0') {
399 if (str[i] == '\n') {
400 ++tot;
401 }
402 ++i;
403 }
404
405 return tot;
406}
407
408/**
409 * Frees a CMSF array.
410 *
411 * @param cmsf CMSF array to free
2298f329 412 * @return 0 if successful, or error USTCTL_ERR_ARG
ab33e65c 413 */
2298f329 414int ustctl_free_cmsf(struct marker_status *cmsf)
772030fe 415{
ab33e65c 416 if (cmsf == NULL) {
2298f329 417 return USTCTL_ERR_ARG;
ab33e65c
PP
418 }
419
420 unsigned int i = 0;
421 while (cmsf[i].channel != NULL) {
422 free(cmsf[i].channel);
423 free(cmsf[i].marker);
424 free(cmsf[i].fs);
425 ++i;
426 }
427 free(cmsf);
428
429 return 0;
430}
431
432/**
433 * Gets channel/marker/state/format string for a given PID.
434 *
435 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
2298f329 436 * frees with `ustctl_free_cmsf')
ab33e65c 437 * @param pid Targeted PID
2a79ceeb 438 * @return 0 if successful, or -1 on error
ab33e65c 439 */
2298f329 440int ustctl_get_cmsf(struct marker_status **cmsf, const pid_t pid)
772030fe 441{
72098143 442 struct ustcomm_header req_header, res_header;
08230db7 443 char *big_str = NULL;
72098143 444 int result, app_fd;
08230db7 445 struct marker_status *tmp_cmsf = NULL;
ef290fca
PMF
446 unsigned int i = 0, cmsf_ind = 0;
447
ab33e65c 448 if (cmsf == NULL) {
2a79ceeb 449 return -1;
ab33e65c 450 }
72098143
NC
451
452 if (ustcomm_connect_app(pid, &app_fd)) {
453 ERR("could not connect to PID %u", (unsigned int) pid);
454 return -1;
455 }
456
457 req_header.command = LIST_MARKERS;
458 req_header.size = 0;
459
460 result = ustcomm_send(app_fd, &req_header, NULL);
461 if (result <= 0) {
462 PERROR("error while requesting markers list for process %d", pid);
2a79ceeb 463 return -1;
ab33e65c
PP
464 }
465
72098143
NC
466 result = ustcomm_recv_alloc(app_fd, &res_header, &big_str);
467 if (result <= 0) {
468 ERR("error while receiving markers list");
469 return -1;
470 }
471
472 close(app_fd);
473
474 tmp_cmsf = (struct marker_status *) zmalloc(sizeof(struct marker_status) *
2298f329 475 (ustctl_count_nl(big_str) + 1));
ab33e65c 476 if (tmp_cmsf == NULL) {
dc46f6e6 477 ERR("Failed to allocate CMSF array");
2a79ceeb 478 return -1;
ab33e65c
PP
479 }
480
77957c95 481 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
ab33e65c 482 while (big_str[i] != '\0') {
ab33e65c 483 char state;
ef290fca 484
264f6231 485 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
72098143
NC
486 &tmp_cmsf[cmsf_ind].channel,
487 &tmp_cmsf[cmsf_ind].marker,
488 &state,
489 &tmp_cmsf[cmsf_ind].fs);
2298f329
NC
490 tmp_cmsf[cmsf_ind].state = (state == USTCTL_MS_CHR_ON ?
491 USTCTL_MS_ON : USTCTL_MS_OFF); /* Marker state */
ab33e65c
PP
492
493 while (big_str[i] != '\n') {
77957c95 494 ++i; /* Go to next '\n' */
ab33e65c 495 }
77957c95 496 ++i; /* Skip current pointed '\n' */
ab33e65c
PP
497 ++cmsf_ind;
498 }
499 tmp_cmsf[cmsf_ind].channel = NULL;
500 tmp_cmsf[cmsf_ind].marker = NULL;
501 tmp_cmsf[cmsf_ind].fs = NULL;
502
503 *cmsf = tmp_cmsf;
504
505 free(big_str);
506 return 0;
507}
508
a3adfb05
NC
509
510/**
511 * Frees a TES array.
512 *
513 * @param tes TES array to free
2298f329 514 * @return 0 if successful, or error USTCTL_ERR_ARG
a3adfb05 515 */
2298f329 516int ustctl_free_tes(struct trace_event_status *tes)
a3adfb05
NC
517{
518 if (tes == NULL) {
2298f329 519 return USTCTL_ERR_ARG;
a3adfb05
NC
520 }
521
522 unsigned int i = 0;
523 while (tes[i].name != NULL) {
524 free(tes[i].name);
525 ++i;
526 }
527 free(tes);
528
529 return 0;
530}
531
532/**
533 * Gets trace_events string for a given PID.
534 *
535 * @param tes Pointer to TES array to be filled (callee allocates, caller
2298f329 536 * frees with `ustctl_free_tes')
a3adfb05
NC
537 * @param pid Targeted PID
538 * @return 0 if successful, or -1 on error
539 */
2298f329 540int ustctl_get_tes(struct trace_event_status **tes,
72098143 541 const pid_t pid)
a3adfb05 542{
72098143 543 struct ustcomm_header req_header, res_header;
a3adfb05 544 char *big_str = NULL;
72098143 545 int result, app_fd;
a3adfb05
NC
546 struct trace_event_status *tmp_tes = NULL;
547 unsigned int i = 0, tes_ind = 0;
548
549 if (tes == NULL) {
550 return -1;
551 }
552
72098143
NC
553 if (ustcomm_connect_app(pid, &app_fd)) {
554 ERR("could not connect to PID %u", (unsigned int) pid);
555 return -1;
556 }
557
558 req_header.command = LIST_TRACE_EVENTS;
559 req_header.size = 0;
560
561 result = ustcomm_send(app_fd, &req_header, NULL);
562 if (result != 1) {
563 ERR("error while requesting trace_event list");
564 return -1;
565 }
566
567 result = ustcomm_recv_alloc(app_fd, &res_header, &big_str);
a3adfb05 568 if (result != 1) {
72098143 569 ERR("error while receiving markers list");
a3adfb05
NC
570 return -1;
571 }
572
72098143
NC
573 close(app_fd);
574
a3adfb05
NC
575 tmp_tes = (struct trace_event_status *)
576 zmalloc(sizeof(struct trace_event_status) *
2298f329 577 (ustctl_count_nl(big_str) + 1));
a3adfb05
NC
578 if (tmp_tes == NULL) {
579 ERR("Failed to allocate TES array");
580 return -1;
581 }
582
583 /* Parse received reply string (format: "[name]"): */
584 while (big_str[i] != '\0') {
a3adfb05 585 sscanf(big_str + i, "trace_event: %a[^\n]",
72098143 586 &tmp_tes[tes_ind].name);
a3adfb05
NC
587 while (big_str[i] != '\n') {
588 ++i; /* Go to next '\n' */
589 }
590 ++i; /* Skip current pointed '\n' */
591 ++tes_ind;
592 }
593 tmp_tes[tes_ind].name = NULL;
594
595 *tes = tmp_tes;
596
597 free(big_str);
598 return 0;
599}
600
b2fb2f91
AH
601/**
602 * Set socket path
603 *
604 * @param sock_path Socket path
605 * @param pid Traced process ID
606 * @return 0 if successful, or error
607 */
2298f329 608int ustctl_set_sock_path(const char *sock_path, pid_t pid)
b2fb2f91 609{
28c1bb40 610 int result;
72098143 611 struct ustcomm_header req_header, res_header;
28c1bb40 612 struct ustcomm_single_field sock_path_msg;
72098143 613
28c1bb40
NC
614 result = ustcomm_pack_single_field(&req_header,
615 &sock_path_msg,
616 sock_path);
617 if (result < 0) {
618 errno = -result;
08b8805e
DG
619 return -1;
620 }
b2fb2f91 621
72098143 622 req_header.command = SET_SOCK_PATH;
b2fb2f91 623
72098143
NC
624 return do_cmd(pid, &req_header, (char *)&sock_path_msg,
625 &res_header, NULL);
b2fb2f91
AH
626}
627
628/**
629 * Get socket path
630 *
631 * @param sock_path Pointer to where the socket path will be returned
632 * @param pid Traced process ID
633 * @return 0 if successful, or error
634 */
2298f329 635int ustctl_get_sock_path(char **sock_path, pid_t pid)
b2fb2f91 636{
b2fb2f91 637 int result;
72098143 638 struct ustcomm_header req_header, res_header;
28c1bb40 639 struct ustcomm_single_field *sock_path_msg;
72098143
NC
640
641 req_header.command = GET_SOCK_PATH;
642 req_header.size = 0;
b2fb2f91 643
72098143
NC
644 result = do_cmd(pid, &req_header, NULL, &res_header,
645 (char **)&sock_path_msg);
646 if (result < 0) {
647 return -1;
08b8805e 648 }
b2fb2f91 649
28c1bb40 650 result = ustcomm_unpack_single_field(sock_path_msg);
72098143
NC
651 if (result < 0) {
652 return result;
b2fb2f91
AH
653 }
654
28c1bb40 655 *sock_path = strdup(sock_path_msg->field);
b2fb2f91 656
72098143 657 free(sock_path_msg);
b9318b35
AH
658
659 return 0;
660}
661
2298f329 662int ustctl_force_switch(pid_t pid)
772030fe 663{
72098143 664 struct ustcomm_header req_header, res_header;
ab33e65c 665
72098143
NC
666 req_header.command = FORCE_SUBBUF_SWITCH;
667 req_header.size = 0;
ab33e65c 668
72098143 669 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c 670}
72098143 671
This page took 0.062191 seconds and 4 git commands to generate.