1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
/**
* Connect to a coopgamma server, and start it if necessary
*
* Use `libcoopgamma_context_destroy` to disconnect
*
* SIGCHLD must not be ignored or blocked
*
* @param method The adjustment method, `NULL` for automatic
* @param site The site, `NULL` for automatic
* @param ctx The state of the library, must be initialised
* @return Zero on success, -1 on error. On error, `errno` is set
* to 0 if the server could not be initialised.
*/
int
libcoopgamma_connect(const char *restrict method, const char *restrict site, libcoopgamma_context_t *restrict ctx)
{
const char *(args[6]) = {COOPGAMMAD};
struct sockaddr_un address;
char *path;
int saved_errno;
int tries = 0, status;
pid_t pid;
size_t i = 1;
ctx->blocking = 1;
if (method) args[i++] = "-m", args[i++] = method;
if (site) args[i++] = "-s", args[i++] = site;
args[i] = NULL;
path = libcoopgamma_get_socket_file(method, site);
if (!path)
return -1;
if (strlen(path) >= sizeof(address.sun_path)) {
free(path);
errno = ENAMETOOLONG;
return -1;
}
address.sun_family = AF_UNIX;
stpcpy(address.sun_path, path);
free(path);
if ((ctx->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
return -1;
retry:
if (connect(ctx->fd, (const struct sockaddr *)&address, (socklen_t)sizeof(address)) < 0) {
if ((errno == ECONNREFUSED || errno == ENOENT || errno == ENOTDIR) && !tries++) {
switch ((pid = fork())) {
case -1:
goto fail;
case 0:
/* Child */
close(ctx->fd);
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif
execvp(COOPGAMMAD, (char *const *)(args));
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
perror(NAME_OF_THE_PROCESS);
exit(1);
default:
/* Parent */
if (waitpid(pid, &status, 0) < 0)
goto fail;
if (status) {
errno = 0;
goto fail;
}
break;
}
goto retry;
}
goto fail;
}
return 0;
fail:
saved_errno = errno;
close(ctx->fd);
ctx->fd = -1;
errno = saved_errno;
return -1;
}
|