d8fa3ca18777faba7bd1f1da23a9b69989ce19a5
[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 #include <ltt/libltt.h>
27
28
29 /* Private interface */
30
31 enum {
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
53 struct 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
76 static int lttctl_errno = LTTCTL_ERR_NONE;
77
78
79 static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h,
80 const void *msg, size_t len);
81
82 static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h,
83 unsigned char *buf, size_t len,
84 int timeout);
85
86 static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h,
87 const struct msghdr *msg,
88 unsigned int flags);
89
90 static char *lttctl_strerror(int errcode);
91
92 static 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
102 static 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
112 static 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
182 static 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 */
196 struct 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 */
239 int 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
249 int 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
270 int 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
290 int 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
310 int 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.049146 seconds and 3 git commands to generate.