multipathd: Use standard lists for CLI handling
[multipath-tools/.git] / libmultipath / uxsock.c
1 /*
2  * Original author : tridge@samba.org, January 2002
3  *
4  * Copyright (c) 2005 Christophe Varoqui
5  * Copyright (c) 2005 Alasdair Kergon, Redhat
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdarg.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 #include <sys/poll.h>
17 #include <signal.h>
18 #include <errno.h>
19 #ifdef USE_SYSTEMD
20 #include <systemd/sd-daemon.h>
21 #endif
22
23 #include "memory.h"
24 #include "uxsock.h"
25 #include "debug.h"
26
27 /*
28  * connect to a unix domain socket
29  */
30 int ux_socket_connect(const char *name)
31 {
32         int fd, len;
33         struct sockaddr_un addr;
34
35         memset(&addr, 0, sizeof(addr));
36         addr.sun_family = AF_LOCAL;
37         addr.sun_path[0] = '\0';
38         len = strlen(name) + 1 + sizeof(sa_family_t);
39         strncpy(&addr.sun_path[1], name, len);
40
41         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
42         if (fd == -1) {
43                 condlog(3, "Couldn't create ux_socket, error %d", errno);
44                 return -1;
45         }
46
47         if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
48                 condlog(3, "Couldn't connect to ux_socket, error %d", errno);
49                 close(fd);
50                 return -1;
51         }
52
53         return fd;
54 }
55
56 /*
57  * create a unix domain socket and start listening on it
58  * return a file descriptor open on the socket
59  */
60 int ux_socket_listen(const char *name)
61 {
62         int fd, len;
63 #ifdef USE_SYSTEMD
64         int num;
65 #endif
66         struct sockaddr_un addr;
67
68 #ifdef USE_SYSTEMD
69         num = sd_listen_fds(0);
70         if (num > 1) {
71                 condlog(3, "sd_listen_fds returned %d fds", num);
72                 return -1;
73         } else if (num == 1) {
74                 fd = SD_LISTEN_FDS_START + 0;
75                 condlog(3, "using fd %d from sd_listen_fds", fd);
76                 return fd;
77         }
78 #endif
79         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
80         if (fd == -1) {
81                 condlog(3, "Couldn't create ux_socket, error %d", errno);
82                 return -1;
83         }
84
85         memset(&addr, 0, sizeof(addr));
86         addr.sun_family = AF_LOCAL;
87         addr.sun_path[0] = '\0';
88         len = strlen(name) + 1 + sizeof(sa_family_t);
89         strncpy(&addr.sun_path[1], name, len);
90
91         if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
92                 condlog(3, "Couldn't bind to ux_socket, error %d", errno);
93                 close(fd);
94                 return -1;
95         }
96
97         if (listen(fd, 10) == -1) {
98                 condlog(3, "Couldn't listen to ux_socket, error %d", errno);
99                 close(fd);
100                 return -1;
101         }
102         return fd;
103 }
104
105 /*
106  * keep writing until it's all sent
107  */
108 size_t write_all(int fd, const void *buf, size_t len)
109 {
110         size_t total = 0;
111
112         while (len) {
113                 ssize_t n = write(fd, buf, len);
114                 if (n < 0) {
115                         if ((errno == EINTR) || (errno == EAGAIN))
116                                 continue;
117                         return total;
118                 }
119                 if (!n)
120                         return total;
121                 buf = n + (char *)buf;
122                 len -= n;
123                 total += n;
124         }
125         return total;
126 }
127
128 /*
129  * keep reading until its all read
130  */
131 ssize_t read_all(int fd, void *buf, size_t len, unsigned int timeout)
132 {
133         size_t total = 0;
134         ssize_t n;
135         int ret;
136         struct pollfd pfd;
137
138         while (len) {
139                 pfd.fd = fd;
140                 pfd.events = POLLIN;
141                 ret = poll(&pfd, 1, timeout);
142                 if (!ret) {
143                         return -ETIMEDOUT;
144                 } else if (ret < 0) {
145                         if (errno == EINTR)
146                                 continue;
147                         return -errno;
148                 } else if (!pfd.revents & POLLIN)
149                         continue;
150                 n = read(fd, buf, len);
151                 if (n < 0) {
152                         if ((errno == EINTR) || (errno == EAGAIN))
153                                 continue;
154                         return -errno;
155                 }
156                 if (!n)
157                         return total;
158                 buf = n + (char *)buf;
159                 len -= n;
160                 total += n;
161         }
162         return total;
163 }
164
165 /*
166  * send a packet in length prefix format
167  */
168 int send_packet(int fd, const char *buf, size_t len)
169 {
170         int ret = 0;
171         sigset_t set, old;
172
173         /* Block SIGPIPE */
174         sigemptyset(&set);
175         sigaddset(&set, SIGPIPE);
176         pthread_sigmask(SIG_BLOCK, &set, &old);
177
178         if (write_all(fd, &len, sizeof(len)) != sizeof(len))
179                 ret = -1;
180         if (!ret && write_all(fd, buf, len) != len)
181                 ret = -1;
182
183         /* And unblock it again */
184         pthread_sigmask(SIG_SETMASK, &old, NULL);
185
186         return ret;
187 }
188
189 /*
190  * receive a packet in length prefix format
191  */
192 int recv_packet(int fd, char **buf, size_t *len, unsigned int timeout)
193 {
194         ssize_t ret;
195
196         ret = read_all(fd, len, sizeof(*len), timeout);
197         if (ret < 0) {
198                 (*buf) = NULL;
199                 *len = 0;
200                 return ret;
201         }
202         if (ret < sizeof(*len)) {
203                 (*buf) = NULL;
204                 *len = 0;
205                 return -EIO;
206         }
207         if (len == 0) {
208                 (*buf) = NULL;
209                 return 0;
210         }
211         (*buf) = MALLOC(*len);
212         if (!*buf)
213                 return -ENOMEM;
214         ret = read_all(fd, *buf, *len, timeout);
215         if (ret != *len) {
216                 FREE(*buf);
217                 (*buf) = NULL;
218                 *len = 0;
219                 return ret < 0 ? ret : -EIO;
220         }
221         return 0;
222 }