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