diff options
| author | manuel <manuel@mausz.at> | 2013-02-04 00:08:53 +0100 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2013-02-04 00:08:53 +0100 |
| commit | 69aec538b456402170dc723af417ba5c05389c32 (patch) | |
| tree | e6f34c543f17c6392447ea337b2e2868212424d1 /spawn.c | |
| download | qmail-69aec538b456402170dc723af417ba5c05389c32.tar.gz qmail-69aec538b456402170dc723af417ba5c05389c32.tar.bz2 qmail-69aec538b456402170dc723af417ba5c05389c32.zip | |
qmail 1.03 import
Diffstat (limited to 'spawn.c')
| -rw-r--r-- | spawn.c | 259 |
1 files changed, 259 insertions, 0 deletions
| @@ -0,0 +1,259 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <sys/stat.h> | ||
| 3 | #include "sig.h" | ||
| 4 | #include "wait.h" | ||
| 5 | #include "substdio.h" | ||
| 6 | #include "byte.h" | ||
| 7 | #include "str.h" | ||
| 8 | #include "stralloc.h" | ||
| 9 | #include "select.h" | ||
| 10 | #include "exit.h" | ||
| 11 | #include "coe.h" | ||
| 12 | #include "open.h" | ||
| 13 | #include "error.h" | ||
| 14 | #include "auto_qmail.h" | ||
| 15 | #include "auto_uids.h" | ||
| 16 | #include "auto_spawn.h" | ||
| 17 | |||
| 18 | extern int truncreport; | ||
| 19 | extern int spawn(); | ||
| 20 | extern void report(); | ||
| 21 | extern void initialize(); | ||
| 22 | |||
| 23 | struct delivery | ||
| 24 | { | ||
| 25 | int used; | ||
| 26 | int fdin; /* pipe input */ | ||
| 27 | int pid; /* zero if child is dead */ | ||
| 28 | int wstat; /* if !pid: status of child */ | ||
| 29 | int fdout; /* pipe output, -1 if !pid; delays eof until after death */ | ||
| 30 | stralloc output; | ||
| 31 | } | ||
| 32 | ; | ||
| 33 | |||
| 34 | struct delivery *d; | ||
| 35 | |||
| 36 | void sigchld() | ||
| 37 | { | ||
| 38 | int wstat; | ||
| 39 | int pid; | ||
| 40 | int i; | ||
| 41 | while ((pid = wait_nohang(&wstat)) > 0) | ||
| 42 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 43 | if (d[i].pid == pid) | ||
| 44 | { | ||
| 45 | close(d[i].fdout); d[i].fdout = -1; | ||
| 46 | d[i].wstat = wstat; d[i].pid = 0; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | int flagwriting = 1; | ||
| 51 | |||
| 52 | int okwrite(fd,buf,n) int fd; char *buf; int n; | ||
| 53 | { | ||
| 54 | int w; | ||
| 55 | if (!flagwriting) return n; | ||
| 56 | w = write(fd,buf,n); | ||
| 57 | if (w != -1) return w; | ||
| 58 | if (errno == error_intr) return -1; | ||
| 59 | flagwriting = 0; close(fd); | ||
| 60 | return n; | ||
| 61 | } | ||
| 62 | |||
| 63 | int flagreading = 1; | ||
| 64 | char outbuf[1024]; substdio ssout; | ||
| 65 | |||
| 66 | int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */ | ||
| 67 | int flagabort = 0; /* if 1, everything except delnum is garbage */ | ||
| 68 | int delnum; | ||
| 69 | stralloc messid = {0}; | ||
| 70 | stralloc sender = {0}; | ||
| 71 | stralloc recip = {0}; | ||
| 72 | |||
| 73 | void err(s) char *s; | ||
| 74 | { | ||
| 75 | char ch; ch = delnum; substdio_put(&ssout,&ch,1); | ||
| 76 | substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1); | ||
| 77 | } | ||
| 78 | |||
| 79 | void docmd() | ||
| 80 | { | ||
| 81 | int f; | ||
| 82 | int i; | ||
| 83 | int j; | ||
| 84 | int fdmess; | ||
| 85 | int pi[2]; | ||
| 86 | struct stat st; | ||
| 87 | |||
| 88 | if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } | ||
| 89 | if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; } | ||
| 90 | if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; } | ||
| 91 | if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; } | ||
| 92 | for (i = 0;i < messid.len;++i) | ||
| 93 | if (messid.s[i]) | ||
| 94 | if (!i || (messid.s[i] != '/')) | ||
| 95 | if ((unsigned char) (messid.s[i] - '0') > 9) | ||
| 96 | { err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; } | ||
| 97 | if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; } | ||
| 98 | if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; } | ||
| 99 | |||
| 100 | if (!stralloc_copys(&d[delnum].output,"")) | ||
| 101 | { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; } | ||
| 102 | |||
| 103 | j = byte_rchr(recip.s,recip.len,'@'); | ||
| 104 | if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; } | ||
| 105 | |||
| 106 | fdmess = open_read(messid.s); | ||
| 107 | if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; } | ||
| 108 | |||
| 109 | if (fstat(fdmess,&st) == -1) | ||
| 110 | { close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; } | ||
| 111 | if ((st.st_mode & S_IFMT) != S_IFREG) | ||
| 112 | { close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; } | ||
| 113 | if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */ | ||
| 114 | /* your security is already toast at this point. damage control... */ | ||
| 115 | { close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; } | ||
| 116 | |||
| 117 | if (pipe(pi) == -1) | ||
| 118 | { close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; } | ||
| 119 | |||
| 120 | coe(pi[0]); | ||
| 121 | |||
| 122 | f = spawn(fdmess,pi[1],sender.s,recip.s,j); | ||
| 123 | close(fdmess); | ||
| 124 | if (f == -1) | ||
| 125 | { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; } | ||
| 126 | |||
| 127 | d[delnum].fdin = pi[0]; | ||
| 128 | d[delnum].fdout = pi[1]; coe(pi[1]); | ||
| 129 | d[delnum].pid = f; | ||
| 130 | d[delnum].used = 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | char cmdbuf[1024]; | ||
| 134 | |||
| 135 | void getcmd() | ||
| 136 | { | ||
| 137 | int i; | ||
| 138 | int r; | ||
| 139 | char ch; | ||
| 140 | |||
| 141 | r = read(0,cmdbuf,sizeof(cmdbuf)); | ||
| 142 | if (r == 0) | ||
| 143 | { flagreading = 0; return; } | ||
| 144 | if (r == -1) | ||
| 145 | { | ||
| 146 | if (errno != error_intr) | ||
| 147 | flagreading = 0; | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | for (i = 0;i < r;++i) | ||
| 152 | { | ||
| 153 | ch = cmdbuf[i]; | ||
| 154 | switch(stage) | ||
| 155 | { | ||
| 156 | case 0: | ||
| 157 | delnum = (unsigned int) (unsigned char) ch; | ||
| 158 | messid.len = 0; stage = 1; break; | ||
| 159 | case 1: | ||
| 160 | if (!stralloc_append(&messid,&ch)) flagabort = 1; | ||
| 161 | if (ch) break; | ||
| 162 | sender.len = 0; stage = 2; break; | ||
| 163 | case 2: | ||
| 164 | if (!stralloc_append(&sender,&ch)) flagabort = 1; | ||
| 165 | if (ch) break; | ||
| 166 | recip.len = 0; stage = 3; break; | ||
| 167 | case 3: | ||
| 168 | if (!stralloc_append(&recip,&ch)) flagabort = 1; | ||
| 169 | if (ch) break; | ||
| 170 | docmd(); | ||
| 171 | flagabort = 0; stage = 0; break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | char inbuf[128]; | ||
| 177 | |||
| 178 | void main(argc,argv) | ||
| 179 | int argc; | ||
| 180 | char **argv; | ||
| 181 | { | ||
| 182 | char ch; | ||
| 183 | int i; | ||
| 184 | int r; | ||
| 185 | fd_set rfds; | ||
| 186 | int nfds; | ||
| 187 | |||
| 188 | if (chdir(auto_qmail) == -1) _exit(111); | ||
| 189 | if (chdir("queue/mess") == -1) _exit(111); | ||
| 190 | if (!stralloc_copys(&messid,"")) _exit(111); | ||
| 191 | if (!stralloc_copys(&sender,"")) _exit(111); | ||
| 192 | if (!stralloc_copys(&recip,"")) _exit(111); | ||
| 193 | |||
| 194 | d = (struct delivery *) alloc((auto_spawn + 10) * sizeof(struct delivery)); | ||
| 195 | if (!d) _exit(111); | ||
| 196 | |||
| 197 | substdio_fdbuf(&ssout,okwrite,1,outbuf,sizeof(outbuf)); | ||
| 198 | |||
| 199 | sig_pipeignore(); | ||
| 200 | sig_childcatch(sigchld); | ||
| 201 | |||
| 202 | initialize(argc,argv); | ||
| 203 | |||
| 204 | ch = auto_spawn; substdio_putflush(&ssout,&ch,1); | ||
| 205 | |||
| 206 | for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; } | ||
| 207 | |||
| 208 | for (;;) | ||
| 209 | { | ||
| 210 | if (!flagreading) | ||
| 211 | { | ||
| 212 | for (i = 0;i < auto_spawn;++i) if (d[i].used) break; | ||
| 213 | if (i >= auto_spawn) _exit(0); | ||
| 214 | } | ||
| 215 | sig_childunblock(); | ||
| 216 | |||
| 217 | FD_ZERO(&rfds); | ||
| 218 | if (flagreading) FD_SET(0,&rfds); | ||
| 219 | nfds = 1; | ||
| 220 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 221 | { FD_SET(d[i].fdin,&rfds); if (d[i].fdin >= nfds) nfds = d[i].fdin + 1; } | ||
| 222 | |||
| 223 | r = select(nfds,&rfds,(fd_set *) 0,(fd_set *) 0,(struct timeval *) 0); | ||
| 224 | sig_childblock(); | ||
| 225 | |||
| 226 | if (r != -1) | ||
| 227 | { | ||
| 228 | if (flagreading) | ||
| 229 | if (FD_ISSET(0,&rfds)) | ||
| 230 | getcmd(); | ||
| 231 | for (i = 0;i < auto_spawn;++i) if (d[i].used) | ||
| 232 | if (FD_ISSET(d[i].fdin,&rfds)) | ||
| 233 | { | ||
| 234 | r = read(d[i].fdin,inbuf,128); | ||
| 235 | if (r == -1) | ||
| 236 | continue; /* read error on a readable pipe? be serious */ | ||
| 237 | if (r == 0) | ||
| 238 | { | ||
| 239 | ch = i; substdio_put(&ssout,&ch,1); | ||
| 240 | report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len); | ||
| 241 | substdio_put(&ssout,"",1); | ||
| 242 | substdio_flush(&ssout); | ||
| 243 | close(d[i].fdin); d[i].used = 0; | ||
| 244 | continue; | ||
| 245 | } | ||
| 246 | while (!stralloc_readyplus(&d[i].output,r)) sleep(10); /*XXX*/ | ||
| 247 | byte_copy(d[i].output.s + d[i].output.len,r,inbuf); | ||
| 248 | d[i].output.len += r; | ||
| 249 | if (truncreport > 100) | ||
| 250 | if (d[i].output.len > truncreport) | ||
| 251 | { | ||
| 252 | char *truncmess = "\nError report too long, sorry.\n"; | ||
| 253 | d[i].output.len = truncreport - str_len(truncmess) - 3; | ||
| 254 | stralloc_cats(&d[i].output,truncmess); | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
