change benign WARN to DBG
[ust.git] / libustcomm / ustcomm.c
CommitLineData
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
d0b5f2b9 18#define _GNU_SOURCE
f9e5ce61
PMF
19#include <sys/types.h>
20#include <signal.h>
21#include <errno.h>
22#include <sys/socket.h>
23#include <sys/un.h>
d0b5f2b9 24#include <unistd.h>
aca1ad90 25#include <poll.h>
803a4f58 26#include <sys/stat.h>
f9e5ce61
PMF
27
28#include <stdio.h>
29#include <stdlib.h>
d0b5f2b9 30#include <string.h>
b0540e11 31#include <execinfo.h>
d0b5f2b9
PMF
32
33#include "ustcomm.h"
6af64c43 34#include "usterr.h"
2dae156b 35#include "share.h"
f9e5ce61
PMF
36
37#define UNIX_PATH_MAX 108
f9e5ce61 38
058a68cb 39#define MSG_MAX 10000
d0b5f2b9 40
aca1ad90
PMF
41/* FIXME: ustcomm blocks on message sending, which might be problematic in
42 * some cases. Fix the poll() usage so sends are buffered until they don't
43 * block.
44 */
45
3847c3ba
PMF
46//static void bt(void)
47//{
48// void *buffer[100];
49// int result;
50//
51// result = backtrace(&buffer, 100);
52// backtrace_symbols_fd(buffer, result, STDERR_FILENO);
53//}
b0540e11 54
d6d27063
PMF
55static int mkdir_p(const char *path, mode_t mode)
56{
c555b133 57 const char *path_p;
d6d27063
PMF
58 char *tmp;
59
60 int retval = 0;
61 int result;
62
63 tmp = malloc(strlen(path) + 1);
64 if (tmp == NULL)
65 return -1;
66
67 /* skip first / */
68 path_p = path+1;
69
70 for(;;) {
71 while (*path_p != '/') {
72 if(*path_p == 0)
73 break;
74 ++path_p;
75 }
76 if (*path_p == '/') {
77 strncpy(tmp, path, path_p - path);
78 tmp[path_p-path] = '\0';
79 if (tmp[path_p - path - 1] != '/') {
80 result = mkdir(tmp, mode);
81 if(result == -1) {
82 if (!(errno == EEXIST || errno == EACCES || errno == EROFS)) {
83 /* Then this is a real error */
84 retval = -1;
85 break;
86 }
87 }
88 }
89 /* pass / */
90 path_p++;
91 } else {
92 /* last component */
93 result = mkdir(path, mode);
94 if (result == -1)
95 retval = -1;
96 break;
97 }
98 }
99
100 free(tmp);
101 return retval;
102}
103
688760ef
PMF
104char *strdup_malloc(const char *s)
105{
106 char *retval;
107
108 if(s == NULL)
109 return NULL;
110
111 retval = (char *) malloc(strlen(s)+1);
112
113 strcpy(retval, s);
114
115 return retval;
116}
117
52c51a47 118static int signal_process(pid_t pid)
f9e5ce61 119{
52c51a47 120 return 0;
f9e5ce61
PMF
121}
122
5932431b
PMF
123void ustcomm_init_connection(struct ustcomm_connection *conn)
124{
125 conn->recv_buf = NULL;
126 conn->recv_buf_size = 0;
127 conn->recv_buf_alloc = 0;
128}
129
ab33e65c 130int pid_is_online(pid_t pid) {
2944a629 131 return 1;
ab33e65c
PP
132}
133
2dae156b
PMF
134/* Send a message
135 *
136 * @fd: file descriptor to send to
137 * @msg: a null-terminated string containing the message to send
138 *
139 * Return value:
140 * -1: error
141 * 0: connection closed
142 * 1: success
143 */
144
4e2a8808 145static int send_message_fd(int fd, const char *msg)
811e4b93
PMF
146{
147 int result;
148
2dae156b
PMF
149 /* Send including the final \0 */
150 result = patient_send(fd, msg, strlen(msg)+1, MSG_NOSIGNAL);
811e4b93 151 if(result == -1) {
2dae156b
PMF
152 if(errno != EPIPE)
153 PERROR("send");
811e4b93
PMF
154 return -1;
155 }
688760ef
PMF
156 else if(result == 0) {
157 return 0;
158 }
811e4b93 159
2dae156b 160 DBG("sent message \"%s\"", msg);
688760ef 161 return 1;
811e4b93
PMF
162}
163
b0540e11
PMF
164/* Called by an app to ask the consumer daemon to connect to it. */
165
166int ustcomm_request_consumer(pid_t pid, const char *channel)
167{
168 char path[UNIX_PATH_MAX];
169 int result;
08230db7
PMF
170 char *msg=NULL;
171 int retval = 0;
172 struct ustcomm_connection conn;
c97d4437
PMF
173 char *explicit_daemon_socket_path;
174
175 explicit_daemon_socket_path = getenv("UST_DAEMON_SOCKET");
176 if(explicit_daemon_socket_path) {
177 /* user specified explicitly a socket path */
178 result = snprintf(path, UNIX_PATH_MAX, "%s", explicit_daemon_socket_path);
179 }
180 else {
181 /* just use the default path */
182 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
183 }
b0540e11 184
b0540e11 185 if(result >= UNIX_PATH_MAX) {
08230db7 186 ERR("string overflow allocating socket name");
b0540e11
PMF
187 return -1;
188 }
189
190 asprintf(&msg, "collect %d %s", pid, channel);
191
08230db7
PMF
192 /* don't signal it because it's the daemon */
193 result = ustcomm_connect_path(path, &conn, -1);
194 if(result == -1) {
195 WARN("ustcomm_connect_path failed");
196 retval = -1;
197 goto del_string;
198 }
199
200 result = ustcomm_send_request(&conn, msg, NULL);
201 if(result == -1) {
202 WARN("ustcomm_send_request failed");
203 retval = -1;
204 goto disconnect;
205 }
206
207 disconnect:
208 ustcomm_disconnect(&conn);
209 del_string:
b0540e11
PMF
210 free(msg);
211
08230db7 212 return retval;
b0540e11
PMF
213}
214
688760ef 215/* returns 1 to indicate a message was received
da000ba4 216 * returns 0 to indicate no message was received (end of stream)
688760ef
PMF
217 * returns -1 to indicate an error
218 */
811e4b93 219
5932431b 220#define RECV_INCREMENT 1000
da000ba4 221#define RECV_INITIAL_BUF_SIZE 10
2dae156b 222
5932431b 223static int recv_message_fd(int fd, char **recv_buf, int *recv_buf_size, int *recv_buf_alloc, char **msg)
d0b5f2b9 224{
d0b5f2b9 225 int result;
d0b5f2b9 226
5932431b
PMF
227 /* 1. Check if there is a message in the buf */
228 /* 2. If not, do:
229 2.1 receive chunk and put it in buffer
230 2.2 process full message if there is one
231 -- while no message arrived
232 */
b02e31e5 233
2dae156b 234 for(;;) {
5932431b
PMF
235 int i;
236 int nulfound = 0;
237
238 /* Search for full message in buffer */
239 for(i=0; i<*recv_buf_size; i++) {
240 if((*recv_buf)[i] == '\0') {
241 nulfound = 1;
242 break;
da000ba4 243 }
2dae156b 244 }
b0540e11 245
5932431b
PMF
246 /* Process found message */
247 if(nulfound == 1) {
248 char *newbuf;
249
250 if(i == 0) {
251 /* problem */
2a79ceeb 252 WARN("received empty message");
5932431b
PMF
253 }
254 *msg = strndup(*recv_buf, i);
255
256 /* Remove processed message from buffer */
257 newbuf = (char *) malloc(*recv_buf_size - (i+1));
258 memcpy(newbuf, *recv_buf + (i+1), *recv_buf_size - (i+1));
259 free(*recv_buf);
260 *recv_buf = newbuf;
261 *recv_buf_size -= (i+1);
262 *recv_buf_alloc -= (i+1);
263
264 return 1;
265 }
266
267 /* Receive a chunk from the fd */
268 if(*recv_buf_alloc - *recv_buf_size < RECV_INCREMENT) {
269 *recv_buf_alloc += RECV_INCREMENT - (*recv_buf_alloc - *recv_buf_size);
270 *recv_buf = (char *) realloc(*recv_buf, *recv_buf_alloc);
271 }
272
273 result = recv(fd, *recv_buf+*recv_buf_size, RECV_INCREMENT, 0);
2dae156b 274 if(result == -1) {
5932431b
PMF
275 if(errno == ECONNRESET) {
276 *recv_buf_size = 0;
277 return 0;
278 }
279 /* real error */
280 PERROR("recv");
2dae156b
PMF
281 return -1;
282 }
283 if(result == 0) {
5932431b 284 return 0;
2dae156b 285 }
5932431b 286 *recv_buf_size += result;
2dae156b 287
5932431b 288 /* Go back to the beginning to check if there is a full message in the buffer */
2dae156b 289 }
b0540e11 290
5932431b 291 DBG("received message \"%s\"", *recv_buf);
811e4b93 292
688760ef 293 return 1;
2dae156b 294
d0b5f2b9
PMF
295}
296
5932431b
PMF
297static int recv_message_conn(struct ustcomm_connection *conn, char **msg)
298{
299 return recv_message_fd(conn->fd, &conn->recv_buf, &conn->recv_buf_size, &conn->recv_buf_alloc, msg);
300}
301
811e4b93
PMF
302int ustcomm_send_reply(struct ustcomm_server *server, char *msg, struct ustcomm_source *src)
303{
304 int result;
305
4e2a8808 306 result = send_message_fd(src->fd, msg);
3a7b90de 307 if(result < 0) {
811e4b93
PMF
308 ERR("error in send_message_fd");
309 return -1;
310 }
311
312 return 0;
313}
314
99b72dc0
PMF
315/* Called after a fork. */
316
317int ustcomm_close_all_connections(struct ustcomm_server *server)
318{
319 struct ustcomm_connection *conn;
320 struct ustcomm_connection *deletable_conn = NULL;
321
322 list_for_each_entry(conn, &server->connections, list) {
323 free(deletable_conn);
324 deletable_conn = conn;
2a79ceeb 325 ustcomm_close_app(conn);
99b72dc0
PMF
326 list_del(&conn->list);
327 }
328
329 return 0;
330}
331
688760ef
PMF
332/* @timeout: max blocking time in milliseconds, -1 means infinity
333 *
334 * returns 1 to indicate a message was received
335 * returns 0 to indicate no message was received
336 * returns -1 to indicate an error
337 */
338
339int ustcomm_recv_message(struct ustcomm_server *server, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 340{
aca1ad90 341 struct pollfd *fds;
5932431b 342 struct ustcomm_connection **conn_table;
aca1ad90
PMF
343 struct ustcomm_connection *conn;
344 int result;
345 int retval;
346
347 for(;;) {
348 int idx = 0;
349 int n_fds = 1;
350
811e4b93 351 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
352 n_fds++;
353 }
354
355 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
356 if(fds == NULL) {
357 ERR("malloc returned NULL");
358 return -1;
359 }
360
5932431b
PMF
361 conn_table = (struct ustcomm_connection **) malloc(n_fds * sizeof(struct ustcomm_connection *));
362 if(conn_table == NULL) {
363 ERR("malloc returned NULL");
2a79ceeb
PMF
364 retval = -1;
365 goto free_fds_return;
5932431b
PMF
366 }
367
aca1ad90 368 /* special idx 0 is for listening socket */
811e4b93 369 fds[idx].fd = server->listen_fd;
aca1ad90
PMF
370 fds[idx].events = POLLIN;
371 idx++;
372
811e4b93 373 list_for_each_entry(conn, &server->connections, list) {
aca1ad90
PMF
374 fds[idx].fd = conn->fd;
375 fds[idx].events = POLLIN;
5932431b 376 conn_table[idx] = conn;
aca1ad90
PMF
377 idx++;
378 }
379
69ba0156
PMF
380 while((result = poll(fds, n_fds, timeout)) == -1 && errno == EINTR)
381 /* nothing */;
aca1ad90
PMF
382 if(result == -1) {
383 PERROR("poll");
2a79ceeb
PMF
384 retval = -1;
385 goto free_conn_table_return;
aca1ad90
PMF
386 }
387
2a79ceeb
PMF
388 if(result == 0) {
389 retval = 0;
390 goto free_conn_table_return;
391 }
688760ef 392
aca1ad90
PMF
393 if(fds[0].revents) {
394 struct ustcomm_connection *newconn;
395 int newfd;
396
811e4b93 397 result = newfd = accept(server->listen_fd, NULL, NULL);
aca1ad90
PMF
398 if(result == -1) {
399 PERROR("accept");
2a79ceeb
PMF
400 retval = -1;
401 goto free_conn_table_return;
aca1ad90
PMF
402 }
403
404 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
405 if(newconn == NULL) {
406 ERR("malloc returned NULL");
407 return -1;
408 }
409
5932431b 410 ustcomm_init_connection(newconn);
aca1ad90
PMF
411 newconn->fd = newfd;
412
811e4b93 413 list_add(&newconn->list, &server->connections);
aca1ad90
PMF
414 }
415
416 for(idx=1; idx<n_fds; idx++) {
417 if(fds[idx].revents) {
5932431b 418 retval = recv_message_conn(conn_table[idx], msg);
2dae156b
PMF
419 if(src)
420 src->fd = fds[idx].fd;
421
e2b815a9 422 if(retval == 0) {
aca1ad90 423 /* connection finished */
811e4b93 424 list_for_each_entry(conn, &server->connections, list) {
aca1ad90 425 if(conn->fd == fds[idx].fd) {
750f9da4 426 ustcomm_close_app(conn);
aca1ad90 427 list_del(&conn->list);
750f9da4 428 free(conn);
aca1ad90
PMF
429 break;
430 }
431 }
432 }
433 else {
2a79ceeb 434 goto free_conn_table_return;
aca1ad90
PMF
435 }
436 }
437 }
438
439 free(fds);
2a79ceeb 440 free(conn_table);
aca1ad90
PMF
441 }
442
2a79ceeb
PMF
443free_conn_table_return:
444 free(conn_table);
aca1ad90
PMF
445free_fds_return:
446 free(fds);
447 return retval;
b0540e11
PMF
448}
449
688760ef 450int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src, int timeout)
811e4b93 451{
688760ef 452 return ustcomm_recv_message(&ustd->server, msg, src, timeout);
811e4b93
PMF
453}
454
688760ef 455int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src, int timeout)
b0540e11 456{
688760ef 457 return ustcomm_recv_message(&app->server, msg, src, timeout);
b0540e11
PMF
458}
459
46ef48cd
PMF
460/* This removes src from the list of active connections of app.
461 */
462
463int ustcomm_app_detach_client(struct ustcomm_app *app, struct ustcomm_source *src)
464{
465 struct ustcomm_server *server = (struct ustcomm_server *)app;
466 struct ustcomm_connection *conn;
467
468 list_for_each_entry(conn, &server->connections, list) {
469 if(conn->fd == src->fd) {
470 list_del(&conn->list);
471 goto found;
472 }
473 }
474
475 return -1;
476found:
477 return src->fd;
478}
479
08230db7 480static int init_named_socket(const char *name, char **path_out)
d0b5f2b9
PMF
481{
482 int result;
483 int fd;
484
485 struct sockaddr_un addr;
486
aca1ad90 487 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
d0b5f2b9
PMF
488 if(result == -1) {
489 PERROR("socket");
490 return -1;
491 }
492
493 addr.sun_family = AF_UNIX;
494
495 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
496 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
497
aca1ad90
PMF
498 result = access(name, F_OK);
499 if(result == 0) {
500 /* file exists */
501 result = unlink(name);
502 if(result == -1) {
503 PERROR("unlink of socket file");
504 goto close_sock;
505 }
69c37f74 506 DBG("socket already exists; overwriting");
aca1ad90
PMF
507 }
508
d0b5f2b9
PMF
509 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
510 if(result == -1) {
511 PERROR("bind");
512 goto close_sock;
513 }
514
aca1ad90
PMF
515 result = listen(fd, 1);
516 if(result == -1) {
517 PERROR("listen");
518 goto close_sock;
519 }
520
b0540e11 521 if(path_out) {
803a4f58 522 *path_out = strdup(addr.sun_path);
b0540e11 523 }
d0b5f2b9
PMF
524
525 return fd;
526
527 close_sock:
528 close(fd);
529
530 return -1;
531}
532
34b460e6
PMF
533/*
534 * Return value:
535 * 0: Success, but no reply because recv() returned 0
536 * 1: Success
537 * -1: Error
538 *
539 * On error, the error message is printed, except on
540 * ECONNRESET, which is normal when the application dies.
541 */
542
772030fe 543int ustcomm_send_request(struct ustcomm_connection *conn, const char *req, char **reply)
4e2a8808
PMF
544{
545 int result;
546
2dae156b
PMF
547 /* Send including the final \0 */
548 result = send_message_fd(conn->fd, req);
549 if(result != 1)
550 return result;
4e2a8808
PMF
551
552 if(!reply)
553 return 1;
554
5932431b 555 result = recv_message_conn(conn, reply);
4e2a8808 556 if(result == -1) {
4e2a8808
PMF
557 return -1;
558 }
559 else if(result == 0) {
560 return 0;
561 }
562
4e2a8808
PMF
563 return 1;
564}
565
2a79ceeb
PMF
566/* Return value:
567 * 0: success
568 * -1: error
569 */
570
08230db7 571int ustcomm_connect_path(const char *path, struct ustcomm_connection *conn, pid_t signalpid)
4e2a8808
PMF
572{
573 int fd;
574 int result;
575 struct sockaddr_un addr;
576
5932431b
PMF
577 ustcomm_init_connection(conn);
578
4e2a8808
PMF
579 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
580 if(result == -1) {
581 PERROR("socket");
582 return -1;
583 }
584
585 addr.sun_family = AF_UNIX;
586
587 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
588 if(result >= UNIX_PATH_MAX) {
589 ERR("string overflow allocating socket name");
590 return -1;
591 }
592
52c51a47
PMF
593 if(signalpid >= 0) {
594 result = signal_process(signalpid);
595 if(result == -1) {
596 ERR("could not signal process");
597 return -1;
598 }
599 }
4e2a8808
PMF
600
601 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
602 if(result == -1) {
2dae156b 603 PERROR("connect (path=%s)", path);
4e2a8808
PMF
604 return -1;
605 }
606
607 conn->fd = fd;
608
609 return 0;
610}
611
612int ustcomm_disconnect(struct ustcomm_connection *conn)
613{
614 return close(conn->fd);
615}
616
2a79ceeb
PMF
617/* Open a connection to a traceable app.
618 *
619 * Return value:
620 * 0: success
621 * -1: error
622 */
623
4e2a8808
PMF
624int ustcomm_connect_app(pid_t pid, struct ustcomm_connection *conn)
625{
626 int result;
627 char path[UNIX_PATH_MAX];
628
629
630 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
631 if(result >= UNIX_PATH_MAX) {
08230db7 632 ERR("string overflow allocating socket name");
4e2a8808
PMF
633 return -1;
634 }
635
636 return ustcomm_connect_path(path, conn, pid);
637}
638
750f9da4
PMF
639/* Close a connection to a traceable app. It frees the
640 * resources. It however does not free the
641 * ustcomm_connection itself.
642 */
2a79ceeb
PMF
643
644int ustcomm_close_app(struct ustcomm_connection *conn)
645{
646 close(conn->fd);
647 free(conn->recv_buf);
648
649 return 0;
650}
651
dce0b474
PMF
652static int ensure_dir_exists(const char *dir)
653{
654 struct stat st;
655 int result;
656
657 if(!strcmp(dir, ""))
658 return -1;
659
660 result = stat(dir, &st);
661 if(result == -1 && errno != ENOENT) {
662 return -1;
663 }
664 else if(result == -1) {
665 /* ENOENT */
dce0b474
PMF
666 int result;
667
d6d27063 668 result = mkdir_p(dir, 0777);
dce0b474 669 if(result != 0) {
d6d27063 670 ERR("executing in recursive creation of directory %s", dir);
dce0b474
PMF
671 return -1;
672 }
673 }
674
675 return 0;
676}
677
08230db7
PMF
678/* Called by an application to initialize its server so daemons can
679 * connect to it.
680 */
4e2a8808 681
d0b5f2b9
PMF
682int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
683{
684 int result;
685 char *name;
686
687 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
688 if(result >= UNIX_PATH_MAX) {
689 ERR("string overflow allocating socket name");
690 return -1;
691 }
692
dce0b474
PMF
693 result = ensure_dir_exists(SOCK_DIR);
694 if(result == -1) {
695 ERR("Unable to create socket directory %s", SOCK_DIR);
696 return -1;
697 }
698
811e4b93
PMF
699 handle->server.listen_fd = init_named_socket(name, &(handle->server.socketpath));
700 if(handle->server.listen_fd < 0) {
68ab7a5d 701 ERR("Error initializing named socket (%s). Check that directory exists and that it is writable.", name);
d0b5f2b9
PMF
702 goto free_name;
703 }
704 free(name);
705
811e4b93 706 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 707
d0b5f2b9
PMF
708 return 0;
709
710free_name:
711 free(name);
712 return -1;
713}
714
08230db7
PMF
715/* Used by the daemon to initialize its server so applications
716 * can connect to it.
717 */
718
c97d4437 719int ustcomm_init_ustd(struct ustcomm_ustd *handle, const char *sock_path)
d0b5f2b9 720{
3847c3ba 721 char *name;
c97d4437 722 int retval = 0;
3847c3ba 723
c97d4437
PMF
724 if(sock_path) {
725 asprintf(&name, "%s", sock_path);
726 }
727 else {
dce0b474
PMF
728 int result;
729
730 /* Only check if socket dir exists if we are using the default directory */
731 result = ensure_dir_exists(SOCK_DIR);
732 if(result == -1) {
733 ERR("Unable to create socket directory %s", SOCK_DIR);
734 return -1;
735 }
736
c97d4437 737 asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
3847c3ba
PMF
738 }
739
811e4b93
PMF
740 handle->server.listen_fd = init_named_socket(name, &handle->server.socketpath);
741 if(handle->server.listen_fd < 0) {
6cb88bc0 742 ERR("error initializing named socket at %s", name);
c97d4437 743 retval = -1;
aca1ad90
PMF
744 goto free_name;
745 }
d0b5f2b9 746
811e4b93 747 INIT_LIST_HEAD(&handle->server.connections);
aca1ad90 748
aca1ad90
PMF
749free_name:
750 free(name);
c97d4437
PMF
751
752 return retval;
d0b5f2b9 753}
b02e31e5 754
2a79ceeb 755static void ustcomm_fini_server(struct ustcomm_server *server, int keep_socket_file)
803a4f58
PMF
756{
757 int result;
758 struct stat st;
759
2a79ceeb
PMF
760 if(!keep_socket_file) {
761 /* Destroy socket */
762 result = stat(server->socketpath, &st);
763 if(result == -1) {
764 PERROR("stat (%s)", server->socketpath);
765 return;
766 }
803a4f58 767
2a79ceeb
PMF
768 /* Paranoid check before deleting. */
769 result = S_ISSOCK(st.st_mode);
770 if(!result) {
771 ERR("The socket we are about to delete is not a socket.");
772 return;
773 }
774
775 result = unlink(server->socketpath);
776 if(result == -1) {
777 PERROR("unlink");
778 }
803a4f58
PMF
779 }
780
2a79ceeb
PMF
781 free(server->socketpath);
782
783 result = close(server->listen_fd);
803a4f58 784 if(result == -1) {
2a79ceeb
PMF
785 PERROR("close");
786 return;
803a4f58
PMF
787 }
788}
789
750f9da4
PMF
790/* Free a traceable application server */
791
2a79ceeb
PMF
792void ustcomm_fini_app(struct ustcomm_app *handle, int keep_socket_file)
793{
794 ustcomm_fini_server(&handle->server, keep_socket_file);
795}
796
750f9da4
PMF
797/* Free a ustd server */
798
2a79ceeb
PMF
799void ustcomm_fini_ustd(struct ustcomm_ustd *handle)
800{
801 ustcomm_fini_server(&handle->server, 0);
802}
803
7e92827d 804static const char *find_tok(const char *str)
b02e31e5
PMF
805{
806 while(*str == ' ') {
807 str++;
808
809 if(*str == 0)
810 return NULL;
811 }
812
813 return str;
814}
815
7e92827d 816static const char *find_sep(const char *str)
b02e31e5
PMF
817{
818 while(*str != ' ') {
819 str++;
820
821 if(*str == 0)
822 break;
823 }
824
825 return str;
826}
827
7e92827d 828int nth_token_is(const char *str, const char *token, int tok_no)
b02e31e5
PMF
829{
830 int i;
7e92827d
PMF
831 const char *start;
832 const char *end;
b02e31e5
PMF
833
834 for(i=0; i<=tok_no; i++) {
835 str = find_tok(str);
836 if(str == NULL)
837 return -1;
838
839 start = str;
840
841 str = find_sep(str);
842 if(str == NULL)
843 return -1;
844
845 end = str;
846 }
847
848 if(end-start != strlen(token))
849 return 0;
850
851 if(strncmp(start, token, end-start))
852 return 0;
853
854 return 1;
855}
856
7e92827d 857char *nth_token(const char *str, int tok_no)
b02e31e5
PMF
858{
859 static char *retval = NULL;
860 int i;
7e92827d
PMF
861 const char *start;
862 const char *end;
b02e31e5
PMF
863
864 for(i=0; i<=tok_no; i++) {
865 str = find_tok(str);
866 if(str == NULL)
867 return NULL;
868
869 start = str;
870
871 str = find_sep(str);
872 if(str == NULL)
873 return NULL;
874
875 end = str;
876 }
877
878 if(retval) {
879 free(retval);
880 retval = NULL;
881 }
882
aca1ad90 883 asprintf(&retval, "%.*s", (int)(end-start), start);
b02e31e5
PMF
884
885 return retval;
886}
887
This page took 0.069075 seconds and 4 git commands to generate.