Commit | Line | Data |
---|---|---|
68c1021b PMF |
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> | |
98963de4 | 7 | #include <sched.h> |
fbd8191b PMF |
8 | |
9 | #include "marker.h" | |
10 | ||
68c1021b PMF |
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 | ||
98963de4 PMF |
23 | #define MAX_MSG_SIZE (100) |
24 | #define MSG_NOTIF 1 | |
25 | #define MSG_REGISTER_NOTIF 2 | |
26 | ||
68c1021b PMF |
27 | struct tracecmd { /* no padding */ |
28 | uint32_t size; | |
29 | uint16_t command; | |
30 | }; | |
31 | ||
98963de4 PMF |
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 | }; | |
68c1021b PMF |
45 | |
46 | pid_t mypid; | |
47 | char mysocketfile[UNIX_PATH_MAX] = ""; | |
98963de4 | 48 | int pfd = -1; |
68c1021b | 49 | |
fbd8191b PMF |
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 | ||
68c1021b PMF |
64 | void do_command(struct tracecmd *cmd) |
65 | { | |
66 | } | |
67 | ||
68 | void receive_commands() | |
69 | { | |
70 | } | |
71 | ||
98963de4 PMF |
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 | ||
fbd8191b PMF |
94 | char recvbuf[10000]; |
95 | ||
98963de4 PMF |
96 | int listener_main(void *p) |
97 | { | |
98 | int result; | |
99 | ||
98963de4 | 100 | for(;;) { |
98963de4 | 101 | uint32_t size; |
98963de4 PMF |
102 | struct sockaddr_un addr; |
103 | socklen_t addrlen = sizeof(addr); | |
aafb1650 PMF |
104 | char trace_name[] = "auto"; |
105 | char trace_type[] = "ustrelay"; | |
98963de4 | 106 | |
98963de4 PMF |
107 | for(;;) { |
108 | struct trctl_msg msg; | |
fbd8191b | 109 | int len; |
98963de4 | 110 | |
fbd8191b | 111 | result = len = recvfrom(pfd, recvbuf, sizeof(recvbuf), 0, &addr, &addrlen); |
98963de4 | 112 | if(result == -1) { |
fbd8191b | 113 | PERROR("recvfrom"); |
98963de4 PMF |
114 | continue; |
115 | } | |
116 | ||
aafb1650 PMF |
117 | if(recvbuf[len-1] == '\n') |
118 | recvbuf[len-1] = '\0'; | |
98963de4 | 119 | |
fbd8191b | 120 | fprintf(stderr, "received a message! it's: %s\n", recvbuf); |
98963de4 | 121 | |
fbd8191b PMF |
122 | |
123 | if(!strcmp(recvbuf, "print_markers")) { | |
124 | print_markers(); | |
125 | } | |
126 | else if(!strcmp(recvbuf, "trace_setup")) { | |
127 | DBG("trace setup"); | |
aafb1650 PMF |
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 | } | |
fbd8191b PMF |
140 | } |
141 | else if(!strcmp(recvbuf, "trace_alloc")) { | |
142 | DBG("trace alloc"); | |
aafb1650 PMF |
143 | |
144 | result = ltt_trace_alloc(trace_name); | |
145 | if(result < 0) { | |
146 | ERR("ltt_trace_alloc failed"); | |
147 | return; | |
148 | } | |
fbd8191b PMF |
149 | } |
150 | else if(!strcmp(recvbuf, "trace_start")) { | |
151 | DBG("trace start"); | |
aafb1650 PMF |
152 | |
153 | result = ltt_trace_start(trace_name); | |
154 | if(result < 0) { | |
155 | ERR("ltt_trace_start failed"); | |
156 | return; | |
157 | } | |
fbd8191b PMF |
158 | } |
159 | else if(!strcmp(recvbuf, "trace_stop")) { | |
160 | DBG("trace stop"); | |
aafb1650 PMF |
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 | } | |
fbd8191b | 177 | } |
98963de4 PMF |
178 | } |
179 | next_conn:; | |
180 | } | |
181 | } | |
182 | ||
183 | void create_listener(void) | |
184 | { | |
185 | int result; | |
186 | static char listener_stack[16384]; | |
187 | ||
fbd8191b | 188 | result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL); |
98963de4 PMF |
189 | if(result == -1) { |
190 | perror("clone"); | |
191 | } | |
192 | } | |
193 | ||
68c1021b PMF |
194 | /* The signal handler itself. */ |
195 | ||
196 | void sighandler(int sig) | |
197 | { | |
198 | DBG("sighandler"); | |
fbd8191b | 199 | create_listener(); |
68c1021b PMF |
200 | } |
201 | ||
202 | /* Called by the app signal handler to chain it to us. */ | |
203 | ||
98963de4 | 204 | void chain_signal(void) |
68c1021b PMF |
205 | { |
206 | sighandler(USTSIGNAL); | |
207 | } | |
208 | ||
98963de4 | 209 | static int init_socket(void) |
68c1021b PMF |
210 | { |
211 | int result; | |
212 | int fd; | |
213 | char pidstr[6]; | |
214 | int pidlen; | |
215 | ||
216 | struct sockaddr_un addr; | |
217 | ||
fbd8191b | 218 | result = fd = socket(PF_UNIX, SOCK_DGRAM, 0); |
68c1021b PMF |
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 | ||
98963de4 PMF |
241 | pfd = fd; |
242 | return 0; | |
243 | ||
68c1021b PMF |
244 | close_sock: |
245 | close(fd); | |
246 | ||
247 | return -1; | |
248 | } | |
249 | ||
98963de4 | 250 | static void destroy_socket(void) |
68c1021b PMF |
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 | ||
98963de4 | 263 | static int init_signal_handler(void) |
68c1021b PMF |
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 | ||
98963de4 | 294 | static void __attribute__((constructor)) init() |
68c1021b PMF |
295 | { |
296 | int result; | |
297 | ||
298 | mypid = getpid(); | |
299 | ||
4db647c5 PMF |
300 | if(getenv("UST_TRACE")) { |
301 | char trace_name[] = "auto"; | |
302 | char trace_type[] = "ustrelay"; | |
303 | ||
304 | DBG("starting early tracing"); | |
305 | ||
306 | /* Ensure marker control is initialized */ | |
307 | init_marker_control(); | |
308 | ||
309 | /* Ensure relay is initialized */ | |
310 | init_ustrelay_transport(); | |
311 | ||
312 | /* Ensure markers are initialized */ | |
313 | init_markers(); | |
314 | ||
315 | result = ltt_marker_connect("foo", "bar", "default"); | |
316 | if(result) | |
317 | ERR("ltt_marker_connect"); | |
aafb1650 PMF |
318 | |
319 | result = ltt_marker_connect("foo", "bar2", "default"); | |
320 | if(result) | |
321 | ERR("ltt_marker_connect"); | |
4db647c5 PMF |
322 | |
323 | result = ltt_trace_setup(trace_name); | |
324 | if(result < 0) { | |
325 | ERR("ltt_trace_setup failed"); | |
326 | return; | |
327 | } | |
328 | ||
329 | result = ltt_trace_set_type(trace_name, trace_type); | |
330 | if(result < 0) { | |
331 | ERR("ltt_trace_set_type failed"); | |
332 | return; | |
333 | } | |
334 | ||
335 | result = ltt_trace_alloc(trace_name); | |
336 | if(result < 0) { | |
337 | ERR("ltt_trace_alloc failed"); | |
338 | return; | |
339 | } | |
340 | ||
341 | result = ltt_trace_start(trace_name); | |
342 | if(result < 0) { | |
343 | ERR("ltt_trace_start failed"); | |
344 | return; | |
345 | } | |
346 | } | |
347 | ||
98963de4 PMF |
348 | /* Must create socket before signal handler to prevent races |
349 | * on pfd variable. | |
350 | */ | |
68c1021b | 351 | result = init_socket(); |
98963de4 PMF |
352 | if(result == -1) { |
353 | ERR("init_socket error"); | |
354 | return; | |
355 | } | |
356 | result = init_signal_handler(); | |
357 | if(result == -1) { | |
358 | ERR("init_signal_handler error"); | |
359 | return; | |
360 | } | |
68c1021b PMF |
361 | |
362 | return; | |
363 | ||
364 | /* should decrementally destroy stuff if error */ | |
365 | ||
366 | } | |
367 | ||
368 | /* This is only called if we terminate normally, not with an unhandled signal, | |
369 | * so we cannot rely on it. */ | |
370 | ||
98963de4 | 371 | static void __attribute__((destructor)) fini() |
68c1021b PMF |
372 | { |
373 | destroy_socket(); | |
374 | } |