home *** CD-ROM | disk | FTP | other *** search
- /* uux.c
- Prepare to execute a command on a remote system.
-
- Copyright (C) 1991, 1992, 1993, 1994, 1995 Ian Lance Taylor
-
- This file is part of the Taylor UUCP package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The author of the program may be contacted at ian@airs.com or
- c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
- */
-
- #include "uucp.h"
-
- #if USE_RCS_ID
- const char uux_rcsid[] = "$Id: uux.c,v 1.82 1995/08/20 19:21:42 ian Rel $";
- #endif
-
- #include "uudefs.h"
- #include "uuconf.h"
- #include "system.h"
- #include "sysdep.h"
- #include "getopt.h"
-
- #include <ctype.h>
- #include <errno.h>
-
- /* These character lists should, perhaps, be in sysdep.h. */
-
- /* This is the list of shell metacharacters that we check for. If one
- of these is present, we request uuxqt to execute the command with
- /bin/sh. Otherwise we let it execute using execve. */
-
- #define ZSHELLCHARS "\"'`*?[;&()|<>\\$"
-
- /* This is the list of word separators. We break filename arguments
- at these characters. */
- #define ZSHELLSEPS ";&*|<> \t"
-
- /* This is the list of word separators without the redirection
- operators. */
- #define ZSHELLNONREDIRSEPS ";&*| \t"
-
- /* Whether this execution is occurring on the local system. */
- static boolean fXxqtlocal;
-
- /* The execution system. */
- static struct uuconf_system sXxqtsys;
-
- /* The name of local system from the point of view of the execution
- system. */
- static const char *zXxqtloc;
-
- /* The job grade to use. */
- static char bXgrade = BDEFAULT_UUX_GRADE;
-
- /* The temporary file name of the execute file. */
- static char abXxqt_tname[CFILE_NAME_LEN];
-
- /* The name of the execute file on the remote system. */
- static char abXxqt_xname[CFILE_NAME_LEN];
-
- /* The execute file we are creating. */
- static FILE *eXxqt_file;
-
- /* A list of commands to be spooled. */
- static struct scmd *pasXcmds;
- static int cXcmds;
-
- /* A file to close if we're forced to exit. */
- static FILE *eXclose;
-
- /* A list of file names which will match the file names which appear
- in the uucico logs. */
- static char *zXnames;
-
- /* Local functions. */
- static void uxusage P((void));
- static void uxhelp P((void));
- static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2));
- static void uxadd_send_file P((const char *zfrom, const char *zto,
- const char *zoptions, const char *ztemp,
- const char *zforward));
- static void uxcopy_stdin P((FILE *e));
- static void uxrecord_file P((const char *zfile));
- static void uxabort P((void));
- static void uxadd_name P((const char *));
-
- /* Long getopt options. */
- static const struct option asXlongopts[] =
- {
- { "requestor", required_argument, NULL, 'a' },
- { "return-stdin", no_argument, NULL, 'b' },
- { "nocopy", no_argument, NULL, 'c' },
- { "copy", no_argument, NULL, 'C' },
- { "grade", required_argument, NULL, 'g' },
- { "jobid", no_argument, NULL, 'j' },
- { "link", no_argument, NULL, 'l' },
- { "notification", required_argument, NULL, 2 },
- { "stdin", no_argument, NULL, 'p' },
- { "nouucico", no_argument, NULL, 'r' },
- { "status", required_argument, NULL, 's' },
- { "noexpand", no_argument, NULL, 'W' },
- { "config", required_argument, NULL, 'I' },
- { "debug", required_argument, NULL, 'x' },
- { "version", no_argument, NULL, 'v' },
- { "help", no_argument, NULL, 1 },
- { NULL, 0, NULL, 0 }
- };
-
- /* The main routine. */
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- /* -a: requestor address for status reports. */
- const char *zrequestor = NULL;
- /* -b: if true, return standard input on error. */
- boolean fretstdin = FALSE;
- /* -c,-C: if true, copy to spool directory. */
- boolean fcopy = FALSE;
- /* -c: set if -c appears explicitly; if it and -l appear, then if the
- link fails we don't copy the file. */
- boolean fdontcopy = FALSE;
- /* -I: configuration file name. */
- const char *zconfig = NULL;
- /* -j: output job id. */
- boolean fjobid = FALSE;
- /* -l: link file to spool directory. */
- boolean flink = FALSE;
- /* -n: do not notify upon command completion. */
- boolean fno_ack = FALSE;
- /* -p: read standard input for command standard input. */
- boolean fread_stdin = FALSE;
- /* -r: do not start uucico when finished. */
- boolean fuucico = TRUE;
- /* -s: report status to named file. */
- const char *zstatus_file = NULL;
- /* -W: only expand local file names. */
- boolean fexpand = TRUE;
- /* -z: report status only on error. */
- boolean ferror_ack = FALSE;
- int iopt;
- pointer puuconf;
- int iuuconf;
- const char *zlocalname;
- int i;
- size_t clen;
- char *zargs;
- char *zarg;
- char *zcmd;
- const char *zsys;
- char *zexclam;
- boolean fgetcwd;
- const char *zuser;
- char *zforward;
- char **pzargs;
- int calloc_args;
- int cargs;
- const char *zinput_from;
- const char *zinput_to;
- const char *zinput_temp;
- boolean finputcopied;
- char *zcall_system;
- boolean fcall_any;
- struct uuconf_system slocalsys;
- boolean fneedshell;
- char *zfullcmd;
- boolean fpoll;
- char aboptions[10];
- boolean fexit;
-
- zProgram = argv[0];
-
- /* We need to be able to read a single - as an option, which getopt
- won't do. We handle this by using getopt to scan the argument
- list multiple times, replacing any single "-" with "-p". */
- opterr = 0;
- while (1)
- {
- while (getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wvx:z",
- asXlongopts, (int *) NULL) != EOF)
- ;
- if (optind >= argc || strcmp (argv[optind], "-") != 0)
- break;
- argv[optind] = zbufcpy ("-p");
- optind = 0;
- }
- opterr = 1;
- optind = 0;
-
- /* The leading + in the getopt string means to stop processing
- options as soon as a non-option argument is seen. */
- while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wvx:z",
- asXlongopts, (int *) NULL)) != EOF)
- {
- switch (iopt)
- {
- case 'a':
- /* Set requestor name: mail address to which status reports
- should be sent. */
- zrequestor = optarg;
- break;
-
- case 'b':
- /* Return standard input on error. */
- fretstdin = TRUE;
- break;
-
- case 'c':
- /* Do not copy local files to spool directory. */
- fcopy = FALSE;
- fdontcopy = TRUE;
- break;
-
- case 'C':
- /* Copy local files to spool directory. */
- fcopy = TRUE;
- break;
-
- case 'I':
- /* Configuration file name. */
- if (fsysdep_other_config (optarg))
- zconfig = optarg;
- break;
-
- case 'j':
- /* Output jobid. */
- fjobid = TRUE;
- break;
-
- case 'g':
- /* Set job grade. */
- bXgrade = optarg[0];
- break;
-
- case 'l':
- /* Link file to spool directory. */
- flink = TRUE;
- break;
-
- case 'n':
- /* Do not notify upon command completion. */
- fno_ack = TRUE;
- break;
-
- case 'p':
- /* Read standard input for command standard input. */
- fread_stdin = TRUE;
- break;
-
- case 'r':
- /* Do not start uucico when finished. */
- fuucico = FALSE;
- break;
-
- case 's':
- /* Report status to named file. */
- zstatus_file = optarg;
- break;
-
- case 'W':
- /* Only expand local file names. */
- fexpand = FALSE;
- break;
-
- case 'x':
- #if DEBUG > 1
- /* Set debugging level. */
- iDebug |= idebug_parse (optarg);
- #endif
- break;
-
- case 'z':
- /* Report status only on error. */
- ferror_ack = TRUE;
- break;
-
- case 2:
- /* --notify={true,false,error}. */
- if (*optarg == 't'
- || *optarg == 'T'
- || *optarg == 'y'
- || *optarg == 'Y'
- || *optarg == 'e'
- || *optarg == 'E')
- {
- ferror_ack = TRUE;
- fno_ack = FALSE;
- }
- else if (*optarg == 'f'
- || *optarg == 'F'
- || *optarg == 'n'
- || *optarg == 'N')
- {
- ferror_ack = FALSE;
- fno_ack = TRUE;
- }
- break;
-
- case 'v':
- /* Print version and exit. */
- printf ("%s: Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
- zProgram, VERSION);
- exit (EXIT_SUCCESS);
- /*NOTREACHED*/
-
- case 1:
- /* --help. */
- uxhelp ();
- exit (EXIT_SUCCESS);
- /*NOTREACHED*/
-
- case 0:
- /* Long option found and flag set. */
- break;
-
- default:
- uxusage ();
- break;
- }
- }
-
- if (! UUCONF_GRADE_LEGAL (bXgrade)
- || ((bXgrade < '0' || bXgrade > '9')
- && (bXgrade < 'a' || bXgrade > 'z')
- && (bXgrade < 'A' || bXgrade > 'Z')))
- {
- ulog (LOG_ERROR, "Ignoring illegal grade");
- bXgrade = BDEFAULT_UUX_GRADE;
- }
-
- if (optind == argc)
- uxusage ();
-
- iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
- if (iuuconf != UUCONF_SUCCESS)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
-
- #if DEBUG > 1
- {
- const char *zdebug;
-
- iuuconf = uuconf_debuglevel (puuconf, &zdebug);
- if (iuuconf != UUCONF_SUCCESS)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- if (zdebug != NULL)
- iDebug |= idebug_parse (zdebug);
- }
- #endif
-
- /* The command and files arguments could be quoted in any number of
- ways, so we split them apart ourselves. We do this before
- calling usysdep_initialize because we want to set fgetcwd
- correctly. */
- clen = 1;
- for (i = optind; i < argc; i++)
- clen += strlen (argv[i]) + 1;
-
- zargs = zbufalc (clen);
- *zargs = '\0';
- for (i = optind; i < argc; i++)
- {
- strcat (zargs, argv[i]);
- strcat (zargs, " ");
- }
-
- /* The first argument is the command to execute. */
- clen = strcspn (zargs, ZSHELLSEPS);
- zcmd = zbufalc (clen + 1);
- strncpy (zcmd, zargs, clen);
- zcmd[clen] = '\0';
- zargs += clen;
-
- /* Split the arguments out into an array. We break the arguments
- into alternating sequences of characters not in ZSHELLSEPS
- and characters in ZSHELLSEPS. We remove whitespace. We
- separate the redirection characters '>' and '<' into their
- own arguments to make them easier to process below. */
- calloc_args = 10;
- pzargs = (char **) xmalloc (calloc_args * sizeof (char *));
- cargs = 0;
-
- for (zarg = strtok (zargs, " \t");
- zarg != NULL;
- zarg = strtok ((char *) NULL, " \t"))
- {
- while (*zarg != '\0')
- {
- if (cargs + 1 >= calloc_args)
- {
- calloc_args += 10;
- pzargs = (char **) xrealloc ((pointer) pzargs,
- calloc_args * sizeof (char *));
- }
-
- if (*zarg == '(')
- clen = strlen (zarg);
- else
- clen = strcspn (zarg, ZSHELLSEPS);
- if (clen > 0)
- {
- pzargs[cargs] = zbufalc (clen + 1);
- memcpy (pzargs[cargs], zarg, clen);
- pzargs[cargs][clen] = '\0';
- ++cargs;
- zarg += clen;
- }
-
- /* We deliberately separate '>' and '<' out. */
- if (*zarg != '\0')
- {
- clen = strspn (zarg, ZSHELLNONREDIRSEPS);
- if (clen == 0)
- clen = 1;
- pzargs[cargs] = zbufalc (clen + 1);
- memcpy (pzargs[cargs], zarg, clen);
- pzargs[cargs][clen] = '\0';
- ++cargs;
- zarg += clen;
- }
- }
- }
-
- /* Now look through the arguments to see if we are going to need the
- current working directory. We don't try to make a precise
- determination, just a conservative one. The basic idea is that
- we don't want to get the cwd for 'foo!rmail - user' (note that we
- don't examine the command itself). */
- fgetcwd = FALSE;
- for (i = 0; i < cargs; i++)
- {
- if (pzargs[i][0] == '(')
- continue;
- zexclam = strrchr (pzargs[i], '!');
- if (zexclam != NULL && fsysdep_needs_cwd (zexclam + 1))
- {
- fgetcwd = TRUE;
- break;
- }
- if ((pzargs[i][0] == '<' || pzargs[i][0] == '>')
- && i + 1 < cargs
- && strchr (pzargs[i + 1], '!') == NULL
- && fsysdep_needs_cwd (pzargs[i + 1]))
- {
- fgetcwd = TRUE;
- break;
- }
- }
-
- #ifdef SIGINT
- usysdep_signal (SIGINT);
- #endif
- #ifdef SIGHUP
- usysdep_signal (SIGHUP);
- #endif
- #ifdef SIGQUIT
- usysdep_signal (SIGQUIT);
- #endif
- #ifdef SIGTERM
- usysdep_signal (SIGTERM);
- #endif
- #ifdef SIGPIPE
- usysdep_signal (SIGPIPE);
- #endif
-
- usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0));
-
- ulog_fatal_fn (uxabort);
-
- zuser = zsysdep_login_name ();
-
- /* Get the local system name. */
- iuuconf = uuconf_localname (puuconf, &zlocalname);
- if (iuuconf == UUCONF_NOT_FOUND)
- {
- zlocalname = zsysdep_localname ();
- if (zlocalname == NULL)
- exit (EXIT_FAILURE);
- }
- else if (iuuconf != UUCONF_SUCCESS)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
-
- /* Get the local system information. */
- iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys);
- if (iuuconf != UUCONF_SUCCESS)
- {
- if (iuuconf != UUCONF_NOT_FOUND)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- iuuconf = uuconf_system_local (puuconf, &slocalsys);
- if (iuuconf != UUCONF_SUCCESS)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- slocalsys.uuconf_zname = (char *) zlocalname;
- }
-
- /* Figure out which system the command is to be executed on. */
- zcmd = zremove_local_sys (&slocalsys, zcmd);
- zexclam = strchr (zcmd, '!');
- if (zexclam == NULL)
- {
- zsys = zlocalname;
- fXxqtlocal = TRUE;
- zforward = NULL;
- }
- else
- {
- *zexclam = '\0';
- zsys = zcmd;
- zcmd = zexclam + 1;
- fXxqtlocal = FALSE;
-
- /* See if we must forward this command through other systems
- (e.g. uux a!b!cmd). */
- zexclam = strrchr (zcmd, '!');
- if (zexclam == NULL)
- zforward = NULL;
- else
- {
- clen = zexclam - zcmd;
- zforward = zbufalc (clen);
- memcpy (zforward, zcmd, clen);
- zforward[clen] = '\0';
- zcmd = zexclam + 1;
- }
- }
-
- if (fXxqtlocal)
- sXxqtsys = slocalsys;
- else
- {
- iuuconf = uuconf_system_info (puuconf, zsys, &sXxqtsys);
- if (iuuconf != UUCONF_SUCCESS)
- {
- if (iuuconf != UUCONF_NOT_FOUND)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- if (! funknown_system (puuconf, zsys, &sXxqtsys))
- ulog (LOG_FATAL, "%s: System not found", zsys);
- }
- }
-
- /* Get the local name the remote system know us as. */
- zXxqtloc = sXxqtsys.uuconf_zlocalname;
- if (zXxqtloc == NULL)
- zXxqtloc = zlocalname;
-
- /* Look through the arguments. Any argument containing an
- exclamation point character is interpreted as a file name, and is
- sent to the appropriate system. */
- zinput_from = NULL;
- zinput_to = NULL;
- zinput_temp = NULL;
- finputcopied = FALSE;
- zcall_system = NULL;
- fcall_any = FALSE;
-
- for (i = 0; i < cargs; i++)
- {
- const char *zsystem;
- char *zfile;
- char *zforw;
- boolean finput, foutput;
- boolean flocal, fonxqt;
-
- /* Check for a parenthesized argument; remove the parentheses
- and otherwise ignore it (this is how an exclamation point is
- quoted). */
- if (pzargs[i][0] == '(')
- {
- clen = strlen (pzargs[i]);
- if (pzargs[i][clen - 1] != ')')
- ulog (LOG_ERROR, "Mismatched parentheses");
- else
- pzargs[i][clen - 1] = '\0';
- ++pzargs[i];
- continue;
- }
-
- /* Check whether we are doing a redirection. */
- finput = FALSE;
- foutput = FALSE;
- if (i + 1 < cargs)
- {
- if (pzargs[i][0] == '<')
- finput = TRUE;
- else if (pzargs[i][0] == '>')
- foutput = TRUE;
- if (finput || foutput)
- {
- pzargs[i] = NULL;
- i++;
- }
- }
-
- zexclam = strchr (pzargs[i], '!');
-
- /* If there is no exclamation point and no redirection, this
- argument is left untouched. */
- if (zexclam == NULL && ! finput && ! foutput)
- continue;
-
- if (zexclam != NULL)
- {
- pzargs[i] = zremove_local_sys (&slocalsys, pzargs[i]);
- zexclam = strchr (pzargs[i], '!');
- }
-
- /* Get the system name and file name for this file. */
- if (zexclam == NULL)
- {
- zsystem = zlocalname;
- zfile = pzargs[i];
- flocal = TRUE;
- zforw = NULL;
- }
- else
- {
- *zexclam = '\0';
- zsystem = pzargs[i];
- zfile = zexclam + 1;
- flocal = FALSE;
- zexclam = strrchr (zfile, '!');
- if (zexclam == NULL)
- zforw = NULL;
- else
- {
- *zexclam = '\0';
- zforw = zfile;
- zfile = zexclam + 1;
- }
- }
-
- /* Check if the file is already on the execution system. */
- if (flocal)
- fonxqt = fXxqtlocal;
- else if (fXxqtlocal)
- fonxqt = FALSE;
- else if (zforward == NULL ? zforw != NULL : zforw == NULL)
- fonxqt = FALSE;
- else if (zforward != NULL
- && zforw != NULL
- && strcmp (zforward, zforw) != 0)
- fonxqt = FALSE;
- else if (strcmp (zsystem, sXxqtsys.uuconf_zname) == 0)
- fonxqt = TRUE;
- else if (sXxqtsys.uuconf_pzalias == NULL)
- fonxqt = FALSE;
- else
- {
- char **pzal;
-
- fonxqt = FALSE;
- for (pzal = sXxqtsys.uuconf_pzalias; *pzal != NULL; pzal++)
- {
- if (strcmp (zsystem, *pzal) == 0)
- {
- fonxqt = TRUE;
- break;
- }
- }
- }
-
- /* Turn the file into an absolute path. */
- if (flocal)
- zfile = zsysdep_local_file_cwd (zfile, sXxqtsys.uuconf_zpubdir,
- (boolean *) NULL);
- else if (fexpand)
- zfile = zsysdep_add_cwd (zfile);
- if (zfile == NULL)
- uxabort ();
-
- /* Check for output redirection. */
- if (foutput)
- {
- if (flocal)
- {
- if (! fin_directory_list (zfile,
- sXxqtsys.uuconf_pzremote_receive,
- sXxqtsys.uuconf_zpubdir, TRUE,
- FALSE, (const char *) NULL))
- ulog (LOG_FATAL, "Not permitted to create %s", zfile);
- }
-
- /* There are various cases of output redirection.
-
- uux cmd >out: The command is executed on the local
- system, and the output file is placed on the local
- system (fonxqt is TRUE).
-
- uux cmd >a!out: The command is executed on the local
- system, and the output file is sent to a.
-
- uux a!cmd >out: The command is executed on a, and the
- output file is returned to the local system (flocal
- is TRUE).
-
- uux a!cmd >a!out: The command is executed on a, and the
- output file is left on a (fonxqt is TRUE).
-
- uux a!cmd >b!out: The command is executed on a, and the
- output file is sent to b; traditionally, I believe
- that b is relative to a, rather than to the local
- system. However, this essentially contradicts the
- previous two cases, in which the output file is
- relative to the local system.
-
- Now, the cases that we don't handle.
-
- uux cmd >a!b!out: The command is executed on the local
- system, and the output file is sent to b via a. This
- requires the local uuxqt to support forwarding of the
- output file.
-
- uux a!b!cmd >out: The command is executed on b, which is
- reached via a. Probably the output file is intended
- for the local system, in which case the uuxqt on b
- must support forwarding of the output file.
-
- uux a!b!cmd >c!out: Is c relative to b or to the local
- system? If it's relative to b this is easy to
- handle. Otherwise, we must arrange for the file to
- be sent back to the local system and for the local
- system to send it on to c.
-
- There are many variations of the last case. It's not at
- all clear to me how they should be handled. */
- if (zforward != NULL || zforw != NULL)
- ulog (LOG_FATAL, "May not forward standard output");
-
- if (fonxqt)
- uxadd_xqt_line ('O', zfile, (const char *) NULL);
- else if (flocal)
- uxadd_xqt_line ('O', zfile, zXxqtloc);
- else
- uxadd_xqt_line ('O', zfile, zsystem);
- pzargs[i] = NULL;
- continue;
- }
-
- if (finput)
- {
- if (fread_stdin)
- ulog (LOG_FATAL, "Standard input specified twice");
- pzargs[i] = NULL;
- }
-
- if (flocal)
- {
- char *zuse;
- char *zdata;
- char abtname[CFILE_NAME_LEN];
- char abdname[CFILE_NAME_LEN];
-
- /* It's a local file. If requested by -C, copy the file to
- the spool directory. If requested by -l, link the file
- to the spool directory; if the link fails, we copy the
- file, unless -c was explictly used. If the execution is
- occurring on the local system, we force the copy as well,
- because otherwise we would have to have some way to tell
- uuxqt not to move the file. If the file is being shipped
- to another system, we must set up a transfer request.
- First make sure the user has legitimate access, since we
- are running setuid. */
- if (! fsysdep_access (zfile))
- uxabort ();
-
- zdata = zsysdep_data_file_name (&sXxqtsys, zXxqtloc, bXgrade, FALSE,
- abtname, abdname, (char *) NULL);
- if (zdata == NULL)
- uxabort ();
-
- if (fcopy || flink || fXxqtlocal)
- {
- boolean fdid;
-
- uxrecord_file (zdata);
-
- fdid = FALSE;
- if (flink)
- {
- boolean fworked;
-
- if (! fsysdep_link (zfile, zdata, &fworked))
- uxabort ();
-
- if (fworked)
- fdid = TRUE;
- else if (fdontcopy)
- ulog (LOG_FATAL, "%s: Can't link to spool directory",
- zfile);
- }
-
- if (! fdid)
- {
- openfile_t efile;
-
- efile = esysdep_user_fopen (zfile, TRUE, TRUE);
- if (! ffileisopen (efile))
- uxabort ();
- if (! fcopy_open_file (efile, zdata, FALSE, TRUE, TRUE))
- uxabort ();
- (void) ffileclose (efile);
- }
-
- zuse = abtname;
- }
- else
- {
- /* We don't actually use the spool file name, but we
- need a name to use as the destination. */
- ubuffree (zdata);
- /* Make sure the daemon can access the file. */
- if (! fsysdep_daemon_access (zfile))
- uxabort ();
- if (! fin_directory_list (zfile, sXxqtsys.uuconf_pzlocal_send,
- sXxqtsys.uuconf_zpubdir, TRUE,
- TRUE, zuser))
- ulog (LOG_FATAL, "Not permitted to send from %s",
- zfile);
-
- zuse = zfile;
- }
-
- if (fXxqtlocal)
- {
- if (finput)
- uxadd_xqt_line ('I', zuse, (char *) NULL);
- else
- pzargs[i] = zuse;
- }
- else
- {
- finputcopied = fcopy || flink;
-
- if (finput)
- {
- zinput_from = zuse;
- zinput_to = zbufcpy (abdname);
- zinput_temp = zbufcpy (abtname);
- }
- else
- {
- char *zbase;
-
- uxadd_send_file (zuse, abdname,
- finputcopied ? "C" : "c",
- abtname, zforward);
- zbase = zsysdep_base_name (zfile);
- if (zbase == NULL)
- uxabort ();
- uxadd_xqt_line ('F', abdname, zbase);
- pzargs[i] = zbase;
- }
- }
- }
- else if (fonxqt)
- {
- /* The file is already on the system where the command is to
- be executed. */
- if (finput)
- uxadd_xqt_line ('I', zfile, (const char *) NULL);
- else
- pzargs[i] = zfile;
- }
- else
- {
- struct uuconf_system sfromsys;
- char abtname[CFILE_NAME_LEN];
- struct scmd s;
- char *zjobid;
-
- /* We need to request a remote file. */
- iuuconf = uuconf_system_info (puuconf, zsystem, &sfromsys);
- if (iuuconf != UUCONF_SUCCESS)
- {
- if (iuuconf != UUCONF_NOT_FOUND)
- ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
- if (! funknown_system (puuconf, zsystem, &sfromsys))
- ulog (LOG_FATAL, "%s: System not found", zsystem);
- }
-
- if (fonxqt)
- {
- /* The file is already on the system where the command is to
- be executed. */
- if (finput)
- uxadd_xqt_line ('I', zfile, (const char *) NULL);
- else
- pzargs[i] = zfile;
- }
- else
- {
- char *zdata;
-
- if (! sfromsys.uuconf_fcall_transfer
- && ! sfromsys.uuconf_fcalled_transfer)
- ulog (LOG_FATAL,
- "Not permitted to transfer files to or from %s",
- sfromsys.uuconf_zname);
-
- if (zforw != NULL)
- {
- /* This is ``uux cmd a!b!file''. To make this work,
- we would have to be able to set up a request to a
- to fetch file from b and send it to us. But it
- turns out that that will not work, because when a
- sends us the file we will put it in a's spool
- directory, not the local system spool directory.
- So we won't have any way to find it. This is not
- a conceptual problem, and it could doubtless be
- solved. Please feel free to solve it and send me
- the solution. */
- ulog (LOG_FATAL, "File forwarding not supported");
- }
-
- /* We must request the file from the remote system to
- this one. */
- zdata = zsysdep_data_file_name (&slocalsys, zXxqtloc, bXgrade,
- FALSE, abtname, (char *) NULL,
- (char *) NULL);
- if (zdata == NULL)
- uxabort ();
- ubuffree (zdata);
-
- /* Request the file. The special option '9' is a signal
- to uucico that it's OK to receive a file into the
- spool directory; normally such requests are rejected.
- This privilege is easy to abuse. */
- s.bcmd = 'R';
- s.bgrade = bXgrade;
- s.pseq = NULL;
- s.zfrom = zfile;
- s.zto = zbufcpy (abtname);
- s.zuser = zuser;
- s.zoptions = "9";
- s.ztemp = "";
- s.imode = 0600;
- s.znotify = "";
- s.cbytes = -1;
- s.zcmd = NULL;
- s.ipos = 0;
-
- zjobid = zsysdep_spool_commands (&sfromsys, bXgrade, 1, &s);
- if (zjobid == NULL)
- uxabort ();
-
- if (fjobid)
- printf ("%s\n", zjobid);
-
- ubuffree (zjobid);
-
- if (fcall_any)
- {
- ubuffree (zcall_system);
- zcall_system = NULL;
- }
- else
- {
- fcall_any = TRUE;
- zcall_system = zbufcpy (sfromsys.uuconf_zname);
- }
-
- if (fXxqtlocal)
- {
- /* Tell the command execution to wait until the file
- has been received, and tell it the real file
- name. */
- if (finput)
- {
- uxadd_xqt_line ('F', abtname, (char *) NULL);
- uxadd_xqt_line ('I', abtname, (char *) NULL);
- }
- else
- {
- char *zbase;
-
- zbase = zsysdep_base_name (zfile);
- if (zbase == NULL)
- uxabort ();
- uxadd_xqt_line ('F', abtname, zbase);
- pzargs[i] = zbase;
- }
- }
- else
- {
- char abxtname[CFILE_NAME_LEN];
- char *zbase;
- char *zxqt;
- FILE *e;
-
- /* Now we must arrange to forward the file on to the
- execution system. We need to get a name to give
- the file on the execution system (abxtname). */
- zdata = zsysdep_data_file_name (&sXxqtsys, zXxqtloc,
- bXgrade, TRUE, abxtname,
- (char *) NULL,
- (char *) NULL);
- if (zdata == NULL)
- uxabort ();
- ubuffree (zdata);
-
- zbase = zsysdep_base_name (zfile);
- if (zbase == NULL)
- uxabort ();
-
- zxqt = zsysdep_xqt_file_name ();
- if (zxqt == NULL)
- uxabort ();
- e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
- if (e == NULL)
- uxabort ();
- uxrecord_file (zxqt);
-
- fprintf (e, "U %s %s\n", zsysdep_login_name (),
- zlocalname);
- fprintf (e, "F %s %s\n", abtname, zbase);
- fprintf (e, "C uucp -C -W -d -g %c %s %s!", bXgrade,
- zbase, sXxqtsys.uuconf_zname);
- if (zforward != NULL)
- fprintf (e, "%s!", zforward);
- fprintf (e, "%s\n", abxtname);
-
- if (! fstdiosync (e, zxqt))
- ulog (LOG_FATAL, "fsync failed");
- if (fclose (e) != 0)
- ulog (LOG_FATAL, "fclose: %s", strerror (errno));
-
- if (finput)
- {
- uxadd_xqt_line ('F', abxtname, (char *) NULL);
- uxadd_xqt_line ('I', abxtname, (char *) NULL);
- ubuffree (zbase);
- }
- else
- {
- uxadd_xqt_line ('F', abxtname, zbase);
- pzargs[i] = zbase;
- }
- }
- }
-
- (void) uuconf_system_free (puuconf, &sfromsys);
- }
- }
-
- /* If standard input is to be read from the stdin of uux, we read it
- here into a temporary file and send it to the execute system. */
- if (fread_stdin)
- {
- char *zdata;
- char abtname[CFILE_NAME_LEN];
- char abdname[CFILE_NAME_LEN];
- FILE *e;
-
- zdata = zsysdep_data_file_name (&sXxqtsys, zXxqtloc, bXgrade, FALSE,
- abtname, abdname, (char *) NULL);
- if (zdata == NULL)
- uxabort ();
-
- e = esysdep_fopen (zdata, FALSE, FALSE, TRUE);
- if (e == NULL)
- uxabort ();
-
- eXclose = e;
- uxrecord_file (zdata);
-
- uxcopy_stdin (e);
-
- if (! fstdiosync (e, zdata))
- ulog (LOG_FATAL, "fsync failed");
- eXclose = NULL;
- if (fclose (e) != 0)
- ulog (LOG_FATAL, "fclose: %s", strerror (errno));
-
- if (fXxqtlocal)
- uxadd_xqt_line ('I', abtname, (const char *) NULL);
- else
- {
- zinput_from = zbufcpy (abtname);
- zinput_to = zbufcpy (abdname);
- zinput_temp = zinput_from;
- finputcopied = TRUE;
- }
- }
-
- /* If we are returning standard input, or we're putting the status
- in a file, we can't use an E command. */
- if (fretstdin)
- uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL);
-
- if (zstatus_file != NULL)
- uxadd_xqt_line ('M', zstatus_file, (const char *) NULL);
-
- /* Get the complete command line, and decide whether the command
- needs to be executed by the shell. */
- fneedshell = FALSE;
-
- if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0')
- fneedshell = TRUE;
-
- clen = strlen (zcmd) + 1;
- for (i = 0; i < cargs; i++)
- {
- if (pzargs[i] != NULL)
- {
- clen += strlen (pzargs[i]) + 1;
- if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0')
- fneedshell = TRUE;
- }
- }
-
- zfullcmd = zbufalc (clen);
-
- strcpy (zfullcmd, zcmd);
- for (i = 0; i < cargs; i++)
- {
- if (pzargs[i] != NULL)
- {
- strcat (zfullcmd, " ");
- strcat (zfullcmd, pzargs[i]);
- }
- }
-
- fpoll = FALSE;
-
- /* If we haven't written anything to the execution file yet, and we
- have a standard input file, and we're not forwarding, then every
- other option can be handled in an E command. */
- if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL)
- {
- struct scmd s;
- char *zoptions;
-
- /* Set up an E command. */
- s.bcmd = 'E';
- s.bgrade = bXgrade;
- s.pseq = NULL;
- s.zuser = zuser;
- s.zfrom = zinput_from;
- s.zto = zinput_to;
- s.zoptions = aboptions;
- zoptions = aboptions;
- *zoptions++ = finputcopied ? 'C' : 'c';
- if (fno_ack)
- *zoptions++ = 'N';
- if (ferror_ack)
- *zoptions++ = 'Z';
- if (zrequestor != NULL)
- *zoptions++ = 'R';
- if (fneedshell)
- *zoptions++ = 'e';
- *zoptions = '\0';
- s.ztemp = zinput_temp;
- s.imode = 0666;
- if (zrequestor == NULL)
- zrequestor = "\"\"";
- s.znotify = zrequestor;
- s.cbytes = -1;
- s.zcmd = zfullcmd;
- s.ipos = 0;
-
- ++cXcmds;
- pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
- cXcmds * sizeof (struct scmd));
- pasXcmds[cXcmds - 1] = s;
-
- uxadd_name (zinput_from);
- }
- else if (*zfullcmd == '\0'
- && eXxqt_file == NULL
- && zinput_from == NULL
- && cXcmds == 0)
- {
- /* As a special case, if we are asked to execute an empty
- command, we create a poll file instead. */
- fpoll = TRUE;
- }
- else
- {
- /* Finish up the execute file. */
- uxadd_xqt_line ('U', zuser, zXxqtloc);
- if (zinput_from != NULL)
- {
- uxadd_xqt_line ('F', zinput_to, (char *) NULL);
- uxadd_xqt_line ('I', zinput_to, (char *) NULL);
- uxadd_send_file (zinput_from, zinput_to,
- finputcopied ? "C" : "c",
- zinput_temp, zforward);
- }
- if (fno_ack)
- uxadd_xqt_line ('N', (const char *) NULL, (const char *) NULL);
- if (ferror_ack)
- uxadd_xqt_line ('Z', (const char *) NULL, (const char *) NULL);
- if (zrequestor != NULL)
- uxadd_xqt_line ('R', zrequestor, (const char *) NULL);
- if (fneedshell)
- uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL);
- uxadd_xqt_line ('C', zfullcmd, (const char *) NULL);
- if (! fstdiosync (eXxqt_file, "execution file"))
- ulog (LOG_FATAL, "fsync failed");
- if (fclose (eXxqt_file) != 0)
- ulog (LOG_FATAL, "fclose: %s", strerror (errno));
- eXxqt_file = NULL;
-
- /* If the execution is to occur on another system, we must now
- arrange to copy the execute file to this system. */
- if (! fXxqtlocal)
- uxadd_send_file (abXxqt_tname, abXxqt_xname, "C", abXxqt_tname,
- zforward);
- }
-
- /* If we got a signal, get out before spooling anything. */
- if (FGOT_SIGNAL ())
- uxabort ();
-
- /* From here on in, it's too late. We don't call uxabort. */
- if (cXcmds > 0 || fpoll)
- {
- char *zjobid;
-
- if (! fpoll
- && ! sXxqtsys.uuconf_fcall_transfer
- && ! sXxqtsys.uuconf_fcalled_transfer)
- ulog (LOG_FATAL, "Not permitted to transfer files to or from %s",
- sXxqtsys.uuconf_zname);
-
- zjobid = zsysdep_spool_commands (&sXxqtsys, bXgrade, cXcmds, pasXcmds);
- if (zjobid == NULL)
- {
- ulog_close ();
- usysdep_exit (FALSE);
- }
-
- if (fjobid)
- printf ("%s\n", zjobid);
-
- ubuffree (zjobid);
-
- if (fcall_any)
- {
- ubuffree (zcall_system);
- zcall_system = NULL;
- }
- else
- {
- fcall_any = TRUE;
- zcall_system = zbufcpy (sXxqtsys.uuconf_zname);
- }
- }
-
- if (! fpoll)
- {
- /* If all that worked, make a log file entry. All log file
- reports up to this point went to stderr. */
- ulog_to_file (puuconf, TRUE);
- ulog_system (sXxqtsys.uuconf_zname);
- ulog_user (zuser);
-
- if (zXnames == NULL)
- ulog (LOG_NORMAL, "Queuing %s", zfullcmd);
- else
- ulog (LOG_NORMAL, "Queuing %s (%s)", zfullcmd, zXnames);
-
- ulog_close ();
- }
-
- if (! fuucico
- || (zcall_system == NULL && ! fcall_any))
- {
- if (! fXxqtlocal || ! fuucico)
- fexit = TRUE;
- else
- {
- char *zconfigarg;
-
- if (zconfig == NULL)
- zconfigarg = NULL;
- else
- {
- zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
- sprintf (zconfigarg, "-I%s", zconfig);
- }
-
- fexit = fsysdep_run (FALSE, "uuxqt", zconfigarg,
- (const char *) NULL);
- }
- }
- else
- {
- const char *zcicoarg;
- char *zconfigarg;
-
- if (zcall_system == NULL)
- zcicoarg = "-r1";
- else
- {
- char *z;
-
- z = zbufalc (sizeof "-Cs" + strlen (zcall_system));
- sprintf (z, "-Cs%s", zcall_system);
- zcicoarg = z;
- }
-
- if (zconfig == NULL)
- zconfigarg = NULL;
- else
- {
- zconfigarg = zbufalc (sizeof "-I" + strlen (zconfig));
- sprintf (zconfigarg, "-I%s", zconfig);
- }
-
- fexit = fsysdep_run (FALSE, "uucico", zcicoarg, zconfigarg);
- }
-
- usysdep_exit (fexit);
-
- /* Avoid error about not returning a value. */
- return 0;
- }
-
- /* Report command usage. */
-
- static void
- uxhelp ()
- {
- printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n",
- VERSION);
- printf ("Usage: %s [options] [-] command\n", zProgram);
- printf (" -,-p,--stdin: Read standard input for standard input of command\n");
- printf (" -c,--nocopy: Do not copy local files to spool directory (default)\n");
- printf (" -C,--copy: Copy local files to spool directory\n");
- printf (" -l,--link: link local files to spool directory\n");
- printf (" -g,--grade grade: Set job grade (must be alphabetic)\n");
- printf (" -n,--notification=no: Do not report completion status\n");
- printf (" -z,--notification=error: Report completion status only on error\n");
- printf (" -r,--nouucico: Do not start uucico daemon\n");
- printf (" -a,--requestor address: Address to mail status report to\n");
- printf (" -b,--return-stdin: Return standard input with status report\n");
- printf (" -s,--status file: Report completion status to file\n");
- printf (" -j,--jobid: Report job id\n");
- printf (" -x,--debug debug: Set debugging level\n");
- #if HAVE_TAYLOR_CONFIG
- printf (" -I,--config file: Set configuration file to use\n");
- #endif /* HAVE_TAYLOR_CONFIG */
- printf (" -v,--version: Print version and exit\n");
- printf (" --help: Print help and exit\n");
- }
-
- static void
- uxusage ()
- {
- fprintf (stderr,
- "Usage: %s [options] [-] command\n", zProgram);
- fprintf (stderr, "Use %s --help for help\n", zProgram);
- exit (EXIT_FAILURE);
- }
-
- /* Add a line to the execute file. */
-
- static void
- uxadd_xqt_line (bchar, z1, z2)
- int bchar;
- const char *z1;
- const char *z2;
- {
- if (eXxqt_file == NULL)
- {
- const char *zxqt_name;
-
- if (fXxqtlocal)
- zxqt_name = zsysdep_xqt_file_name ();
- else
- zxqt_name = zsysdep_data_file_name (&sXxqtsys, zXxqtloc, bXgrade, TRUE,
- abXxqt_tname, (char *) NULL,
- abXxqt_xname);
- if (zxqt_name == NULL)
- uxabort ();
-
- uxrecord_file (zxqt_name);
-
- eXxqt_file = esysdep_fopen (zxqt_name, FALSE, FALSE, TRUE);
- if (eXxqt_file == NULL)
- uxabort ();
- }
-
- if (z1 == NULL)
- fprintf (eXxqt_file, "%c\n", bchar);
- else if (z2 == NULL)
- fprintf (eXxqt_file, "%c %s\n", bchar, z1);
- else
- fprintf (eXxqt_file, "%c %s %s\n", bchar, z1, z2);
- }
-
- /* Add a file to be sent to the execute system. */
-
- static void
- uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward)
- const char *zfrom;
- const char *zto;
- const char *zoptions;
- const char *ztemp;
- const char *zforward;
- {
- struct scmd s;
-
- if (zforward != NULL)
- {
- char *zbase;
- char *zxqt;
- char abtname[CFILE_NAME_LEN];
- char abdname[CFILE_NAME_LEN];
- char abxname[CFILE_NAME_LEN];
- FILE *e;
-
- /* We want to forward this file through the first execution
- system to other systems. We set up a remote execution of
- uucp to forward the file. */
- zbase = zsysdep_base_name (zfrom);
- if (zbase == NULL)
- uxabort ();
-
- zxqt = zsysdep_data_file_name (&sXxqtsys, zXxqtloc, bXgrade, TRUE,
- abtname, abdname, abxname);
- if (zxqt == NULL)
- uxabort ();
- e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE);
- if (e == NULL)
- uxabort ();
- uxrecord_file (zxqt);
-
- fprintf (e, "U %s %s\n", zsysdep_login_name (), zXxqtloc);
- fprintf (e, "F %s %s\n", abdname, zbase);
- fprintf (e, "C uucp -C -W -d -g %c %s %s!%s\n",
- bXgrade, zbase, zforward, zto);
-
- ubuffree (zbase);
-
- if (! fstdiosync (e, zxqt))
- ulog (LOG_FATAL, "fsync failed");
- if (fclose (e) != 0)
- ulog (LOG_FATAL, "fclose: %s", strerror (errno));
-
- /* Send the execution file. */
- s.bcmd = 'S';
- s.bgrade = bXgrade;
- s.pseq = NULL;
- s.zfrom = zbufcpy (abtname);
- s.zto = zbufcpy (abxname);
- s.zuser = zsysdep_login_name ();
- s.zoptions = "C";
- s.ztemp = s.zfrom;
- s.imode = 0666;
- s.znotify = NULL;
- s.cbytes = -1;
- s.zcmd = NULL;
- s.ipos = 0;
-
- ++cXcmds;
- pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
- cXcmds * sizeof (struct scmd));
- pasXcmds[cXcmds - 1] = s;
-
- uxadd_name (abtname);
-
- /* Send the data file to abdname where the execution file will
- expect it. */
- zto = abdname;
- }
-
- s.bcmd = 'S';
- s.bgrade = bXgrade;
- s.pseq = NULL;
- s.zfrom = zbufcpy (zfrom);
- s.zto = zbufcpy (zto);
- s.zuser = zsysdep_login_name ();
- s.zoptions = zbufcpy (zoptions);
- s.ztemp = zbufcpy (ztemp);
- s.imode = 0666;
- s.znotify = "";
- s.cbytes = -1;
- s.zcmd = NULL;
- s.ipos = 0;
-
- ++cXcmds;
- pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
- cXcmds * sizeof (struct scmd));
- pasXcmds[cXcmds - 1] = s;
-
- uxadd_name (zfrom);
- }
-
- /* Copy stdin to a file. This is a separate function because it may
- call setjmp. */
-
- static void
- uxcopy_stdin (e)
- FILE *e;
- {
- CATCH_PROTECT size_t cread;
- char ab[1024];
-
- do
- {
- size_t cwrite;
-
- /* I want to use fread here, but there is a bug in some versions
- of SVR4 which causes fread to return less than a complete
- buffer even if EOF has not been reached. This is not online
- time, so speed is not critical, but it's still quite annoying
- to have to use an inefficient algorithm. */
- cread = 0;
- if (fsysdep_catch ())
- {
- usysdep_start_catch ();
-
- while (cread < sizeof (ab))
- {
- int b;
-
- if (FGOT_SIGNAL ())
- uxabort ();
-
- /* There's an unimportant race here. If the user hits
- ^C between the FGOT_SIGNAL we just did and the time
- we enter getchar, we won't know about the signal
- (unless we're doing a longjmp, but we normally
- aren't). It's not a big problem, because the user
- can just hit ^C again. */
- b = getchar ();
- if (b == EOF)
- break;
- ab[cread] = b;
- ++cread;
- }
- }
-
- usysdep_end_catch ();
-
- if (FGOT_SIGNAL ())
- uxabort ();
-
- if (cread > 0)
- {
- cwrite = fwrite (ab, sizeof (char), cread, e);
- if (cwrite != cread)
- ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d",
- (int) cwrite, (int) cread);
- }
- }
- while (cread == sizeof ab);
- }
-
- /* Keep track of all files we have created so that we can delete them
- if we get a signal. The argument will be on the heap. */
-
- static int cXfiles;
- static const char **pXaz;
-
- static void
- uxrecord_file (zfile)
- const char *zfile;
- {
- pXaz = (const char **) xrealloc ((pointer) pXaz,
- (cXfiles + 1) * sizeof (const char *));
- pXaz[cXfiles] = zfile;
- ++cXfiles;
- }
-
- /* Delete all the files we have recorded and exit. */
-
- static void
- uxabort ()
- {
- int i;
-
- if (eXxqt_file != NULL)
- (void) fclose (eXxqt_file);
- if (eXclose != NULL)
- (void) fclose (eXclose);
- for (i = 0; i < cXfiles; i++)
- (void) remove (pXaz[i]);
- ulog_close ();
- usysdep_exit (FALSE);
- }
-
- /* Add a name to the list of file names we are going to log. We log
- all the file names which will appear in the uucico log file. This
- permits people to associate the file send in the uucico log with
- the uux entry which created the file. Normally only one file name
- will appear. */
-
- static void
- uxadd_name (z)
- const char *z;
- {
- if (zXnames == NULL)
- zXnames = zbufcpy (z);
- else
- {
- size_t cold, cadd;
- char *znew;
-
- cold = strlen (zXnames);
- cadd = strlen (z);
- znew = zbufalc (cold + 2 + cadd);
- memcpy (znew, zXnames, cold);
- znew[cold] = ' ';
- memcpy (znew + cold + 1, z, cadd + 1);
- ubuffree (zXnames);
- zXnames = znew;
- }
- }
-