current todo
[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
26#include <ltt/libltt.h>
27
28
29/* Private interface */
30
31enum {
32 LTTCTL_ERR_NONE = 0,
33 LTTCTL_ERR_IMPL,
34 LTTCTL_ERR_HANDLE,
35 LTTCTL_ERR_SOCKET,
36 LTTCTL_ERR_BIND,
37 LTTCTL_ERR_BUFFER,
38 LTTCTL_ERR_RECV,
39 LTTCTL_ERR_NLEOF,
40 LTTCTL_ERR_ADDRLEN,
41 LTTCTL_ERR_STRUNC,
42 LTTCTL_ERR_RTRUNC,
43 LTTCTL_ERR_NLRECV,
44 LTTCTL_ERR_SEND,
45 LTTCTL_ERR_SUPP,
46 LTTCTL_ERR_RECVBUF,
47 LTTCTL_ERR_TIMEOUT,
48 LTTCTL_ERR_PROTOCOL
49};
50#define LTTCTL_MAXERR LTTCTL_ERR_PROTOCOL
51
52
53struct lttctl_errmap_t {
54 int errcode;
55 char *message;
56} lttctl_errmap[] = {
57 { IPQ_ERR_NONE, "Unknown error" },
58 { IPQ_ERR_IMPL, "Implementation error" },
59 { IPQ_ERR_HANDLE, "Unable to create netlink handle" },
60 { IPQ_ERR_SOCKET, "Unable to create netlink socket" },
61 { IPQ_ERR_BIND, "Unable to bind netlink socket" },
62 { IPQ_ERR_BUFFER, "Unable to allocate buffer" },
63 { IPQ_ERR_RECV, "Failed to receive netlink message" },
64 { IPQ_ERR_NLEOF, "Received EOF on netlink socket" },
65 { IPQ_ERR_ADDRLEN, "Invalid peer address length" },
66 { IPQ_ERR_STRUNC, "Sent message truncated" },
67 { IPQ_ERR_RTRUNC, "Received message truncated" },
68 { IPQ_ERR_NLRECV, "Received error from netlink" },
69 { IPQ_ERR_SEND, "Failed to send netlink message" },
70 { IPQ_ERR_SUPP, "Operation not supported" },
71 { IPQ_ERR_RECVBUF, "Receive buffer size invalid" },
72 { IPQ_ERR_TIMEOUT, "Timeout"},
73 { IPQ_ERR_PROTOCOL, "Invalid protocol specified" }
74};
75
76static int lttctl_errno = LTTCTL_ERR_NONE;
77
78
79static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
80 const void *msg, size_t len);
81
82static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
83 unsigned char *buf, size_t len,
84 int timeout);
85
86static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
87 const struct msghdr *msg,
88 unsigned int flags);
89
90static char *lttctl_strerror(int errcode);
91
92static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
93 const void *msg, size_t len)
94{
95 int status = sendto(h->fd, msg, len, 0,
96 (struct sockaddr *)&h->peer, sizeof(h->peer));
97 if (status < 0)
98 lttctl_errno = LTTCTL_ERR_SEND;
99 return status;
100}
101
102static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
103 const struct msghdr *msg,
104 unsigned int flags)
105{
106 int status = sendmsg(h->fd, msg, flags);
107 if (status < 0)
108 lttctl_errno = LTTCTL_ERR_SEND;
109 return status;
110}
111
112static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
113 unsigned char *buf, size_t len,
114 int timeout)
115{
116 int addrlen, status;
117 struct nlmsghdr *nlh;
118
119 if (len < sizeof(struct nlmsgerr)) {
120 lttctl_errno = LTTCTL_ERR_RECVBUF;
121 return -1;
122 }
123 addrlen = sizeof(h->peer);
124
125 if (timeout != 0) {
126 int ret;
127 struct timeval tv;
128 fd_set read_fds;
129
130 if (timeout < 0) {
131 /* non-block non-timeout */
132 tv.tv_sec = 0;
133 tv.tv_usec = 0;
134 } else {
135 tv.tv_sec = timeout / 1000000;
136 tv.tv_usec = timeout % 1000000;
137 }
138
139 FD_ZERO(&read_fds);
140 FD_SET(h->fd, &read_fds);
141 ret = select(h->fd+1, &read_fds, NULL, NULL, &tv);
142 if (ret < 0) {
143 if (errno == EINTR) {
144 return 0;
145 } else {
146 lttctl_errno = lttctl_ERR_RECV;
147 return -1;
148 }
149 }
150 if (!FD_ISSET(h->fd, &read_fds)) {
151 lttctl_errno = lttctl_ERR_TIMEOUT;
152 return 0;
153 }
154 }
155 status = recvfrom(h->fd, buf, len, 0,
156 (struct sockaddr *)&h->peer, &addrlen);
157 if (status < 0) {
158 lttctl_errno = LTTCTL_ERR_RECV;
159 return status;
160 }
161 if (addrlen != sizeof(h->peer)) {
162 lttctl_errno = LTTCTL_ERR_RECV;
163 return -1;
164 }
165 if (h->peer.nl_pid != 0) {
166 lttctl_errno = LTTCTL_ERR_RECV;
167 return -1;
168 }
169 if (status == 0) {
170 lttctl_errno = LTTCTL_ERR_NLEOF;
171 return -1;
172 }
173 nlh = (struct nlmsghdr *)buf;
174 if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) {
175 lttctl_errno = LTTCTL_ERR_RTRUNC;
176 return -1;
177 }
178 return status;
179}
180
181
182static char *lttctl_strerror(int errcode)
183{
184 if (errcode < 0 || errcode > LTTCTL_MAXERR)
185 errcode = LTTCTL_ERR_IMPL;
186 return lttctl_errmap[errcode].message;
187}
188
189
190
191/* public interface */
192
193/*
194 * Create and initialise an lttctl handle.
195 */
196struct lttctl_handle *lttctl_create_handle(void)
197{
198 int status;
199 struct lttctl_handle *h;
200
201 h = (struct lttctl_handle *)malloc(sizeof(struct lttctl_handle));
202 if (h == NULL) {
203 lttctl_errno = lttctl_ERR_HANDLE;
204 return NULL;
205 }
206
207 memset(h, 0, sizeof(struct lttctl_handle));
208
209 h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LTT);
210
211 if (h->fd == -1) {
212 lttctl_errno = LTTCTL_ERR_SOCKET;
213 close(h->fd);
214 free(h);
215 return NULL;
216 }
217 memset(&h->local, 0, sizeof(struct sockaddr_nl));
218 h->local.nl_family = AF_NETLINK;
219 h->local.nl_pid = getpid();
220 h->local.nl_groups = 0;
221 status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local));
222 if (status == -1) {
223 lttctl_errno = LTTCTL_ERR_BIND;
224 close(h->fd);
225 free(h);
226 return NULL;
227 }
228 memset(&h->peer, 0, sizeof(struct sockaddr_nl));
229 h->peer.nl_family = AF_NETLINK;
230 h->peer.nl_pid = 0;
231 h->peer.nl_groups = 0;
232 return h;
233}
234
235/*
236 * No error condition is checked here at this stage, but it may happen
237 * if/when reliable messaging is implemented.
238 */
239int lttctl_destroy_handle(struct lttctl_handle *h)
240{
241 if (h) {
242 close(h->fd);
243 free(h);
244 }
245 return 0;
246}
247
248
249int lttctl_create_trace(const struct ipq_handle *h,
250 char *name, enum trace_mode mode)
251{
252 struct {
253 struct nlmsghdr nlh;
254 lttctl_peer_msg_t msg;
255 } req;
256
257 memset(&req, 0, sizeof(req));
258 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
259 req.nlh.nlmsg_flags = NLM_F_REQUEST;
260 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
261 req.nlh.nlmsg_pid = h->local.nl_pid;
262
263 strncpy(req.msg.trace_name, name, NAME_MAX);
264 req.msg.op = OP_CREATE;
265 req.msg.args.mode = mode;
266
267 return lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
268}
269
270int lttctl_destroy_trace(const struct ipq_handle *h,
271 char *name)
272{
273 struct {
274 struct nlmsghdr nlh;
275 lttctl_peer_msg_t msg;
276 } req;
277
278 memset(&req, 0, sizeof(req));
279 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
280 req.nlh.nlmsg_flags = NLM_F_REQUEST;
281 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
282 req.nlh.nlmsg_pid = h->local.nl_pid;
283
284 strncpy(req.msg.trace_name, name, NAME_MAX);
285 req.msg.op = OP_DESTROY;
286
287 return lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
288}
289
290int lttctl_start(const struct ipq_handle *h,
291 char *name)
292{
293 struct {
294 struct nlmsghdr nlh;
295 lttctl_peer_msg_t msg;
296 } req;
297
298 memset(&req, 0, sizeof(req));
299 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
300 req.nlh.nlmsg_flags = NLM_F_REQUEST;
301 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
302 req.nlh.nlmsg_pid = h->local.nl_pid;
303
304 strncpy(req.msg.trace_name, name, NAME_MAX);
305 req.msg.op = OP_START;
306
307 return lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
308}
309
310int lttctl_stop(const struct ipq_handle *h,
311 char *name)
312{
313 struct {
314 struct nlmsghdr nlh;
315 lttctl_peer_msg_t msg;
316 } req;
317
318 memset(&req, 0, sizeof(req));
319 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req));
320 req.nlh.nlmsg_flags = NLM_F_REQUEST;
321 req.nlh.nlmsg_type = LTTCTLM_CONTROL;
322 req.nlh.nlmsg_pid = h->local.nl_pid;
323
324 strncpy(req.msg.trace_name, name, NAME_MAX);
325 req.msg.op = OP_STOP;
326
327 return lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len);
328}
This page took 0.033081 seconds and 4 git commands to generate.