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