Commit | Line | Data |
---|---|---|
c39c72ee PMF |
1 | /* Copyright (C) 2009 Pierre-Marc Fournier |
2 | * | |
3 | * This library is free software; you can redistribute it and/or | |
4 | * modify it under the terms of the GNU Lesser General Public | |
5 | * License as published by the Free Software Foundation; either | |
6 | * version 2.1 of the License, or (at your option) any later version. | |
7 | * | |
8 | * This library is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * Lesser General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU Lesser General Public | |
14 | * License along with this library; if not, write to the Free Software | |
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
16 | */ | |
17 | ||
93e5ce29 PMF |
18 | /* API used by UST components to communicate with each other via sockets. */ |
19 | ||
d0b5f2b9 | 20 | #define _GNU_SOURCE |
f9e5ce61 PMF |
21 | #include <sys/types.h> |
22 | #include <signal.h> | |
23 | #include <errno.h> | |
24 | #include <sys/socket.h> | |
25 | #include <sys/un.h> | |
d0b5f2b9 | 26 | #include <unistd.h> |
aca1ad90 | 27 | #include <poll.h> |
4723ca09 | 28 | #include <sys/epoll.h> |
803a4f58 | 29 | #include <sys/stat.h> |
f9e5ce61 PMF |
30 | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
d0b5f2b9 | 33 | #include <string.h> |
b0540e11 | 34 | #include <execinfo.h> |
d0b5f2b9 PMF |
35 | |
36 | #include "ustcomm.h" | |
6af64c43 | 37 | #include "usterr.h" |
2dae156b | 38 | #include "share.h" |
f9e5ce61 | 39 | |
d6d27063 PMF |
40 | static int mkdir_p(const char *path, mode_t mode) |
41 | { | |
c555b133 | 42 | const char *path_p; |
d6d27063 PMF |
43 | char *tmp; |
44 | ||
45 | int retval = 0; | |
46 | int result; | |
18baca84 | 47 | mode_t old_umask; |
d6d27063 | 48 | |
7032c7d3 | 49 | tmp = zmalloc(strlen(path) + 1); |
d6d27063 PMF |
50 | if (tmp == NULL) |
51 | return -1; | |
52 | ||
53 | /* skip first / */ | |
54 | path_p = path+1; | |
55 | ||
18baca84 | 56 | old_umask = umask(0); |
d6d27063 PMF |
57 | for(;;) { |
58 | while (*path_p != '/') { | |
59 | if(*path_p == 0) | |
60 | break; | |
61 | ++path_p; | |
62 | } | |
63 | if (*path_p == '/') { | |
64 | strncpy(tmp, path, path_p - path); | |
65 | tmp[path_p-path] = '\0'; | |
66 | if (tmp[path_p - path - 1] != '/') { | |
67 | result = mkdir(tmp, mode); | |
68 | if(result == -1) { | |
69 | if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) { | |
70 | /* Then this is a real error */ | |
71 | retval = -1; | |
72 | break; | |
73 | } | |
74 | } | |
75 | } | |
76 | /* pass / */ | |
77 | path_p++; | |
78 | } else { | |
79 | /* last component */ | |
80 | result = mkdir(path, mode); | |
81 | if (result == -1) | |
82 | retval = -1; | |
83 | break; | |
84 | } | |
85 | } | |
86 | ||
87 | free(tmp); | |
18baca84 | 88 | umask(old_umask); |
d6d27063 PMF |
89 | return retval; |
90 | } | |
91 | ||
4723ca09 NC |
92 | static struct sockaddr_un * create_sock_addr(const char *name, |
93 | size_t *sock_addr_size) | |
f9e5ce61 | 94 | { |
4723ca09 NC |
95 | struct sockaddr_un * addr; |
96 | size_t alloc_size; | |
f9e5ce61 | 97 | |
4723ca09 NC |
98 | alloc_size = (size_t) (((struct sockaddr_un *) 0)->sun_path) + |
99 | strlen(name) + 1; | |
5932431b | 100 | |
4723ca09 NC |
101 | addr = malloc(alloc_size); |
102 | if (addr < 0) { | |
103 | ERR("allocating addr failed"); | |
104 | return NULL; | |
105 | } | |
ab33e65c | 106 | |
4723ca09 NC |
107 | addr->sun_family = AF_UNIX; |
108 | strcpy(addr->sun_path, name); | |
109 | ||
110 | *sock_addr_size = alloc_size; | |
111 | ||
112 | return addr; | |
113 | } | |
2dae156b | 114 | |
4723ca09 NC |
115 | struct ustcomm_sock * ustcomm_init_sock(int fd, int epoll_fd, |
116 | struct list_head *list) | |
811e4b93 | 117 | { |
4723ca09 NC |
118 | struct epoll_event ev; |
119 | struct ustcomm_sock *sock; | |
811e4b93 | 120 | |
4723ca09 NC |
121 | sock = malloc(sizeof(struct ustcomm_sock)); |
122 | if (!sock) { | |
123 | perror("malloc: couldn't allocate ustcomm_sock"); | |
124 | return NULL; | |
811e4b93 | 125 | } |
4723ca09 NC |
126 | |
127 | ev.events = EPOLLIN; | |
128 | ev.data.ptr = sock; | |
129 | sock->fd = fd; | |
130 | ||
131 | if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock->fd, &ev) == -1) { | |
132 | perror("epoll_ctl: failed to add socket\n"); | |
133 | free(sock); | |
134 | return NULL; | |
688760ef | 135 | } |
811e4b93 | 136 | |
4723ca09 NC |
137 | sock->epoll_fd = epoll_fd; |
138 | if (list) { | |
139 | list_add(&sock->list, list); | |
140 | } else { | |
141 | INIT_LIST_HEAD(&sock->list); | |
142 | } | |
143 | ||
144 | return sock; | |
811e4b93 PMF |
145 | } |
146 | ||
4723ca09 NC |
147 | void ustcomm_del_sock(struct ustcomm_sock *sock, int keep_in_epoll) |
148 | { | |
149 | list_del(&sock->list); | |
150 | if (!keep_in_epoll) { | |
151 | if (epoll_ctl(sock->epoll_fd, EPOLL_CTL_DEL, sock->fd, NULL) == -1) { | |
152 | PERROR("epoll_ctl: failed to delete socket"); | |
153 | } | |
154 | } | |
155 | close(sock->fd); | |
156 | free(sock); | |
157 | } | |
b0540e11 | 158 | |
4723ca09 NC |
159 | struct ustcomm_sock * ustcomm_init_named_socket(const char *name, |
160 | int epoll_fd) | |
b0540e11 | 161 | { |
b0540e11 | 162 | int result; |
4723ca09 NC |
163 | int fd; |
164 | size_t sock_addr_size; | |
165 | struct sockaddr_un * addr; | |
166 | struct ustcomm_sock *sock; | |
c97d4437 | 167 | |
4723ca09 NC |
168 | fd = socket(PF_UNIX, SOCK_STREAM, 0); |
169 | if(fd == -1) { | |
170 | PERROR("socket"); | |
171 | return NULL; | |
c97d4437 | 172 | } |
b0540e11 | 173 | |
4723ca09 NC |
174 | addr = create_sock_addr(name, &sock_addr_size); |
175 | if (addr == NULL) { | |
176 | ERR("allocating addr, UST thread bailing"); | |
177 | goto close_sock; | |
b0540e11 PMF |
178 | } |
179 | ||
4723ca09 NC |
180 | result = access(name, F_OK); |
181 | if(result == 0) { | |
182 | /* file exists */ | |
183 | result = unlink(name); | |
184 | if(result == -1) { | |
185 | PERROR("unlink of socket file"); | |
186 | goto free_addr; | |
187 | } | |
188 | DBG("socket already exists; overwriting"); | |
08b8805e | 189 | } |
b0540e11 | 190 | |
4723ca09 | 191 | result = bind(fd, (struct sockaddr *)addr, sock_addr_size); |
08230db7 | 192 | if(result == -1) { |
4723ca09 NC |
193 | PERROR("bind"); |
194 | goto free_addr; | |
08230db7 PMF |
195 | } |
196 | ||
4723ca09 | 197 | result = listen(fd, 1); |
08230db7 | 198 | if(result == -1) { |
4723ca09 NC |
199 | PERROR("listen"); |
200 | goto free_addr; | |
08230db7 PMF |
201 | } |
202 | ||
4723ca09 NC |
203 | sock = ustcomm_init_sock(fd, epoll_fd, |
204 | NULL); | |
205 | if (!sock) { | |
206 | ERR("failed to create ustcomm_sock"); | |
207 | goto free_addr; | |
208 | } | |
b0540e11 | 209 | |
4723ca09 | 210 | free(addr); |
b0540e11 | 211 | |
4723ca09 | 212 | return sock; |
811e4b93 | 213 | |
4723ca09 NC |
214 | free_addr: |
215 | free(addr); | |
216 | close_sock: | |
217 | close(fd); | |
2dae156b | 218 | |
4723ca09 NC |
219 | return NULL; |
220 | } | |
221 | ||
222 | void ustcomm_del_named_sock(struct ustcomm_sock *sock, | |
223 | int keep_socket_file) | |
d0b5f2b9 | 224 | { |
4723ca09 NC |
225 | int result, fd; |
226 | struct stat st; | |
227 | struct sockaddr dummy; | |
228 | struct sockaddr_un *sockaddr = NULL; | |
229 | int alloc_size; | |
d0b5f2b9 | 230 | |
4723ca09 | 231 | fd = sock->fd; |
b02e31e5 | 232 | |
4723ca09 | 233 | if(!keep_socket_file) { |
5932431b | 234 | |
4723ca09 NC |
235 | /* Get the socket name */ |
236 | alloc_size = sizeof(dummy); | |
237 | if (getsockname(fd, &dummy, (socklen_t *)&alloc_size) < 0) { | |
238 | PERROR("getsockname failed"); | |
239 | goto del_sock; | |
2dae156b | 240 | } |
b0540e11 | 241 | |
4723ca09 NC |
242 | sockaddr = zmalloc(alloc_size); |
243 | if (!sockaddr) { | |
244 | ERR("failed to allocate sockaddr"); | |
245 | goto del_sock; | |
5932431b PMF |
246 | } |
247 | ||
4723ca09 NC |
248 | if (getsockname(fd, sockaddr, (socklen_t *)&alloc_size) < 0) { |
249 | PERROR("getsockname failed"); | |
250 | goto free_sockaddr; | |
5932431b PMF |
251 | } |
252 | ||
4723ca09 NC |
253 | /* Destroy socket */ |
254 | result = stat(sockaddr->sun_path, &st); | |
255 | if(result < 0) { | |
256 | PERROR("stat (%s)", sockaddr->sun_path); | |
257 | goto free_sockaddr; | |
2dae156b | 258 | } |
4723ca09 NC |
259 | |
260 | /* Paranoid check before deleting. */ | |
261 | result = S_ISSOCK(st.st_mode); | |
262 | if(!result) { | |
263 | ERR("The socket we are about to delete is not a socket."); | |
264 | goto free_sockaddr; | |
2dae156b PMF |
265 | } |
266 | ||
4723ca09 NC |
267 | result = unlink(sockaddr->sun_path); |
268 | if(result < 0) { | |
269 | PERROR("unlink"); | |
270 | } | |
2dae156b | 271 | } |
b0540e11 | 272 | |
4723ca09 NC |
273 | free_sockaddr: |
274 | free(sockaddr); | |
2dae156b | 275 | |
4723ca09 NC |
276 | del_sock: |
277 | ustcomm_del_sock(sock, keep_socket_file); | |
d0b5f2b9 PMF |
278 | } |
279 | ||
5932431b | 280 | |
4723ca09 NC |
281 | /* Called by an app to ask the consumer daemon to connect to it. */ |
282 | ||
283 | int ustcomm_request_consumer(pid_t pid, const char *channel) | |
811e4b93 | 284 | { |
4723ca09 NC |
285 | int result, daemon_fd; |
286 | int retval = 0; | |
287 | char *msg=NULL; | |
288 | char *explicit_daemon_socket_path, *daemon_path; | |
811e4b93 | 289 | |
4723ca09 NC |
290 | explicit_daemon_socket_path = getenv("UST_DAEMON_SOCKET"); |
291 | if (explicit_daemon_socket_path) { | |
292 | /* user specified explicitly a socket path */ | |
293 | result = asprintf(&daemon_path, "%s", explicit_daemon_socket_path); | |
294 | } else { | |
295 | /* just use the default path */ | |
296 | result = asprintf(&daemon_path, "%s/ustd", SOCK_DIR); | |
297 | } | |
298 | if (result < 0) { | |
299 | ERR("string overflow allocating socket name"); | |
811e4b93 PMF |
300 | return -1; |
301 | } | |
302 | ||
4723ca09 NC |
303 | if (asprintf(&msg, "collect %d %s", pid, channel) < 0) { |
304 | ERR("ustcomm_request_consumer : asprintf failed (collect %d/%s)", | |
305 | pid, channel); | |
306 | retval = -1; | |
307 | goto free_daemon_path; | |
308 | } | |
99b72dc0 | 309 | |
4723ca09 NC |
310 | result = ustcomm_connect_path(daemon_path, &daemon_fd); |
311 | if (result < 0) { | |
312 | WARN("ustcomm_connect_path failed, daemon_path: %s", | |
313 | daemon_path); | |
314 | retval = -1; | |
315 | goto del_string; | |
316 | } | |
99b72dc0 | 317 | |
4723ca09 NC |
318 | result = ustcomm_send_request(daemon_fd, msg, NULL); |
319 | if (result < 0) { | |
320 | WARN("ustcomm_send_request failed, daemon path: %s", | |
321 | daemon_path); | |
322 | retval = -1; | |
99b72dc0 PMF |
323 | } |
324 | ||
4723ca09 NC |
325 | close(daemon_fd); |
326 | del_string: | |
327 | free(msg); | |
328 | free_daemon_path: | |
329 | free(daemon_path); | |
330 | ||
331 | return retval; | |
99b72dc0 PMF |
332 | } |
333 | ||
4723ca09 NC |
334 | /* returns 1 to indicate a message was received |
335 | * returns 0 to indicate no message was received (end of stream) | |
688760ef PMF |
336 | * returns -1 to indicate an error |
337 | */ | |
4723ca09 NC |
338 | int ustcomm_recv_fd(int sock, |
339 | struct ustcomm_header *header, | |
340 | char **data, int *fd) | |
b0540e11 | 341 | { |
aca1ad90 PMF |
342 | int result; |
343 | int retval; | |
4723ca09 NC |
344 | struct ustcomm_header peek_header; |
345 | struct iovec iov[2]; | |
346 | struct msghdr msg; | |
347 | struct cmsghdr *cmsg; | |
348 | char buf[CMSG_SPACE(sizeof(int))]; | |
349 | ||
350 | result = recv(sock, &peek_header, sizeof(peek_header), | |
351 | MSG_PEEK | MSG_WAITALL); | |
352 | if (result <= 0) { | |
353 | if(errno == ECONNRESET) { | |
354 | return 0; | |
355 | } else if (errno == EINTR) { | |
356 | return -1; | |
357 | } else if (result < 0) { | |
358 | PERROR("recv"); | |
aca1ad90 PMF |
359 | return -1; |
360 | } | |
4723ca09 NC |
361 | return 0; |
362 | } | |
aca1ad90 | 363 | |
4723ca09 | 364 | memset(&msg, 0, sizeof(msg)); |
5932431b | 365 | |
4723ca09 NC |
366 | iov[0].iov_base = (char *)header; |
367 | iov[0].iov_len = sizeof(struct ustcomm_header); | |
aca1ad90 | 368 | |
4723ca09 NC |
369 | msg.msg_iov = iov; |
370 | msg.msg_iovlen = 1; | |
aca1ad90 | 371 | |
4723ca09 NC |
372 | if (peek_header.size) { |
373 | if (peek_header.size < 0 || peek_header.size > 100) { | |
374 | WARN("big peek header! %d", peek_header.size); | |
f05eefd8 | 375 | } |
4723ca09 NC |
376 | *data = malloc(peek_header.size); |
377 | if (!*data) { | |
378 | ERR("failed to allocate space for message"); | |
2a79ceeb | 379 | } |
688760ef | 380 | |
4723ca09 NC |
381 | iov[1].iov_base = (char *)*data; |
382 | iov[1].iov_len = peek_header.size; | |
aca1ad90 | 383 | |
4723ca09 NC |
384 | msg.msg_iovlen++; |
385 | } | |
aca1ad90 | 386 | |
4723ca09 NC |
387 | if (fd && peek_header.fd_included) { |
388 | msg.msg_control = buf; | |
389 | msg.msg_controllen = sizeof(buf); | |
390 | } | |
aca1ad90 | 391 | |
4723ca09 NC |
392 | result = recvmsg(sock, &msg, |
393 | MSG_WAITALL); | |
aca1ad90 | 394 | |
4723ca09 NC |
395 | if (result <= 0) { |
396 | if(errno == ECONNRESET) { | |
397 | retval = 0; | |
398 | } else if (errno == EINTR) { | |
399 | retval = -1; | |
400 | } else if (result < 0) { | |
401 | PERROR("recv"); | |
402 | retval = -1; | |
403 | } else { | |
404 | retval = 0; | |
aca1ad90 | 405 | } |
4723ca09 NC |
406 | free(*data); |
407 | return retval; | |
408 | } | |
409 | ||
410 | if (fd && peek_header.fd_included) { | |
411 | cmsg = CMSG_FIRSTHDR(&msg); | |
412 | result = 0; | |
413 | while (cmsg != NULL) { | |
414 | if (cmsg->cmsg_level == SOL_SOCKET | |
415 | && cmsg->cmsg_type == SCM_RIGHTS) { | |
416 | *fd = *(int *) CMSG_DATA(cmsg); | |
417 | result = 1; | |
418 | break; | |
aca1ad90 | 419 | } |
4723ca09 NC |
420 | cmsg = CMSG_NXTHDR(&msg, cmsg); |
421 | } | |
422 | if (!result) { | |
423 | ERR("Failed to receive file descriptor\n"); | |
aca1ad90 | 424 | } |
aca1ad90 PMF |
425 | } |
426 | ||
4723ca09 | 427 | return 1; |
b0540e11 PMF |
428 | } |
429 | ||
4723ca09 NC |
430 | int ustcomm_recv(int sock, |
431 | struct ustcomm_header *header, | |
432 | char **data) | |
811e4b93 | 433 | { |
4723ca09 | 434 | return ustcomm_recv_fd(sock, header, data, NULL); |
811e4b93 PMF |
435 | } |
436 | ||
4723ca09 NC |
437 | |
438 | int recv_message_conn(int sock, char **msg) | |
b0540e11 | 439 | { |
4723ca09 | 440 | struct ustcomm_header header; |
b0540e11 | 441 | |
4723ca09 NC |
442 | return ustcomm_recv(sock, &header, msg); |
443 | } | |
46ef48cd | 444 | |
4723ca09 NC |
445 | int ustcomm_send_fd(int sock, |
446 | const struct ustcomm_header *header, | |
447 | const char *data, | |
448 | int *fd) | |
46ef48cd | 449 | { |
4723ca09 NC |
450 | struct iovec iov[2]; |
451 | struct msghdr msg; | |
452 | int result; | |
453 | struct cmsghdr *cmsg; | |
454 | char buf[CMSG_SPACE(sizeof(int))]; | |
455 | ||
456 | memset(&msg, 0, sizeof(msg)); | |
457 | ||
458 | iov[0].iov_base = (char *)header; | |
459 | iov[0].iov_len = sizeof(struct ustcomm_header); | |
460 | ||
461 | msg.msg_iov = iov; | |
462 | msg.msg_iovlen = 1; | |
463 | ||
464 | if (header->size) { | |
465 | iov[1].iov_base = (char *)data; | |
466 | iov[1].iov_len = header->size; | |
467 | ||
468 | msg.msg_iovlen++; | |
46ef48cd | 469 | |
46ef48cd PMF |
470 | } |
471 | ||
4723ca09 NC |
472 | if (fd && header->fd_included) { |
473 | msg.msg_control = buf; | |
474 | msg.msg_controllen = sizeof(buf); | |
475 | cmsg = CMSG_FIRSTHDR(&msg); | |
476 | cmsg->cmsg_level = SOL_SOCKET; | |
477 | cmsg->cmsg_type = SCM_RIGHTS; | |
478 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); | |
479 | *(int *) CMSG_DATA(cmsg) = *fd; | |
480 | msg.msg_controllen = cmsg->cmsg_len; | |
481 | } | |
482 | ||
483 | result = sendmsg(sock, &msg, MSG_NOSIGNAL); | |
484 | if (result < 0 && errno != EPIPE) { | |
485 | PERROR("sendmsg failed"); | |
486 | } | |
487 | return result; | |
46ef48cd PMF |
488 | } |
489 | ||
4723ca09 NC |
490 | int ustcomm_send(int sock, |
491 | const struct ustcomm_header *header, | |
492 | const char *data) | |
d0b5f2b9 | 493 | { |
4723ca09 NC |
494 | return ustcomm_send_fd(sock, header, data, NULL); |
495 | } | |
d0b5f2b9 | 496 | |
4723ca09 NC |
497 | int ustcomm_send_reply(char *msg, int sock) |
498 | { | |
499 | int result; | |
500 | struct ustcomm_header header; | |
d0b5f2b9 | 501 | |
4723ca09 | 502 | memset(&header, 0, sizeof(header)); |
d0b5f2b9 | 503 | |
4723ca09 | 504 | header.size = strlen(msg) + 1; |
d0b5f2b9 | 505 | |
4723ca09 NC |
506 | result = ustcomm_send(sock, &header, msg); |
507 | if(result < 0) { | |
508 | ERR("error in ustcomm_send"); | |
509 | return result; | |
aca1ad90 PMF |
510 | } |
511 | ||
4723ca09 NC |
512 | return 0; |
513 | } | |
d0b5f2b9 | 514 | |
4723ca09 NC |
515 | int ustcomm_send_req(int sock, |
516 | const struct ustcomm_header *req_header, | |
517 | const char *data, | |
518 | char **response) | |
519 | { | |
520 | int result; | |
521 | struct ustcomm_header res_header; | |
aca1ad90 | 522 | |
4723ca09 NC |
523 | result = ustcomm_send(sock, req_header, data); |
524 | if ( result <= 0) { | |
525 | return result; | |
b0540e11 | 526 | } |
d0b5f2b9 | 527 | |
4723ca09 NC |
528 | if (!response) { |
529 | return 1; | |
530 | } | |
d0b5f2b9 | 531 | |
4723ca09 NC |
532 | return ustcomm_recv(sock, |
533 | &res_header, | |
534 | response); | |
d0b5f2b9 | 535 | |
d0b5f2b9 PMF |
536 | } |
537 | ||
34b460e6 PMF |
538 | /* |
539 | * Return value: | |
540 | * 0: Success, but no reply because recv() returned 0 | |
541 | * 1: Success | |
542 | * -1: Error | |
543 | * | |
544 | * On error, the error message is printed, except on | |
545 | * ECONNRESET, which is normal when the application dies. | |
546 | */ | |
547 | ||
4723ca09 | 548 | int ustcomm_send_request(int sock, const char *req, char **reply) |
4e2a8808 | 549 | { |
4723ca09 | 550 | struct ustcomm_header req_header; |
4e2a8808 | 551 | |
4723ca09 | 552 | req_header.size = strlen(req) + 1; |
4e2a8808 | 553 | |
4723ca09 NC |
554 | return ustcomm_send_req(sock, |
555 | &req_header, | |
556 | req, | |
557 | reply); | |
4e2a8808 | 558 | |
4e2a8808 PMF |
559 | } |
560 | ||
2a79ceeb PMF |
561 | /* Return value: |
562 | * 0: success | |
563 | * -1: error | |
564 | */ | |
565 | ||
4723ca09 | 566 | int ustcomm_connect_path(const char *name, int *connection_fd) |
4e2a8808 | 567 | { |
4723ca09 NC |
568 | int result, fd; |
569 | size_t sock_addr_size; | |
570 | struct sockaddr_un *addr; | |
4e2a8808 | 571 | |
4723ca09 NC |
572 | fd = socket(PF_UNIX, SOCK_STREAM, 0); |
573 | if(fd == -1) { | |
4e2a8808 PMF |
574 | PERROR("socket"); |
575 | return -1; | |
576 | } | |
577 | ||
4723ca09 NC |
578 | addr = create_sock_addr(name, &sock_addr_size); |
579 | if (addr == NULL) { | |
580 | ERR("allocating addr failed"); | |
581 | goto close_sock; | |
52c51a47 | 582 | } |
4e2a8808 | 583 | |
4723ca09 | 584 | result = connect(fd, (struct sockaddr *)addr, sock_addr_size); |
4e2a8808 | 585 | if(result == -1) { |
4723ca09 NC |
586 | PERROR("connect (path=%s)", name); |
587 | goto free_sock_addr; | |
4e2a8808 PMF |
588 | } |
589 | ||
4723ca09 NC |
590 | *connection_fd = fd; |
591 | ||
592 | free(addr); | |
4e2a8808 PMF |
593 | |
594 | return 0; | |
4e2a8808 | 595 | |
4723ca09 NC |
596 | free_sock_addr: |
597 | free(addr); | |
598 | close_sock: | |
599 | close(fd); | |
600 | ||
601 | return -1; | |
4e2a8808 PMF |
602 | } |
603 | ||
4723ca09 | 604 | |
2a79ceeb PMF |
605 | /* Open a connection to a traceable app. |
606 | * | |
607 | * Return value: | |
608 | * 0: success | |
609 | * -1: error | |
610 | */ | |
611 | ||
4723ca09 | 612 | int ustcomm_connect_app(pid_t pid, int *app_fd) |
4e2a8808 PMF |
613 | { |
614 | int result; | |
4723ca09 NC |
615 | int retval = 0; |
616 | char *name; | |
4e2a8808 | 617 | |
4723ca09 NC |
618 | result = asprintf(&name, "%s/%d", SOCK_DIR, pid); |
619 | if (result < 0) { | |
620 | ERR("failed to allocate socket name"); | |
4e2a8808 PMF |
621 | return -1; |
622 | } | |
623 | ||
4723ca09 NC |
624 | result = ustcomm_connect_path(name, app_fd); |
625 | if (result < 0) { | |
626 | ERR("failed to connect to app"); | |
627 | retval = -1; | |
628 | } | |
2a79ceeb | 629 | |
4723ca09 | 630 | free(name); |
2a79ceeb | 631 | |
4723ca09 | 632 | return retval; |
2a79ceeb PMF |
633 | } |
634 | ||
4723ca09 | 635 | int ensure_dir_exists(const char *dir) |
dce0b474 PMF |
636 | { |
637 | struct stat st; | |
638 | int result; | |
639 | ||
640 | if(!strcmp(dir, "")) | |
641 | return -1; | |
642 | ||
643 | result = stat(dir, &st); | |
644 | if(result == -1 && errno != ENOENT) { | |
645 | return -1; | |
646 | } | |
647 | else if(result == -1) { | |
648 | /* ENOENT */ | |
dce0b474 PMF |
649 | int result; |
650 | ||
18baca84 DG |
651 | /* mkdir mode to 0777 */ |
652 | result = mkdir_p(dir, S_IRWXU | S_IRWXG | S_IRWXO); | |
dce0b474 | 653 | if(result != 0) { |
d6d27063 | 654 | ERR("executing in recursive creation of directory %s", dir); |
dce0b474 PMF |
655 | return -1; |
656 | } | |
657 | } | |
658 | ||
659 | return 0; | |
660 | } | |
661 | ||
08230db7 PMF |
662 | /* Used by the daemon to initialize its server so applications |
663 | * can connect to it. | |
664 | */ | |
665 | ||
2a79ceeb | 666 | |
7e92827d | 667 | static const char *find_tok(const char *str) |
b02e31e5 PMF |
668 | { |
669 | while(*str == ' ') { | |
670 | str++; | |
671 | ||
672 | if(*str == 0) | |
673 | return NULL; | |
674 | } | |
675 | ||
676 | return str; | |
677 | } | |
678 | ||
7e92827d | 679 | static const char *find_sep(const char *str) |
b02e31e5 PMF |
680 | { |
681 | while(*str != ' ') { | |
682 | str++; | |
683 | ||
684 | if(*str == 0) | |
685 | break; | |
686 | } | |
687 | ||
688 | return str; | |
689 | } | |
690 | ||
7e92827d | 691 | int nth_token_is(const char *str, const char *token, int tok_no) |
b02e31e5 PMF |
692 | { |
693 | int i; | |
7e92827d PMF |
694 | const char *start; |
695 | const char *end; | |
b02e31e5 PMF |
696 | |
697 | for(i=0; i<=tok_no; i++) { | |
698 | str = find_tok(str); | |
699 | if(str == NULL) | |
700 | return -1; | |
701 | ||
702 | start = str; | |
703 | ||
704 | str = find_sep(str); | |
705 | if(str == NULL) | |
706 | return -1; | |
707 | ||
708 | end = str; | |
709 | } | |
710 | ||
711 | if(end-start != strlen(token)) | |
712 | return 0; | |
713 | ||
714 | if(strncmp(start, token, end-start)) | |
715 | return 0; | |
716 | ||
717 | return 1; | |
718 | } | |
719 | ||
7e92827d | 720 | char *nth_token(const char *str, int tok_no) |
b02e31e5 PMF |
721 | { |
722 | static char *retval = NULL; | |
723 | int i; | |
7e92827d PMF |
724 | const char *start; |
725 | const char *end; | |
b02e31e5 PMF |
726 | |
727 | for(i=0; i<=tok_no; i++) { | |
728 | str = find_tok(str); | |
729 | if(str == NULL) | |
730 | return NULL; | |
731 | ||
732 | start = str; | |
733 | ||
734 | str = find_sep(str); | |
735 | if(str == NULL) | |
736 | return NULL; | |
737 | ||
738 | end = str; | |
739 | } | |
740 | ||
741 | if(retval) { | |
742 | free(retval); | |
743 | retval = NULL; | |
744 | } | |
745 | ||
08b8805e DG |
746 | if (asprintf(&retval, "%.*s", (int)(end-start), start) < 0) { |
747 | ERR("nth_token : asprintf failed (%.*s)", | |
748 | (int)(end-start), start); | |
749 | return NULL; | |
750 | } | |
b02e31e5 PMF |
751 | |
752 | return retval; | |
753 | } |