Commit | Line | Data |
---|---|---|
b0a99af4 MD |
1 | /* |
2 | * ust-basic-tracing.c - Basic single-session, single-channel, single-process UST tracing | |
3 | * | |
4 | * Copyright (C) 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
5 | * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the Free | |
9 | * Software Foundation; only version 2 of the License. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
18 | * Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | */ | |
20 | ||
21 | #define _LARGEFILE64_SOURCE | |
9d335227 | 22 | #define _GNU_SOURCE |
b0a99af4 MD |
23 | #include <errno.h> |
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | #include <signal.h> | |
28 | #include <unistd.h> | |
29 | #include <sys/wait.h> | |
30 | #include <sys/types.h> | |
31 | #include <sys/stat.h> | |
32 | #include <fcntl.h> | |
33 | #include <sys/mman.h> | |
34 | #include <limits.h> | |
35 | #include <urcu/futex.h> | |
36 | #include <urcu/uatomic.h> | |
37 | #include <assert.h> | |
38 | #include <sys/socket.h> | |
39 | ||
a3bb4b27 | 40 | #include <ust-comm.h> |
b0a99af4 MD |
41 | #include "../../libringbuffer/backend.h" |
42 | #include "../../libringbuffer/frontend.h" | |
e5757a90 | 43 | #include "../../liblttng-ust/compat.h" /* For ENODATA */ |
b0a99af4 MD |
44 | |
45 | #define MAX_NR_STREAMS 64 | |
46 | #define MAX_NR_EVENTS 128 | |
47 | ||
b0a99af4 | 48 | static int session_handle; |
61f02aea MD |
49 | static struct lttng_ust_object_data metadata_stream_data; |
50 | static struct lttng_ust_object_data metadata_data; | |
51 | static struct lttng_ust_object_data channel_data; | |
52 | static struct lttng_ust_object_data stream_data[MAX_NR_STREAMS]; | |
b0a99af4 | 53 | static int event_handle[MAX_NR_EVENTS]; |
8de38cf7 | 54 | static int context_handle; |
b0a99af4 MD |
55 | |
56 | static int apps_socket = -1; | |
57 | static char apps_sock_path[PATH_MAX]; | |
58 | static char local_apps_wait_shm_path[PATH_MAX]; | |
59 | ||
60 | static volatile int quit_program; | |
61 | ||
62 | static void handle_signals(int signo) | |
63 | { | |
64 | quit_program = 1; | |
65 | } | |
66 | ||
b0a99af4 | 67 | static |
61f02aea | 68 | int open_streams(int sock, int channel_handle, struct lttng_ust_object_data *stream_datas, |
b0a99af4 MD |
69 | int nr_check) |
70 | { | |
71 | int ret, k = 0; | |
72 | ||
73 | for (;;) { | |
57773204 MD |
74 | struct ustcomm_ust_msg lum; |
75 | struct ustcomm_ust_reply lur; | |
b0a99af4 MD |
76 | |
77 | memset(&lum, 0, sizeof(lum)); | |
78 | lum.handle = channel_handle; | |
79 | lum.cmd = LTTNG_UST_STREAM; | |
57773204 | 80 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
81 | if (!ret) { |
82 | assert(k < nr_check); | |
83 | stream_datas[k].handle = lur.ret_val; | |
84 | printf("received stream handle %u\n", | |
85 | stream_datas[k].handle); | |
57773204 | 86 | if (lur.ret_code == USTCOMM_OK) { |
b0a99af4 MD |
87 | ssize_t len; |
88 | ||
89 | stream_datas[k].memory_map_size = lur.u.stream.memory_map_size; | |
90 | /* get shm fd */ | |
57773204 | 91 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
92 | if (len < 0) |
93 | return -EINVAL; | |
94 | stream_datas[k].shm_fd = len; | |
95 | /* get wait fd */ | |
57773204 | 96 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
97 | if (len < 0) |
98 | return -EINVAL; | |
99 | stream_datas[k].wait_fd = len; | |
100 | } | |
101 | k++; | |
102 | } | |
103 | if (ret == -ENOENT) | |
104 | break; | |
105 | if (ret) | |
106 | return ret; | |
107 | } | |
108 | return 0; | |
109 | } | |
110 | ||
111 | static | |
61f02aea | 112 | int close_streams(int sock, struct lttng_ust_object_data *stream_datas, int nr_check) |
b0a99af4 MD |
113 | { |
114 | int ret, k; | |
115 | ||
116 | for (k = 0; k < nr_check; k++) { | |
57773204 MD |
117 | struct ustcomm_ust_msg lum; |
118 | struct ustcomm_ust_reply lur; | |
b0a99af4 MD |
119 | |
120 | if (!stream_datas[k].handle) | |
121 | continue; | |
122 | memset(&lum, 0, sizeof(lum)); | |
123 | lum.handle = stream_datas[k].handle; | |
124 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 125 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
126 | if (ret) { |
127 | printf("Error closing stream\n"); | |
128 | return ret; | |
129 | } | |
130 | if (stream_datas[k].shm_fd >= 0) { | |
131 | ret = close(stream_datas[k].shm_fd); | |
132 | if (ret) { | |
133 | printf("Error closing stream shm_fd\n"); | |
134 | return ret; | |
135 | } | |
136 | } | |
137 | if (stream_datas[k].wait_fd >= 0) { | |
138 | ret = close(stream_datas[k].wait_fd); | |
139 | if (ret) { | |
140 | printf("Error closing stream wait_fd\n"); | |
141 | return ret; | |
142 | } | |
143 | } | |
144 | } | |
145 | return 0; | |
146 | } | |
147 | ||
148 | static | |
38fae1d3 | 149 | struct lttng_ust_shm_handle *map_channel(struct lttng_ust_object_data *chan_data, |
61f02aea | 150 | struct lttng_ust_object_data *stream_datas, int nr_check) |
b0a99af4 | 151 | { |
38fae1d3 | 152 | struct lttng_ust_shm_handle *handle; |
b0a99af4 MD |
153 | struct channel *chan; |
154 | int k, ret; | |
155 | ||
156 | /* map metadata channel */ | |
157 | handle = channel_handle_create(chan_data->shm_fd, | |
158 | chan_data->wait_fd, | |
159 | chan_data->memory_map_size); | |
160 | if (!handle) { | |
161 | printf("create handle error\n"); | |
162 | return NULL; | |
163 | } | |
164 | chan_data->shm_fd = -1; | |
165 | chan_data->wait_fd = -1; | |
166 | chan = shmp(handle, handle->chan); | |
167 | ||
168 | for (k = 0; k < nr_check; k++) { | |
61f02aea | 169 | struct lttng_ust_object_data *stream_data = &stream_datas[k]; |
b0a99af4 MD |
170 | |
171 | if (!stream_data->handle) | |
172 | break; | |
173 | /* map stream */ | |
174 | ret = channel_handle_add_stream(handle, | |
175 | stream_data->shm_fd, | |
176 | stream_data->wait_fd, | |
177 | stream_data->memory_map_size); | |
178 | if (ret) { | |
179 | printf("add stream error\n"); | |
180 | goto error_destroy; | |
181 | } | |
182 | stream_data->shm_fd = -1; | |
183 | stream_data->wait_fd = -1; | |
184 | } | |
185 | return handle; | |
186 | ||
187 | error_destroy: | |
188 | channel_destroy(chan, handle, 1); | |
189 | return NULL; | |
190 | } | |
191 | ||
192 | static | |
38fae1d3 | 193 | void unmap_channel(struct lttng_ust_shm_handle *handle) |
b0a99af4 MD |
194 | { |
195 | struct channel *chan; | |
196 | ||
197 | chan = shmp(handle, handle->chan); | |
198 | /* unmap channel */ | |
199 | channel_destroy(chan, handle, 1); | |
200 | } | |
201 | ||
202 | static | |
38fae1d3 | 203 | int consume_stream(struct lttng_ust_shm_handle *handle, int cpu, char *outfile) |
b0a99af4 MD |
204 | { |
205 | struct channel *chan; | |
4cfec15c | 206 | struct lttng_ust_lib_ring_buffer *buf; |
b0a99af4 | 207 | int outfd, ret; |
ef9ff354 MD |
208 | int *shm_fd, *wait_fd; |
209 | uint64_t *memory_map_size; | |
b0a99af4 MD |
210 | |
211 | chan = shmp(handle, handle->chan); | |
212 | ||
213 | /* open stream */ | |
214 | buf = channel_get_ring_buffer(&chan->backend.config, | |
215 | chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); | |
216 | if (!buf) | |
217 | return -ENOENT; | |
218 | ret = lib_ring_buffer_open_read(buf, handle, 1); | |
219 | if (ret) { | |
220 | return -1; | |
221 | } | |
222 | ||
223 | /* copy */ | |
224 | outfd = open(outfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC, | |
225 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); | |
226 | if (outfd < 0) { | |
227 | perror("open output"); | |
228 | return -1; | |
229 | } | |
230 | ||
231 | printf("Waiting for buffer data for %s\n", outfile); | |
232 | for (;;) { | |
233 | unsigned long read_size; | |
234 | unsigned long copy_size; | |
235 | char *ptr; | |
236 | ||
237 | ret = lib_ring_buffer_get_next_subbuf(buf, handle); | |
238 | printf("get next ret %d\n", ret); | |
239 | if (ret == -ENODATA) | |
240 | break; | |
241 | if (ret == -EAGAIN) { | |
242 | sleep(1); | |
243 | continue; | |
244 | } | |
245 | if (ret) { | |
246 | printf("Error %d in lib_ring_buffer_get_next_subbuf\n", ret); | |
247 | return -1; | |
248 | } | |
249 | read_size = lib_ring_buffer_get_read_data_size( | |
250 | &chan->backend.config, buf, handle); | |
251 | read_size = PAGE_ALIGN(read_size); | |
252 | ptr = lib_ring_buffer_read_offset_address( | |
253 | &buf->backend, 0, handle); | |
254 | printf("WRITE: copy %lu bytes\n", read_size); | |
255 | copy_size = write(outfd, ptr, read_size); | |
256 | if (copy_size < read_size) { | |
f97e7ae1 | 257 | printf("write issue: copied %lu, expected %lu\n", copy_size, read_size); |
b0a99af4 MD |
258 | } |
259 | lib_ring_buffer_put_next_subbuf(buf, handle); | |
260 | } | |
261 | ||
262 | ret = close(outfd); | |
263 | if (ret) { | |
264 | perror("close"); | |
265 | return -1; | |
266 | } | |
267 | ||
268 | /* close stream */ | |
269 | lib_ring_buffer_release_read(buf, handle, 1); | |
270 | return 0; | |
271 | } | |
272 | ||
273 | static | |
274 | int consume_buffers(const char *outputpath) | |
275 | { | |
276 | int k, ret; | |
277 | mode_t old_umask; | |
278 | char pathname[PATH_MAX]; | |
38fae1d3 | 279 | struct lttng_ust_shm_handle *handle; |
b0a99af4 MD |
280 | |
281 | snprintf(pathname, PATH_MAX - 1, "%s", outputpath); | |
282 | old_umask = umask(0); | |
283 | ret = mkdir(pathname, S_IRWXU | S_IRWXG); | |
284 | if (ret && errno != EEXIST) { | |
285 | perror("mkdir"); | |
286 | umask(old_umask); | |
287 | return -1; | |
288 | } | |
289 | umask(old_umask); | |
290 | ||
291 | /* copy metadata */ | |
292 | handle = map_channel(&metadata_data, | |
293 | &metadata_stream_data, 1); | |
294 | if (!handle) | |
295 | return -1; | |
296 | snprintf(pathname, PATH_MAX - 1, | |
297 | "%s/metadata", outputpath); | |
298 | ret = consume_stream(handle, -1, pathname); | |
299 | if (ret && ret != -ENOENT) { | |
300 | printf("Error in consume_stream\n"); | |
301 | return ret; | |
302 | } | |
303 | unmap_channel(handle); | |
304 | ||
305 | /* copy binary data */ | |
306 | handle = map_channel(&channel_data, | |
307 | stream_data, MAX_NR_STREAMS); | |
308 | if (!handle) | |
309 | return -1; | |
310 | for (k = 0; k < MAX_NR_STREAMS; k++) { | |
311 | snprintf(pathname, PATH_MAX - 1, | |
312 | "%s/data_%u", outputpath, k); | |
313 | ret = consume_stream(handle, k, pathname); | |
314 | if (ret && ret != -ENOENT) { | |
315 | printf("Error in consume_stream\n"); | |
316 | return ret; | |
317 | } | |
318 | } | |
319 | unmap_channel(handle); | |
320 | ||
321 | return 0; | |
322 | } | |
323 | ||
57773204 | 324 | static |
b0a99af4 MD |
325 | int send_app_msgs(int sock, const char *outputpath, |
326 | unsigned int nr_events, const char **event_names) | |
327 | { | |
57773204 MD |
328 | struct ustcomm_ust_msg lum; |
329 | struct ustcomm_ust_reply lur; | |
b0a99af4 MD |
330 | int ret, k; |
331 | ||
332 | /* Create session */ | |
333 | memset(&lum, 0, sizeof(lum)); | |
334 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
335 | lum.cmd = LTTNG_UST_SESSION; | |
57773204 | 336 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
337 | if (ret) |
338 | return ret; | |
339 | session_handle = lur.ret_val; | |
340 | printf("received session handle %u\n", session_handle); | |
341 | ||
342 | /* Create metadata channel */ | |
343 | memset(&lum, 0, sizeof(lum)); | |
344 | lum.handle = session_handle; | |
345 | lum.cmd = LTTNG_UST_METADATA; | |
346 | lum.u.channel.overwrite = 0; | |
347 | lum.u.channel.subbuf_size = 32768; | |
348 | lum.u.channel.num_subbuf = 4; | |
349 | lum.u.channel.switch_timer_interval = 0; | |
350 | lum.u.channel.read_timer_interval = 0; | |
351 | lum.u.channel.output = LTTNG_UST_MMAP; | |
57773204 | 352 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
353 | if (ret) |
354 | return ret; | |
355 | metadata_data.handle = lur.ret_val; | |
356 | printf("received metadata handle %u\n", metadata_data.handle); | |
57773204 | 357 | if (lur.ret_code == USTCOMM_OK) { |
b0a99af4 MD |
358 | ssize_t len; |
359 | ||
360 | metadata_data.memory_map_size = lur.u.channel.memory_map_size; | |
361 | /* get shm fd */ | |
57773204 | 362 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
363 | if (len < 0) |
364 | return -EINVAL; | |
365 | metadata_data.shm_fd = len; | |
366 | /* get wait fd */ | |
57773204 | 367 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
368 | if (len < 0) |
369 | return -EINVAL; | |
370 | metadata_data.wait_fd = len; | |
371 | } | |
372 | ||
373 | ret = open_streams(sock, metadata_data.handle, | |
374 | &metadata_stream_data, 1); | |
375 | if (ret) { | |
376 | printf("Error in open_streams\n"); | |
377 | return ret; | |
378 | } | |
379 | ||
380 | /* Create data channel */ | |
381 | memset(&lum, 0, sizeof(lum)); | |
382 | lum.handle = session_handle; | |
383 | lum.cmd = LTTNG_UST_CHANNEL; | |
384 | //lum.u.channel.overwrite = 0; | |
385 | lum.u.channel.overwrite = 1; | |
386 | lum.u.channel.subbuf_size = 32768; | |
387 | lum.u.channel.num_subbuf = 8; | |
388 | //lum.u.channel.num_subbuf = 4; | |
389 | //lum.u.channel.num_subbuf = 2; | |
390 | lum.u.channel.switch_timer_interval = 0; | |
391 | lum.u.channel.read_timer_interval = 0; | |
392 | lum.u.channel.output = LTTNG_UST_MMAP; | |
57773204 | 393 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
394 | if (ret) |
395 | return ret; | |
396 | channel_data.handle = lur.ret_val; | |
397 | printf("received channel handle %u\n", channel_data.handle); | |
57773204 | 398 | if (lur.ret_code == USTCOMM_OK) { |
b0a99af4 MD |
399 | ssize_t len; |
400 | ||
401 | channel_data.memory_map_size = lur.u.channel.memory_map_size; | |
402 | /* get shm fd */ | |
57773204 | 403 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
404 | if (len < 0) |
405 | return -EINVAL; | |
406 | channel_data.shm_fd = len; | |
407 | /* get wait fd */ | |
57773204 | 408 | len = ustcomm_recv_fd(sock); |
b0a99af4 MD |
409 | if (len < 0) |
410 | return -EINVAL; | |
411 | channel_data.wait_fd = len; | |
412 | } | |
413 | ||
414 | /* Create events */ | |
415 | for (k = 0; k < nr_events; k++) { | |
416 | memset(&lum, 0, sizeof(lum)); | |
417 | lum.handle = channel_data.handle; | |
418 | lum.cmd = LTTNG_UST_EVENT; | |
419 | strncpy(lum.u.event.name, event_names[k], | |
420 | LTTNG_UST_SYM_NAME_LEN); | |
421 | lum.u.event.instrumentation = LTTNG_UST_TRACEPOINT; | |
57773204 | 422 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
423 | if (ret) |
424 | return ret; | |
425 | event_handle[k] = lur.ret_val; | |
426 | printf("received event handle %u\n", event_handle[k]); | |
427 | } | |
428 | ||
3b402b40 | 429 | /* Attach vtid context */ |
8de38cf7 MD |
430 | memset(&lum, 0, sizeof(lum)); |
431 | lum.handle = channel_data.handle; | |
432 | lum.cmd = LTTNG_UST_CONTEXT; | |
3b402b40 MD |
433 | lum.u.context.ctx = LTTNG_UST_CONTEXT_VTID; |
434 | //lum.u.context.ctx = LTTNG_UST_CONTEXT_PTHREAD_ID; | |
4847e9bb MD |
435 | //lum.u.context.ctx = LTTNG_UST_CONTEXT_VPID; |
436 | //lum.u.context.ctx = LTTNG_UST_CONTEXT_PROCNAME; | |
57773204 | 437 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
8de38cf7 MD |
438 | if (ret) |
439 | return ret; | |
440 | context_handle = lur.ret_val; | |
441 | printf("received context handle %u\n", context_handle); | |
442 | ||
b0a99af4 MD |
443 | /* Get references to channel streams */ |
444 | ret = open_streams(sock, channel_data.handle, | |
445 | stream_data, MAX_NR_STREAMS); | |
446 | if (ret) { | |
447 | printf("Error in open_streams\n"); | |
448 | return ret; | |
449 | } | |
450 | ||
451 | memset(&lum, 0, sizeof(lum)); | |
452 | lum.handle = session_handle; | |
453 | lum.cmd = LTTNG_UST_SESSION_START; | |
57773204 | 454 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
455 | if (ret) |
456 | return ret; | |
457 | printf("Session handle %u started.\n", session_handle); | |
458 | ||
459 | /* Tell application registration is done */ | |
460 | memset(&lum, 0, sizeof(lum)); | |
461 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
462 | lum.cmd = LTTNG_UST_REGISTER_DONE; | |
57773204 | 463 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
464 | if (ret) |
465 | return ret; | |
466 | printf("Registration done acknowledged.\n"); | |
467 | ||
468 | sleep(4); | |
469 | ||
470 | ret = consume_buffers(outputpath); | |
471 | if (ret) { | |
472 | printf("Error in consume_buffers\n"); | |
473 | return ret; | |
474 | } | |
475 | ||
476 | /* Release data channel */ | |
477 | /* Release streams */ | |
478 | ret = close_streams(sock, stream_data, | |
479 | MAX_NR_STREAMS); | |
480 | if (ret) | |
481 | return ret; | |
482 | ||
8de38cf7 MD |
483 | /* Release context */ |
484 | memset(&lum, 0, sizeof(lum)); | |
485 | lum.handle = context_handle; | |
486 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 487 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
8de38cf7 MD |
488 | if (ret) |
489 | return ret; | |
490 | ||
b0a99af4 MD |
491 | /* Release events */ |
492 | for (k = 0; k < nr_events; k++) { | |
493 | memset(&lum, 0, sizeof(lum)); | |
494 | lum.handle = event_handle[k]; | |
495 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 496 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
497 | if (ret) |
498 | return ret; | |
499 | } | |
500 | memset(&lum, 0, sizeof(lum)); | |
501 | lum.handle = channel_data.handle; | |
502 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 503 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
504 | if (ret) |
505 | return ret; | |
506 | if (channel_data.shm_fd >= 0) { | |
507 | ret = close(channel_data.shm_fd); | |
508 | if (ret) | |
509 | return ret; | |
510 | } | |
511 | if (channel_data.wait_fd >= 0) { | |
512 | ret = close(channel_data.wait_fd); | |
513 | if (ret) | |
514 | return ret; | |
515 | } | |
516 | ||
517 | /* Release metadata channel */ | |
518 | ret = close_streams(sock, &metadata_stream_data, 1); | |
519 | if (ret) | |
520 | return ret; | |
521 | ||
522 | memset(&lum, 0, sizeof(lum)); | |
523 | lum.handle = metadata_data.handle; | |
524 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 525 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
526 | if (ret) |
527 | return ret; | |
528 | if (metadata_data.shm_fd >= 0) { | |
529 | ret = close(metadata_data.shm_fd); | |
530 | if (ret) | |
531 | return ret; | |
532 | } | |
533 | if (metadata_data.wait_fd >= 0) { | |
534 | ret = close(metadata_data.wait_fd); | |
535 | if (ret) | |
536 | return ret; | |
537 | } | |
538 | ||
539 | /* Release session */ | |
540 | memset(&lum, 0, sizeof(lum)); | |
541 | lum.handle = session_handle; | |
542 | lum.cmd = LTTNG_UST_RELEASE; | |
57773204 | 543 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
b0a99af4 MD |
544 | if (ret) |
545 | return ret; | |
546 | ||
547 | return 0; | |
548 | } | |
549 | ||
550 | /* | |
551 | * Using fork to set umask in the child process (not multi-thread safe). We | |
552 | * deal with the shm_open vs ftruncate race (happening when the sessiond owns | |
553 | * the shm and does not let everybody modify it, to ensure safety against | |
554 | * shm_unlink) by simply letting the mmap fail and retrying after a few | |
555 | * seconds. For global shm, everybody has rw access to it until the sessiond | |
556 | * starts. | |
557 | */ | |
558 | static int get_wait_shm(char *shm_path, size_t mmap_size, int global) | |
559 | { | |
560 | int wait_shm_fd, ret; | |
561 | mode_t mode; | |
562 | ||
563 | /* Default permissions */ | |
564 | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; | |
565 | ||
566 | /* Change owner of the shm path */ | |
567 | if (global) { | |
568 | ret = chown(shm_path, 0, 0); | |
569 | if (ret < 0) { | |
570 | if (errno != ENOENT) { | |
571 | perror("chown wait shm"); | |
572 | goto error; | |
573 | } | |
574 | } | |
575 | ||
576 | /* | |
577 | * If global session daemon, any application can register so the shm | |
578 | * needs to be set in read-only mode for others. | |
579 | */ | |
580 | mode |= S_IROTH; | |
581 | } else { | |
582 | ret = chown(shm_path, getuid(), getgid()); | |
583 | if (ret < 0) { | |
584 | if (errno != ENOENT) { | |
585 | perror("chown wait shm"); | |
586 | goto error; | |
587 | } | |
588 | } | |
589 | } | |
590 | ||
591 | /* | |
592 | * Set permissions to the shm even if we did not create the shm. | |
593 | */ | |
594 | ret = chmod(shm_path, mode); | |
595 | if (ret < 0) { | |
596 | if (errno != ENOENT) { | |
597 | perror("chmod wait shm"); | |
598 | goto error; | |
599 | } | |
600 | } | |
601 | ||
602 | /* | |
603 | * We're alone in a child process, so we can modify the process-wide | |
604 | * umask. | |
605 | */ | |
606 | umask(~mode); | |
607 | ||
608 | /* | |
609 | * Try creating shm (or get rw access). We don't do an exclusive open, | |
610 | * because we allow other processes to create+ftruncate it concurrently. | |
611 | */ | |
612 | wait_shm_fd = shm_open(shm_path, O_RDWR | O_CREAT, mode); | |
613 | if (wait_shm_fd < 0) { | |
614 | perror("shm_open wait shm"); | |
615 | goto error; | |
616 | } | |
617 | ||
618 | ret = ftruncate(wait_shm_fd, mmap_size); | |
619 | if (ret < 0) { | |
620 | perror("ftruncate wait shm"); | |
621 | exit(EXIT_FAILURE); | |
622 | } | |
623 | ||
624 | ret = fchmod(wait_shm_fd, mode); | |
625 | if (ret < 0) { | |
626 | perror("fchmod"); | |
627 | exit(EXIT_FAILURE); | |
628 | } | |
629 | ||
630 | printf("Got the wait shm fd %d\n", wait_shm_fd); | |
631 | ||
632 | return wait_shm_fd; | |
633 | ||
634 | error: | |
635 | printf("Failing to get the wait shm fd\n"); | |
636 | ||
637 | return -1; | |
638 | } | |
639 | ||
640 | int update_futex(int fd, int active) | |
641 | { | |
642 | size_t mmap_size = sysconf(_SC_PAGE_SIZE); | |
643 | char *wait_shm_mmap; | |
644 | int ret; | |
645 | ||
646 | wait_shm_mmap = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, | |
647 | MAP_SHARED, fd, 0); | |
648 | if (wait_shm_mmap == MAP_FAILED) { | |
649 | perror("mmap"); | |
650 | goto error; | |
651 | } | |
652 | ||
653 | if (active) { | |
654 | uatomic_set((int32_t *) wait_shm_mmap, 1); | |
655 | futex_async((int32_t *) wait_shm_mmap, FUTEX_WAKE, | |
656 | INT_MAX, NULL, NULL, 0); | |
657 | } else { | |
658 | uatomic_set((int32_t *) wait_shm_mmap, 0); | |
659 | } | |
660 | ret = munmap(wait_shm_mmap, mmap_size); | |
661 | if (ret) { | |
662 | perror("Error unmapping wait shm"); | |
663 | goto error; | |
664 | } | |
665 | return 0; | |
666 | error: | |
667 | return -1; | |
668 | } | |
669 | ||
670 | /* | |
671 | * Set open files limit to unlimited. This daemon can open a large number of | |
672 | * file descriptors in order to consumer multiple kernel traces. | |
673 | */ | |
674 | static void set_ulimit(void) | |
675 | { | |
676 | int ret; | |
677 | struct rlimit lim; | |
678 | ||
679 | /* | |
680 | * If not root, we cannot increase our max open files. But our | |
681 | * scope is then limited to processes from a single user. | |
682 | */ | |
683 | if (getuid() != 0) | |
684 | return; | |
685 | /* The kernel does not allowed an infinite limit for open files */ | |
686 | lim.rlim_cur = 65535; | |
687 | lim.rlim_max = 65535; | |
688 | ||
689 | ret = setrlimit(RLIMIT_NOFILE, &lim); | |
690 | if (ret < 0) { | |
691 | perror("failed to set open files limit"); | |
692 | } | |
693 | } | |
694 | ||
695 | /* | |
696 | * Usage: | |
697 | * ./ust-basic-tracing outputpath event_name1 event_name2 .... | |
698 | */ | |
699 | int main(int argc, const char **argv) | |
700 | { | |
701 | const char *home_dir; | |
702 | int ret, wait_shm_fd; | |
703 | struct sigaction act; | |
fb50c39d | 704 | mode_t old_umask = 0; |
b0a99af4 MD |
705 | const char *outputpath; |
706 | const char **event_names; | |
707 | unsigned int nr_events; | |
708 | ||
709 | if (argc < 2) { | |
710 | printf("Usage:\n"); | |
711 | printf("%s outputpath event_name1 event_name2 ...\n", | |
712 | argv[0]); | |
713 | exit(-1); | |
714 | } | |
715 | outputpath = argv[1]; | |
716 | event_names = &argv[2]; | |
717 | nr_events = argc - 2; | |
718 | ||
719 | set_ulimit(); | |
720 | ||
721 | /* Ignore sigpipe */ | |
722 | memset(&act, 0, sizeof(act)); | |
723 | ret = sigemptyset(&act.sa_mask); | |
724 | if (ret == -1) { | |
725 | perror("sigemptyset"); | |
726 | return -1; | |
727 | } | |
728 | ||
729 | act.sa_handler = SIG_IGN; | |
730 | ret = sigaction(SIGPIPE, &act, NULL); | |
731 | if (ret == -1) { | |
732 | perror("sigaction"); | |
733 | return -1; | |
734 | } | |
735 | ||
736 | /* Handle SIGTERM */ | |
737 | act.sa_handler = handle_signals; | |
738 | ret = sigaction(SIGTERM, &act, NULL); | |
739 | if (ret == -1) { | |
740 | perror("sigaction"); | |
741 | return -1; | |
742 | } | |
743 | /* Handle SIGINT */ | |
744 | ret = sigaction(SIGINT, &act, NULL); | |
745 | if (ret == -1) { | |
746 | perror("sigaction"); | |
747 | return -1; | |
748 | } | |
749 | ||
750 | if (geteuid() == 0) { | |
751 | ret = mkdir(LTTNG_RUNDIR, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); | |
752 | if (ret && errno != EEXIST) { | |
753 | perror("mkdir"); | |
754 | return -1; | |
755 | } | |
756 | wait_shm_fd = get_wait_shm(DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH, | |
757 | sysconf(_SC_PAGE_SIZE), 1); | |
758 | if (wait_shm_fd < 0) { | |
759 | perror("global wait shm error"); | |
760 | return -1; | |
761 | } | |
762 | strcpy(apps_sock_path, DEFAULT_GLOBAL_APPS_UNIX_SOCK); | |
763 | old_umask = umask(0); | |
764 | } else { | |
765 | snprintf(local_apps_wait_shm_path, PATH_MAX, | |
766 | DEFAULT_HOME_APPS_WAIT_SHM_PATH, getuid()); | |
767 | wait_shm_fd = get_wait_shm(local_apps_wait_shm_path, | |
768 | sysconf(_SC_PAGE_SIZE), 0); | |
769 | if (wait_shm_fd < 0) { | |
770 | perror("local wait shm error"); | |
771 | return -1; | |
772 | } | |
773 | home_dir = (const char *) getenv("HOME"); | |
774 | if (!home_dir) { | |
775 | perror("getenv error"); | |
776 | return -ENOENT; | |
777 | } | |
778 | snprintf(apps_sock_path, PATH_MAX, | |
779 | DEFAULT_HOME_APPS_UNIX_SOCK, home_dir); | |
780 | } | |
781 | ||
57773204 | 782 | ret = ustcomm_create_unix_sock(apps_sock_path); |
b0a99af4 MD |
783 | if (ret < 0) { |
784 | perror("create error"); | |
785 | return ret; | |
786 | } | |
787 | apps_socket = ret; | |
788 | ||
789 | if (getuid() == 0) { | |
790 | /* File permission MUST be 666 */ | |
791 | ret = chmod(apps_sock_path, | |
792 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); | |
793 | if (ret < 0) { | |
794 | printf("Set file permissions failed: %s\n", apps_sock_path); | |
795 | perror("chmod"); | |
796 | goto end; | |
797 | } | |
798 | umask(old_umask); | |
799 | } | |
57773204 | 800 | ret = ustcomm_listen_unix_sock(apps_socket); |
b0a99af4 MD |
801 | if (ret < 0) { |
802 | perror("listen error"); | |
803 | return ret; | |
804 | } | |
805 | ||
806 | /* wake up futexes */ | |
807 | ret = update_futex(wait_shm_fd, 1); | |
808 | if (ret) { | |
809 | fprintf(stderr, "Error wakeup futex\n"); | |
810 | return -1; | |
811 | } | |
812 | ||
813 | for (;;) { | |
814 | int sock; | |
815 | ssize_t len; | |
816 | struct { | |
817 | uint32_t major; | |
818 | uint32_t minor; | |
819 | pid_t pid; | |
820 | pid_t ppid; | |
821 | uid_t uid; | |
822 | gid_t gid; | |
823 | char name[16]; /* Process name */ | |
824 | } reg_msg; | |
825 | char bufname[17]; | |
826 | ||
827 | if (quit_program) | |
828 | break; | |
829 | ||
830 | printf("Accepting application registration\n"); | |
57773204 | 831 | sock = ustcomm_accept_unix_sock(apps_socket); |
b0a99af4 MD |
832 | if (sock < 0) { |
833 | perror("accept error"); | |
834 | goto end; | |
835 | } | |
836 | ||
837 | /* | |
838 | * Basic recv here to handle the very simple data | |
839 | * that the libust send to register (reg_msg). | |
840 | */ | |
57773204 | 841 | len = ustcomm_recv_unix_sock(sock, ®_msg, sizeof(reg_msg)); |
b0a99af4 | 842 | if (len < 0 || len != sizeof(reg_msg)) { |
57773204 | 843 | perror("ustcomm_recv_unix_sock"); |
b0a99af4 MD |
844 | continue; |
845 | } | |
846 | memcpy(bufname, reg_msg.name, 16); | |
847 | bufname[16] = '\0'; | |
848 | printf("Application %s pid %u ppid %u uid %u gid %u has registered (version : %u.%u)\n", | |
849 | bufname, reg_msg.pid, reg_msg.ppid, reg_msg.uid, | |
850 | reg_msg.gid, reg_msg.major, reg_msg.minor); | |
851 | ret = send_app_msgs(sock, outputpath, nr_events, event_names); | |
852 | if (ret) { | |
853 | printf("Error in send_app_msgs.\n"); | |
854 | sleep(1); | |
855 | } | |
856 | close(sock); | |
857 | } | |
858 | ||
859 | end: | |
860 | printf("quitting.\n"); | |
861 | /* Let applications know we are not responding anymore */ | |
862 | ret = update_futex(wait_shm_fd, 0); | |
863 | if (ret) { | |
864 | fprintf(stderr, "Error wakeup futex\n"); | |
865 | return -1; | |
866 | } | |
867 | ||
868 | return 0; | |
869 | } |