multipathd: fix reservation_key check
[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 <poll.h>
17 #include <signal.h>
18 #include <errno.h>
19 #ifdef USE_SYSTEMD
20 #include <systemd/sd-daemon.h>
21 #endif
22 #include "mpath_cmd.h"
23
24 #include "memory.h"
25 #include "uxsock.h"
26 #include "debug.h"
27
28 /*
29  * Code is similar with mpath_recv_reply() with data size limitation
30  * and debug-able malloc.
31  * When limit == 0, it means no limit on data size, used for socket client
32  * to receiving data from multipathd.
33  */
34 static int _recv_packet(int fd, char **buf, unsigned int timeout,
35                         ssize_t limit);
36
37 /*
38  * create a unix domain socket and start listening on it
39  * return a file descriptor open on the socket
40  */
41 int ux_socket_listen(const char *name)
42 {
43         int fd, len;
44 #ifdef USE_SYSTEMD
45         int num;
46 #endif
47         struct sockaddr_un addr;
48
49 #ifdef USE_SYSTEMD
50         num = sd_listen_fds(0);
51         if (num > 1) {
52                 condlog(3, "sd_listen_fds returned %d fds", num);
53                 return -1;
54         } else if (num == 1) {
55                 fd = SD_LISTEN_FDS_START + 0;
56                 condlog(3, "using fd %d from sd_listen_fds", fd);
57                 return fd;
58         }
59 #endif
60         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
61         if (fd == -1) {
62                 condlog(3, "Couldn't create ux_socket, error %d", errno);
63                 return -1;
64         }
65
66         memset(&addr, 0, sizeof(addr));
67         addr.sun_family = AF_LOCAL;
68         addr.sun_path[0] = '\0';
69         len = strlen(name) + 1 + sizeof(sa_family_t);
70         strncpy(&addr.sun_path[1], name, len);
71
72         if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
73                 condlog(3, "Couldn't bind to ux_socket, error %d", errno);
74                 close(fd);
75                 return -1;
76         }
77
78         if (listen(fd, 10) == -1) {
79                 condlog(3, "Couldn't listen to ux_socket, error %d", errno);
80                 close(fd);
81                 return -1;
82         }
83         return fd;
84 }
85
86 /*
87  * send a packet in length prefix format
88  */
89 int send_packet(int fd, const char *buf)
90 {
91         if (mpath_send_cmd(fd, buf) < 0)
92                 return -errno;
93         return 0;
94 }
95
96 static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit)
97 {
98         int err = 0;
99         ssize_t len = 0;
100
101         *buf = NULL;
102         len = mpath_recv_reply_len(fd, timeout);
103         if (len == 0)
104                 return len;
105         if (len < 0)
106                 return -errno;
107         if ((limit > 0) && (len > limit))
108                 return -EINVAL;
109         (*buf) = MALLOC(len);
110         if (!*buf)
111                 return -ENOMEM;
112         err = mpath_recv_reply_data(fd, *buf, len, timeout);
113         if (err != 0) {
114                 FREE(*buf);
115                 (*buf) = NULL;
116                 return -errno;
117         }
118         return err;
119 }
120
121 /*
122  * receive a packet in length prefix format
123  */
124 int recv_packet(int fd, char **buf, unsigned int timeout)
125 {
126         return _recv_packet(fd, buf, timeout, 0 /* no limit */);
127 }
128
129 int recv_packet_from_client(int fd, char **buf, unsigned int timeout)
130 {
131         return _recv_packet(fd, buf, timeout, _MAX_CMD_LEN);
132 }