Introduce a new communication protocol for UST v5
[ust.git] / libustcmd / ustcmd.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"
d6c9f207 28#include "ust/ustcmd.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
08230db7 86pid_t *ustcmd_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 &&
72098143 107 !!strcmp(dirent->d_name, "ustd")) {
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/**
136 * Sets marker state (USTCMD_MS_ON or USTCMD_MS_OFF).
137 *
138 * @param mn Marker name
139 * @param state Marker's new state
140 * @param pid Traced process ID
141 * @return 0 if successful, or errors {USTCMD_ERR_GEN, USTCMD_ERR_ARG}
142 */
72098143
NC
143int ustcmd_set_marker_state(const char *channel, const char *marker,
144 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,
152 channel,
153 marker);
154 if (result < 0) {
155 errno = -result;
156 return -1;
08b8805e 157 }
ab33e65c 158
72098143 159 req_header.command = state ? ENABLE_MARKER : DISABLE_MARKER;
ab33e65c 160
72098143
NC
161 return do_cmd(pid, &req_header, (char *)&marker_inf,
162 &res_header, NULL);
ab33e65c
PP
163}
164
763f41e5
DS
165/**
166 * Set subbuffer size.
167 *
168 * @param channel_size Channel name and size
169 * @param pid Traced process ID
170 * @return 0 if successful, or error
171 */
72098143
NC
172int ustcmd_set_subbuf_size(const char *channel, unsigned int subbuf_size,
173 pid_t pid)
763f41e5 174{
72098143
NC
175 struct ustcomm_header req_header, res_header;
176 struct ustcomm_channel_info ch_inf;
763f41e5
DS
177 int result;
178
72098143
NC
179 result = ustcomm_pack_channel_info(&req_header,
180 &ch_inf,
181 channel);
182 if (result < 0) {
183 errno = -result;
08b8805e
DG
184 return -1;
185 }
763f41e5 186
72098143
NC
187 req_header.command = SET_SUBBUF_SIZE;
188 ch_inf.subbuf_size = subbuf_size;
763f41e5 189
72098143
NC
190 return do_cmd(pid, &req_header, (char *)&ch_inf,
191 &res_header, NULL);
763f41e5
DS
192}
193
194/**
195 * Set subbuffer num.
196 *
197 * @param channel_num Channel name and num
198 * @param pid Traced process ID
199 * @return 0 if successful, or error
200 */
72098143
NC
201int ustcmd_set_subbuf_num(const char *channel, unsigned int num,
202 pid_t pid)
763f41e5 203{
72098143
NC
204 struct ustcomm_header req_header, res_header;
205 struct ustcomm_channel_info ch_inf;
763f41e5
DS
206 int result;
207
72098143
NC
208 result = ustcomm_pack_channel_info(&req_header,
209 &ch_inf,
210 channel);
211 if (result < 0) {
212 errno = -result;
08b8805e
DG
213 return -1;
214 }
763f41e5 215
72098143
NC
216 req_header.command = SET_SUBBUF_NUM;
217 ch_inf.subbuf_num = num;
218
219 return do_cmd(pid, &req_header, (char *)&ch_inf,
220 &res_header, NULL);
763f41e5 221
763f41e5
DS
222}
223
72098143
NC
224static int ustcmd_get_subbuf_num_size(const char *channel, pid_t pid,
225 int *num, int *size)
e77b8e8e 226{
72098143
NC
227 struct ustcomm_header req_header, res_header;
228 struct ustcomm_channel_info ch_inf, *ch_inf_res;
e77b8e8e
DS
229 int result;
230
72098143
NC
231
232 result = ustcomm_pack_channel_info(&req_header,
233 &ch_inf,
234 channel);
235 if (result < 0) {
236 errno = -result;
08b8805e
DG
237 return -1;
238 }
e77b8e8e 239
72098143
NC
240 req_header.command = GET_SUBBUF_NUM_SIZE;
241
242 result = do_cmd(pid, &req_header, (char *)&ch_inf,
243 &res_header, (char **)&ch_inf_res);
244 if (result < 0) {
e77b8e8e
DS
245 return -1;
246 }
247
72098143
NC
248 *num = ch_inf_res->subbuf_num;
249 *size = ch_inf_res->subbuf_size;
250
251 free(ch_inf_res);
252
253 return 0;
e77b8e8e
DS
254}
255
256/**
257 * Get subbuffer num.
258 *
259 * @param channel Channel name
260 * @param pid Traced process ID
261 * @return subbuf cnf if successful, or error
262 */
263int ustcmd_get_subbuf_num(const char *channel, pid_t pid)
264{
72098143 265 int num, size, result;
e77b8e8e 266
72098143
NC
267 result = ustcmd_get_subbuf_num_size(channel, pid,
268 &num, &size);
269 if (result < 0) {
270 errno = -result;
08b8805e
DG
271 return -1;
272 }
e77b8e8e 273
72098143
NC
274 return num;
275}
276
277/**
278 * Get subbuffer size.
279 *
280 * @param channel Channel name
281 * @param pid Traced process ID
282 * @return subbuf size if successful, or error
283 */
284int ustcmd_get_subbuf_size(const char *channel, pid_t pid)
285{
286 int num, size, result;
287
288 result = ustcmd_get_subbuf_num_size(channel, pid,
289 &num, &size);
290 if (result < 0) {
291 errno = -result;
e77b8e8e
DS
292 return -1;
293 }
294
72098143 295 return size;
e77b8e8e 296}
763f41e5 297
ab33e65c
PP
298/**
299 * Destroys an UST trace according to a PID.
300 *
301 * @param pid Traced process ID
302 * @return 0 if successful, or error USTCMD_ERR_GEN
303 */
772030fe
PMF
304int ustcmd_destroy_trace(pid_t pid)
305{
72098143 306 struct ustcomm_header req_header, res_header;
ab33e65c 307
72098143
NC
308 req_header.command = DESTROY_TRACE;
309 req_header.size = 0;
ab33e65c 310
72098143 311 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c
PP
312}
313
314/**
315 * Starts an UST trace (and setups it) according to a PID.
316 *
317 * @param pid Traced process ID
318 * @return 0 if successful, or error USTCMD_ERR_GEN
319 */
772030fe
PMF
320int ustcmd_setup_and_start(pid_t pid)
321{
72098143 322 struct ustcomm_header req_header, res_header;
ab33e65c 323
72098143
NC
324 req_header.command = START;
325 req_header.size = 0;
ab33e65c 326
72098143 327 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c
PP
328}
329
62ec620f
PMF
330/**
331 * Creates an UST trace according to a PID.
332 *
333 * @param pid Traced process ID
334 * @return 0 if successful, or error USTCMD_ERR_GEN
335 */
336int ustcmd_create_trace(pid_t pid)
337{
72098143 338 struct ustcomm_header req_header, res_header;
62ec620f 339
72098143
NC
340 req_header.command = CREATE_TRACE;
341 req_header.size = 0;
62ec620f 342
72098143 343 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
62ec620f
PMF
344}
345
ab33e65c
PP
346/**
347 * Starts an UST trace according to a PID.
348 *
349 * @param pid Traced process ID
350 * @return 0 if successful, or error USTCMD_ERR_GEN
351 */
772030fe
PMF
352int ustcmd_start_trace(pid_t pid)
353{
72098143 354 struct ustcomm_header req_header, res_header;
ab33e65c 355
72098143
NC
356 req_header.command = START_TRACE;
357 req_header.size = 0;
ab33e65c 358
72098143 359 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c
PP
360}
361
763f41e5
DS
362/**
363 * Alloc an UST trace according to a PID.
364 *
365 * @param pid Traced process ID
366 * @return 0 if successful, or error USTCMD_ERR_GEN
367 */
368int ustcmd_alloc_trace(pid_t pid)
369{
72098143 370 struct ustcomm_header req_header, res_header;
763f41e5 371
72098143
NC
372 req_header.command = ALLOC_TRACE;
373 req_header.size = 0;
763f41e5 374
72098143 375 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
763f41e5
DS
376}
377
ab33e65c
PP
378/**
379 * Stops an UST trace according to a PID.
380 *
381 * @param pid Traced process ID
382 * @return 0 if successful, or error USTCMD_ERR_GEN
383 */
772030fe
PMF
384int ustcmd_stop_trace(pid_t pid)
385{
72098143 386 struct ustcomm_header req_header, res_header;
ab33e65c 387
72098143
NC
388 req_header.command = STOP_TRACE;
389 req_header.size = 0;
ab33e65c 390
72098143 391 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c
PP
392}
393
394/**
395 * Counts newlines ('\n') in a string.
396 *
397 * @param str String to search in
398 * @return Total newlines count
399 */
08230db7 400unsigned int ustcmd_count_nl(const char *str)
772030fe 401{
ab33e65c
PP
402 unsigned int i = 0, tot = 0;
403
404 while (str[i] != '\0') {
405 if (str[i] == '\n') {
406 ++tot;
407 }
408 ++i;
409 }
410
411 return tot;
412}
413
414/**
415 * Frees a CMSF array.
416 *
417 * @param cmsf CMSF array to free
418 * @return 0 if successful, or error USTCMD_ERR_ARG
419 */
08230db7 420int ustcmd_free_cmsf(struct marker_status *cmsf)
772030fe 421{
ab33e65c
PP
422 if (cmsf == NULL) {
423 return USTCMD_ERR_ARG;
424 }
425
426 unsigned int i = 0;
427 while (cmsf[i].channel != NULL) {
428 free(cmsf[i].channel);
429 free(cmsf[i].marker);
430 free(cmsf[i].fs);
431 ++i;
432 }
433 free(cmsf);
434
435 return 0;
436}
437
438/**
439 * Gets channel/marker/state/format string for a given PID.
440 *
441 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
442 * frees with `ustcmd_free_cmsf')
443 * @param pid Targeted PID
2a79ceeb 444 * @return 0 if successful, or -1 on error
ab33e65c 445 */
08230db7 446int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid)
772030fe 447{
72098143 448 struct ustcomm_header req_header, res_header;
08230db7 449 char *big_str = NULL;
72098143 450 int result, app_fd;
08230db7 451 struct marker_status *tmp_cmsf = NULL;
ef290fca
PMF
452 unsigned int i = 0, cmsf_ind = 0;
453
ab33e65c 454 if (cmsf == NULL) {
2a79ceeb 455 return -1;
ab33e65c 456 }
72098143
NC
457
458 if (ustcomm_connect_app(pid, &app_fd)) {
459 ERR("could not connect to PID %u", (unsigned int) pid);
460 return -1;
461 }
462
463 req_header.command = LIST_MARKERS;
464 req_header.size = 0;
465
466 result = ustcomm_send(app_fd, &req_header, NULL);
467 if (result <= 0) {
468 PERROR("error while requesting markers list for process %d", pid);
2a79ceeb 469 return -1;
ab33e65c
PP
470 }
471
72098143
NC
472 result = ustcomm_recv_alloc(app_fd, &res_header, &big_str);
473 if (result <= 0) {
474 ERR("error while receiving markers list");
475 return -1;
476 }
477
478 close(app_fd);
479
480 tmp_cmsf = (struct marker_status *) zmalloc(sizeof(struct marker_status) *
481 (ustcmd_count_nl(big_str) + 1));
ab33e65c 482 if (tmp_cmsf == NULL) {
dc46f6e6 483 ERR("Failed to allocate CMSF array");
2a79ceeb 484 return -1;
ab33e65c
PP
485 }
486
77957c95 487 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
ab33e65c 488 while (big_str[i] != '\0') {
ab33e65c 489 char state;
ef290fca 490
264f6231 491 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
72098143
NC
492 &tmp_cmsf[cmsf_ind].channel,
493 &tmp_cmsf[cmsf_ind].marker,
494 &state,
495 &tmp_cmsf[cmsf_ind].fs);
ab33e65c 496 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
72098143 497 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
ab33e65c
PP
498
499 while (big_str[i] != '\n') {
77957c95 500 ++i; /* Go to next '\n' */
ab33e65c 501 }
77957c95 502 ++i; /* Skip current pointed '\n' */
ab33e65c
PP
503 ++cmsf_ind;
504 }
505 tmp_cmsf[cmsf_ind].channel = NULL;
506 tmp_cmsf[cmsf_ind].marker = NULL;
507 tmp_cmsf[cmsf_ind].fs = NULL;
508
509 *cmsf = tmp_cmsf;
510
511 free(big_str);
512 return 0;
513}
514
a3adfb05
NC
515
516/**
517 * Frees a TES array.
518 *
519 * @param tes TES array to free
520 * @return 0 if successful, or error USTCMD_ERR_ARG
521 */
522int ustcmd_free_tes(struct trace_event_status *tes)
523{
524 if (tes == NULL) {
525 return USTCMD_ERR_ARG;
526 }
527
528 unsigned int i = 0;
529 while (tes[i].name != NULL) {
530 free(tes[i].name);
531 ++i;
532 }
533 free(tes);
534
535 return 0;
536}
537
538/**
539 * Gets trace_events string for a given PID.
540 *
541 * @param tes Pointer to TES array to be filled (callee allocates, caller
542 * frees with `ustcmd_free_tes')
543 * @param pid Targeted PID
544 * @return 0 if successful, or -1 on error
545 */
546int ustcmd_get_tes(struct trace_event_status **tes,
72098143 547 const pid_t pid)
a3adfb05 548{
72098143 549 struct ustcomm_header req_header, res_header;
a3adfb05 550 char *big_str = NULL;
72098143 551 int result, app_fd;
a3adfb05
NC
552 struct trace_event_status *tmp_tes = NULL;
553 unsigned int i = 0, tes_ind = 0;
554
555 if (tes == NULL) {
556 return -1;
557 }
558
72098143
NC
559 if (ustcomm_connect_app(pid, &app_fd)) {
560 ERR("could not connect to PID %u", (unsigned int) pid);
561 return -1;
562 }
563
564 req_header.command = LIST_TRACE_EVENTS;
565 req_header.size = 0;
566
567 result = ustcomm_send(app_fd, &req_header, NULL);
568 if (result != 1) {
569 ERR("error while requesting trace_event list");
570 return -1;
571 }
572
573 result = ustcomm_recv_alloc(app_fd, &res_header, &big_str);
a3adfb05 574 if (result != 1) {
72098143 575 ERR("error while receiving markers list");
a3adfb05
NC
576 return -1;
577 }
578
72098143
NC
579 close(app_fd);
580
a3adfb05
NC
581 tmp_tes = (struct trace_event_status *)
582 zmalloc(sizeof(struct trace_event_status) *
583 (ustcmd_count_nl(big_str) + 1));
584 if (tmp_tes == NULL) {
585 ERR("Failed to allocate TES array");
586 return -1;
587 }
588
589 /* Parse received reply string (format: "[name]"): */
590 while (big_str[i] != '\0') {
a3adfb05 591 sscanf(big_str + i, "trace_event: %a[^\n]",
72098143 592 &tmp_tes[tes_ind].name);
a3adfb05
NC
593 while (big_str[i] != '\n') {
594 ++i; /* Go to next '\n' */
595 }
596 ++i; /* Skip current pointed '\n' */
597 ++tes_ind;
598 }
599 tmp_tes[tes_ind].name = NULL;
600
601 *tes = tmp_tes;
602
603 free(big_str);
604 return 0;
605}
606
b2fb2f91
AH
607/**
608 * Set socket path
609 *
610 * @param sock_path Socket path
611 * @param pid Traced process ID
612 * @return 0 if successful, or error
613 */
614int ustcmd_set_sock_path(const char *sock_path, pid_t pid)
615{
72098143
NC
616 int offset = 0;
617 struct ustcomm_header req_header, res_header;
618 struct ustcomm_sock_path sock_path_msg;
619
620 sock_path_msg.sock_path = ustcomm_print_data(sock_path_msg.data,
621 sizeof(sock_path_msg.data),
622 &offset,
623 sock_path);
624 if (sock_path_msg.sock_path == USTCOMM_POISON_PTR) {
08b8805e
DG
625 return -1;
626 }
b2fb2f91 627
72098143
NC
628 req_header.command = SET_SOCK_PATH;
629 req_header.size = COMPUTE_MSG_SIZE(&sock_path_msg, offset);
b2fb2f91 630
72098143
NC
631 return do_cmd(pid, &req_header, (char *)&sock_path_msg,
632 &res_header, NULL);
b2fb2f91
AH
633}
634
635/**
636 * Get socket path
637 *
638 * @param sock_path Pointer to where the socket path will be returned
639 * @param pid Traced process ID
640 * @return 0 if successful, or error
641 */
642int ustcmd_get_sock_path(char **sock_path, pid_t pid)
643{
b2fb2f91 644 int result;
72098143
NC
645 struct ustcomm_header req_header, res_header;
646 struct ustcomm_sock_path *sock_path_msg;
647
648 req_header.command = GET_SOCK_PATH;
649 req_header.size = 0;
b2fb2f91 650
72098143
NC
651 result = do_cmd(pid, &req_header, NULL, &res_header,
652 (char **)&sock_path_msg);
653 if (result < 0) {
654 return -1;
08b8805e 655 }
b2fb2f91 656
72098143
NC
657 result = ustcomm_unpack_sock_path(sock_path_msg);
658 if (result < 0) {
659 return result;
b2fb2f91
AH
660 }
661
72098143 662 *sock_path = strdup(sock_path_msg->sock_path);
b2fb2f91 663
72098143 664 free(sock_path_msg);
b9318b35
AH
665
666 return 0;
667}
668
72098143 669int ustcmd_force_switch(pid_t pid)
772030fe 670{
72098143 671 struct ustcomm_header req_header, res_header;
ab33e65c 672
72098143
NC
673 req_header.command = FORCE_SUBBUF_SWITCH;
674 req_header.size = 0;
ab33e65c 675
72098143 676 return do_cmd(pid, &req_header, NULL, &res_header, NULL);
ab33e65c 677}
72098143 678
This page took 0.060713 seconds and 4 git commands to generate.