detailed event list redesign
[lttv.git] / ltt / branches / poly / libltt / libltt.c
1 /* libltt
2 *
3 * Linux Trace Toolkit Netlink Control Library
4 *
5 * Controls the ltt-control kernel module through a netlink socket.
6 *
7 * Heavily inspired from libipq.c (iptables) made by
8 * James Morris <jmorris@intercode.com.au>
9 *
10 * Copyright 2005 -
11 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <libltt/libltt.h>
31 #include <errno.h>
32 #include <stdio.h>
33
34
35 /* Private interface */
36
37 enum {
38 LTTCTL_ERR_NONE = 0,
39 LTTCTL_ERR_IMPL,
40 LTTCTL_ERR_HANDLE,
41 LTTCTL_ERR_SOCKET,
42 LTTCTL_ERR_BIND,
43 LTTCTL_ERR_BUFFER,
44 LTTCTL_ERR_RECV,
45 LTTCTL_ERR_NLEOF,
46 LTTCTL_ERR_ADDRLEN,
47 LTTCTL_ERR_STRUNC,
48 LTTCTL_ERR_RTRUNC,
49 LTTCTL_ERR_NLRECV,
50 LTTCTL_ERR_SEND,
51 LTTCTL_ERR_SUPP,
52 LTTCTL_ERR_RECVBUF,
53 LTTCTL_ERR_TIMEOUT,
54 LTTCTL_ERR_PROTOCOL
55 };
56 #define LTTCTL_MAXERR LTTCTL_ERR_PROTOCOL
57
58
59 struct lttctl_errmap_t {
60 int errcode;
61 char *message;
62 } lttctl_errmap[] = {
63 { LTTCTL_ERR_NONE, "Unknown error" },
64 { LTTCTL_ERR_IMPL, "Implementation error" },
65 { LTTCTL_ERR_HANDLE, "Unable to create netlink handle" },
66 { LTTCTL_ERR_SOCKET, "Unable to create netlink socket" },
67 { LTTCTL_ERR_BIND, "Unable to bind netlink socket" },
68 { LTTCTL_ERR_BUFFER, "Unable to allocate buffer" },
69 { LTTCTL_ERR_RECV, "Failed to receive netlink message" },
70 { LTTCTL_ERR_NLEOF, "Received EOF on netlink socket" },
71 { LTTCTL_ERR_ADDRLEN, "Invalid peer address length" },
72 { LTTCTL_ERR_STRUNC, "Sent message truncated" },
73 { LTTCTL_ERR_RTRUNC, "Received message truncated" },
74 { LTTCTL_ERR_NLRECV, "Received error from netlink" },
75 { LTTCTL_ERR_SEND, "Failed to send netlink message" },
76 { LTTCTL_ERR_SUPP, "Operation not supported" },
77 { LTTCTL_ERR_RECVBUF, "Receive buffer size invalid" },
78 { LTTCTL_ERR_TIMEOUT, "Timeout"},
79 { LTTCTL_ERR_PROTOCOL, "Invalid protocol specified" }
80 };
81
82 static int lttctl_errno = LTTCTL_ERR_NONE;
83
84
85 static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
86 const void *msg, size_t len);
87
88 static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
89 unsigned char *buf, size_t len,
90 int timeout);
91
92 static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
93 const struct msghdr *msg,
94 unsigned int flags);
95
96 static char *lttctl_strerror(int errcode);
97
98 void lttctl_perror(const char *s);
99
100 static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
101 const void *msg, size_t len)
102 {
103 int status = sendto(h->fd, msg, len, 0,
104 (struct sockaddr *)&h->peer, sizeof(h->peer));
105 if (status < 0)
106 lttctl_errno = LTTCTL_ERR_SEND;
107
108 return status;
109 }
110
111 static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
112 const struct msghdr *msg,
113 unsigned int flags)
114 {
115 int status = sendmsg(h->fd, msg, flags);
116 if (status < 0)
117 lttctl_errno = LTTCTL_ERR_SEND;
118 return status;
119 }
120
121 static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
122 unsigned char *buf, size_t len,
123 int timeout)
124 {
125 int addrlen, status;
126 struct nlmsghdr *nlh;
127
128 if (len < sizeof(struct nlmsghdr)) {
129 lttctl_errno = LTTCTL_ERR_RECVBUF;
130 lttctl_perror("Netlink recvfrom");
131 return -1;
132 }
133 addrlen = sizeof(h->peer);
134
135 if (timeout != 0) {
136 int ret;
137 struct timeval tv;
138 fd_set read_fds;
139
140 if (timeout < 0) {
141 /* non-block non-timeout */
142 tv.tv_sec = 0;
143 tv.tv_usec = 0;
144 } else {
145 tv.tv_sec = timeout / 1000000;
146 tv.tv_usec = timeout % 1000000;
147 }
148
149 FD_ZERO(&read_fds);
150 FD_SET(h->fd, &read_fds);
151 ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
152 if (ret < 0) {
153 if (errno == EINTR) {
154 printf("eintr\n");
155 return 0;
156 } else {
157 lttctl_errno = LTTCTL_ERR_RECV;
158 lttctl_perror("Netlink recvfrom");
159 return -1;
160 }
161 }
162 if (!FD_ISSET(h->fd, &read_fds)) {
163 lttctl_errno = LTTCTL_ERR_TIMEOUT;
164 printf("timeout\n");
165 return 0;
166 }
167 }
168 status = recvfrom(h->fd, buf, len, 0,
169 (struct sockaddr *)&h->peer, &addrlen);
170
171 if (status < 0) {
172 lttctl_errno = LTTCTL_ERR_RECV;
173 lttctl_perror("Netlink recvfrom");
174 return status;
175 }
176 if (addrlen != sizeof(h->peer)) {
177 lttctl_errno = LTTCTL_ERR_RECV;
178 lttctl_perror("Netlink recvfrom");
179 return -1;
180 }
181 if (h->peer.nl_pid != 0) {
182 lttctl_errno = LTTCTL_ERR_RECV;
183 lttctl_perror("Netlink recvfrom");
184 return -1;
185 }
186 if (status == 0) {
187 lttctl_errno = LTTCTL_ERR_NLEOF;
188 lttctl_perror("Netlink recvfrom");
189 return -1;
190 }
191 nlh = (struct nlmsghdr *)buf;
192 if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
193 lttctl_errno = LTTCTL_ERR_RTRUNC;
194 lttctl_perror("Netlink recvfrom");
195 return -1;
196 }
197
198
199 return status;
200 }
201
202
203 static char *lttctl_strerror(int errcode)
204 {
205 if (errcode < 0 || errcode > LTTCTL_MAXERR)
206 errcode = LTTCTL_ERR_IMPL;
207 return lttctl_errmap[errcode].message;
208 }
209
210
211 char *lttctl_errstr(void)
212 {
213 return lttctl_strerror(lttctl_errno);
214 }
215
216 void lttctl_perror(const char *s)
217 {
218 if (s)
219 fputs(s, stderr);
220 else
221 fputs("ERROR", stderr);
222 if (lttctl_errno)
223 fprintf(stderr, ": %s", lttctl_errstr());
224 if (errno)
225 fprintf(stderr, ": %s", strerror(errno));
226 fputc('\n', stderr);
227 }
228
229 /* public interface */
230
231 /*
232 * Create and initialise an lttctl handle.
233 */
234 struct lttctl_handle *lttctl_create_handle(void)
235 {
236 int status;
237 struct lttctl_handle *h;
238
239 h = (struct lttctl_handle *)malloc(sizeof(struct lttctl_handle));
240 if (h == NULL) {
241 lttctl_errno = LTTCTL_ERR_HANDLE;
242 lttctl_perror("Create handle");
243 goto alloc_error;
244 }
245
246 memset(h, 0, sizeof(struct lttctl_handle));
247
248 h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LTT);
249
250 if (h->fd == -1) {
251 lttctl_errno = LTTCTL_ERR_SOCKET;
252 lttctl_perror("Create handle");
253 goto socket_error;
254 }
255 memset(&h->local, 0, sizeof(struct sockaddr_nl));
256 h->local.nl_family = AF_NETLINK;
257 h->local.nl_pid = getpid();
258 h->local.nl_groups = 0;
259 status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
260 if (status == -1) {
261 lttctl_errno = LTTCTL_ERR_BIND;
262 lttctl_perror("Create handle");
263 goto bind_error;
264 }
265 memset(&h->peer, 0, sizeof(struct sockaddr_nl));
266 h->peer.nl_family = AF_NETLINK;
267 h->peer.nl_pid = 0;
268 h->peer.nl_groups = 0;
269 return h;
270
271 /* Error condition */
272 bind_error:
273 socket_error:
274 close(h->fd);
275 alloc_error:
276 free(h);
277 return NULL;
278 }
279
280 /*
281 * No error condition is checked here at this stage, but it may happen
282 * if/when reliable messaging is implemented.
283 */
284 int lttctl_destroy_handle(struct lttctl_handle *h)
285 {
286 if (h) {
287 close(h->fd);
288 free(h);
289 }
290 return 0;
291 }
292
293
294 int lttctl_create_trace(const struct lttctl_handle *h,
295 char *name, enum trace_mode mode, unsigned subbuf_size, unsigned n_subbufs)
296 {
297 int err;
298
299 struct {
300 struct nlmsghdr nlh;
301 lttctl_peer_msg_t msg;
302 } req;
303 struct {
304 struct nlmsghdr nlh;
305 struct nlmsgerr nlerr;
306 lttctl_peer_msg_t msg;
307 } ack;
308
309 memset(&req, 0, sizeof(req));
310 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
311 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
312 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
313 req.nlh.nlmsg_pid = h->local.nl_pid;
314 req.nlh.nlmsg_seq = 0;
315
316 strncpy(req.msg.trace_name, name, NAME_MAX);
317 req.msg.op = OP_CREATE;
318 req.msg.args.new_trace.mode = mode;
319 req.msg.args.new_trace.subbuf_size = subbuf_size;
320 req.msg.args.new_trace.n_subbufs = n_subbufs;
321
322 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
323 if(err < 0) goto senderr;
324
325 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
326 if(err < 0) goto senderr;
327
328 err = ack.nlerr.error;
329 if(err != 0) {
330 errno = err;
331 lttctl_perror("Create Trace Error");
332 return -1;
333 }
334
335 return 0;
336
337 senderr:
338 lttctl_perror("Create Trace Error");
339 return err;
340 }
341
342 int lttctl_destroy_trace(const struct lttctl_handle *h,
343 char *name)
344 {
345 struct {
346 struct nlmsghdr nlh;
347 lttctl_peer_msg_t msg;
348 } req;
349 struct {
350 struct nlmsghdr nlh;
351 struct nlmsgerr nlerr;
352 lttctl_peer_msg_t msg;
353 } ack;
354 int err;
355
356 memset(&req, 0, sizeof(req));
357 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
358 req.nlh.nlmsg_flags = NLM_F_REQUEST;
359 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
360 req.nlh.nlmsg_pid = h->local.nl_pid;
361
362 strncpy(req.msg.trace_name, name, NAME_MAX);
363 req.msg.op = OP_DESTROY;
364
365 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
366 if(err < 0) goto senderr;
367
368 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
369 if(err < 0) goto senderr;
370
371 err = ack.nlerr.error;
372 if(err != 0) {
373 errno = err;
374 lttctl_perror("Destroy Trace Channels Error");
375 return -1;
376 }
377
378 return 0;
379
380 senderr:
381 lttctl_perror("Destroy Trace Channels Error");
382 return err;
383
384 }
385
386 int lttctl_start(const struct lttctl_handle *h,
387 char *name)
388 {
389 struct {
390 struct nlmsghdr nlh;
391 lttctl_peer_msg_t msg;
392 } req;
393 struct {
394 struct nlmsghdr nlh;
395 struct nlmsgerr nlerr;
396 lttctl_peer_msg_t msg;
397 } ack;
398
399 int err;
400
401 memset(&req, 0, sizeof(req));
402 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
403 req.nlh.nlmsg_flags = NLM_F_REQUEST;
404 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
405 req.nlh.nlmsg_pid = h->local.nl_pid;
406
407 strncpy(req.msg.trace_name, name, NAME_MAX);
408 req.msg.op = OP_START;
409
410 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
411 if(err < 0) goto senderr;
412
413 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
414 if(err < 0) goto senderr;
415
416 err = ack.nlerr.error;
417 if(err != 0) {
418 errno = err;
419 lttctl_perror("Start Trace Error");
420 return -1;
421 }
422
423 return 0;
424
425 senderr:
426 lttctl_perror("Start Trace Error");
427 return err;
428
429 }
430
431 int lttctl_stop(const struct lttctl_handle *h,
432 char *name)
433 {
434 struct {
435 struct nlmsghdr nlh;
436 lttctl_peer_msg_t msg;
437 } req;
438 struct {
439 struct nlmsghdr nlh;
440 struct nlmsgerr nlerr;
441 lttctl_peer_msg_t msg;
442 } ack;
443 int err;
444
445 memset(&req, 0, sizeof(req));
446 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t));
447 req.nlh.nlmsg_flags = NLM_F_REQUEST;
448 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
449 req.nlh.nlmsg_pid = h->local.nl_pid;
450
451 strncpy(req.msg.trace_name, name, NAME_MAX);
452 req.msg.op = OP_STOP;
453
454 err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
455 if(err < 0) goto senderr;
456
457 err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0);
458 if(err < 0) goto senderr;
459
460 err = ack.nlerr.error;
461 if(err != 0) {
462 errno = err;
463 lttctl_perror("Stop Trace Error");
464 return -1;
465 }
466
467 return 0;
468
469 senderr:
470 lttctl_perror("Stop Trace Error");
471 return err;
472 }
473
This page took 0.039959 seconds and 4 git commands to generate.