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