ust: collect many channels and start work on pipe listener
[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 #define UNIX_PATH_MAX 108
9
10 //#define SOCKETDIR "/var/run/ust/socks"
11 #define SOCKETDIR "/tmp/socks"
12 #define SOCKETDIRLEN sizeof(SOCKETDIR)
13 #define USTSIGNAL SIGIO
14
15 #define DBG(fmt, args...) fprintf(stderr, fmt "\n", ## args)
16 #define WARN(fmt, args...) fprintf(stderr, "usertrace: WARNING: " fmt "\n", ## args)
17 #define ERR(fmt, args...) fprintf(stderr, "usertrace: ERROR: " fmt "\n", ## args)
18 #define PERROR(call) perror("usertrace: ERROR: " call)
19
20 #define MAX_MSG_SIZE (100)
21 #define MSG_NOTIF 1
22 #define MSG_REGISTER_NOTIF 2
23
24 struct tracecmd { /* no padding */
25 uint32_t size;
26 uint16_t command;
27 };
28
29 //struct listener_arg {
30 // int pipe_fd;
31 //};
32
33 struct trctl_msg {
34 /* size: the size of all the fields except size itself */
35 uint32_t size;
36 uint16_t type;
37 /* Only the necessary part of the payload is transferred. It
38 * may even be none of it.
39 */
40 char payload[94];
41 };
42
43 pid_t mypid;
44 char mysocketfile[UNIX_PATH_MAX] = "";
45 int pfd = -1;
46
47 void do_command(struct tracecmd *cmd)
48 {
49 }
50
51 void receive_commands()
52 {
53 }
54
55 int fd_notif = -1;
56 void notif_cb(void)
57 {
58 int result;
59 struct trctl_msg msg;
60
61 /* FIXME: fd_notif should probably be protected by a spinlock */
62
63 if(fd_notif == -1)
64 return;
65
66 msg.type = MSG_NOTIF;
67 msg.size = sizeof(msg.type);
68
69 /* FIXME: don't block here */
70 result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
71 if(result == -1) {
72 PERROR("write");
73 return;
74 }
75 }
76
77 int listener_main(void *p)
78 {
79 int result;
80
81 /* Allowing only 1 connection for now. */
82 result = listen(pfd, 1);
83 if(result == -1) {
84 PERROR("listen");
85 return 1;
86 }
87
88 for(;;) {
89
90 uint32_t size;
91 int fd;
92 struct sockaddr_un addr;
93 socklen_t addrlen = sizeof(addr);
94
95 result = fd = accept(pfd, (struct sockaddr *)&addr, &addrlen);
96 if(result == -1) {
97 PERROR("accept");
98 continue;
99 }
100
101 for(;;) {
102 struct trctl_msg msg;
103 unsigned char dontclose=0;
104
105 result = read(fd, &msg.size, sizeof(msg.size));
106 if(result == -1) {
107 PERROR("read");
108 continue;
109 }
110
111 if(size > MAX_MSG_SIZE) {
112 ERR("trctl message too big");
113 break;
114 }
115
116 result = read(fd, &msg.type, sizeof(msg.type));
117 if(result == -1) {
118 PERROR("read");
119 continue;
120 }
121
122 switch(msg.type) {
123 case MSG_REGISTER_NOTIF:
124 /* TODO: put it in notif mode */
125 goto next_conn;
126 };
127 }
128 next_conn:;
129 }
130 }
131
132 void create_listener(void)
133 {
134 int result;
135 static char listener_stack[16384];
136
137 result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM, NULL);
138 if(result == -1) {
139 perror("clone");
140 }
141 }
142
143 /* The signal handler itself. */
144
145 void sighandler(int sig)
146 {
147 DBG("sighandler");
148 receive_commands();
149 }
150
151 /* Called by the app signal handler to chain it to us. */
152
153 void chain_signal(void)
154 {
155 sighandler(USTSIGNAL);
156 }
157
158 static int init_socket(void)
159 {
160 int result;
161 int fd;
162 char pidstr[6];
163 int pidlen;
164
165 struct sockaddr_un addr;
166
167 result = fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
168 if(result == -1) {
169 PERROR("socket");
170 return -1;
171 }
172
173 addr.sun_family = AF_UNIX;
174
175 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s/%d", SOCKETDIR, mypid);
176 if(result >= UNIX_PATH_MAX) {
177 ERR("string overflow allocating socket name");
178 goto close_sock;
179 }
180 //DBG("opening socket at %s", addr.sun_path);
181
182 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
183 if(result == -1) {
184 PERROR("bind");
185 goto close_sock;
186 }
187
188 strcpy(mysocketfile, addr.sun_path);
189
190 pfd = fd;
191 return 0;
192
193 close_sock:
194 close(fd);
195
196 return -1;
197 }
198
199 static void destroy_socket(void)
200 {
201 int result;
202
203 if(mysocketfile[0] == '\0')
204 return;
205
206 result = unlink(mysocketfile);
207 if(result == -1) {
208 PERROR("unlink");
209 }
210 }
211
212 static int init_signal_handler(void)
213 {
214 /* Attempt to handler SIGIO. If the main program wants to
215 * handle it, fine, it'll override us. They it'll have to
216 * use the chaining function.
217 */
218
219 int result;
220 struct sigaction act;
221
222 result = sigemptyset(&act.sa_mask);
223 if(result == -1) {
224 PERROR("sigemptyset");
225 return -1;
226 }
227
228 act.sa_handler = sighandler;
229 act.sa_flags = SA_RESTART;
230
231 /* Only defer ourselves. Also, try to restart interrupted
232 * syscalls to disturb the traced program as little as possible.
233 */
234 result = sigaction(SIGIO, &act, NULL);
235 if(result == -1) {
236 PERROR("sigaction");
237 return -1;
238 }
239
240 return 0;
241 }
242
243 static void __attribute__((constructor)) init()
244 {
245 int result;
246
247 mypid = getpid();
248
249 /* Must create socket before signal handler to prevent races
250 * on pfd variable.
251 */
252 result = init_socket();
253 if(result == -1) {
254 ERR("init_socket error");
255 return;
256 }
257 result = init_signal_handler();
258 if(result == -1) {
259 ERR("init_signal_handler error");
260 return;
261 }
262
263 return;
264
265 /* should decrementally destroy stuff if error */
266
267 }
268
269 /* This is only called if we terminate normally, not with an unhandled signal,
270 * so we cannot rely on it. */
271
272 static void __attribute__((destructor)) fini()
273 {
274 destroy_socket();
275 }
This page took 0.036597 seconds and 4 git commands to generate.