code cleanups
[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"
29
30#define _GNU_SOURCE
31
772030fe
PMF
32pid_t* ustcmd_get_online_pids(void)
33{
ab33e65c
PP
34 struct dirent* dirent;
35 DIR* dir;
ef290fca 36 unsigned int ret_size = 1 * sizeof(pid_t), i = 0;
ab33e65c
PP
37
38 dir = opendir(SOCK_DIR);
39 if (!dir) {
40 return NULL;
41 }
42
ab33e65c
PP
43 pid_t* ret = (pid_t*) malloc(ret_size);
44
772030fe 45 while ((dirent = readdir(dir))) {
ab33e65c
PP
46 if (!strcmp(dirent->d_name, ".") ||
47 !strcmp(dirent->d_name, "..")) {
48
49 continue;
50 }
51
52 if (dirent->d_type != DT_DIR &&
53 !!strcmp(dirent->d_name, "ustd")) {
54
55 sscanf(dirent->d_name, "%u", (unsigned int*) &ret[i]);
56 if (pid_is_online(ret[i])) {
57 ret_size += sizeof(pid_t);
58 ret = (pid_t*) realloc(ret, ret_size);
59 ++i;
60 }
61 }
62 }
63
77957c95 64 ret[i] = 0; /* Array end */
ab33e65c 65
77957c95 66 if (ret[0] == 0) { /* 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 */
ef290fca
PMF
83int ustcmd_set_marker_state(const char* mn, int state, pid_t pid)
84{
85 char* cmd_str [] = {"disable_marker", "enable_marker"};
86 char* cmd;
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
ef290fca
PMF
95 result = ustcmd_shoot(cmd, pid, NULL);
96 if (result) {
ab33e65c
PP
97 free(cmd);
98 return USTCMD_ERR_GEN;
99 }
100
101 free(cmd);
102 return 0;
103}
104
105/**
106 * Destroys an UST trace according to a PID.
107 *
108 * @param pid Traced process ID
109 * @return 0 if successful, or error USTCMD_ERR_GEN
110 */
772030fe
PMF
111int ustcmd_destroy_trace(pid_t pid)
112{
113 int result;
ab33e65c 114
772030fe
PMF
115 result = ustcmd_shoot("destroy", pid, NULL);
116 if (result) {
ab33e65c
PP
117 return USTCMD_ERR_GEN;
118 }
119
120 return 0;
121}
122
123/**
124 * Starts an UST trace (and setups it) according to a PID.
125 *
126 * @param pid Traced process ID
127 * @return 0 if successful, or error USTCMD_ERR_GEN
128 */
772030fe
PMF
129int ustcmd_setup_and_start(pid_t pid)
130{
131 int result;
ab33e65c 132
772030fe
PMF
133 result = ustcmd_shoot("start", pid, NULL);
134 if (result) {
ab33e65c
PP
135 return USTCMD_ERR_GEN;
136 }
137
138 return 0;
139}
140
141/**
142 * Starts an UST trace according to a PID.
143 *
144 * @param pid Traced process ID
145 * @return 0 if successful, or error USTCMD_ERR_GEN
146 */
772030fe
PMF
147int ustcmd_start_trace(pid_t pid)
148{
149 int result;
ab33e65c 150
772030fe
PMF
151 result = ustcmd_shoot("trace_start", pid, NULL);
152 if (result) {
ab33e65c
PP
153 return USTCMD_ERR_GEN;
154 }
155
156 return 0;
157}
158
159/**
160 * Stops an UST trace according to a PID.
161 *
162 * @param pid Traced process ID
163 * @return 0 if successful, or error USTCMD_ERR_GEN
164 */
772030fe
PMF
165int ustcmd_stop_trace(pid_t pid)
166{
167 int result;
ab33e65c 168
772030fe
PMF
169 result = ustcmd_shoot("trace_stop", pid, NULL);
170 if (result) {
ab33e65c
PP
171 return USTCMD_ERR_GEN;
172 }
173
174 return 0;
175}
176
177/**
178 * Counts newlines ('\n') in a string.
179 *
180 * @param str String to search in
181 * @return Total newlines count
182 */
772030fe
PMF
183unsigned int ustcmd_count_nl(const char* str)
184{
ab33e65c
PP
185 unsigned int i = 0, tot = 0;
186
187 while (str[i] != '\0') {
188 if (str[i] == '\n') {
189 ++tot;
190 }
191 ++i;
192 }
193
194 return tot;
195}
196
197/**
198 * Frees a CMSF array.
199 *
200 * @param cmsf CMSF array to free
201 * @return 0 if successful, or error USTCMD_ERR_ARG
202 */
772030fe
PMF
203int ustcmd_free_cmsf(struct USTcmd_cmsf* cmsf)
204{
ab33e65c
PP
205 if (cmsf == NULL) {
206 return USTCMD_ERR_ARG;
207 }
208
209 unsigned int i = 0;
210 while (cmsf[i].channel != NULL) {
211 free(cmsf[i].channel);
212 free(cmsf[i].marker);
213 free(cmsf[i].fs);
214 ++i;
215 }
216 free(cmsf);
217
218 return 0;
219}
220
221/**
222 * Gets channel/marker/state/format string for a given PID.
223 *
224 * @param cmsf Pointer to CMSF array to be filled (callee allocates, caller
225 * frees with `ustcmd_free_cmsf')
226 * @param pid Targeted PID
227 * @return 0 if successful, or errors {USTCMD_ERR_ARG, USTCMD_ERR_GEN}
228 */
772030fe
PMF
229int ustcmd_get_cmsf(struct USTcmd_cmsf** cmsf, const pid_t pid)
230{
ef290fca
PMF
231 char* big_str = NULL;
232 int result;
233 struct USTcmd_cmsf* tmp_cmsf = NULL;
234 unsigned int i = 0, cmsf_ind = 0;
235
ab33e65c
PP
236 if (cmsf == NULL) {
237 return USTCMD_ERR_ARG;
238 }
ef290fca
PMF
239 result = ustcmd_shoot("list_markers", pid, &big_str);
240 if (result) {
ab33e65c
PP
241 return USTCMD_ERR_GEN;
242 }
243
244 if (big_str == NULL) {
245 fprintf(stderr, "ustcmd: error while getting markers list\n");
246 return USTCMD_ERR_GEN;
247 }
248
ab33e65c
PP
249 tmp_cmsf = (struct USTcmd_cmsf*) malloc(sizeof(struct USTcmd_cmsf) *
250 (ustcmd_count_nl(big_str) + 1));
251 if (tmp_cmsf == NULL) {
252 return USTCMD_ERR_GEN;
253 }
254
77957c95 255 /* Parse received reply string (format: "[chan]/[mark] [st] [fs]"): */
ab33e65c 256 while (big_str[i] != '\0') {
ab33e65c 257 char state;
ef290fca 258
ab33e65c
PP
259 sscanf(big_str + i, "%a[^/]/%a[^ ] %c %a[^\n]",
260 &tmp_cmsf[cmsf_ind].channel,
261 &tmp_cmsf[cmsf_ind].marker,
262 &state,
263 &tmp_cmsf[cmsf_ind].fs);
264 tmp_cmsf[cmsf_ind].state = (state == USTCMD_MS_CHR_ON ?
77957c95 265 USTCMD_MS_ON : USTCMD_MS_OFF); /* Marker state */
ab33e65c
PP
266
267 while (big_str[i] != '\n') {
77957c95 268 ++i; /* Go to next '\n' */
ab33e65c 269 }
77957c95 270 ++i; /* Skip current pointed '\n' */
ab33e65c
PP
271 ++cmsf_ind;
272 }
273 tmp_cmsf[cmsf_ind].channel = NULL;
274 tmp_cmsf[cmsf_ind].marker = NULL;
275 tmp_cmsf[cmsf_ind].fs = NULL;
276
277 *cmsf = tmp_cmsf;
278
279 free(big_str);
280 return 0;
281}
282
283/**
284 * Shoots a given command using ustcomm.
285 *
286 * @param cmd Null-terminated command to shoot
287 * @param pid Targeted PID
288 * @param reply Pointer to string to be filled with a reply string (must
289 * be NULL if no reply is needed for the given command).
290 * @return 0 if successful, or errors {USTCMD_ERR_ARG, USTCMD_ERR_CONN}
291 */
772030fe
PMF
292
293int ustcmd_shoot(const char* cmd, const pid_t pid, char** reply)
294{
295 struct ustcomm_connection conn;
296
ab33e65c
PP
297 if (cmd == NULL) {
298 return USTCMD_ERR_ARG;
299 }
300
ab33e65c
PP
301 if (ustcomm_connect_app(pid, &conn)) {
302 fprintf(stderr, "ustcmd_shoot: could not connect to PID %u\n",
303 (unsigned int) pid);
304 return USTCMD_ERR_CONN;
305 }
306
307 ustcomm_send_request(&conn, cmd, reply);
308
309 return 0;
310}
This page took 0.034765 seconds and 4 git commands to generate.