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