Invalid error code when using multipathd CLI
[multipath-tools/.git] / libmultipath / uxsock.c
index d5d1be9..7e5a144 100644 (file)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <signal.h>
 #include <errno.h>
+#ifdef USE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+#include "mpath_cmd.h"
 
 #include "memory.h"
 #include "uxsock.h"
+#include "debug.h"
 
 /*
- * connect to a unix domain socket
+ * Code is similar with mpath_recv_reply() with data size limitation
+ * and debug-able malloc.
+ * When limit == 0, it means no limit on data size, used for socket client
+ * to receiving data from multipathd.
  */
-int ux_socket_connect(const char *name)
-{
-       int fd;
-       struct sockaddr_un addr;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strncpy(addr.sun_path, name, sizeof(addr.sun_path));
-
-       fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd == -1) {
-               return -1;
-       }
-
-       if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-               close(fd);
-               return -1;
-       }
-
-       return fd;
-}
+static int _recv_packet(int fd, char **buf, unsigned int timeout,
+                       ssize_t limit);
 
 /*
  * create a unix domain socket and start listening on it
@@ -51,114 +40,93 @@ int ux_socket_connect(const char *name)
  */
 int ux_socket_listen(const char *name)
 {
-       int fd;
+       int fd, len;
+#ifdef USE_SYSTEMD
+       int num;
+#endif
        struct sockaddr_un addr;
 
-       /* get rid of any old socket */
-       unlink(name);
-
-       fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd == -1) return -1;
+#ifdef USE_SYSTEMD
+       num = sd_listen_fds(0);
+       if (num > 1) {
+               condlog(3, "sd_listen_fds returned %d fds", num);
+               return -1;
+       } else if (num == 1) {
+               fd = SD_LISTEN_FDS_START + 0;
+               condlog(3, "using fd %d from sd_listen_fds", fd);
+               return fd;
+       }
+#endif
+       fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (fd == -1) {
+               condlog(3, "Couldn't create ux_socket, error %d", errno);
+               return -1;
+       }
 
        memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strncpy(addr.sun_path, name, sizeof(addr.sun_path));
+       addr.sun_family = AF_LOCAL;
+       addr.sun_path[0] = '\0';
+       len = strlen(name) + 1 + sizeof(sa_family_t);
+       strncpy(&addr.sun_path[1], name, len);
 
-       if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+       if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
+               condlog(3, "Couldn't bind to ux_socket, error %d", errno);
                close(fd);
                return -1;
        }
 
        if (listen(fd, 10) == -1) {
+               condlog(3, "Couldn't listen to ux_socket, error %d", errno);
                close(fd);
                return -1;
        }
-
        return fd;
 }
 
 /*
- * keep writing until it's all sent
+ * send a packet in length prefix format
  */
-size_t write_all(int fd, const void *buf, size_t len)
+int send_packet(int fd, const char *buf)
 {
-       size_t total = 0;
-
-       while (len) {
-               ssize_t n = write(fd, buf, len);
-               if (n < 0) {
-                       if ((errno == EINTR) || (errno == EAGAIN))
-                               continue;
-                       return total;
-               }
-               if (!n)
-                       return total;
-               buf = n + (char *)buf;
-               len -= n;
-               total += n;
-       }
-       return total;
+       if (mpath_send_cmd(fd, buf) < 0)
+               return -errno;
+       return 0;
 }
 
-/*
- * keep reading until its all read
- */
-size_t read_all(int fd, void *buf, size_t len)
+static int _recv_packet(int fd, char **buf, unsigned int timeout, ssize_t limit)
 {
-       size_t total = 0;
-
-       while (len) {
-               ssize_t n = read(fd, buf, len);
-               if (n < 0) {
-                       if ((errno == EINTR) || (errno == EAGAIN))
-                               continue;
-                       return total;
-               }
-               if (!n)
-                       return total;
-               buf = n + (char *)buf;
-               len -= n;
-               total += n;
+       int err = 0;
+       ssize_t len = 0;
+
+       *buf = NULL;
+       len = mpath_recv_reply_len(fd, timeout);
+       if (len == 0)
+               return len;
+       if (len < 0)
+               return -errno;
+       if ((limit > 0) && (len > limit))
+               return -EINVAL;
+       (*buf) = MALLOC(len);
+       if (!*buf)
+               return -ENOMEM;
+       err = mpath_recv_reply_data(fd, *buf, len, timeout);
+       if (err != 0) {
+               FREE(*buf);
+               (*buf) = NULL;
+               return -errno;
        }
-       return total;
+       return err;
 }
 
 /*
- * send a packet in length prefix format
+ * receive a packet in length prefix format
  */
-int send_packet(int fd, const char *buf, size_t len)
+int recv_packet(int fd, char **buf, unsigned int timeout)
 {
-       int ret = 0;
-       sigset_t set, old;
-
-       /* Block SIGPIPE */
-       sigemptyset(&set);
-       sigaddset(&set, SIGPIPE);
-       pthread_sigmask(SIG_BLOCK, &set, &old);
-
-       if (write_all(fd, &len, sizeof(len)) != sizeof(len))
-               ret = -1;
-       if (!ret && write_all(fd, buf, len) != len)
-               ret = -1;
-
-       /* And unblock it again */
-       pthread_sigmask(SIG_SETMASK, &old, NULL);
-
-       return ret;
+       return _recv_packet(fd, buf, timeout, 0 /* no limit */);
 }
 
-/*
- * receive a packet in length prefix format
- */
-int recv_packet(int fd, char **buf, size_t *len)
+int recv_packet_from_client(int fd, char **buf, unsigned int timeout)
 {
-       if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) return -1;
-       (*buf) = MALLOC(*len);
-       if (!*buf)
-               return -1;
-       if (read_all(fd, *buf, *len) != *len) {
-               FREE(*buf);
-               return -1;
-       }
-       return 0;
+       return _recv_packet(fd, buf, timeout, _MAX_CMD_LEN);
 }