ust: add markers autoconnect
[ust.git] / libtracectl / tracectl.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <signal.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <sched.h>
8
9 #include "marker.h"
10
11 #define UNIX_PATH_MAX 108
12
13 //#define SOCKETDIR "/var/run/ust/socks"
14 #define SOCKETDIR "/tmp/socks"
15 #define SOCKETDIRLEN sizeof(SOCKETDIR)
16 #define USTSIGNAL SIGIO
17
18 #define DBG(fmt, args...) fprintf(stderr, fmt "\n", ## args)
19 #define WARN(fmt, args...) fprintf(stderr, "usertrace: WARNING: " fmt "\n", ## args)
20 #define ERR(fmt, args...) fprintf(stderr, "usertrace: ERROR: " fmt "\n", ## args)
21 #define PERROR(call) perror("usertrace: ERROR: " call)
22
23 #define MAX_MSG_SIZE (100)
24 #define MSG_NOTIF 1
25 #define MSG_REGISTER_NOTIF 2
26
27 struct tracecmd { /* no padding */
28 uint32_t size;
29 uint16_t command;
30 };
31
32 //struct listener_arg {
33 // int pipe_fd;
34 //};
35
36 struct trctl_msg {
37 /* size: the size of all the fields except size itself */
38 uint32_t size;
39 uint16_t type;
40 /* Only the necessary part of the payload is transferred. It
41 * may even be none of it.
42 */
43 char payload[94];
44 };
45
46 pid_t mypid;
47 char mysocketfile[UNIX_PATH_MAX] = "";
48 int pfd = -1;
49
50
51 static void print_markers(void)
52 {
53 struct marker_iter iter;
54
55 marker_iter_reset(&iter);
56 marker_iter_start(&iter);
57
58 while(iter.marker) {
59 fprintf(stderr, "marker: %s_%s \"%s\"\n", iter.marker->channel, iter.marker->name, iter.marker->format);
60 marker_iter_next(&iter);
61 }
62 }
63
64 void do_command(struct tracecmd *cmd)
65 {
66 }
67
68 void receive_commands()
69 {
70 }
71
72 int fd_notif = -1;
73 void notif_cb(void)
74 {
75 int result;
76 struct trctl_msg msg;
77
78 /* FIXME: fd_notif should probably be protected by a spinlock */
79
80 if(fd_notif == -1)
81 return;
82
83 msg.type = MSG_NOTIF;
84 msg.size = sizeof(msg.type);
85
86 /* FIXME: don't block here */
87 result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
88 if(result == -1) {
89 PERROR("write");
90 return;
91 }
92 }
93
94 char recvbuf[10000];
95
96 int listener_main(void *p)
97 {
98 int result;
99
100 for(;;) {
101 uint32_t size;
102 struct sockaddr_un addr;
103 socklen_t addrlen = sizeof(addr);
104 char trace_name[] = "auto";
105 char trace_type[] = "ustrelay";
106
107 for(;;) {
108 struct trctl_msg msg;
109 int len;
110
111 result = len = recvfrom(pfd, recvbuf, sizeof(recvbuf), 0, &addr, &addrlen);
112 if(result == -1) {
113 PERROR("recvfrom");
114 continue;
115 }
116
117 if(recvbuf[len-1] == '\n')
118 recvbuf[len-1] = '\0';
119
120 fprintf(stderr, "received a message! it's: %s\n", recvbuf);
121
122
123 if(!strcmp(recvbuf, "print_markers")) {
124 print_markers();
125 }
126 else if(!strcmp(recvbuf, "trace_setup")) {
127 DBG("trace setup");
128
129 result = ltt_trace_setup(trace_name);
130 if(result < 0) {
131 ERR("ltt_trace_setup failed");
132 return;
133 }
134
135 result = ltt_trace_set_type(trace_name, trace_type);
136 if(result < 0) {
137 ERR("ltt_trace_set_type failed");
138 return;
139 }
140 }
141 else if(!strcmp(recvbuf, "trace_alloc")) {
142 DBG("trace alloc");
143
144 result = ltt_trace_alloc(trace_name);
145 if(result < 0) {
146 ERR("ltt_trace_alloc failed");
147 return;
148 }
149 }
150 else if(!strcmp(recvbuf, "trace_start")) {
151 DBG("trace start");
152
153 result = ltt_trace_start(trace_name);
154 if(result < 0) {
155 ERR("ltt_trace_start failed");
156 return;
157 }
158 }
159 else if(!strcmp(recvbuf, "trace_stop")) {
160 DBG("trace stop");
161
162 result = ltt_trace_stop(trace_name);
163 if(result < 0) {
164 ERR("ltt_trace_stop failed");
165 return;
166 }
167 }
168 else if(!strcmp(recvbuf, "trace_destroy")) {
169
170 DBG("trace destroy");
171
172 result = ltt_trace_destroy(trace_name);
173 if(result < 0) {
174 ERR("ltt_trace_destroy failed");
175 return;
176 }
177 }
178 }
179 next_conn:;
180 }
181 }
182
183 void create_listener(void)
184 {
185 int result;
186 static char listener_stack[16384];
187
188 result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
189 if(result == -1) {
190 perror("clone");
191 }
192 }
193
194 /* The signal handler itself. */
195
196 void sighandler(int sig)
197 {
198 DBG("sighandler");
199 create_listener();
200 }
201
202 /* Called by the app signal handler to chain it to us. */
203
204 void chain_signal(void)
205 {
206 sighandler(USTSIGNAL);
207 }
208
209 static int init_socket(void)
210 {
211 int result;
212 int fd;
213 char pidstr[6];
214 int pidlen;
215
216 struct sockaddr_un addr;
217
218 result = fd = socket(PF_UNIX, SOCK_DGRAM, 0);
219 if(result == -1) {
220 PERROR("socket");
221 return -1;
222 }
223
224 addr.sun_family = AF_UNIX;
225
226 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%d", SOCKETDIR, mypid);
227 if(result >= UNIX_PATH_MAX) {
228 ERR("string overflow allocating socket name");
229 goto close_sock;
230 }
231 //DBG("opening socket at %s", addr.sun_path);
232
233 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
234 if(result == -1) {
235 PERROR("bind");
236 goto close_sock;
237 }
238
239 strcpy(mysocketfile, addr.sun_path);
240
241 pfd = fd;
242 return 0;
243
244 close_sock:
245 close(fd);
246
247 return -1;
248 }
249
250 static void destroy_socket(void)
251 {
252 int result;
253
254 if(mysocketfile[0] == '\0')
255 return;
256
257 result = unlink(mysocketfile);
258 if(result == -1) {
259 PERROR("unlink");
260 }
261 }
262
263 static int init_signal_handler(void)
264 {
265 /* Attempt to handler SIGIO. If the main program wants to
266 * handle it, fine, it'll override us. They it'll have to
267 * use the chaining function.
268 */
269
270 int result;
271 struct sigaction act;
272
273 result = sigemptyset(&act.sa_mask);
274 if(result == -1) {
275 PERROR("sigemptyset");
276 return -1;
277 }
278
279 act.sa_handler = sighandler;
280 act.sa_flags = SA_RESTART;
281
282 /* Only defer ourselves. Also, try to restart interrupted
283 * syscalls to disturb the traced program as little as possible.
284 */
285 result = sigaction(SIGIO, &act, NULL);
286 if(result == -1) {
287 PERROR("sigaction");
288 return -1;
289 }
290
291 return 0;
292 }
293
294 static void auto_probe_connect(struct marker *m)
295 {
296 int result;
297
298 result = ltt_marker_connect(m->channel, m->name, "default");
299 if(result)
300 ERR("ltt_marker_connect");
301
302 DBG("just auto connected marker %s %s to probe default", m->channel, m->name);
303 }
304
305 static void __attribute__((constructor(101))) init0()
306 {
307 DBG("UST_AUTOPROBE constructor");
308 if(getenv("UST_AUTOPROBE")) {
309 marker_set_new_marker_cb(auto_probe_connect);
310 }
311 }
312
313 static void __attribute__((constructor(1000))) init()
314 {
315 int result;
316
317 DBG("UST_TRACE constructor");
318
319 mypid = getpid();
320
321 if(getenv("UST_TRACE")) {
322 char trace_name[] = "auto";
323 char trace_type[] = "ustrelay";
324
325 DBG("starting early tracing");
326
327 /* Ensure marker control is initialized */
328 init_marker_control();
329
330 /* Ensure relay is initialized */
331 init_ustrelay_transport();
332
333 /* Ensure markers are initialized */
334 init_markers();
335
336 /* In case. */
337 ltt_channels_register("ust");
338
339 result = ltt_trace_setup(trace_name);
340 if(result < 0) {
341 ERR("ltt_trace_setup failed");
342 return;
343 }
344
345 result = ltt_trace_set_type(trace_name, trace_type);
346 if(result < 0) {
347 ERR("ltt_trace_set_type failed");
348 return;
349 }
350
351 result = ltt_trace_alloc(trace_name);
352 if(result < 0) {
353 ERR("ltt_trace_alloc failed");
354 return;
355 }
356
357 result = ltt_trace_start(trace_name);
358 if(result < 0) {
359 ERR("ltt_trace_start failed");
360 return;
361 }
362 }
363
364 /* Must create socket before signal handler to prevent races
365 * on pfd variable.
366 */
367 result = init_socket();
368 if(result == -1) {
369 ERR("init_socket error");
370 return;
371 }
372 result = init_signal_handler();
373 if(result == -1) {
374 ERR("init_signal_handler error");
375 return;
376 }
377
378 return;
379
380 /* should decrementally destroy stuff if error */
381
382 }
383
384 /* This is only called if we terminate normally, not with an unhandled signal,
385 * so we cannot rely on it. */
386
387 static void __attribute__((destructor)) fini()
388 {
389 destroy_socket();
390 }
This page took 0.040997 seconds and 4 git commands to generate.