chiark / gitweb /
fishdescriptor: .so can be loaded
[chiark-utils.git] / fishdescriptor / donate.c
index b7ef5f82125e28b1f1338e4030a9e2133f419729..11c51dbf8cc86ea507f1306efce0dff23a5ba25e 100644 (file)
@@ -2,45 +2,91 @@
  * Copyright (C) 2009 Citrix Ltd.
  * Copyright (C) 2017 Citrix Ltd.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; version 2.1 only. with the special
- * exception on linking described in file LICENSE.
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-int libxl__sendmsg_fds(libxl__gc *gc, int carrier,
-                       const void *data, size_t datalen,
-                       int nfds, const int fds[], const char *what) {
-    struct msghdr msg = { 0 };
-    struct cmsghdr *cmsg;
-    size_t spaceneeded = nfds * sizeof(fds[0]);
-    char control[CMSG_SPACE(spaceneeded)];
-    struct iovec iov;
-    int r;
-
-    iov.iov_base = (void*)data;
-    iov.iov_len  = datalen;
-
-    /* compose the message */
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-    msg.msg_control = control;
-    msg.msg_controllen = sizeof(control);
-
-    /* attach open fd */
-    cmsg = CMSG_FIRSTHDR(&msg);
-    cmsg->cmsg_level = SOL_SOCKET;
-    cmsg->cmsg_type = SCM_RIGHTS;
-    cmsg->cmsg_len = CMSG_LEN(spaceneeded);
-    memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
-
-    msg.msg_controllen = cmsg->cmsg_len;
-
-    r = sendmsg(carrier, &msg, 0);
-    if (r < 0) {
-        LOGE(ERROR, "failed to send fd-carrying message (%s)", what);
-        return ERROR_FAIL;
-    }
-
-    return 0;
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+static int fishdescriptor_sendmsg_fds(int carrier,
+                                      int nfds, const int fds[]) {
+  /* return convention: like a syscall */
+  struct msghdr msg = { 0 };
+  struct cmsghdr *cmsg;
+  size_t spaceneeded = nfds * sizeof(fds[0]);
+  char control[CMSG_SPACE(spaceneeded)];
+  struct iovec iov;
+  int r;
+
+  iov.iov_base = &nfds;
+  iov.iov_len  = sizeof(nfds);
+
+  /* compose the message */
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control;
+  msg.msg_controllen = sizeof(control);
+
+  /* attach open fd */
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(spaceneeded);
+  memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
+
+  msg.msg_controllen = cmsg->cmsg_len;
+    
+  r = sendmsg(carrier, &msg, 0);
+  if (r < 0) return -1;
+
+  return 0;
+}
+
+int fishdescriptor_donate(const char *path, const int *fds) {
+  /* return convention: returns errno value */
+  /* within function: r is like syscall return, errno value is in errno */
+  int r;
+  int esave = errno;
+  int carrier=-1;
+
+  carrier = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (carrier < 0) { r=-1; goto out; }
+
+  struct sockaddr_un suna;
+  memset(&suna,0,sizeof(suna));
+  suna.sun_family = AF_UNIX;
+  if (strlen(path) >= sizeof(suna.sun_path)) { errno=E2BIG; r=-1; goto out; }
+  strcpy(suna.sun_path, path);
+
+  r = connect(carrier, (const struct sockaddr*)&suna, sizeof(suna));
+  if (r) goto out;
+
+  int nfds;
+  for (nfds=0; fds[nfds] > 0; nfds++);
+
+  r = fishdescriptor_sendmsg_fds(carrier, nfds, fds);
+  if (r) goto out;
+
+  r = 0;
+ out:
+  if (carrier >= 0) close(carrier);
+  r = !r ? 0 : !errno ? EIO : errno;
+  errno = esave;
+  return r;
 }