Added callbacks to handle child process initialization.
[ashd.git] / lib / proc.c
CommitLineData
0c16b406
FT
1/*
2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
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 <string.h>
21#include <unistd.h>
22#include <sys/socket.h>
23#include <errno.h>
992ce9ef 24#include <ctype.h>
0c16b406
FT
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29#include <utils.h>
30#include <log.h>
31#include <proc.h>
992ce9ef 32#include <req.h>
0c16b406 33
6a7a868e 34int stdmkchild(char **argv, void (*chinit)(void *), void *idata)
0c16b406
FT
35{
36 int i;
37 pid_t pid;
38 int fd[2];
39
820f9137 40 if(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fd))
0c16b406
FT
41 return(-1);
42 if((pid = fork()) < 0)
43 return(-1);
44 if(pid == 0) {
6a7a868e
FT
45 if(chinit != NULL)
46 chinit(idata);
0c16b406
FT
47 for(i = 3; i < FD_SETSIZE; i++) {
48 if(i != fd[0])
49 close(i);
50 }
51 dup2(fd[0], 0);
52 close(fd[0]);
53 execvp(argv[0], argv);
54 flog(LOG_WARNING, "could not exec child program %s: %s", argv[0], strerror(errno));
55 exit(127);
56 }
57 close(fd[0]);
58 return(fd[1]);
59}
60
61int sendfd(int sock, int fd, char *data, size_t datalen)
62{
63 struct msghdr msg;
64 struct cmsghdr *cmsg;
65 char cmbuf[CMSG_SPACE(sizeof(int))];
66 struct iovec bufvec;
67
68 memset(&msg, 0, sizeof(msg));
69 msg.msg_iov = &bufvec;
70 msg.msg_iovlen = 1;
71 bufvec.iov_base = data;
72 bufvec.iov_len = datalen;
73
74 msg.msg_control = cmbuf;
75 msg.msg_controllen = sizeof(cmbuf);
76 cmsg = CMSG_FIRSTHDR(&msg);
77 cmsg->cmsg_level = SOL_SOCKET;
78 cmsg->cmsg_type = SCM_RIGHTS;
79 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
80 *((int *)CMSG_DATA(cmsg)) = fd;
81 msg.msg_controllen = cmsg->cmsg_len;
82
83 return(sendmsg(sock, &msg, MSG_NOSIGNAL | MSG_DONTWAIT));
84}
85
86int recvfd(int sock, char **data, size_t *datalen)
87{
88 int ret, fd;
3a42b6b1 89 char *buf, cbuf[1024];
0c16b406
FT
90 struct msghdr msg;
91 struct cmsghdr *cmsg;
92 struct iovec bufvec;
93
94 buf = smalloc(65536);
95 memset(&msg, 0, sizeof(msg));
96
97 msg.msg_iov = &bufvec;
98 msg.msg_iovlen = 1;
99 bufvec.iov_base = buf;
100 bufvec.iov_len = 65536;
101 msg.msg_control = cbuf;
102 msg.msg_controllen = sizeof(cbuf);
103
104 ret = recvmsg(sock, &msg, 0);
820f9137 105 if(ret <= 0) {
0c16b406 106 free(buf);
820f9137
FT
107 if(ret == 0)
108 errno = 0;
0c16b406
FT
109 return(-1);
110 }
111
112 fd = -1;
113 for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
114 if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS)) {
115 fd = *((int *)CMSG_DATA(cmsg));
116 }
117 }
118 if(fd < 0) {
119 free(buf);
120 errno = EPROTO;
121 return(-1);
122 }
123 buf = realloc(buf, ret);
124 *data = buf;
125 *datalen = ret;
126 return(fd);
127}
992ce9ef 128
6a7a868e 129pid_t stdforkserve(char **argv, struct hthead *req, int fd, void (*chinit)(void *), void *idata)
992ce9ef
FT
130{
131 int i;
132 char *ebuf, *p;
133 pid_t pid;
134 struct charvbuf args;
135
136 if((pid = fork()) < 0)
137 return(-1);
138 if(pid == 0) {
6a7a868e
FT
139 if(chinit != NULL)
140 chinit(idata);
141
992ce9ef
FT
142 dup2(fd, 0);
143 dup2(fd, 1);
144 for(i = 3; i < FD_SETSIZE; i++)
145 close(i);
146
147 bufinit(args);
148 for(i = 0; argv[i]; i++)
149 bufadd(args, argv[i]);
150 bufadd(args, req->method);
151 bufadd(args, req->url);
152 bufadd(args, req->rest);
153 bufadd(args, NULL);
154
155 for(i = 0; i < req->noheaders; i++) {
156 ebuf = sstrdup(req->headers[i][0]);
157 for(p = ebuf; *p; p++) {
158 if(isalnum(*p))
159 *p = toupper(*p);
160 else
161 *p = '_';
162 }
163 putenv(sprintf2("REQ_%s=%s", ebuf, req->headers[i][1]));
164 }
165 putenv(sprintf2("HTTP_VERSION=%s", req->ver));
166
167 execvp(args.b[0], args.b);
168 flog(LOG_WARNING, "could not exec child program %s: %s", argv[0], strerror(errno));
169 exit(127);
170 }
992ce9ef
FT
171 return(pid);
172}