create libustd from ustd
[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"
28#include "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]);
ab33e65c
PP
55 if (pid_is_online(ret[i])) {
56 ret_size += sizeof(pid_t);
08230db7 57 ret = (pid_t *) realloc(ret, ret_size);
ab33e65c
PP
58 ++i;
59 }
60 }
61 }
62
77957c95 63 ret[i] = 0; /* Array end */
ab33e65c 64
08230db7
PMF
65 if (ret[0] == 0) {
66 /* No PID at all */
ab33e65c
PP
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 */
08230db7 83int ustcmd_set_marker_state(const char *mn, int state, pid_t pid)
ef290fca 84{
08230db7
PMF
85 char *cmd_str [] = {"disable_marker", "enable_marker"};
86 char *cmd;
ef290fca
PMF
87 int result;
88
ab33e65c
PP
89 if (mn == NULL) {
90 return USTCMD_ERR_ARG;
91 }
92
ab33e65c
PP
93 asprintf(&cmd, "%s %s", cmd_str[state], mn);
94
08230db7 95 result = ustcmd_send_cmd(cmd, pid, NULL);
ef290fca 96 if (result) {
ab33e65c
PP
97 free(cmd);
98 return USTCMD_ERR_GEN;
99 }
100
101 free(cmd);
102 return 0;
103}
104
763f41e5
DS
105/**
106 * Set subbuffer size.
107 *
108 * @param channel_size Channel name and size
109 * @param pid Traced process ID
110 * @return 0 if successful, or error
111 */
112int ustcmd_set_subbuf_size(const char *channel_size, pid_t pid)
113{
114 char *cmd;
115 int result;
116
117 asprintf(&cmd, "%s %s", "set_subbuf_size", channel_size);
118
119 result = ustcmd_send_cmd(cmd, pid, NULL);
2a79ceeb 120 if (result != 1) {
763f41e5
DS
121 free(cmd);
122 return 1;
123 }
124
125 free(cmd);
126 return 0;
127}
128
129/**
130 * Set subbuffer num.
131 *
132 * @param channel_num Channel name and num
133 * @param pid Traced process ID
134 * @return 0 if successful, or error
135 */
136int ustcmd_set_subbuf_num(const char *channel_size, pid_t pid)
137{
138 char *cmd;
139 int result;
140
141 asprintf(&cmd, "%s %s", "set_subbuf_num", channel_size);
142
143 result = ustcmd_send_cmd(cmd, pid, NULL);
2a79ceeb 144 if (result != 1) {
763f41e5
DS
145 free(cmd);
146 return 1;
147 }
148
149 free(cmd);
150 return 0;
151}
152
e77b8e8e
DS
153/**
154 * Get subbuffer size.
155 *
156 * @param channel Channel name
157 * @param pid Traced process ID
158 * @return subbuf size if successful, or error
159 */
160int ustcmd_get_subbuf_size(const char *channel, pid_t pid)
161{
162 char *cmd, *reply;
163 int result;
164
165 /* format: channel_cpu */
166 asprintf(&cmd, "%s %s_0", "get_subbuf_size", channel);
167
168 result = ustcmd_send_cmd(cmd, pid, &reply);
169 if (result) {
170 free(cmd);
171 free(reply);
172 return -1;
173 }
174
175 result = atoi(reply);
176 free(cmd);
177 free(reply);
178 return result;
179}
180
181/**
182 * Get subbuffer num.
183 *
184 * @param channel Channel name
185 * @param pid Traced process ID
186 * @return subbuf cnf if successful, or error
187 */
188int ustcmd_get_subbuf_num(const char *channel, pid_t pid)
189{
190 char *cmd, *reply;
191 int result;
192
193 /* format: channel_cpu */
194 asprintf(&cmd, "%s %s_0", "get_n_subbufs", channel);
195
196 result = ustcmd_send_cmd(cmd, pid, &reply);
197 if (result) {
198 free(cmd);
199 free(reply);
200 return -1;
201 }
202
203 result = atoi(reply);
204 free(cmd);
205 free(reply);
206 return result;
207}
763f41e5 208
ab33e65c
PP
209/**
210 * Destroys an UST trace according to a PID.
211 *
212 * @param pid Traced process ID
213 * @return 0 if successful, or error USTCMD_ERR_GEN
214 */
772030fe
PMF
215int ustcmd_destroy_trace(pid_t pid)
216{
217 int result;
ab33e65c 218
b5b073e2 219 result = ustcmd_send_cmd("trace_destroy", pid, NULL);
2a79ceeb 220 if (result != 1) {
ab33e65c
PP
221 return USTCMD_ERR_GEN;
222 }
223
224 return 0;
225}
226
227/**
228 * Starts an UST trace (and setups it) according to a PID.
229 *
230 * @param pid Traced process ID
231 * @return 0 if successful, or error USTCMD_ERR_GEN
232 */
772030fe
PMF
233int ustcmd_setup_and_start(pid_t pid)
234{
235 int result;
ab33e65c 236
08230db7 237 result = ustcmd_send_cmd("start", pid, NULL);
2a79ceeb 238 if (result != 1) {
ab33e65c
PP
239 return USTCMD_ERR_GEN;
240 }
241
242 return 0;
243}
244
62ec620f
PMF
245/**
246 * Creates an UST trace according to a PID.
247 *
248 * @param pid Traced process ID
249 * @return 0 if successful, or error USTCMD_ERR_GEN
250 */
251int ustcmd_create_trace(pid_t pid)
252{
253 int result;
254
255 result = ustcmd_send_cmd("trace_create", pid, NULL);
2a79ceeb 256 if (result != 1) {
62ec620f
PMF
257 return USTCMD_ERR_GEN;
258 }
259
260 return 0;
261}
262
ab33e65c
PP
263/**
264 * Starts 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 */
772030fe
PMF
269int ustcmd_start_trace(pid_t pid)
270{
271 int result;
ab33e65c 272
08230db7 273 result = ustcmd_send_cmd("trace_start", pid, NULL);
2a79ceeb 274 if (result != 1) {
ab33e65c
PP
275 return USTCMD_ERR_GEN;
276 }
277
278 return 0;
279}
280
763f41e5
DS
281/**
282 * Alloc 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 */
287int ustcmd_alloc_trace(pid_t pid)
288{
289 int result;
290
291 result = ustcmd_send_cmd("trace_alloc", pid, NULL);
2a79ceeb 292 if (result != 1) {
763f41e5
DS
293 return USTCMD_ERR_GEN;
294 }
295
296 return 0;
297}
298
ab33e65c
PP
299/**
300 * Stops 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 */
772030fe
PMF
305int ustcmd_stop_trace(pid_t pid)
306{
307 int result;
ab33e65c 308
08230db7 309 result = ustcmd_send_cmd("trace_stop", pid, NULL);
2a79ceeb 310 if (result != 1) {
ab33e65c
PP
311 return USTCMD_ERR_GEN;
312 }
313
314 return 0;
315}
316
317/**
318 * Counts newlines ('\n') in a string.
319 *
320 * @param str String to search in
321 * @return Total newlines count
322 */
08230db7 323unsigned int ustcmd_count_nl(const char *str)
772030fe 324{
ab33e65c
PP
325 unsigned int i = 0, tot = 0;
326
327 while (str[i] != '\0') {
328 if (str[i] == '\n') {
329 ++tot;
330 }
331 ++i;
332 }
333
334 return tot;
335}
336
337/**
338 * Frees a CMSF array.
339 *
340 * @param cmsf CMSF array to free
341 * @return 0 if successful, or error USTCMD_ERR_ARG
342 */
08230db7 343int ustcmd_free_cmsf(struct marker_status *cmsf)
772030fe 344{
ab33e65c
PP
345 if (cmsf == NULL) {
346 return USTCMD_ERR_ARG;
347 }
348
349 unsigned int i = 0;
350 while (cmsf[i].channel != NULL) {
351 free(cmsf[i].channel);
352 free(cmsf[i].marker);
353 free(cmsf[i].fs);
354 ++i;
355 }
356 free(cmsf);
357
358 return 0;
359}
360
361/**
362 * Gets channel/marker/state/format string for a given PID.
363 *
364 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
365 * frees with `ustcmd_free_cmsf')
366 * @param pid Targeted PID
2a79ceeb 367 * @return 0 if successful, or -1 on error
ab33e65c 368 */
08230db7 369int ustcmd_get_cmsf(struct marker_status **cmsf, const pid_t pid)
772030fe 370{
08230db7 371 char *big_str = NULL;
ef290fca 372 int result;
08230db7 373 struct marker_status *tmp_cmsf = NULL;
ef290fca
PMF
374 unsigned int i = 0, cmsf_ind = 0;
375
ab33e65c 376 if (cmsf == NULL) {
2a79ceeb 377 return -1;
ab33e65c 378 }
08230db7 379 result = ustcmd_send_cmd("list_markers", pid, &big_str);
2a79ceeb
PMF
380 if (result != 1) {
381 return -1;
ab33e65c
PP
382 }
383
2a79ceeb
PMF
384 if (result != 1) {
385 ERR("error while getting markers list");
386 return -1;
ab33e65c
PP
387 }
388
08230db7 389 tmp_cmsf = (struct marker_status *) malloc(sizeof(struct marker_status) *
ab33e65c
PP
390 (ustcmd_count_nl(big_str) + 1));
391 if (tmp_cmsf == NULL) {
2a79ceeb 392 return -1;
ab33e65c
PP
393 }
394
77957c95 395 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
ab33e65c 396 while (big_str[i] != '\0') {
ab33e65c 397 char state;
ef290fca 398
264f6231 399 sscanf(big_str + i, "marker: %a[^/]/%a[^ ] %c %a[^\n]",
ab33e65c
PP
400 &tmp_cmsf[cmsf_ind].channel,
401 &tmp_cmsf[cmsf_ind].marker,
402 &state,
403 &tmp_cmsf[cmsf_ind].fs);
404 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
77957c95 405 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
ab33e65c
PP
406
407 while (big_str[i] != '\n') {
77957c95 408 ++i; /* Go to next '\n' */
ab33e65c 409 }
77957c95 410 ++i; /* Skip current pointed '\n' */
ab33e65c
PP
411 ++cmsf_ind;
412 }
413 tmp_cmsf[cmsf_ind].channel = NULL;
414 tmp_cmsf[cmsf_ind].marker = NULL;
415 tmp_cmsf[cmsf_ind].fs = NULL;
416
417 *cmsf = tmp_cmsf;
418
419 free(big_str);
420 return 0;
421}
422
423/**
2a79ceeb 424 * Sends a given command to a traceable process
ab33e65c 425 *
2a79ceeb 426 * @param cmd Null-terminated command to send
ab33e65c
PP
427 * @param pid Targeted PID
428 * @param reply Pointer to string to be filled with a reply string (must
429 * be NULL if no reply is needed for the given command).
2a79ceeb 430 * @return -1 if successful, 0 on EOT, 1 on success
ab33e65c 431 */
772030fe 432
08230db7 433int ustcmd_send_cmd(const char *cmd, const pid_t pid, char **reply)
772030fe
PMF
434{
435 struct ustcomm_connection conn;
2a79ceeb 436 int retval;
ab33e65c 437
ab33e65c 438 if (ustcomm_connect_app(pid, &conn)) {
2a79ceeb
PMF
439 ERR("could not connect to PID %u", (unsigned int) pid);
440 return -1;
ab33e65c
PP
441 }
442
2a79ceeb 443 retval = ustcomm_send_request(&conn, cmd, reply);
ab33e65c 444
2a79ceeb
PMF
445 ustcomm_close_app(&conn);
446
447 return retval;
ab33e65c 448}
This page took 0.070771 seconds and 4 git commands to generate.