78ed81a3 |
1 | /* uux.c |
2 | Prepare to execute a command on a remote system. |
3 | |
4 | Copyright (C) 1991, 1992 Ian Lance Taylor |
5 | |
6 | This file is part of the Taylor UUCP package. |
7 | |
8 | This program is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU General Public License as |
10 | published by the Free Software Foundation; either version 2 of the |
11 | License, or (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, but |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | |
22 | The author of the program may be contacted at ian@airs.com or |
23 | c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. |
24 | */ |
25 | |
26 | #include "uucp.h" |
27 | |
28 | #if USE_RCS_ID |
29 | const char uux_rcsid[] = "$Id: uux.c,v 1.1 1993/08/04 19:37:14 jtc Exp $"; |
30 | #endif |
31 | |
32 | #include "uudefs.h" |
33 | #include "uuconf.h" |
34 | #include "system.h" |
35 | #include "sysdep.h" |
36 | #include "getopt.h" |
37 | |
38 | #include <ctype.h> |
39 | #include <errno.h> |
40 | \f |
41 | /* These character lists should, perhaps, be in sysdep.h. */ |
42 | |
43 | /* This is the list of shell metacharacters that we check for. If one |
44 | of these is present, we request uuxqt to execute the command with |
45 | /bin/sh. Otherwise we let it execute using execve. */ |
46 | |
47 | #define ZSHELLCHARS "\"'`*?[;&()|<>\\$" |
48 | |
49 | /* This is the list of word separators. We break filename arguments |
50 | at these characters. */ |
51 | #define ZSHELLSEPS ";&*|<> \t" |
52 | |
53 | /* This is the list of word separators without the redirection |
54 | operators. */ |
55 | #define ZSHELLNONREDIRSEPS ";&*| \t" |
56 | \f |
57 | /* The program name. */ |
58 | char abProgram[] = "uux"; |
59 | |
60 | /* The name of the execute file. */ |
61 | const char *zXxqt_name; |
62 | |
63 | /* The execute file we are creating. */ |
64 | static FILE *eXxqt_file; |
65 | |
66 | /* A list of commands to be spooled. */ |
67 | static struct scmd *pasXcmds; |
68 | static int cXcmds; |
69 | |
70 | /* A file to close if we're forced to exit. */ |
71 | static FILE *eXclose; |
72 | \f |
73 | /* Local functions. */ |
74 | static void uxusage P((void)); |
75 | static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2)); |
76 | static void uxadd_send_file P((const char *zfrom, const char *zto, |
77 | const char *zoptions, const char *ztemp, |
78 | const char *zforward, |
79 | const struct uuconf_system *qxqtsys, |
80 | const char *zxqtloc, |
81 | int bgrade)); |
82 | static void uxcopy_stdin P((FILE *e)); |
83 | static void uxrecord_file P((const char *zfile)); |
84 | static void uxabort P((void)); |
85 | \f |
86 | /* Long getopt options. */ |
87 | static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } }; |
88 | |
89 | /* The main routine. */ |
90 | |
91 | int |
92 | main (argc, argv) |
93 | int argc; |
94 | char **argv; |
95 | { |
96 | /* -a: requestor address for status reports. */ |
97 | const char *zrequestor = NULL; |
98 | /* -b: if true, return standard input on error. */ |
99 | boolean fretstdin = FALSE; |
100 | /* -c,-C: if true, copy to spool directory. */ |
101 | boolean fcopy = FALSE; |
102 | /* -c: set if -c appears explicitly; if it and -l appear, then if the |
103 | link fails we don't copy the file. */ |
104 | boolean fdontcopy = FALSE; |
105 | /* -I: configuration file name. */ |
106 | const char *zconfig = NULL; |
107 | /* -j: output job id. */ |
108 | boolean fjobid = FALSE; |
109 | /* -g: job grade. */ |
110 | char bgrade = BDEFAULT_UUX_GRADE; |
111 | /* -l: link file to spool directory. */ |
112 | boolean flink = FALSE; |
113 | /* -n: do not notify upon command completion. */ |
114 | boolean fno_ack = FALSE; |
115 | /* -p: read standard input for command standard input. */ |
116 | boolean fread_stdin = FALSE; |
117 | /* -r: do not start uucico when finished. */ |
118 | boolean fuucico = TRUE; |
119 | /* -s: report status to named file. */ |
120 | const char *zstatus_file = NULL; |
121 | /* -W: only expand local file names. */ |
122 | boolean fexpand = TRUE; |
123 | /* -z: report status only on error. */ |
124 | boolean ferror_ack = FALSE; |
125 | int iopt; |
126 | pointer puuconf; |
127 | int iuuconf; |
128 | const char *zlocalname; |
129 | const char *zxqtloc; |
130 | int i; |
131 | size_t clen; |
132 | char *zargs; |
133 | char *zarg; |
134 | char *zcmd; |
135 | const char *zsys; |
136 | char *zexclam; |
137 | boolean fgetcwd; |
138 | const char *zuser; |
139 | struct uuconf_system sxqtsys; |
140 | boolean fxqtlocal; |
141 | char *zforward; |
142 | char **pzargs; |
143 | int calloc_args; |
144 | int cargs; |
145 | char abxqt_tname[CFILE_NAME_LEN]; |
146 | char abxqt_xname[CFILE_NAME_LEN]; |
147 | const char *zinput_from; |
148 | const char *zinput_to; |
149 | const char *zinput_temp; |
150 | boolean finputcopied; |
151 | char *zcall_system; |
152 | boolean fcall_any; |
153 | struct uuconf_system slocalsys; |
154 | boolean fneedshell; |
155 | char *zfullcmd; |
156 | boolean fexit; |
157 | |
158 | /* We need to be able to read a single - as an option, which getopt |
159 | won't do. So that we can still use getopt, we run through the |
160 | options looking for an option "-"; if we find one we change it to |
161 | "-p", which is equivalent to "-". */ |
162 | for (i = 1; i < argc; i++) |
163 | { |
164 | if (argv[i][0] != '-') |
165 | break; |
166 | if (argv[i][1] == '\0') |
167 | argv[i] = zbufcpy ("-p"); |
168 | else |
169 | { |
170 | const char *z; |
171 | |
172 | for (z = argv[i] + 1; *z != '\0'; z++) |
173 | { |
174 | /* If the option takes an argument, and the argument is |
175 | not appended, then skip the next argument. */ |
176 | if (*z == 'a' || *z == 'g' || *z == 'I' |
177 | || *z == 's' || *z == 'x') |
178 | { |
179 | if (z[1] == '\0') |
180 | i++; |
181 | break; |
182 | } |
183 | } |
184 | } |
185 | } |
186 | |
187 | /* The leading + in the getopt string means to stop processing |
188 | options as soon as a non-option argument is seen. */ |
189 | while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wx:z", |
190 | asXlongopts, (int *) NULL)) != EOF) |
191 | { |
192 | switch (iopt) |
193 | { |
194 | case 'a': |
195 | /* Set requestor name: mail address to which status reports |
196 | should be sent. */ |
197 | zrequestor = optarg; |
198 | break; |
199 | |
200 | case 'b': |
201 | /* Return standard input on error. */ |
202 | fretstdin = TRUE; |
203 | break; |
204 | |
205 | case 'c': |
206 | /* Do not copy local files to spool directory. */ |
207 | fcopy = FALSE; |
208 | fdontcopy = TRUE; |
209 | break; |
210 | |
211 | case 'C': |
212 | /* Copy local files to spool directory. */ |
213 | fcopy = TRUE; |
214 | break; |
215 | |
216 | case 'I': |
217 | /* Configuration file name. */ |
218 | if (fsysdep_other_config (optarg)) |
219 | zconfig = optarg; |
220 | break; |
221 | |
222 | case 'j': |
223 | /* Output jobid. */ |
224 | fjobid = TRUE; |
225 | break; |
226 | |
227 | case 'g': |
228 | /* Set job grade. */ |
229 | bgrade = optarg[0]; |
230 | break; |
231 | |
232 | case 'l': |
233 | /* Link file to spool directory. */ |
234 | flink = TRUE; |
235 | break; |
236 | |
237 | case 'n': |
238 | /* Do not notify upon command completion. */ |
239 | fno_ack = TRUE; |
240 | break; |
241 | |
242 | case 'p': |
243 | /* Read standard input for command standard input. */ |
244 | fread_stdin = TRUE; |
245 | break; |
246 | |
247 | case 'r': |
248 | /* Do not start uucico when finished. */ |
249 | fuucico = FALSE; |
250 | break; |
251 | |
252 | case 's': |
253 | /* Report status to named file. */ |
254 | zstatus_file = optarg; |
255 | break; |
256 | |
257 | case 'W': |
258 | /* Only expand local file names. */ |
259 | fexpand = FALSE; |
260 | break; |
261 | |
262 | case 'x': |
263 | #if DEBUG > 1 |
264 | /* Set debugging level. */ |
265 | iDebug |= idebug_parse (optarg); |
266 | #endif |
267 | break; |
268 | |
269 | case 'z': |
270 | /* Report status only on error. */ |
271 | ferror_ack = TRUE; |
272 | break; |
273 | |
274 | case 0: |
275 | /* Long option found and flag set. */ |
276 | break; |
277 | |
278 | default: |
279 | uxusage (); |
280 | break; |
281 | } |
282 | } |
283 | |
284 | if (! UUCONF_GRADE_LEGAL (bgrade)) |
285 | { |
286 | ulog (LOG_ERROR, "Ignoring illegal grade"); |
287 | bgrade = BDEFAULT_UUX_GRADE; |
288 | } |
289 | |
290 | if (optind == argc) |
291 | uxusage (); |
292 | |
293 | iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); |
294 | if (iuuconf != UUCONF_SUCCESS) |
295 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
296 | |
297 | #if DEBUG > 1 |
298 | { |
299 | const char *zdebug; |
300 | |
301 | iuuconf = uuconf_debuglevel (puuconf, &zdebug); |
302 | if (iuuconf != UUCONF_SUCCESS) |
303 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
304 | if (zdebug != NULL) |
305 | iDebug |= idebug_parse (zdebug); |
306 | } |
307 | #endif |
308 | |
309 | /* The command and files arguments could be quoted in any number of |
310 | ways, so we split them apart ourselves. We do this before |
311 | calling usysdep_initialize because we want to set fgetcwd |
312 | correctly. */ |
313 | clen = 1; |
314 | for (i = optind; i < argc; i++) |
315 | clen += strlen (argv[i]) + 1; |
316 | |
317 | zargs = zbufalc (clen); |
318 | *zargs = '\0'; |
319 | for (i = optind; i < argc; i++) |
320 | { |
321 | strcat (zargs, argv[i]); |
322 | strcat (zargs, " "); |
323 | } |
324 | |
325 | /* The first argument is the command to execute. */ |
326 | clen = strcspn (zargs, ZSHELLSEPS); |
327 | zcmd = zbufalc (clen + 1); |
328 | strncpy (zcmd, zargs, clen); |
329 | zcmd[clen] = '\0'; |
330 | zargs += clen; |
331 | |
332 | /* Split the arguments out into an array. We break the arguments |
333 | into alternating sequences of characters not in ZSHELLSEPS |
334 | and characters in ZSHELLSEPS. We remove whitespace. We |
335 | separate the redirection characters '>' and '<' into their |
336 | own arguments to make them easier to process below. */ |
337 | calloc_args = 10; |
338 | pzargs = (char **) xmalloc (calloc_args * sizeof (char *)); |
339 | cargs = 0; |
340 | |
341 | for (zarg = strtok (zargs, " \t"); |
342 | zarg != NULL; |
343 | zarg = strtok ((char *) NULL, " \t")) |
344 | { |
345 | while (*zarg != '\0') |
346 | { |
347 | if (cargs + 1 >= calloc_args) |
348 | { |
349 | calloc_args += 10; |
350 | pzargs = (char **) xrealloc ((pointer) pzargs, |
351 | calloc_args * sizeof (char *)); |
352 | } |
353 | |
354 | clen = strcspn (zarg, ZSHELLSEPS); |
355 | if (clen > 0) |
356 | { |
357 | pzargs[cargs] = zbufalc (clen + 1); |
358 | memcpy (pzargs[cargs], zarg, clen); |
359 | pzargs[cargs][clen] = '\0'; |
360 | ++cargs; |
361 | zarg += clen; |
362 | } |
363 | |
364 | /* We deliberately separate '>' and '<' out. */ |
365 | if (*zarg != '\0') |
366 | { |
367 | clen = strspn (zarg, ZSHELLNONREDIRSEPS); |
368 | if (clen == 0) |
369 | clen = 1; |
370 | pzargs[cargs] = zbufalc (clen + 1); |
371 | memcpy (pzargs[cargs], zarg, clen); |
372 | pzargs[cargs][clen] = '\0'; |
373 | ++cargs; |
374 | zarg += clen; |
375 | } |
376 | } |
377 | } |
378 | |
379 | /* Now look through the arguments to see if we are going to need the |
380 | current working directory. We don't try to make a precise |
381 | determination, just a conservative one. The basic idea is that |
382 | we don't want to get the cwd for 'foo!rmail - user' (note that we |
383 | don't examine the command itself). */ |
384 | fgetcwd = FALSE; |
385 | for (i = 0; i < cargs; i++) |
386 | { |
387 | if (pzargs[i][0] == '(') |
388 | continue; |
389 | zexclam = strrchr (pzargs[i], '!'); |
390 | if (zexclam != NULL && fsysdep_needs_cwd (zexclam + 1)) |
391 | { |
392 | fgetcwd = TRUE; |
393 | break; |
394 | } |
395 | if ((pzargs[i][0] == '<' || pzargs[i][0] == '>') |
396 | && i + 1 < cargs |
397 | && strchr (pzargs[i + 1], '!') == NULL |
398 | && fsysdep_needs_cwd (pzargs[i + 1])) |
399 | { |
400 | fgetcwd = TRUE; |
401 | break; |
402 | } |
403 | } |
404 | |
405 | #ifdef SIGINT |
406 | usysdep_signal (SIGINT); |
407 | #endif |
408 | #ifdef SIGHUP |
409 | usysdep_signal (SIGHUP); |
410 | #endif |
411 | #ifdef SIGQUIT |
412 | usysdep_signal (SIGQUIT); |
413 | #endif |
414 | #ifdef SIGTERM |
415 | usysdep_signal (SIGTERM); |
416 | #endif |
417 | #ifdef SIGPIPE |
418 | usysdep_signal (SIGPIPE); |
419 | #endif |
420 | |
421 | usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0)); |
422 | |
423 | ulog_fatal_fn (uxabort); |
424 | |
425 | zuser = zsysdep_login_name (); |
426 | |
427 | /* Get the local system name. */ |
428 | iuuconf = uuconf_localname (puuconf, &zlocalname); |
429 | if (iuuconf == UUCONF_NOT_FOUND) |
430 | { |
431 | zlocalname = zsysdep_localname (); |
432 | if (zlocalname == NULL) |
433 | exit (EXIT_FAILURE); |
434 | } |
435 | else if (iuuconf != UUCONF_SUCCESS) |
436 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
437 | |
438 | /* Get the local system information. */ |
439 | iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys); |
440 | if (iuuconf != UUCONF_SUCCESS) |
441 | { |
442 | if (iuuconf != UUCONF_NOT_FOUND) |
443 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
444 | iuuconf = uuconf_system_local (puuconf, &slocalsys); |
445 | if (iuuconf != UUCONF_SUCCESS) |
446 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
447 | } |
448 | |
449 | /* Figure out which system the command is to be executed on. Some |
450 | mailers apparently pass local!rmail, so we must explicitly check |
451 | for that. */ |
452 | zexclam = strchr (zcmd, '!'); |
453 | while (zexclam != NULL) |
454 | { |
455 | *zexclam = '\0'; |
456 | if (strcmp (zcmd, zlocalname) == 0) |
457 | ; |
458 | else if (slocalsys.uuconf_pzalias == NULL) |
459 | break; |
460 | else |
461 | { |
462 | char **pzal; |
463 | |
464 | for (pzal = slocalsys.uuconf_pzalias; *pzal != NULL; pzal++) |
465 | if (strcmp (zcmd, *pzal) == 0) |
466 | break; |
467 | if (*pzal == NULL) |
468 | break; |
469 | } |
470 | zcmd = zexclam + 1; |
471 | zexclam = strchr (zcmd, '!'); |
472 | } |
473 | if (zexclam == NULL) |
474 | { |
475 | zsys = zlocalname; |
476 | fxqtlocal = TRUE; |
477 | zforward = NULL; |
478 | } |
479 | else |
480 | { |
481 | zsys = zcmd; |
482 | zcmd = zexclam + 1; |
483 | fxqtlocal = FALSE; |
484 | |
485 | /* See if we must forward this command through other systems |
486 | (e.g. uux a!b!cmd). */ |
487 | zexclam = strrchr (zcmd, '!'); |
488 | if (zexclam == NULL) |
489 | zforward = NULL; |
490 | else |
491 | { |
492 | clen = zexclam - zcmd; |
493 | zforward = zbufalc (clen); |
494 | memcpy (zforward, zcmd, clen); |
495 | zforward[clen] = '\0'; |
496 | zcmd = zexclam + 1; |
497 | } |
498 | } |
499 | |
500 | if (fxqtlocal) |
501 | sxqtsys = slocalsys; |
502 | else |
503 | { |
504 | iuuconf = uuconf_system_info (puuconf, zsys, &sxqtsys); |
505 | if (iuuconf != UUCONF_SUCCESS) |
506 | { |
507 | if (iuuconf != UUCONF_NOT_FOUND) |
508 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
509 | if (! funknown_system (puuconf, zsys, &sxqtsys)) |
510 | ulog (LOG_FATAL, "%s: System not found", zsys); |
511 | } |
512 | } |
513 | |
514 | /* Get the local name the remote system know us as. */ |
515 | zxqtloc = sxqtsys.uuconf_zlocalname; |
516 | if (zxqtloc == NULL) |
517 | zxqtloc = zlocalname; |
518 | |
519 | /* We can send this as an E command if the execution is on a |
520 | different, directly connected, system and the only file used is |
521 | the standard input and comes from this system. This is true of |
522 | the common cases of rmail and rnews. We get an execute file name |
523 | here in case we need it. */ |
524 | if (fxqtlocal) |
525 | zXxqt_name = zsysdep_xqt_file_name (); |
526 | else |
527 | zXxqt_name = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, TRUE, |
528 | abxqt_tname, (char *) NULL, |
529 | abxqt_xname); |
530 | if (zXxqt_name == NULL) |
531 | uxabort (); |
532 | |
533 | uxrecord_file (zXxqt_name); |
534 | |
535 | /* Look through the arguments. Any argument containing an |
536 | exclamation point character is interpreted as a file name, and is |
537 | sent to the appropriate system. */ |
538 | zinput_from = NULL; |
539 | zinput_to = NULL; |
540 | zinput_temp = NULL; |
541 | finputcopied = FALSE; |
542 | zcall_system = NULL; |
543 | fcall_any = FALSE; |
544 | |
545 | for (i = 0; i < cargs; i++) |
546 | { |
547 | const char *zsystem; |
548 | char *zfile; |
549 | char *zforw; |
550 | boolean finput, foutput; |
551 | boolean flocal, fonxqt; |
552 | |
553 | /* Check for a parenthesized argument; remove the parentheses |
554 | and otherwise ignore it (this is how an exclamation point is |
555 | quoted). */ |
556 | if (pzargs[i][0] == '(') |
557 | { |
558 | clen = strlen (pzargs[i]); |
559 | if (pzargs[i][clen - 1] != ')') |
560 | ulog (LOG_ERROR, "Mismatched parentheses"); |
561 | else |
562 | pzargs[i][clen - 1] = '\0'; |
563 | ++pzargs[i]; |
564 | continue; |
565 | } |
566 | |
567 | /* Check whether we are doing a redirection. */ |
568 | finput = FALSE; |
569 | foutput = FALSE; |
570 | if (i + 1 < cargs) |
571 | { |
572 | if (pzargs[i][0] == '<') |
573 | finput = TRUE; |
574 | else if (pzargs[i][0] == '>') |
575 | foutput = TRUE; |
576 | if (finput || foutput) |
577 | { |
578 | pzargs[i] = NULL; |
579 | i++; |
580 | } |
581 | } |
582 | |
583 | zexclam = strchr (pzargs[i], '!'); |
584 | |
585 | /* If there is no exclamation point and no redirection, this |
586 | argument is left untouched. */ |
587 | if (zexclam == NULL && ! finput && ! foutput) |
588 | continue; |
589 | |
590 | /* Get the system name and file name for this file. */ |
591 | if (zexclam == NULL) |
592 | { |
593 | zsystem = zlocalname; |
594 | zfile = pzargs[i]; |
595 | flocal = TRUE; |
596 | zforw = NULL; |
597 | } |
598 | else |
599 | { |
600 | *zexclam = '\0'; |
601 | zsystem = pzargs[i]; |
602 | if (*zsystem != '\0') |
603 | flocal = FALSE; |
604 | else |
605 | { |
606 | zsystem = zlocalname; |
607 | flocal = TRUE; |
608 | } |
609 | zfile = zexclam + 1; |
610 | zexclam = strrchr (zfile, '!'); |
611 | if (zexclam == NULL) |
612 | zforw = NULL; |
613 | else |
614 | { |
615 | if (flocal) |
616 | ulog (LOG_FATAL, "!%s: Can't figure out where to get file", |
617 | zfile); |
618 | *zexclam = '\0'; |
619 | zforw = zfile; |
620 | zfile = zexclam + 1; |
621 | } |
622 | } |
623 | |
624 | /* Check if the file is already on the execution system. */ |
625 | if (flocal) |
626 | fonxqt = fxqtlocal; |
627 | else if (fxqtlocal) |
628 | fonxqt = FALSE; |
629 | else if (zforward == NULL ? zforw != NULL : zforw == NULL) |
630 | fonxqt = FALSE; |
631 | else if (zforward != NULL |
632 | && zforw != NULL |
633 | && strcmp (zforward, zforw) != 0) |
634 | fonxqt = FALSE; |
635 | else if (strcmp (zsystem, sxqtsys.uuconf_zname) == 0) |
636 | fonxqt = TRUE; |
637 | else if (sxqtsys.uuconf_pzalias == NULL) |
638 | fonxqt = FALSE; |
639 | else |
640 | { |
641 | char **pzal; |
642 | |
643 | fonxqt = FALSE; |
644 | for (pzal = sxqtsys.uuconf_pzalias; *pzal != NULL; pzal++) |
645 | { |
646 | if (strcmp (zsystem, *pzal) == 0) |
647 | { |
648 | fonxqt = TRUE; |
649 | break; |
650 | } |
651 | } |
652 | } |
653 | |
654 | /* Turn the file into an absolute path. */ |
655 | if (flocal) |
656 | zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir); |
657 | else if (fexpand) |
658 | zfile = zsysdep_add_cwd (zfile); |
659 | if (zfile == NULL) |
660 | uxabort (); |
661 | |
662 | /* Check for output redirection. */ |
663 | if (foutput) |
664 | { |
665 | if (flocal) |
666 | { |
667 | if (! fin_directory_list (zfile, |
668 | sxqtsys.uuconf_pzremote_receive, |
669 | sxqtsys.uuconf_zpubdir, TRUE, |
670 | FALSE, (const char *) NULL)) |
671 | ulog (LOG_FATAL, "Not permitted to create %s", zfile); |
672 | } |
673 | |
674 | /* There are various cases of output redirection. |
675 | |
676 | uux cmd >out: The command is executed on the local |
677 | system, and the output file is placed on the local |
678 | system (fonxqt is TRUE). |
679 | |
680 | uux cmd >a!out: The command is executed on the local |
681 | system, and the output file is sent to a. |
682 | |
683 | uux a!cmd >out: The command is executed on a, and the |
684 | output file is returned to the local system (flocal |
685 | is TRUE). |
686 | |
687 | uux a!cmd >a!out: The command is executed on a, and the |
688 | output file is left on a (fonxqt is TRUE). |
689 | |
690 | uux a!cmd >b!out: The command is executed on a, and the |
691 | output file is sent to b; traditionally, I believe |
692 | that b is relative to a, rather than to the local |
693 | system. However, this essentially contradicts the |
694 | previous two cases, in which the output file is |
695 | relative to the local system. |
696 | |
697 | Now, the cases that we don't handle. |
698 | |
699 | uux cmd >a!b!out: The command is executed on the local |
700 | system, and the output file is sent to b via a. This |
701 | requires the local uuxqt to support forwarding of the |
702 | output file. |
703 | |
704 | uux a!b!cmd >out: The command is executed on b, which is |
705 | reached via a. Probably the output file is intended |
706 | for the local system, in which case the uuxqt on b |
707 | must support forwarding of the output file. |
708 | |
709 | uux a!b!cmd >c!out: Is c relative to b or to the local |
710 | system? If it's relative to b this is easy to |
711 | handle. Otherwise, we must arrange for the file to |
712 | be sent back to the local system and for the local |
713 | system to send it on to c. |
714 | |
715 | There are many variations of the last case. It's not at |
716 | all clear to me how they should be handled. */ |
717 | if (zforward != NULL || zforw != NULL) |
718 | ulog (LOG_FATAL, "May not forward standard output"); |
719 | |
720 | if (fonxqt) |
721 | uxadd_xqt_line ('O', zfile, (const char *) NULL); |
722 | else if (flocal) |
723 | uxadd_xqt_line ('O', zfile, zxqtloc); |
724 | else |
725 | uxadd_xqt_line ('O', zfile, zsystem); |
726 | pzargs[i] = NULL; |
727 | continue; |
728 | } |
729 | |
730 | if (finput) |
731 | { |
732 | if (fread_stdin) |
733 | ulog (LOG_FATAL, "Standard input specified twice"); |
734 | pzargs[i] = NULL; |
735 | } |
736 | |
737 | if (flocal) |
738 | { |
739 | char *zuse; |
740 | char *zdata; |
741 | char abtname[CFILE_NAME_LEN]; |
742 | char abdname[CFILE_NAME_LEN]; |
743 | |
744 | /* It's a local file. If requested by -C, copy the file to |
745 | the spool directory. If requested by -l, link the file |
746 | to the spool directory; if the link fails, we copy the |
747 | file, unless -c was explictly used. If the execution is |
748 | occurring on the local system, we force the copy as well, |
749 | because otherwise we would have to have some way to tell |
750 | uuxqt not to move the file. If the file is being shipped |
751 | to another system, we must set up a transfer request. |
752 | First make sure the user has legitimate access, since we |
753 | are running setuid. */ |
754 | if (! fsysdep_access (zfile)) |
755 | uxabort (); |
756 | |
757 | zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, |
758 | abtname, abdname, (char *) NULL); |
759 | if (zdata == NULL) |
760 | uxabort (); |
761 | |
762 | if (fcopy || flink || fxqtlocal) |
763 | { |
764 | boolean fdid; |
765 | |
766 | uxrecord_file (zdata); |
767 | |
768 | fdid = FALSE; |
769 | if (flink) |
770 | { |
771 | boolean fworked; |
772 | |
773 | if (! fsysdep_link (zfile, zdata, &fworked)) |
774 | uxabort (); |
775 | |
776 | if (fworked) |
777 | fdid = TRUE; |
778 | else if (fdontcopy) |
779 | ulog (LOG_FATAL, "%s: Can't link to spool directory", |
780 | zfile); |
781 | } |
782 | |
783 | if (! fdid) |
784 | { |
785 | openfile_t efile; |
786 | |
787 | efile = esysdep_user_fopen (zfile, TRUE, TRUE); |
788 | if (! ffileisopen (efile)) |
789 | uxabort (); |
790 | if (! fcopy_open_file (efile, zdata, FALSE, TRUE)) |
791 | uxabort (); |
792 | (void) ffileclose (efile); |
793 | } |
794 | |
795 | zuse = abtname; |
796 | } |
797 | else |
798 | { |
799 | /* We don't actually use the spool file name, but we |
800 | need a name to use as the destination. */ |
801 | ubuffree (zdata); |
802 | /* Make sure the daemon can access the file. */ |
803 | if (! fsysdep_daemon_access (zfile)) |
804 | uxabort (); |
805 | if (! fin_directory_list (zfile, sxqtsys.uuconf_pzlocal_send, |
806 | sxqtsys.uuconf_zpubdir, TRUE, |
807 | TRUE, zuser)) |
808 | ulog (LOG_FATAL, "Not permitted to send from %s", |
809 | zfile); |
810 | |
811 | zuse = zfile; |
812 | } |
813 | |
814 | if (fxqtlocal) |
815 | { |
816 | if (finput) |
817 | uxadd_xqt_line ('I', zuse, (char *) NULL); |
818 | else |
819 | pzargs[i] = zuse; |
820 | } |
821 | else |
822 | { |
823 | finputcopied = fcopy || flink; |
824 | |
825 | if (finput) |
826 | { |
827 | zinput_from = zuse; |
828 | zinput_to = zbufcpy (abdname); |
829 | zinput_temp = zbufcpy (abtname); |
830 | } |
831 | else |
832 | { |
833 | char *zbase; |
834 | |
835 | uxadd_send_file (zuse, abdname, |
836 | finputcopied ? "C" : "c", |
837 | abtname, zforward, &sxqtsys, |
838 | zxqtloc, bgrade); |
839 | zbase = zsysdep_base_name (zfile); |
840 | if (zbase == NULL) |
841 | uxabort (); |
842 | uxadd_xqt_line ('F', abdname, zbase); |
843 | pzargs[i] = zbase; |
844 | } |
845 | } |
846 | } |
847 | else if (fonxqt) |
848 | { |
849 | /* The file is already on the system where the command is to |
850 | be executed. */ |
851 | if (finput) |
852 | uxadd_xqt_line ('I', zfile, (const char *) NULL); |
853 | else |
854 | pzargs[i] = zfile; |
855 | } |
856 | else |
857 | { |
858 | struct uuconf_system sfromsys; |
859 | char abtname[CFILE_NAME_LEN]; |
860 | struct scmd s; |
861 | char *zjobid; |
862 | |
863 | /* We need to request a remote file. */ |
864 | iuuconf = uuconf_system_info (puuconf, zsystem, &sfromsys); |
865 | if (iuuconf != UUCONF_SUCCESS) |
866 | { |
867 | if (iuuconf != UUCONF_NOT_FOUND) |
868 | ulog_uuconf (LOG_FATAL, puuconf, iuuconf); |
869 | if (! funknown_system (puuconf, zsystem, &sfromsys)) |
870 | ulog (LOG_FATAL, "%s: System not found", zsystem); |
871 | } |
872 | |
873 | if (fonxqt) |
874 | { |
875 | /* The file is already on the system where the command is to |
876 | be executed. */ |
877 | if (finput) |
878 | uxadd_xqt_line ('I', zfile, (const char *) NULL); |
879 | else |
880 | pzargs[i] = zfile; |
881 | } |
882 | else |
883 | { |
884 | char *zdata; |
885 | |
886 | if (! sfromsys.uuconf_fcall_transfer |
887 | && ! sfromsys.uuconf_fcalled_transfer) |
888 | ulog (LOG_FATAL, |
889 | "Not permitted to transfer files to or from %s", |
890 | sfromsys.uuconf_zname); |
891 | |
892 | if (zforw != NULL) |
893 | { |
894 | /* This is ``uux cmd a!b!file''. To make this work, |
895 | we would have to be able to set up a request to a |
896 | to fetch file from b and send it to us. But it |
897 | turns out that that will not work, because when a |
898 | sends us the file we will put it in a's spool |
899 | directory, not the local system spool directory. |
900 | So we won't have any way to find it. This is not |
901 | a conceptual problem, and it could doubtless be |
902 | solved. Please feel free to solve it and send me |
903 | the solution. */ |
904 | ulog (LOG_FATAL, "File forwarding not supported"); |
905 | } |
906 | |
907 | /* We must request the file from the remote system to |
908 | this one. */ |
909 | zdata = zsysdep_data_file_name (&slocalsys, zxqtloc, bgrade, |
910 | FALSE, abtname, (char *) NULL, |
911 | (char *) NULL); |
912 | if (zdata == NULL) |
913 | uxabort (); |
914 | ubuffree (zdata); |
915 | |
916 | /* Request the file. The special option '9' is a signal |
917 | to uucico that it's OK to receive a file into the |
918 | spool directory; normally such requests are rejected. |
919 | This privilege is easy to abuse. */ |
920 | s.bcmd = 'R'; |
921 | s.pseq = NULL; |
922 | s.zfrom = zfile; |
923 | s.zto = zbufcpy (abtname); |
924 | s.zuser = zuser; |
925 | s.zoptions = "9"; |
926 | s.ztemp = ""; |
927 | s.imode = 0600; |
928 | s.znotify = ""; |
929 | s.cbytes = -1; |
930 | s.zcmd = NULL; |
931 | s.ipos = 0; |
932 | |
933 | zjobid = zsysdep_spool_commands (&sfromsys, bgrade, 1, &s); |
934 | if (zjobid == NULL) |
935 | uxabort (); |
936 | |
937 | if (fjobid) |
938 | printf ("%s\n", zjobid); |
939 | |
940 | ubuffree (zjobid); |
941 | |
942 | if (fcall_any) |
943 | { |
944 | ubuffree (zcall_system); |
945 | zcall_system = NULL; |
946 | } |
947 | else |
948 | { |
949 | fcall_any = TRUE; |
950 | zcall_system = zbufcpy (sfromsys.uuconf_zname); |
951 | } |
952 | |
953 | if (fxqtlocal) |
954 | { |
955 | /* Tell the command execution to wait until the file |
956 | has been received, and tell it the real file |
957 | name. */ |
958 | if (finput) |
959 | { |
960 | uxadd_xqt_line ('F', abtname, (char *) NULL); |
961 | uxadd_xqt_line ('I', abtname, (char *) NULL); |
962 | } |
963 | else |
964 | { |
965 | char *zbase; |
966 | |
967 | zbase = zsysdep_base_name (zfile); |
968 | if (zbase == NULL) |
969 | uxabort (); |
970 | uxadd_xqt_line ('F', abtname, zbase); |
971 | pzargs[i] = zbase; |
972 | } |
973 | } |
974 | else |
975 | { |
976 | char abxtname[CFILE_NAME_LEN]; |
977 | char *zbase; |
978 | char *zxqt; |
979 | FILE *e; |
980 | |
981 | /* Now we must arrange to forward the file on to the |
982 | execution system. We need to get a name to give |
983 | the file on the execution system (abxtname). */ |
984 | zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, |
985 | bgrade, TRUE, abxtname, |
986 | (char *) NULL, |
987 | (char *) NULL); |
988 | if (zdata == NULL) |
989 | uxabort (); |
990 | ubuffree (zdata); |
991 | |
992 | zbase = zsysdep_base_name (zfile); |
993 | if (zbase == NULL) |
994 | uxabort (); |
995 | |
996 | zxqt = zsysdep_xqt_file_name (); |
997 | if (zxqt == NULL) |
998 | uxabort (); |
999 | e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); |
1000 | if (e == NULL) |
1001 | uxabort (); |
1002 | uxrecord_file (zxqt); |
1003 | |
1004 | fprintf (e, "U %s %s\n", zsysdep_login_name (), |
1005 | zlocalname); |
1006 | fprintf (e, "F %s %s\n", abtname, zbase); |
1007 | fprintf (e, "C uucp -C -W -d -g %c %s %s!", bgrade, |
1008 | zbase, sxqtsys.uuconf_zname); |
1009 | if (zforward != NULL) |
1010 | fprintf (e, "%s!", zforward); |
1011 | fprintf (e, "%s\n", abxtname); |
1012 | |
1013 | if (fclose (e) != 0) |
1014 | ulog (LOG_FATAL, "fclose: %s", strerror (errno)); |
1015 | |
1016 | if (finput) |
1017 | { |
1018 | uxadd_xqt_line ('F', abxtname, (char *) NULL); |
1019 | uxadd_xqt_line ('I', abxtname, (char *) NULL); |
1020 | ubuffree (zbase); |
1021 | } |
1022 | else |
1023 | { |
1024 | uxadd_xqt_line ('F', abxtname, zbase); |
1025 | pzargs[i] = zbase; |
1026 | } |
1027 | } |
1028 | } |
1029 | |
1030 | (void) uuconf_system_free (puuconf, &sfromsys); |
1031 | } |
1032 | } |
1033 | |
1034 | /* If standard input is to be read from the stdin of uux, we read it |
1035 | here into a temporary file and send it to the execute system. */ |
1036 | if (fread_stdin) |
1037 | { |
1038 | char *zdata; |
1039 | char abtname[CFILE_NAME_LEN]; |
1040 | char abdname[CFILE_NAME_LEN]; |
1041 | FILE *e; |
1042 | |
1043 | zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, |
1044 | abtname, abdname, (char *) NULL); |
1045 | if (zdata == NULL) |
1046 | uxabort (); |
1047 | |
1048 | e = esysdep_fopen (zdata, FALSE, FALSE, TRUE); |
1049 | if (e == NULL) |
1050 | uxabort (); |
1051 | |
1052 | eXclose = e; |
1053 | uxrecord_file (zdata); |
1054 | |
1055 | uxcopy_stdin (e); |
1056 | |
1057 | eXclose = NULL; |
1058 | if (fclose (e) != 0) |
1059 | ulog (LOG_FATAL, "fclose: %s", strerror (errno)); |
1060 | |
1061 | if (fxqtlocal) |
1062 | uxadd_xqt_line ('I', abtname, (const char *) NULL); |
1063 | else |
1064 | { |
1065 | zinput_from = zbufcpy (abtname); |
1066 | zinput_to = zbufcpy (abdname); |
1067 | zinput_temp = zinput_from; |
1068 | finputcopied = TRUE; |
1069 | } |
1070 | } |
1071 | |
1072 | /* If we are returning standard input, or we're putting the status |
1073 | in a file, we can't use an E command. */ |
1074 | if (fretstdin) |
1075 | uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL); |
1076 | |
1077 | if (zstatus_file != NULL) |
1078 | uxadd_xqt_line ('M', zstatus_file, (const char *) NULL); |
1079 | |
1080 | /* Get the complete command line, and decide whether the command |
1081 | needs to be executed by the shell. */ |
1082 | fneedshell = FALSE; |
1083 | |
1084 | if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0') |
1085 | fneedshell = TRUE; |
1086 | |
1087 | clen = strlen (zcmd) + 1; |
1088 | for (i = 0; i < cargs; i++) |
1089 | { |
1090 | if (pzargs[i] != NULL) |
1091 | { |
1092 | clen += strlen (pzargs[i]) + 1; |
1093 | if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0') |
1094 | fneedshell = TRUE; |
1095 | } |
1096 | } |
1097 | |
1098 | zfullcmd = zbufalc (clen); |
1099 | |
1100 | strcpy (zfullcmd, zcmd); |
1101 | for (i = 0; i < cargs; i++) |
1102 | { |
1103 | if (pzargs[i] != NULL) |
1104 | { |
1105 | strcat (zfullcmd, " "); |
1106 | strcat (zfullcmd, pzargs[i]); |
1107 | } |
1108 | } |
1109 | |
1110 | /* If we haven't written anything to the execution file yet, and we |
1111 | have a standard input file, and we're not forwarding, then every |
1112 | other option can be handled in an E command. */ |
1113 | if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL) |
1114 | { |
1115 | struct scmd s; |
1116 | char aboptions[10]; |
1117 | char *zoptions; |
1118 | |
1119 | /* Set up an E command. */ |
1120 | s.bcmd = 'E'; |
1121 | s.pseq = NULL; |
1122 | s.zuser = zuser; |
1123 | s.zfrom = zinput_from; |
1124 | s.zto = zinput_to; |
1125 | s.zoptions = aboptions; |
1126 | zoptions = aboptions; |
1127 | *zoptions++ = finputcopied ? 'C' : 'c'; |
1128 | if (fno_ack) |
1129 | *zoptions++ = 'N'; |
1130 | if (ferror_ack) |
1131 | *zoptions++ = 'Z'; |
1132 | if (zrequestor != NULL) |
1133 | *zoptions++ = 'R'; |
1134 | if (fneedshell) |
1135 | *zoptions++ = 'e'; |
1136 | *zoptions = '\0'; |
1137 | s.ztemp = zinput_temp; |
1138 | s.imode = 0666; |
1139 | if (zrequestor == NULL) |
1140 | zrequestor = "\"\""; |
1141 | s.znotify = zrequestor; |
1142 | s.cbytes = -1; |
1143 | s.zcmd = zfullcmd; |
1144 | s.ipos = 0; |
1145 | |
1146 | ++cXcmds; |
1147 | pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, |
1148 | cXcmds * sizeof (struct scmd)); |
1149 | pasXcmds[cXcmds - 1] = s; |
1150 | } |
1151 | else |
1152 | { |
1153 | /* Finish up the execute file. */ |
1154 | uxadd_xqt_line ('U', zuser, zxqtloc); |
1155 | if (zinput_from != NULL) |
1156 | { |
1157 | uxadd_xqt_line ('F', zinput_to, (char *) NULL); |
1158 | uxadd_xqt_line ('I', zinput_to, (char *) NULL); |
1159 | uxadd_send_file (zinput_from, zinput_to, |
1160 | finputcopied ? "C" : "c", |
1161 | zinput_temp, zforward, &sxqtsys, zxqtloc, |
1162 | bgrade); |
1163 | } |
1164 | if (fno_ack) |
1165 | uxadd_xqt_line ('N', (const char *) NULL, (const char *) NULL); |
1166 | if (ferror_ack) |
1167 | uxadd_xqt_line ('Z', (const char *) NULL, (const char *) NULL); |
1168 | if (zrequestor != NULL) |
1169 | uxadd_xqt_line ('R', zrequestor, (const char *) NULL); |
1170 | if (fneedshell) |
1171 | uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL); |
1172 | uxadd_xqt_line ('C', zfullcmd, (const char *) NULL); |
1173 | if (fclose (eXxqt_file) != 0) |
1174 | ulog (LOG_FATAL, "fclose: %s", strerror (errno)); |
1175 | eXxqt_file = NULL; |
1176 | |
1177 | /* If the execution is to occur on another system, we must now |
1178 | arrange to copy the execute file to this system. */ |
1179 | if (! fxqtlocal) |
1180 | uxadd_send_file (abxqt_tname, abxqt_xname, "C", abxqt_tname, |
1181 | zforward, &sxqtsys, zxqtloc, bgrade); |
1182 | } |
1183 | |
1184 | /* If we got a signal, get out before spooling anything. */ |
1185 | if (FGOT_SIGNAL ()) |
1186 | uxabort (); |
1187 | |
1188 | /* From here on in, it's too late. We don't call uxabort. */ |
1189 | if (cXcmds > 0) |
1190 | { |
1191 | char *zjobid; |
1192 | |
1193 | if (! sxqtsys.uuconf_fcall_transfer |
1194 | && ! sxqtsys.uuconf_fcalled_transfer) |
1195 | ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", |
1196 | sxqtsys.uuconf_zname); |
1197 | |
1198 | zjobid = zsysdep_spool_commands (&sxqtsys, bgrade, cXcmds, pasXcmds); |
1199 | if (zjobid == NULL) |
1200 | { |
1201 | ulog_close (); |
1202 | usysdep_exit (FALSE); |
1203 | } |
1204 | |
1205 | if (fjobid) |
1206 | printf ("%s\n", zjobid); |
1207 | |
1208 | ubuffree (zjobid); |
1209 | |
1210 | if (fcall_any) |
1211 | { |
1212 | ubuffree (zcall_system); |
1213 | zcall_system = NULL; |
1214 | } |
1215 | else |
1216 | { |
1217 | fcall_any = TRUE; |
1218 | zcall_system = zbufcpy (sxqtsys.uuconf_zname); |
1219 | } |
1220 | } |
1221 | |
1222 | /* If all that worked, make a log file entry. All log file reports |
1223 | up to this point went to stderr. */ |
1224 | ulog_to_file (puuconf, TRUE); |
1225 | ulog_system (sxqtsys.uuconf_zname); |
1226 | ulog_user (zuser); |
1227 | |
1228 | ulog (LOG_NORMAL, "Queuing %s", zfullcmd); |
1229 | |
1230 | ulog_close (); |
1231 | |
1232 | if (! fuucico) |
1233 | fexit = TRUE; |
1234 | else |
1235 | { |
1236 | if (zcall_system != NULL) |
1237 | fexit = fsysdep_run ("uucico", "-s", zcall_system); |
1238 | else if (fcall_any) |
1239 | fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL); |
1240 | else |
1241 | fexit = TRUE; |
1242 | } |
1243 | |
1244 | usysdep_exit (fexit); |
1245 | |
1246 | /* Avoid error about not returning a value. */ |
1247 | return 0; |
1248 | } |
1249 | |
1250 | /* Report command usage. */ |
1251 | |
1252 | static void |
1253 | uxusage () |
1254 | { |
1255 | fprintf (stderr, |
1256 | "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", |
1257 | VERSION); |
1258 | fprintf (stderr, |
1259 | "Usage: uux [options] [-] command\n"); |
1260 | fprintf (stderr, |
1261 | " -,-p: Read standard input for standard input of command\n"); |
1262 | fprintf (stderr, |
1263 | " -c: Do not copy local files to spool directory (default)\n"); |
1264 | fprintf (stderr, |
1265 | " -C: Copy local files to spool directory\n"); |
1266 | fprintf (stderr, |
1267 | " -l: link local files to spool directory\n"); |
1268 | fprintf (stderr, |
1269 | " -g grade: Set job grade (must be alphabetic)\n"); |
1270 | fprintf (stderr, |
1271 | " -n: Do not report completion status\n"); |
1272 | fprintf (stderr, |
1273 | " -z: Report completion status only on error\n"); |
1274 | fprintf (stderr, |
1275 | " -r: Do not start uucico daemon\n"); |
1276 | fprintf (stderr, |
1277 | " -a address: Address to mail status report to\n"); |
1278 | fprintf (stderr, |
1279 | " -b: Return standard input with status report\n"); |
1280 | fprintf (stderr, |
1281 | " -s file: Report completion status to file\n"); |
1282 | fprintf (stderr, |
1283 | " -j: Report job id\n"); |
1284 | fprintf (stderr, |
1285 | " -x debug: Set debugging level\n"); |
1286 | #if HAVE_TAYLOR_CONFIG |
1287 | fprintf (stderr, |
1288 | " -I file: Set configuration file to use\n"); |
1289 | #endif /* HAVE_TAYLOR_CONFIG */ |
1290 | exit (EXIT_FAILURE); |
1291 | } |
1292 | \f |
1293 | /* Add a line to the execute file. */ |
1294 | |
1295 | static void |
1296 | uxadd_xqt_line (bchar, z1, z2) |
1297 | int bchar; |
1298 | const char *z1; |
1299 | const char *z2; |
1300 | { |
1301 | if (eXxqt_file == NULL) |
1302 | { |
1303 | eXxqt_file = esysdep_fopen (zXxqt_name, FALSE, FALSE, TRUE); |
1304 | if (eXxqt_file == NULL) |
1305 | uxabort (); |
1306 | } |
1307 | |
1308 | if (z1 == NULL) |
1309 | fprintf (eXxqt_file, "%c\n", bchar); |
1310 | else if (z2 == NULL) |
1311 | fprintf (eXxqt_file, "%c %s\n", bchar, z1); |
1312 | else |
1313 | fprintf (eXxqt_file, "%c %s %s\n", bchar, z1, z2); |
1314 | } |
1315 | |
1316 | /* Add a file to be sent to the execute system. */ |
1317 | |
1318 | static void |
1319 | uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc, |
1320 | bgrade) |
1321 | const char *zfrom; |
1322 | const char *zto; |
1323 | const char *zoptions; |
1324 | const char *ztemp; |
1325 | const char *zforward; |
1326 | const struct uuconf_system *qxqtsys; |
1327 | const char *zxqtloc; |
1328 | int bgrade; |
1329 | { |
1330 | struct scmd s; |
1331 | |
1332 | if (zforward != NULL) |
1333 | { |
1334 | char *zbase; |
1335 | char *zxqt; |
1336 | char abtname[CFILE_NAME_LEN]; |
1337 | char abdname[CFILE_NAME_LEN]; |
1338 | char abxname[CFILE_NAME_LEN]; |
1339 | FILE *e; |
1340 | |
1341 | /* We want to forward this file through the first execution |
1342 | system to other systems. We set up a remote execution of |
1343 | uucp to forward the file. */ |
1344 | zbase = zsysdep_base_name (zfrom); |
1345 | if (zbase == NULL) |
1346 | uxabort (); |
1347 | |
1348 | zxqt = zsysdep_data_file_name (qxqtsys, zxqtloc, bgrade, TRUE, abtname, |
1349 | abdname, abxname); |
1350 | if (zxqt == NULL) |
1351 | uxabort (); |
1352 | e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); |
1353 | if (e == NULL) |
1354 | uxabort (); |
1355 | uxrecord_file (zxqt); |
1356 | |
1357 | fprintf (e, "U %s %s\n", zsysdep_login_name (), zxqtloc); |
1358 | fprintf (e, "F %s %s\n", abdname, zbase); |
1359 | fprintf (e, "C uucp -C -W -d -g %c %s %s!%s\n", |
1360 | bgrade, zbase, zforward, zto); |
1361 | |
1362 | ubuffree (zbase); |
1363 | |
1364 | if (fclose (e) != 0) |
1365 | ulog (LOG_FATAL, "fclose: %s", strerror (errno)); |
1366 | |
1367 | /* Send the execution file. */ |
1368 | s.bcmd = 'S'; |
1369 | s.pseq = NULL; |
1370 | s.zfrom = zbufcpy (abtname); |
1371 | s.zto = zbufcpy (abxname); |
1372 | s.zuser = zsysdep_login_name (); |
1373 | s.zoptions = "C"; |
1374 | s.ztemp = s.zfrom; |
1375 | s.imode = 0666; |
1376 | s.znotify = NULL; |
1377 | s.cbytes = -1; |
1378 | s.zcmd = NULL; |
1379 | s.ipos = 0; |
1380 | |
1381 | ++cXcmds; |
1382 | pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, |
1383 | cXcmds * sizeof (struct scmd)); |
1384 | pasXcmds[cXcmds - 1] = s; |
1385 | |
1386 | /* Send the data file to abdname where the execution file will |
1387 | expect it. */ |
1388 | zto = abdname; |
1389 | } |
1390 | |
1391 | s.bcmd = 'S'; |
1392 | s.pseq = NULL; |
1393 | s.zfrom = zbufcpy (zfrom); |
1394 | s.zto = zbufcpy (zto); |
1395 | s.zuser = zsysdep_login_name (); |
1396 | s.zoptions = zbufcpy (zoptions); |
1397 | s.ztemp = zbufcpy (ztemp); |
1398 | s.imode = 0666; |
1399 | s.znotify = ""; |
1400 | s.cbytes = -1; |
1401 | s.zcmd = NULL; |
1402 | s.ipos = 0; |
1403 | |
1404 | ++cXcmds; |
1405 | pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, |
1406 | cXcmds * sizeof (struct scmd)); |
1407 | pasXcmds[cXcmds - 1] = s; |
1408 | } |
1409 | \f |
1410 | /* Copy stdin to a file. This is a separate function because it may |
1411 | call setjmp. */ |
1412 | |
1413 | static void |
1414 | uxcopy_stdin (e) |
1415 | FILE *e; |
1416 | { |
1417 | CATCH_PROTECT size_t cread; |
1418 | char ab[1024]; |
1419 | |
1420 | do |
1421 | { |
1422 | size_t cwrite; |
1423 | |
1424 | /* I want to use fread here, but there is a bug in some versions |
1425 | of SVR4 which causes fread to return less than a complete |
1426 | buffer even if EOF has not been reached. This is not online |
1427 | time, so speed is not critical, but it's still quite annoying |
1428 | to have to use an inefficient algorithm. */ |
1429 | cread = 0; |
1430 | if (fsysdep_catch ()) |
1431 | { |
1432 | usysdep_start_catch (); |
1433 | |
1434 | while (cread < sizeof (ab)) |
1435 | { |
1436 | int b; |
1437 | |
1438 | if (FGOT_SIGNAL ()) |
1439 | uxabort (); |
1440 | |
1441 | /* There's an unimportant race here. If the user hits |
1442 | ^C between the FGOT_SIGNAL we just did and the time |
1443 | we enter getchar, we won't know about the signal |
1444 | (unless we're doing a longjmp, but we normally |
1445 | aren't). It's not a big problem, because the user |
1446 | can just hit ^C again. */ |
1447 | b = getchar (); |
1448 | if (b == EOF) |
1449 | break; |
1450 | ab[cread] = b; |
1451 | ++cread; |
1452 | } |
1453 | } |
1454 | |
1455 | usysdep_end_catch (); |
1456 | |
1457 | if (FGOT_SIGNAL ()) |
1458 | uxabort (); |
1459 | |
1460 | if (cread > 0) |
1461 | { |
1462 | cwrite = fwrite (ab, sizeof (char), cread, e); |
1463 | if (cwrite != cread) |
1464 | ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d", |
1465 | (int) cwrite, (int) cread); |
1466 | } |
1467 | } |
1468 | while (cread == sizeof ab); |
1469 | } |
1470 | \f |
1471 | /* Keep track of all files we have created so that we can delete them |
1472 | if we get a signal. The argument will be on the heap. */ |
1473 | |
1474 | static int cXfiles; |
1475 | static const char **pXaz; |
1476 | |
1477 | static void |
1478 | uxrecord_file (zfile) |
1479 | const char *zfile; |
1480 | { |
1481 | pXaz = (const char **) xrealloc ((pointer) pXaz, |
1482 | (cXfiles + 1) * sizeof (const char *)); |
1483 | pXaz[cXfiles] = zfile; |
1484 | ++cXfiles; |
1485 | } |
1486 | |
1487 | /* Delete all the files we have recorded and exit. */ |
1488 | |
1489 | static void |
1490 | uxabort () |
1491 | { |
1492 | int i; |
1493 | |
1494 | if (eXxqt_file != NULL) |
1495 | (void) fclose (eXxqt_file); |
1496 | if (eXclose != NULL) |
1497 | (void) fclose (eXclose); |
1498 | for (i = 0; i < cXfiles; i++) |
1499 | (void) remove (pXaz[i]); |
1500 | ulog_close (); |
1501 | usysdep_exit (FALSE); |
1502 | } |