NetBSD/gnu/libexec/uucp/uux.c

1281 lines
31 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* uux.c
Prepare to execute a command on a remote system.
Copyright (C) 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA.
The author of the program may be contacted at ian@airs.com or
c/o AIRS, P.O. Box 520, Waltham, MA 02254.
$Log: uux.c,v $
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
initial import of 386bsd-0.1 sources
Revision 1.32 1992/03/15 04:51:17 ian
Keep an array of signals we've received rather than a single variable
Revision 1.31 1992/03/12 19:54:43 ian
Debugging based on types rather than number
Revision 1.30 1992/03/02 15:20:43 ian
Check iSignal before entering fread
Revision 1.29 1992/02/29 04:07:08 ian
Added -j option to uucp and uux
Revision 1.28 1992/02/29 01:06:59 ian
Chip Salzenberg: recheck file permissions before sending
Revision 1.27 1992/02/28 05:06:15 ian
T. William Wells: fsysdep_catch must be a macro
Revision 1.26 1992/02/27 05:40:54 ian
T. William Wells: detach from controlling terminal, handle signals safely
Revision 1.25 1992/02/23 03:26:51 ian
Overhaul to use automatic configure shell script
Revision 1.24 1992/02/08 22:33:32 ian
Only get the current working directory if it's going to be needed
Revision 1.23 1992/02/08 20:33:57 ian
Handle all possible signals raised by abort
Revision 1.22 1992/02/08 03:54:18 ian
Include <string.h> only in <uucp.h>, added 1992 copyright
Revision 1.21 1992/02/02 20:34:36 ian
Niels Baggesen: must check user permissions on access to local files
Revision 1.20 1992/01/21 19:39:12 ian
Chip Salzenberg: uucp and uux start uucico for right system, not any
Revision 1.19 1992/01/15 07:06:29 ian
Set configuration directory in Makefile rather than sysdep.h
Revision 1.18 1992/01/05 03:09:17 ian
Changed abProgram and abVersion to non const to avoid compiler bug
Revision 1.17 1992/01/05 02:51:38 ian
Allocate enough space for log message
Revision 1.16 1991/12/29 04:04:18 ian
Added a bunch of extern definitions
Revision 1.15 1991/12/21 21:16:05 ian
Franc,ois Pinard: remove parentheses from ZSHELLSEPS
Revision 1.14 1991/12/20 03:07:54 ian
Added space and tab to ZSHELLSEPS to stop command at whitespace
Revision 1.13 1991/12/18 03:54:14 ian
Made error messages to terminal appear more normal
Revision 1.12 1991/12/14 16:09:07 ian
Added -l option to uux to link files into the spool directory
Revision 1.11 1991/12/11 03:59:19 ian
Create directories when necessary; don't just assume they exist
Revision 1.10 1991/12/07 03:03:12 ian
Split arguments like sh; request sh execution if any metachars appear
Revision 1.9 1991/11/21 22:17:06 ian
Add version string, print version when printing usage
Revision 1.8 1991/11/15 19:17:32 ian
Hannu Strang: copy stdin using fread/fwrite, not fgets/fputs
Revision 1.7 1991/11/13 23:08:40 ian
Expand remote pathnames in uucp and uux; fix up uux special cases
Revision 1.6 1991/11/08 21:53:17 ian
Brian Campbell: fix argument handling when looking for '-'
Revision 1.5 1991/11/07 22:52:49 ian
Chip Salzenberg: avoid recursive strtok, handle redirection better
Revision 1.4 1991/09/19 03:23:34 ian
Chip Salzenberg: append to private debugging file, don't overwrite it
Revision 1.3 1991/09/19 02:30:37 ian
From Chip Salzenberg: check whether signal is ignored differently
Revision 1.2 1991/09/11 02:33:14 ian
Added ffork argument to fsysdep_run
Revision 1.1 1991/09/10 19:40:31 ian
Initial revision
*/
#include "uucp.h"
#if USE_RCS_ID
char uux_rcsid[] = "$Id: uux.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
#endif
#include <ctype.h>
#include <errno.h>
#include "getopt.h"
#include "system.h"
#include "sysdep.h"
/* External functions. */
extern int fclose ();
/* 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"
/* The program name. */
char abProgram[] = "uux";
/* Long getopt options. */
static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } };
const struct option *_getopt_long_options = asXlongopts;
/* 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;
/* Local functions. */
static void uxusage 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));
static void uxcopy_stdin P((FILE *e));
static void uxrecord_file P((const char *zfile));
static void uxabort P((void));
int
main (argc, argv)
int argc;
char **argv;
{
int iopt;
/* -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;
/* -g: job grade. */
char bgrade = BDEFAULT_UUX_GRADE;
/* -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 i;
int clen;
char *zargs;
char *zarg;
char *zcmd;
char *zexclam;
boolean fgetcwd;
const char *zuser;
struct ssysteminfo sxqtsys;
const struct ssysteminfo *qxqtsys;
boolean fxqtlocal;
char **pzargs;
int calloc_args;
int cargs;
const char *zxqtname;
char abxqt_tname[CFILE_NAME_LEN];
char abxqt_xname[CFILE_NAME_LEN];
boolean fneedshell;
char *zprint;
const char *zcall_system;
boolean fcall_any;
boolean fexit;
/* We need to be able to read a single - as an option, which getopt
won't do. So that we can still use getopt, we run through the
options looking for an option "-"; if we find one we change it to
"-p", which is an equivalent option. */
for (i = 1; i < argc; i++)
{
if (argv[i][0] != '-')
break;
if (argv[i][1] == '\0')
argv[i] = xstrdup ("-p");
else
{
const char *z;
for (z = argv[i] + 1; *z != '\0'; z++)
{
/* If the option takes an argument, and the argument is
not appended, then skip the next argument. */
if (*z == 'a' || *z == 'g' || *z == 'I'
|| *z == 's' || *z == 'x')
{
if (z[1] == '\0')
i++;
break;
}
}
}
}
/* The leading + in the getopt string means to stop processing
options as soon as a non-option argument is seen. */
while ((iopt = getopt (argc, argv, "+a:bcCg:I:jlnprs:Wx:z")) != 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. */
zconfig = optarg;
break;
case 'j':
/* Output jobid. */
fjobid = TRUE;
break;
case 'g':
/* Set job grade. */
bgrade = 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 0:
/* Long option found and flag set. */
break;
default:
uxusage ();
break;
}
}
if (! FGRADE_LEGAL (bgrade))
{
ulog (LOG_ERROR, "Ignoring illegal grade");
bgrade = BDEFAULT_UUX_GRADE;
}
if (optind == argc)
uxusage ();
uread_config (zconfig);
/* 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 = (char *) alloca (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 = (char *) alloca (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 >= calloc_args + 1)
{
calloc_args += 10;
pzargs = (char **) xrealloc ((pointer) pzargs,
calloc_args * sizeof (char *));
}
clen = strcspn (zarg, ZSHELLSEPS);
if (clen > 0)
{
pzargs[cargs] = (char *) xmalloc (clen + 1);
strncpy (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] = (char *) xmalloc (clen + 1);
strncpy (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 'rmail - foo!user' (note that we
don't examine the command itself). */
fgetcwd = FALSE;
for (i = 0; i < cargs; i++)
{
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 (FALSE, fgetcwd);
ulog_fatal_fn (uxabort);
zuser = zsysdep_login_name ();
/* Figure out which system the command is to be executed on. */
zexclam = strchr (zcmd, '!');
if (zexclam == NULL)
{
qxqtsys = &sLocalsys;
fxqtlocal = TRUE;
}
else
{
*zexclam = '\0';
if (*zcmd == '\0' || strcmp (zcmd, zLocalname) == 0)
{
qxqtsys = &sLocalsys;
fxqtlocal = TRUE;
}
else
{
if (fread_system_info (zcmd, &sxqtsys))
qxqtsys = &sxqtsys;
else
{
if (! fUnknown_ok)
ulog (LOG_FATAL, "System %s unknown", zcmd);
qxqtsys = &sUnknown;
sUnknown.zname = zcmd;
}
fxqtlocal = FALSE;
}
zcmd = zexclam + 1;
}
/* Make sure we have a spool directory. */
if (! fsysdep_make_spool_dir (qxqtsys))
uxabort ();
/* Name and open the execute file. If the execution is to occur on
a remote system, we must create a data file and copy it over. */
if (fxqtlocal)
zxqtname = zsysdep_xqt_file_name ();
else
zxqtname = zsysdep_data_file_name (qxqtsys, 'X', abxqt_tname,
(char *) NULL, abxqt_xname);
if (zxqtname == NULL)
uxabort ();
eXxqt_file = esysdep_fopen (zxqtname, FALSE, FALSE, TRUE);
if (eXxqt_file == NULL)
uxabort ();
uxrecord_file (xstrdup (zxqtname));
/* Specify the user. */
uxadd_xqt_line ('U', zuser, 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. */
zcall_system = NULL;
fcall_any = FALSE;
for (i = 0; i < cargs; i++)
{
const char *zsystem, *zconst;
char *zfile;
boolean finput, foutput;
boolean flocal;
/* 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;
/* Get the system name and file name for this file. */
if (zexclam == NULL)
{
zsystem = zLocalname;
zfile = pzargs[i];
flocal = TRUE;
}
else
{
*zexclam = '\0';
zsystem = pzargs[i];
if (zsystem[0] != '\0')
flocal = strcmp (zsystem, zLocalname) == 0;
else
{
zsystem = zLocalname;
flocal = TRUE;
}
zfile = zexclam + 1;
}
/* Add the current working directory to the file name if it's
not an absolute path. */
if (fexpand || flocal)
{
zconst = zsysdep_add_cwd (zfile, flocal);
if (zconst == NULL)
uxabort ();
zfile = xstrdup (zconst);
}
/* Check for output redirection. We strip this argument out,
and create an O command which tells uuxqt where to send the
output. */
if (foutput)
{
if (flocal)
{
if (! fin_directory_list (qxqtsys, zfile,
qxqtsys->zremote_receive, TRUE,
FALSE, (const char *) NULL))
ulog (LOG_FATAL, "Not permitted to create %s", zfile);
}
if (strcmp (zsystem, qxqtsys->zname) == 0)
uxadd_xqt_line ('O', zfile, (const char *) NULL);
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;
const 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 ();
if (fcopy || flink || fxqtlocal)
{
char *zdup;
boolean fdid;
zdata = zsysdep_data_file_name (qxqtsys, bgrade, abtname,
abdname, (char *) NULL);
if (zdata == NULL)
uxabort ();
zdup = xstrdup (zdata);
uxrecord_file (zdup);
fdid = FALSE;
if (flink)
{
boolean fworked;
if (! fsysdep_link (zfile, zdup, &fworked))
uxabort ();
if (fworked)
fdid = TRUE;
else if (fdontcopy)
ulog (LOG_FATAL, "%s: Can't link to spool directory",
zfile);
}
if (! fdid)
{
if (! fcopy_file (zfile, zdup, FALSE, TRUE))
uxabort ();
}
xfree ((pointer) zdup);
zuse = abtname;
}
else
{
/* Make sure the daemon can access the file. */
if (! fsysdep_daemon_access (zfile))
uxabort ();
if (! fin_directory_list (&sLocalsys, zfile,
sLocalsys.zlocal_send,
TRUE, TRUE, zuser))
ulog (LOG_FATAL, "Not permitted to send from %s",
zfile);
zuse = zfile;
zdata = zsysdep_data_file_name (qxqtsys, bgrade,
(char *) NULL, abdname,
(char *) NULL);
if (zdata == NULL)
uxabort ();
strcpy (abtname, "D.0");
}
if (fxqtlocal)
{
if (finput)
uxadd_xqt_line ('I', zuse, (char *) NULL);
else
pzargs[i] = zuse;
}
else
{
uxadd_send_file (zuse, abdname,
fcopy || flink || fxqtlocal ? "C" : "c",
abtname);
if (finput)
{
uxadd_xqt_line ('F', abdname, (char *) NULL);
uxadd_xqt_line ('I', abdname, (char *) NULL);
}
else
{
const char *zbase;
zbase = zsysdep_base_name (zfile);
if (zbase == NULL)
uxabort ();
uxadd_xqt_line ('F', abdname, zbase);
pzargs[i] = xstrdup (zbase);
}
}
}
else if (strcmp (qxqtsys->zname, zsystem) == 0)
{
/* 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 ssysteminfo sfromsys;
const struct ssysteminfo *qfromsys;
char abtname[CFILE_NAME_LEN];
char abdname[CFILE_NAME_LEN];
char *ztemp;
struct scmd s;
const char *zjobid;
/* We need to request a remote file. Make sure we have a
spool directory for the remote system. */
if (! fread_system_info (zsystem, &sfromsys))
{
if (! fUnknown_ok)
ulog (LOG_FATAL, "System %s unknown", zsystem);
sfromsys = sUnknown;
sfromsys.zname = zsystem;
}
qfromsys = &sfromsys;
if (! fsysdep_make_spool_dir (qfromsys))
uxabort ();
/* We want the file to wind up in the spool directory of the
local system (whether the execution is occurring
locally or not); we have to use an absolute file name
here, because otherwise the file would wind up in the
spool directory of the system it is coming from. */
if (! fxqtlocal)
{
if (! fsysdep_make_spool_dir (&sLocalsys))
uxabort ();
}
zconst = zsysdep_data_file_name (&sLocalsys, bgrade,
abtname, (char *) NULL,
(char *) NULL);
if (zconst == NULL)
uxabort ();
/* 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. */
s.bcmd = 'R';
s.pseq = NULL;
s.zfrom = zfile;
s.zto = abtname;
s.zuser = zuser;
s.zoptions = "9";
s.ztemp = "";
s.imode = 0600;
s.znotify = "";
s.cbytes = -1;
zjobid = zsysdep_spool_commands (qfromsys, bgrade, 1, &s);
if (zjobid == NULL)
uxabort ();
if (fjobid)
printf ("%s\n", zjobid);
if (fcall_any)
zcall_system = NULL;
else
{
fcall_any = TRUE;
zcall_system = xstrdup (qfromsys->zname);
}
/* Now if the execution is to occur on another system, we
must create an execute file to send the file there. The
name of the file on the execution system is put into
abdname. */
if (fxqtlocal)
ztemp = abtname;
else
{
const char *zxqt_file;
FILE *e;
/* Get a file name to use on the execution system. */
if (zsysdep_data_file_name (qxqtsys, bgrade,
(char *) NULL, abdname,
(char *) NULL) == NULL)
uxabort ();
ztemp = abdname;
/* The local spool directory was created above, if it
didn't already exist. */
zxqt_file = zsysdep_xqt_file_name ();
if (zxqt_file == NULL)
uxabort ();
/* Queue up a uucp command to be executed locally once
the file arrives. We take advantage of the file
renaming and moving that uuxqt does to remove the
file and avoid the hassles of adding the current
directory. The -W switch to uucp prevents from
adding the current directory to the remote file. */
e = esysdep_fopen (zxqt_file, FALSE, FALSE, TRUE);
if (e == NULL)
uxabort ();
eXclose = e;
uxrecord_file (xstrdup (zxqt_file));
fprintf (e, "U %s %s\n", zuser, zLocalname);
fprintf (e, "F %s foo\n", abtname);
fprintf (e, "C uucp -CW foo %s!%s\n", qxqtsys->zname,
abdname);
eXclose = NULL;
if (fclose (e) != 0)
ulog (LOG_FATAL, "fclose: %s", strerror (errno));
}
/* Tell the command execution to wait until the file has
been received, and tell it the real file name to use. */
if (finput)
{
uxadd_xqt_line ('F', ztemp, (char *) NULL);
uxadd_xqt_line ('I', ztemp, (char *) NULL);
}
else
{
const char *zbase;
zbase = zsysdep_base_name (zfile);
if (zbase == NULL)
uxabort ();
uxadd_xqt_line ('F', ztemp, zbase);
pzargs[i] = xstrdup (zbase);
}
}
}
/* 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)
{
const char *zdata;
char abtname[CFILE_NAME_LEN];
char abdname[CFILE_NAME_LEN];
FILE *e;
zdata = zsysdep_data_file_name (qxqtsys, bgrade, abtname, abdname,
(char *) NULL);
if (zdata == NULL)
uxabort ();
e = esysdep_fopen (zdata, FALSE, FALSE, TRUE);
if (e == NULL)
uxabort ();
eXclose = e;
uxrecord_file (xstrdup (zdata));
uxcopy_stdin (e);
eXclose = NULL;
if (fclose (e) != 0)
ulog (LOG_FATAL, "fclose: %s", strerror (errno));
if (fxqtlocal)
uxadd_xqt_line ('I', abtname, (const char *) NULL);
else
{
uxadd_xqt_line ('F', abdname, (const char *) NULL);
uxadd_xqt_line ('I', abdname, (const char *) NULL);
uxadd_send_file (abtname, abdname, "C", abtname);
}
}
/* Here all the arguments have been determined, so the command can
be written out. If any of the arguments contain shell
metacharacters, we request remote execution with /bin/sh (this is
the 'e' command in the execute file). The default is assumed to
be remote execution with execve. */
fprintf (eXxqt_file, "C %s", zcmd);
fneedshell = FALSE;
if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0')
fneedshell = TRUE;
for (i = 0; i < cargs; i++)
{
if (pzargs[i] != NULL)
{
fprintf (eXxqt_file, " %s", pzargs[i]);
if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0')
fneedshell = TRUE;
}
}
fprintf (eXxqt_file, "\n");
/* Write out all the other miscellaneous junk. */
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 (fretstdin)
uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL);
if (zstatus_file != NULL)
uxadd_xqt_line ('M', zstatus_file, (const char *) NULL);
if (fneedshell)
uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL);
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 (! fxqtlocal)
uxadd_send_file (abxqt_tname, abxqt_xname, "C", abxqt_tname);
/* 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)
{
const char *zjobid;
zjobid = zsysdep_spool_commands (qxqtsys, bgrade, cXcmds, pasXcmds);
if (zjobid == NULL)
{
ulog_close ();
usysdep_exit (FALSE);
}
if (fjobid)
printf ("%s\n", zjobid);
if (fcall_any)
zcall_system = NULL;
else
{
fcall_any = TRUE;
zcall_system = qxqtsys->zname;
}
}
/* If all that worked, make a log file entry. All log file reports
up to this point went to stderr. */
ulog_to_file (TRUE);
ulog_system (qxqtsys->zname);
ulog_user (zuser);
clen = strlen (zcmd) + 2;
for (i = 0; i < cargs; i++)
if (pzargs[i] != NULL)
clen += strlen (pzargs[i]) + 1;
zprint = (char *) alloca (clen);
strcpy (zprint, zcmd);
strcat (zprint, " ");
for (i = 0; i < cargs; i++)
{
if (pzargs[i] != NULL)
{
strcat (zprint, pzargs[i]);
strcat (zprint, " ");
}
}
zprint[strlen (zprint) - 1] = '\0';
ulog (LOG_NORMAL, "Queuing %s", zprint);
ulog_close ();
if (! fuucico)
fexit = TRUE;
else
{
if (zcall_system != NULL)
fexit = fsysdep_run (TRUE, "uucico", "-s", zcall_system);
else if (fcall_any)
fexit = fsysdep_run (TRUE, "uucico", "-r1", (const char *) NULL);
else
fexit = TRUE;
}
usysdep_exit (fexit);
/* Avoid error about not returning a value. */
return 0;
}
/* Report command usage. */
static void
uxusage ()
{
fprintf (stderr,
"Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
abVersion);
fprintf (stderr,
"Usage: uux [options] [-] command\n");
fprintf (stderr,
" -,-p: Read standard input for standard input of command\n");
fprintf (stderr,
" -c: Do not copy local files to spool directory (default)\n");
fprintf (stderr,
" -C: Copy local files to spool directory\n");
fprintf (stderr,
" -l: link local files to spool directory\n");
fprintf (stderr,
" -g grade: Set job grade (must be alphabetic)\n");
fprintf (stderr,
" -n: Do not report completion status\n");
fprintf (stderr,
" -z: Report completion status only on error\n");
fprintf (stderr,
" -r: Do not start uucico daemon\n");
fprintf (stderr,
" -a address: Address to mail status report to\n");
fprintf (stderr,
" -b: Return standard input with status report\n");
fprintf (stderr,
" -s file: Report completion status to file\n");
fprintf (stderr,
" -j: Report job id\n");
fprintf (stderr,
" -x debug: Set debugging level\n");
#if HAVE_TAYLOR_CONFIG
fprintf (stderr,
" -I file: Set configuration file to use (default %s%s)\n",
NEWCONFIGLIB, CONFIGFILE);
#endif /* HAVE_TAYLOR_CONFIG */
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 (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)
const char *zfrom;
const char *zto;
const char *zoptions;
const char *ztemp;
{
struct scmd s;
s.bcmd = 'S';
s.pseq = NULL;
s.zfrom = xstrdup (zfrom);
s.zto = xstrdup (zto);
s.zuser = zsysdep_login_name ();
s.zoptions = xstrdup (zoptions);
s.ztemp = xstrdup (ztemp);
s.imode = 0666;
s.znotify = "";
s.cbytes = -1;
++cXcmds;
pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds,
cXcmds * sizeof (struct scmd));
pasXcmds[cXcmds - 1] = s;
}
/* Copy stdin to a file. This is a separate function because it may
call setjump. */
static void
uxcopy_stdin (e)
FILE *e;
{
CATCH_PROTECT int cread;
char ab[1024];
do
{
int cwrite;
if (fsysdep_catch ())
{
usysdep_start_catch ();
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
fread, 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. */
cread = fread (ab, sizeof (char), sizeof ab, stdin);
}
usysdep_end_catch ();
if (FGOT_SIGNAL ())
uxabort ();
if (cread > 0)
{
cwrite = fwrite (ab, sizeof (char), cread, e);
if (cwrite != cread)
{
if (cwrite == EOF)
ulog (LOG_FATAL, "fwrite: %s", strerror (errno));
else
ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d",
cwrite, 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);
}