Fix: rotation client example: leak of handle on error
[lttng-tools.git] / doc / examples / rotation / rotate-client-example.c
CommitLineData
7779bc96
JD
1/*
2 * Session rotation example control application
3 *
4 * Copyright 2017, Julien Desfossez <jdesfossez@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25/*
26 * Compile with:
27 * gcc -o rotate-client rotate-client-example.c -llttng-ctl
28 *
29 * Run with the following command to rotate the session every second and
30 * compress the chunk, until ctrl-c:
31 * ./rotate-client mysession 1 -1 ./rotate-client-compress.sh
32 */
33
95ce9d29
JR
34#include <lttng/lttng.h>
35#include <signal.h>
7779bc96
JD
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
7779bc96 40
95ce9d29 41#define DEFAULT_DATA_AVAILABILITY_WAIT_TIME 200000 /* usec */
7779bc96
JD
42
43static volatile int quit = 0;
44
95ce9d29 45static void sighandler(int signal)
7779bc96
JD
46{
47 printf("Signal caught, exiting\n");
48 quit = 1;
49}
50
95ce9d29 51static int setup_session(const char *session_name, const char *path)
7779bc96
JD
52{
53 int ret;
54 struct lttng_domain dom;
55 struct lttng_event ev;
878fea90 56 struct lttng_handle *chan_handle = NULL;
7779bc96
JD
57
58 printf("Creating session %s\n", session_name);
59 ret = lttng_create_session(session_name, path);
60 if (ret) {
61 fprintf(stderr, "Failed to create session, ret = %d\n", ret);
62 goto end;
63 }
64
65 dom.type = LTTNG_DOMAIN_KERNEL;
66 dom.buf_type = LTTNG_BUFFER_GLOBAL;
67
68 chan_handle = lttng_create_handle(session_name, &dom);
69 if (chan_handle == NULL) {
70 ret = -1;
71 goto end;
72 }
73
74 memset(&ev, 0, sizeof(ev));
75 ev.type = LTTNG_EVENT_SYSCALL;
76 strcpy(ev.name, "*");
77 ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
78
95ce9d29
JR
79 ret = lttng_enable_event_with_exclusions(
80 chan_handle, &ev, "mychan", NULL, 0, NULL);
7779bc96 81 if (ret < 0) {
61e4fc8e 82 fprintf(stderr, "Failed to enable events (ret = %i)\n", ret);
7779bc96
JD
83 goto end;
84 }
85 printf("Enabled all system call kernel events\n");
86
87 ret = lttng_start_tracing(session_name);
88 if (ret < 0) {
89 fprintf(stderr, "Failed to start tracing\n");
90 goto end;
91 }
92
7779bc96
JD
93 ret = 0;
94
95end:
878fea90 96 lttng_destroy_handle(chan_handle);
7779bc96
JD
97 return ret;
98}
99
95ce9d29 100static int cleanup_session(const char *session_name)
7779bc96
JD
101{
102 int ret;
103
104 printf("Stopping session %s", session_name);
105 ret = lttng_stop_tracing_no_wait(session_name);
106 if (ret) {
107 fprintf(stderr, "Failed to stop tracing\n");
108 goto end;
109 }
110
111 fflush(stdout);
112 do {
113 ret = lttng_data_pending(session_name);
114 if (ret < 0) {
115 /* Return the data available call error. */
116 goto end;
117 }
118
119 /*
95ce9d29
JR
120 * Data sleep time before retrying (in usec). Don't sleep if the
121 * call returned value indicates availability.
7779bc96
JD
122 */
123 if (ret) {
124 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
125 printf(".");
126 fflush(stdout);
127 }
128 } while (ret != 0);
129 printf("\n");
130
131 printf("Destroying session %s\n", session_name);
132 ret = lttng_destroy_session(session_name);
133 if (ret) {
134 fprintf(stderr, "Failed to destroy the session\n");
135 goto end;
136 }
137
138 ret = 0;
139
140end:
141 return ret;
142}
143
95ce9d29 144static int rotate_session(const char *session_name, const char *ext_program)
7779bc96
JD
145{
146 int ret;
7779bc96
JD
147 struct lttng_rotation_handle *handle = NULL;
148 enum lttng_rotation_status rotation_status;
61e4fc8e 149 enum lttng_rotation_state rotation_state = LTTNG_ROTATION_STATE_ONGOING;
7779bc96
JD
150 char cmd[PATH_MAX];
151
7779bc96
JD
152 printf("Rotating the output files of session %s", session_name);
153
61e4fc8e 154 ret = lttng_rotate_session(session_name, NULL, &handle);
7779bc96 155 if (ret < 0) {
95ce9d29
JR
156 fprintf(stderr, "Failed to rotate session, %s\n",
157 lttng_strerror(ret));
7779bc96
JD
158 goto end;
159 }
160
161 fflush(stdout);
61e4fc8e 162
7779bc96 163 do {
95ce9d29
JR
164 rotation_status = lttng_rotation_handle_get_state(
165 handle, &rotation_state);
61e4fc8e
JG
166 if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
167 ret = -1;
168 fprintf(stderr, "Failed to get the current rotation's state\n");
7779bc96
JD
169 goto end;
170 }
171
172 /*
61e4fc8e
JG
173 * Data sleep time before retrying (in usec). Don't
174 * sleep if the call returned value indicates
175 * availability.
7779bc96 176 */
61e4fc8e 177 if (rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
7779bc96
JD
178 usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
179 printf(".");
180 fflush(stdout);
181 }
61e4fc8e 182 } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING);
7779bc96
JD
183 printf("\n");
184
61e4fc8e
JG
185 switch (rotation_state) {
186 case LTTNG_ROTATION_STATE_COMPLETED:
187 {
188 const struct lttng_trace_archive_location *location;
189 const char *absolute_path;
190 enum lttng_trace_archive_location_status location_status;
191
192 rotation_status = lttng_rotation_handle_get_archive_location(
193 handle, &location);
194 if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
195 fprintf(stderr, "Failed to retrieve the rotation's completed chunk archive location\n");
196 ret = -1;
197 goto end;
198 }
199
95ce9d29
JR
200 location_status =
201 lttng_trace_archive_location_local_get_absolute_path(
202 location, &absolute_path);
61e4fc8e
JG
203 if (location_status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
204 fprintf(stderr, "Failed to get absolute path of completed chunk archive");
205 ret = -1;
206 goto end;
207 }
208
209 printf("Output files of session %s rotated to %s\n",
210 session_name, absolute_path);
95ce9d29
JR
211 ret = snprintf(cmd, PATH_MAX, "%s %s", ext_program,
212 absolute_path);
7779bc96
JD
213 if (ret < 0) {
214 fprintf(stderr, "Failed to prepare command string\n");
215 goto end;
216 }
217 ret = system(cmd);
218 goto end;
61e4fc8e
JG
219 }
220 case LTTNG_ROTATION_STATE_EXPIRED:
95ce9d29
JR
221 printf("Output files of session %s rotated, but the handle expired\n",
222 session_name);
7779bc96
JD
223 ret = 0;
224 goto end;
61e4fc8e 225 case LTTNG_ROTATION_STATE_ERROR:
95ce9d29
JR
226 fprintf(stderr, "An error occurred with the rotation of session %s\n",
227 session_name);
228 ret = -1;
229 goto end;
230 case LTTNG_ROTATION_STATE_ONGOING:
231 abort();
232 goto end;
233 case LTTNG_ROTATION_STATE_NO_ROTATION:
234 fprintf(stderr, "No rotation was performed on rotation request for session %s\n",
235 session_name);
7779bc96
JD
236 ret = -1;
237 goto end;
238 }
239
240end:
241 lttng_rotation_handle_destroy(handle);
7779bc96
JD
242 return ret;
243}
244
95ce9d29 245static int cleanup_dir(const char *path)
7779bc96
JD
246{
247 char cmd[PATH_MAX];
248 int ret;
249
250 ret = snprintf(cmd, PATH_MAX, "rm -rf %s", path);
251 if (ret < 0) {
252 fprintf(stderr, "Failed to prepare rm -rf command string\n");
253 goto end;
254 }
255 ret = system(cmd);
256
257end:
258 return ret;
259}
260
95ce9d29 261static void usage(const char *prog_name)
7779bc96
JD
262{
263 fprintf(stderr, "Usage: %s <session-name> <delay-sec> <nr-rotate> <program>\n",
264 prog_name);
265 fprintf(stderr, " <session-name>: the name of the session you want to create\n");
266 fprintf(stderr, " <delay-sec>: the delay in seconds between each rotation\n");
95ce9d29
JR
267 fprintf(stderr,
268 " <nr-rotate>: the number of rotation you want to perform, "
7779bc96 269 "-1 for infinite until ctrl-c\n");
95ce9d29
JR
270 fprintf(stderr,
271 " <program>: program to run on each chunk, it must be "
7779bc96
JD
272 "executable, and expect a trace folder as only argument\n");
273 fprintf(stderr, "\nThe trace folder is deleted when this program completes.\n");
274}
275
276int main(int argc, char **argv)
277{
278 int ret;
279 char tmppath[] = "/tmp/lttng-rotate-XXXXXX";
280 char *session_name, *path, *ext_program;
281 int delay, nr;
282
283 if (argc != 5) {
284 usage(argv[0]);
285 ret = -1;
286 goto end;
287 }
288
289 session_name = argv[1];
290 delay = atoi(argv[2]);
291 nr = atoi(argv[3]);
292 ext_program = argv[4];
293
294 if (delay < 0) {
295 fprintf(stderr, "delay-sec must be a positive values\n");
296 ret = -1;
297 goto end;
298 }
299
95ce9d29
JR
300 if (signal(SIGINT, sighandler) == SIG_ERR) {
301 ret = -1;
7779bc96
JD
302 perror("signal handler");
303 goto end;
304 }
305
306 path = mkdtemp(tmppath);
307 if (!path) {
308 fprintf(stderr, "Failed to create temporary path\n");
309 }
310
311 printf("Output directory: %s\n", path);
312
313 ret = setup_session(session_name, path);
314 if (ret) {
315 goto end_cleanup_dir;
316 }
317
318 if (nr > 0) {
319 unsigned int sleep_time;
320 int i;
321
322 for (i = 0; i < nr; i++) {
323 ret = rotate_session(session_name, ext_program);
324 if (ret) {
325 goto end_cleanup;
326 }
327 sleep_time = delay;
328 while (sleep_time > 0) {
329 sleep_time = sleep(sleep_time);
330 }
331 }
332 } else {
95ce9d29 333 for (;;) {
7779bc96
JD
334 if (quit) {
335 break;
336 }
337 ret = rotate_session(session_name, ext_program);
338 if (ret) {
339 goto end_cleanup;
340 }
341 sleep(delay);
342 }
343 }
344
345end_cleanup:
346 ret = cleanup_session(session_name);
347 if (ret) {
348 goto end;
349 }
350end_cleanup_dir:
351 ret = cleanup_dir(path);
352end:
353 return ret;
354}
This page took 0.043206 seconds and 4 git commands to generate.