14 #include "auto_qmail.h"
15 #include "auto_uids.h"
16 #include "auto_spawn.h"
18 extern int truncreport
;
21 extern void initialize();
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 */
41 while ((pid
= wait_nohang(&wstat
)) > 0)
42 for (i
= 0;i
< auto_spawn
;++i
) if (d
[i
].used
)
45 close(d
[i
].fdout
); d
[i
].fdout
= -1;
46 d
[i
].wstat
= wstat
; d
[i
].pid
= 0;
52 int okwrite(fd
,buf
,n
) int fd
; char *buf
; int n
;
55 if (!flagwriting
) return n
;
57 if (w
!= -1) return w
;
58 if (errno
== error_intr
) return -1;
59 flagwriting
= 0; close(fd
);
64 char outbuf
[1024]; substdio ssout
;
66 int stage
= 0; /* reading 0:delnum 1:messid 2:sender 3:recip */
67 int flagabort
= 0; /* if 1, everything except delnum is garbage */
69 stralloc messid
= {0};
70 stralloc sender
= {0};
75 char ch
; ch
= delnum
; substdio_put(&ssout
,&ch
,1);
76 substdio_puts(&ssout
,s
); substdio_putflush(&ssout
,"",1);
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
)
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; }
100 if (!stralloc_copys(&d
[delnum
].output
,""))
101 { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
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; }
106 fdmess
= open_read(messid
.s
);
107 if (fdmess
== -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; }
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; }
118 { close(fdmess
); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; }
122 f
= spawn(fdmess
,pi
[1],sender
.s
,recip
.s
,j
);
125 { close(pi
[0]); close(pi
[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; }
127 d
[delnum
].fdin
= pi
[0];
128 d
[delnum
].fdout
= pi
[1]; coe(pi
[1]);
141 r
= read(0,cmdbuf
,sizeof(cmdbuf
));
143 { flagreading
= 0; return; }
146 if (errno
!= error_intr
)
151 for (i
= 0;i
< r
;++i
)
157 delnum
= (unsigned int) (unsigned char) ch
;
158 messid
.len
= 0; stage
= 1; break;
160 if (!stralloc_append(&messid
,&ch
)) flagabort
= 1;
162 sender
.len
= 0; stage
= 2; break;
164 if (!stralloc_append(&sender
,&ch
)) flagabort
= 1;
166 recip
.len
= 0; stage
= 3; break;
168 if (!stralloc_append(&recip
,&ch
)) flagabort
= 1;
171 flagabort
= 0; stage
= 0; break;
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);
194 d
= (struct delivery
*) alloc((auto_spawn
+ 10) * sizeof(struct delivery
));
197 substdio_fdbuf(&ssout
,okwrite
,1,outbuf
,sizeof(outbuf
));
200 sig_childcatch(sigchld
);
202 initialize(argc
,argv
);
204 ch
= auto_spawn
; substdio_putflush(&ssout
,&ch
,1);
206 for (i
= 0;i
< auto_spawn
;++i
) { d
[i
].used
= 0; d
[i
].output
.s
= 0; }
212 for (i
= 0;i
< auto_spawn
;++i
) if (d
[i
].used
) break;
213 if (i
>= auto_spawn
) _exit(0);
218 if (flagreading
) FD_SET(0,&rfds
);
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; }
223 r
= select(nfds
,&rfds
,(fd_set
*) 0,(fd_set
*) 0,(struct timeval
*) 0);
229 if (FD_ISSET(0,&rfds
))
231 for (i
= 0;i
< auto_spawn
;++i
) if (d
[i
].used
)
232 if (FD_ISSET(d
[i
].fdin
,&rfds
))
234 r
= read(d
[i
].fdin
,inbuf
,128);
236 continue; /* read error on a readable pipe? be serious */
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;
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
)
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
);