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