chiark / gitweb /
11c51dbf8cc86ea507f1306efce0dff23a5ba25e
[chiark-utils.git] / fishdescriptor / donate.c
1 /*
2  * Copyright (C) 2009 Citrix Ltd.
3  * Copyright (C) 2017 Citrix Ltd.
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26
27 static int fishdescriptor_sendmsg_fds(int carrier,
28                                       int nfds, const int fds[]) {
29   /* return convention: like a syscall */
30   struct msghdr msg = { 0 };
31   struct cmsghdr *cmsg;
32   size_t spaceneeded = nfds * sizeof(fds[0]);
33   char control[CMSG_SPACE(spaceneeded)];
34   struct iovec iov;
35   int r;
36
37   iov.iov_base = &nfds;
38   iov.iov_len  = sizeof(nfds);
39
40   /* compose the message */
41   msg.msg_iov = &iov;
42   msg.msg_iovlen = 1;
43   msg.msg_control = control;
44   msg.msg_controllen = sizeof(control);
45
46   /* attach open fd */
47   cmsg = CMSG_FIRSTHDR(&msg);
48   cmsg->cmsg_level = SOL_SOCKET;
49   cmsg->cmsg_type = SCM_RIGHTS;
50   cmsg->cmsg_len = CMSG_LEN(spaceneeded);
51   memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
52
53   msg.msg_controllen = cmsg->cmsg_len;
54     
55   r = sendmsg(carrier, &msg, 0);
56   if (r < 0) return -1;
57
58   return 0;
59 }
60
61 int fishdescriptor_donate(const char *path, const int *fds) {
62   /* return convention: returns errno value */
63   /* within function: r is like syscall return, errno value is in errno */
64   int r;
65   int esave = errno;
66   int carrier=-1;
67
68   carrier = socket(AF_UNIX, SOCK_STREAM, 0);
69   if (carrier < 0) { r=-1; goto out; }
70
71   struct sockaddr_un suna;
72   memset(&suna,0,sizeof(suna));
73   suna.sun_family = AF_UNIX;
74   if (strlen(path) >= sizeof(suna.sun_path)) { errno=E2BIG; r=-1; goto out; }
75   strcpy(suna.sun_path, path);
76
77   r = connect(carrier, (const struct sockaddr*)&suna, sizeof(suna));
78   if (r) goto out;
79
80   int nfds;
81   for (nfds=0; fds[nfds] > 0; nfds++);
82
83   r = fishdescriptor_sendmsg_fds(carrier, nfds, fds);
84   if (r) goto out;
85
86   r = 0;
87  out:
88   if (carrier >= 0) close(carrier);
89   r = !r ? 0 : !errno ? EIO : errno;
90   errno = esave;
91   return r;
92 }