1627 lines
41 KiB
C
1627 lines
41 KiB
C
/* 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.3 1995/08/24 05:23:38 jtc Exp $";
|
||
#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;
|
||
}
|
||
}
|