Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / unix_send_fd.c
blob31d566bb107b846ceb57151a3e8a30a2cfd1fbb0
1 /* $NetBSD: unix_send_fd.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $ */
3 /*++
4 /* NAME
5 /* unix_send_fd 3
6 /* SUMMARY
7 /* send file descriptor
8 /* SYNOPSIS
9 /* #include <iostuff.h>
11 /* int unix_send_fd(fd, sendfd)
12 /* int fd;
13 /* int sendfd;
14 /* DESCRIPTION
15 /* unix_send_fd() sends a file descriptor over the specified
16 /* UNIX-domain socket.
18 /* Arguments:
19 /* .IP fd
20 /* File descriptor.
21 /* .IP sendfd
22 /* Another file descriptor.
23 /* DIAGNOSTICS
24 /* unix_send_fd() returns -1 upon failure.
25 /* LICENSE
26 /* .ad
27 /* .fi
28 /* The Secure Mailer license must be distributed with this software.
29 /* AUTHOR(S)
30 /* Wietse Venema
31 /* IBM T.J. Watson Research
32 /* P.O. Box 704
33 /* Yorktown Heights, NY 10598, USA
34 /*--*/
36 /* System library. */
38 #include <sys_defs.h> /* includes <sys/types.h> */
39 #include <sys/socket.h>
40 #include <sys/uio.h>
41 #include <string.h>
43 /* Utility library. */
45 #include <msg.h>
46 #include <iostuff.h>
48 /* unix_send_fd - send file descriptor */
50 int unix_send_fd(int fd, int sendfd)
54 * This code does not work with version <2.2 Linux kernels, and it does
55 * not compile with version <2 Linux libraries.
57 #ifdef CANT_USE_SEND_RECV_MSG
58 const char *myname = "unix_send_fd";
60 msg_warn("%s: your system has no support for file descriptor passing",
61 myname);
62 return (-1);
63 #else
64 struct msghdr msg;
65 struct iovec iov[1];
68 * Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
69 * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE; the
70 * latter breaks on LP64 systems.
72 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
73 union {
74 struct cmsghdr just_for_alignment;
75 char control[CMSG_SPACE(sizeof(sendfd))];
76 } control_un;
77 struct cmsghdr *cmptr;
79 memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
80 msg.msg_control = control_un.control;
81 msg.msg_controllen = sizeof(control_un.control); /* Fix 200506 */
83 cmptr = CMSG_FIRSTHDR(&msg);
84 cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd));
85 cmptr->cmsg_level = SOL_SOCKET;
86 cmptr->cmsg_type = SCM_RIGHTS;
87 *(int *) CMSG_DATA(cmptr) = sendfd;
88 #else
89 msg.msg_accrights = (char *) &sendfd;
90 msg.msg_accrightslen = sizeof(sendfd);
91 #endif
93 msg.msg_name = 0;
94 msg.msg_namelen = 0;
97 * XXX We don't want to pass any data, just a file descriptor. However,
98 * setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble. See the
99 * comments in the unix_recv_fd() routine.
101 iov->iov_base = "";
102 iov->iov_len = 1;
103 msg.msg_iov = iov;
104 msg.msg_iovlen = 1;
106 return (sendmsg(fd, &msg, 0));
107 #endif
110 #ifdef TEST
113 * Proof-of-concept program. Open a file and send the descriptor, presumably
114 * to the unix_recv_fd test program.
116 #include <unistd.h>
117 #include <string.h>
118 #include <stdlib.h>
119 #include <fcntl.h>
120 #include <split_at.h>
121 #include <connect.h>
123 int main(int argc, char **argv)
125 char *transport;
126 char *endpoint;
127 char *path;
128 int server_sock;
129 int client_fd;
131 if (argc < 3
132 || (endpoint = split_at(transport = argv[1], ':')) == 0
133 || *endpoint == 0 || *transport == 0)
134 msg_fatal("usage: %s transport:endpoint file...", argv[0]);
136 if (strcmp(transport, "unix") == 0) {
137 server_sock = unix_connect(endpoint, BLOCKING, 0);
138 } else {
139 msg_fatal("invalid transport name: %s", transport);
141 if (server_sock < 0)
142 msg_fatal("connect %s:%s: %m", transport, endpoint);
144 argv += 2;
145 while ((path = *argv++) != 0) {
146 if ((client_fd = open(path, O_RDONLY, 0)) < 0)
147 msg_fatal("open %s: %m", path);
148 msg_info("path=%s fd=%d", path, client_fd);
149 if (unix_send_fd(server_sock, client_fd) < 0)
150 msg_fatal("send file descriptor: %m");
151 if (close(client_fd) != 0)
152 msg_fatal("close(%d): %m", client_fd);
154 exit(0);
157 #endif