|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)spawn.c 1.1 (Berkeley) 10/15/87";
3: #endif
4:
5: #include "../common/conf.h"
6:
7: #include "common.h"
8:
9: #include <signal.h>
10:
11: #ifdef XFER_TIMEOUT
12: static int xfer_lines;
13: static int old_xfer_lines;
14: #endif
15:
16: static char tempfile[256];
17:
18: /*
19: * spawn -- create a child process with the input from the client
20: * as stdin.
21: *
22: * Parameters: "path" is the path of the program to invoke.
23: * "name" is the name to call the program.
24: * "flag" is a single flag to be passed to the program.
25: * "cont_code" is the response code to transmit
26: * on successful startup.
27: * "err_code" is the response code to transmit when
28: * something goes wrong.
29: *
30: * Returns: -1 on non-zero return from child,
31: * 0 on error before fork/exec,
32: * 1 otherwise.
33: *
34: * Side effects: Creates and removes temporary file;
35: * accepts input from client; forks and execs.
36: * Can time out if XFER_TIMEOUT is defined.
37: */
38:
39: spawn(path, name, flag, cont_code, err_code, errbuf)
40: char *path;
41: char *name;
42: char *flag;
43: int cont_code;
44: int err_code;
45: char *errbuf;
46: {
47: char line[MAX_STRLEN];
48: register char *cp;
49: int i, fd;
50: int fds[2];
51: int pid, npid;
52: int exit_status;
53: #ifdef XFER_TIMEOUT
54: int xfer_timeout();
55: int (*otimeout)();
56: #endif
57: union wait status;
58: register FILE *fp;
59:
60: (void) strcpy(tempfile, "/tmp/rpostXXXXXX");
61: (void) mktemp(tempfile);
62:
63: fp = fopen(tempfile, "w");
64: if (fp == NULL) {
65: printf("%d Cannot create temporary file.\r\n", err_code);
66: (void) fflush(stdout);
67: return (0);
68: } else {
69: printf("%d Enter news, period on a line by itself to end.\r\n",
70: cont_code);
71: (void) fflush(stdout);
72: }
73:
74: #ifdef XFER_TIMEOUT
75: xfer_lines = old_xfer_lines = 0;
76: otimeout = signal(SIGALRM, xfer_timeout);
77: (void) alarm(XFER_TIMEOUT);
78: #endif
79:
80: while (fgets(line, sizeof(line), stdin) != NULL) {
81: #ifdef XFER_TIMEOUT
82: xfer_lines++;
83: #endif
84: if ((cp = index(line, '\r')) != NULL)
85: *cp = '\0';
86: else if ((cp = index(line, '\n')) != NULL)
87: *cp = '\0';
88:
89: if (line[0] == '.' && line[1] == '\0')
90: break;
91:
92: if (line[0] == '.')
93: fputs(line+1, fp);
94: else
95: fputs(line, fp);
96: putc('\n', fp);
97: }
98: (void) fclose(fp);
99:
100: #ifdef XFER_TIMEOUT
101: (void) alarm(0);
102: (void) signal(SIGALRM, otimeout);
103: #endif
104:
105: /* See if the connection got closed somehow... */
106:
107: if (line[0] != '.' && line[1] != '\0') {
108: (void) unlink(tempfile);
109: #ifdef SYSLOG
110: # ifdef LOG
111: syslog(LOG_ERR, "%s spawn: EOF before period on line by itself",
112: hostname);
113: # else
114: syslog(LOG_ERR, "spawn: EOF before period on line by itself");
115: # endif
116: #endif
117: return (0);
118: }
119:
120: #ifdef POSTER
121: (void) chown(tempfile, uid_poster, gid_poster);
122: #endif
123:
124: /* Set up a pipe so we can see errors from rnews */
125:
126: if (pipe(fds) < 0) {
127: #ifdef SYSLOG
128: syslog(LOG_ERR, "spawn: pipe: %m");
129: #endif
130: (void) unlink(tempfile);
131: return (-1);
132: }
133:
134: /*
135: * Ok, now we have the article in "tempfile". We
136: * should be able to fork off, close fd's 0 to 31 (or
137: * whatever), open "tempfile" for input, thus making
138: * it stdin, and then execl the inews. We think.
139: */
140:
141: pid = vfork();
142: if (pid == 0) { /* We're in child */
143: #ifdef POSTER
144: (void) setuid(uid_poster);
145: (void) setgid(gid_poster);
146: #endif
147:
148: /* Set up stdout and stderr for child */
149:
150: if (fds[1] != 1) {
151: (void) dup2(fds[1], 1);
152: (void) close(fds[1]);
153: }
154: (void) dup2(1, 2);
155:
156: for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */
157: (void) close(i);
158:
159: fd = open(tempfile, O_RDONLY);
160: if (fd != 0) {
161: (void) dup2(fd, 0);
162: (void) close(fd);
163: }
164:
165: execl(path, name, flag, (char *) NULL);
166: fprintf(stderr, "spawn: execl ");
167: perror(path);
168: _exit(-1); /* Error */
169: } else {
170: (void) close(fds[1]);
171: fp = fdopen(fds[0], "r");
172: if (fp == NULL) {
173: printf("%d Cannot fdopen %s pipe\r\n", err_code, path);
174: (void) fflush(stdout);
175: #ifdef SYSLOG
176: syslog(LOG_ERR, "spawn: pipe: %m");
177: #endif
178: (void) unlink(tempfile);
179: return (0);
180: }
181:
182: if (errbuf)
183: *errbuf = '\0';
184:
185: while (fgets(line, sizeof (line), fp) != NULL) {
186: if (line[0] != '\n') {
187: if (errbuf) {
188: if (cp = index(line, '\n'))
189: *cp = '\0';
190: (void) strcat(errbuf, line);
191: (void) strcat(errbuf, "\\");
192: }
193: #ifdef SYSLOG
194: syslog(LOG_ERR, "%s: %s", path, line);
195: #endif
196: }
197: }
198:
199: while ((npid = wait(&status)) > 0)
200: if (npid == pid) {
201: exit_status = status.w_T.w_Retcode;
202: break;
203: }
204:
205: (void) fclose(fp);
206: (void) unlink(tempfile);
207: (void) fflush(stdout);
208: if (npid < 0) {
209: #ifdef SYSLOG
210: syslog(LOG_ERR, "spawn: wait pid %d: %m", pid);
211: #endif
212: return (-1);
213: }
214:
215: #ifdef SYSLOG
216: if (exit_status != 0)
217: syslog(LOG_ERR, "spawn: %s exit status %d",
218: path, exit_status);
219: #endif
220:
221: return (exit_status ? -1 : 1);
222: }
223: }
224:
225: #ifdef XFER_TIMEOUT
226:
227: xfer_timeout()
228: {
229: if (old_xfer_lines < xfer_lines) {
230: old_xfer_lines = xfer_lines;
231: (void) alarm(XFER_TIMEOUT);
232: return;
233: }
234:
235: /* Timed out. */
236:
237: printf("%d timeout after %d seconds, closing connection.\r\n",
238: ERR_FAULT, XFER_TIMEOUT);
239: fflush(stdout);
240:
241: #ifdef LOG
242: syslog(LOG_ERR, "%s transfer_timeout", hostname);
243: #endif LOG
244:
245: (void) unlink(tempfile);
246:
247: exit(1);
248: }
249:
250: #endif XFER_TIMEOUT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.