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