1371 lines
33 KiB
C
1371 lines
33 KiB
C
|
/* uuxqt.c
|
|||
|
Run uux commands.
|
|||
|
|
|||
|
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: uuxqt.c,v $
|
|||
|
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
|||
|
initial import of 386bsd-0.1 sources
|
|||
|
|
|||
|
Revision 1.43 1992/03/17 04:42:41 ian
|
|||
|
Correct bug in previous patch
|
|||
|
|
|||
|
Revision 1.42 1992/03/17 03:15:40 ian
|
|||
|
Pass command to fsysdep_execute as first element of argument array
|
|||
|
|
|||
|
Revision 1.41 1992/03/17 01:07:15 ian
|
|||
|
Miscellaneous cleanup
|
|||
|
|
|||
|
Revision 1.40 1992/03/16 19:44:45 ian
|
|||
|
Cast result of alloca
|
|||
|
|
|||
|
Revision 1.39 1992/03/15 04:51:17 ian
|
|||
|
Keep an array of signals we've received rather than a single variable
|
|||
|
|
|||
|
Revision 1.38 1992/03/15 01:54:46 ian
|
|||
|
All execs are now done in isspawn, all waits are done in iswait
|
|||
|
|
|||
|
Revision 1.37 1992/03/12 19:54:43 ian
|
|||
|
Debugging based on types rather than number
|
|||
|
|
|||
|
Revision 1.36 1992/03/11 22:34:25 ian
|
|||
|
Chip Salzenberg: support Internet mail addresses in uuxqt replies
|
|||
|
|
|||
|
Revision 1.35 1992/03/11 22:06:37 ian
|
|||
|
Marty Shannon: added max-uuxqts command
|
|||
|
|
|||
|
Revision 1.34 1992/03/11 17:04:53 ian
|
|||
|
Jon Zeeff: retry execution later if temporary failure
|
|||
|
|
|||
|
Revision 1.33 1992/03/11 02:09:19 ian
|
|||
|
Correct bug in previous change
|
|||
|
|
|||
|
Revision 1.32 1992/03/04 02:32:26 ian
|
|||
|
Handle executions on local system
|
|||
|
|
|||
|
Revision 1.31 1992/02/29 04:07:08 ian
|
|||
|
Added -j option to uucp and uux
|
|||
|
|
|||
|
Revision 1.30 1992/02/29 01:06:59 ian
|
|||
|
Chip Salzenberg: recheck file permissions before sending
|
|||
|
|
|||
|
Revision 1.29 1992/02/27 05:40:54 ian
|
|||
|
T. William Wells: detach from controlling terminal, handle signals safely
|
|||
|
|
|||
|
Revision 1.28 1992/02/24 04:58:47 ian
|
|||
|
Only permit files to be received into directories that are world-writeable
|
|||
|
|
|||
|
Revision 1.27 1992/02/23 19:50:50 ian
|
|||
|
Handle READ and WRITE in Permissions correctly
|
|||
|
|
|||
|
Revision 1.26 1992/02/23 03:26:51 ian
|
|||
|
Overhaul to use automatic configure shell script
|
|||
|
|
|||
|
Revision 1.25 1992/02/18 19:03:02 ian
|
|||
|
Pass fdaemon argument correctly to usysdep_initialize
|
|||
|
|
|||
|
Revision 1.24 1992/02/18 04:53:26 ian
|
|||
|
T. William Wells: make sure sh execution uses absolute path
|
|||
|
|
|||
|
Revision 1.23 1992/02/14 21:32:50 ian
|
|||
|
Niels Baggesen: under HAVE_BNU_LOGGING, don't lost system name when dieing
|
|||
|
|
|||
|
Revision 1.22 1992/02/08 22:33:32 ian
|
|||
|
Only get the current working directory if it's going to be needed
|
|||
|
|
|||
|
Revision 1.21 1992/02/08 20:33:57 ian
|
|||
|
Handle all possible signals raised by abort
|
|||
|
|
|||
|
Revision 1.20 1992/02/08 03:54:18 ian
|
|||
|
Include <string.h> only in <uucp.h>, added 1992 copyright
|
|||
|
|
|||
|
Revision 1.19 1992/01/16 17:48:41 ian
|
|||
|
Niels Baggesen: was checking strcmp return incorrectly
|
|||
|
|
|||
|
Revision 1.18 1992/01/15 07:06:29 ian
|
|||
|
Set configuration directory in Makefile rather than sysdep.h
|
|||
|
|
|||
|
Revision 1.17 1992/01/05 03:09:17 ian
|
|||
|
Changed abProgram and abVersion to non const to avoid compiler bug
|
|||
|
|
|||
|
Revision 1.16 1992/01/04 21:43:24 ian
|
|||
|
Chip Salzenberg: added ALLOW_FILENAME_ARGUMENTS to permit them
|
|||
|
|
|||
|
Revision 1.15 1992/01/04 04:12:54 ian
|
|||
|
David J. Fiander: make sure execution arguments are not bad file names
|
|||
|
|
|||
|
Revision 1.14 1991/12/29 04:22:41 ian
|
|||
|
The mailing address was not getting initialized
|
|||
|
|
|||
|
Revision 1.13 1991/12/29 04:04:18 ian
|
|||
|
Added a bunch of extern definitions
|
|||
|
|
|||
|
Revision 1.12 1991/12/20 00:17:38 ian
|
|||
|
Don't process execute files for unknown systems
|
|||
|
|
|||
|
Revision 1.11 1991/12/19 03:52:07 ian
|
|||
|
David Nugent: rescan the list of execute files until nothing can be done
|
|||
|
|
|||
|
Revision 1.10 1991/12/18 03:54:14 ian
|
|||
|
Made error messages to terminal appear more normal
|
|||
|
|
|||
|
Revision 1.9 1991/12/17 04:55:01 ian
|
|||
|
David Nugent: ignore SIGHUP in uucico and uuxqt
|
|||
|
|
|||
|
Revision 1.8 1991/12/09 18:49:06 ian
|
|||
|
Richard Todd: the requestor address is relative to the requesting system
|
|||
|
|
|||
|
Revision 1.7 1991/12/06 23:42:18 ian
|
|||
|
Don't acknowledge success by default
|
|||
|
|
|||
|
Revision 1.6 1991/12/01 01:28:44 ian
|
|||
|
Mitch Mitchell: fixed comment listing supported commands
|
|||
|
|
|||
|
Revision 1.5 1991/11/21 22:17:06 ian
|
|||
|
Add version string, print version when printing usage
|
|||
|
|
|||
|
Revision 1.4 1991/11/07 20:52:33 ian
|
|||
|
Chip Salzenberg: pass command as single argument to /bin/sh
|
|||
|
|
|||
|
Revision 1.3 1991/09/19 16:15:58 ian
|
|||
|
Chip Salzenberg: configuration option for permitting execution via sh
|
|||
|
|
|||
|
Revision 1.2 1991/09/19 02:30:37 ian
|
|||
|
From Chip Salzenberg: check whether signal is ignored differently
|
|||
|
|
|||
|
Revision 1.1 1991/09/10 19:40:31 ian
|
|||
|
Initial revision
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include "uucp.h"
|
|||
|
|
|||
|
#if USE_RCS_ID
|
|||
|
char uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
|||
|
#endif
|
|||
|
|
|||
|
#include <errno.h>
|
|||
|
#include <ctype.h>
|
|||
|
|
|||
|
#include "getopt.h"
|
|||
|
|
|||
|
#include "system.h"
|
|||
|
#include "sysdep.h"
|
|||
|
|
|||
|
/* External functions. */
|
|||
|
extern int fclose ();
|
|||
|
|
|||
|
/* The program name. */
|
|||
|
char abProgram[] = "uuxqt";
|
|||
|
|
|||
|
/* Static variables used to unlock things if we get a fatal error. */
|
|||
|
|
|||
|
static int iQunlock_seq = -1;
|
|||
|
static const char *zQunlock_cmd;
|
|||
|
static const char *zQunlock_file;
|
|||
|
static boolean fQunlock_directory;
|
|||
|
|
|||
|
/* Local functions. */
|
|||
|
|
|||
|
static void uqusage P((void));
|
|||
|
static void uqabort P((void));
|
|||
|
static void uqdo_xqt_file P((const char *zfile,
|
|||
|
const struct ssysteminfo *qsys,
|
|||
|
const char *zcmd, boolean *pfprocessed));
|
|||
|
static void uqcleanup P((const char *zfile, int iflags));
|
|||
|
|
|||
|
/* Long getopt options. */
|
|||
|
|
|||
|
static const struct option asQlongopts[] = { { NULL, 0, NULL, 0 } };
|
|||
|
|
|||
|
const struct option *_getopt_long_options = asQlongopts;
|
|||
|
|
|||
|
int
|
|||
|
main (argc, argv)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
{
|
|||
|
int iopt;
|
|||
|
/* The type of command to execute (NULL for any type). */
|
|||
|
const char *zcmd = NULL;
|
|||
|
/* The configuration file name. */
|
|||
|
const char *zconfig = NULL;
|
|||
|
/* The system to execute commands for. */
|
|||
|
const char *zdosys = NULL;
|
|||
|
boolean fany;
|
|||
|
const char *z;
|
|||
|
const char *zgetsys;
|
|||
|
boolean ferr;
|
|||
|
struct ssysteminfo sreadsys;
|
|||
|
const struct ssysteminfo *qreadsys;
|
|||
|
|
|||
|
while ((iopt = getopt (argc, argv, "c:I:s:x:")) != EOF)
|
|||
|
{
|
|||
|
switch (iopt)
|
|||
|
{
|
|||
|
case 'c':
|
|||
|
/* Set the type of command to execute. */
|
|||
|
zcmd = optarg;
|
|||
|
break;
|
|||
|
|
|||
|
case 'I':
|
|||
|
/* Set the configuration file name. */
|
|||
|
zconfig = optarg;
|
|||
|
break;
|
|||
|
|
|||
|
case 's':
|
|||
|
zdosys = optarg;
|
|||
|
break;
|
|||
|
|
|||
|
case 'x':
|
|||
|
#if DEBUG > 1
|
|||
|
/* Set the debugging level. */
|
|||
|
iDebug |= idebug_parse (optarg);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
case 0:
|
|||
|
/* Long option found and flag set. */
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
uqusage ();
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (optind != argc)
|
|||
|
uqusage ();
|
|||
|
|
|||
|
uread_config (zconfig);
|
|||
|
|
|||
|
#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 (TRUE, FALSE);
|
|||
|
|
|||
|
ulog_to_file (TRUE);
|
|||
|
ulog_fatal_fn (uqabort);
|
|||
|
|
|||
|
/* Limit the number of uuxqt processes, and make sure we're the only
|
|||
|
uuxqt daemon running for this command. */
|
|||
|
iQunlock_seq = isysdep_lock_uuxqt (zcmd);
|
|||
|
if (iQunlock_seq < 0)
|
|||
|
{
|
|||
|
ulog_close ();
|
|||
|
usysdep_exit (TRUE);
|
|||
|
}
|
|||
|
zQunlock_cmd = zcmd;
|
|||
|
|
|||
|
/* Keep scanning the execute files until we don't process any of
|
|||
|
them. */
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
fany = FALSE;
|
|||
|
|
|||
|
/* Look for each execute file, and run it. */
|
|||
|
|
|||
|
if (! fsysdep_get_xqt_init ())
|
|||
|
{
|
|||
|
ulog_close ();
|
|||
|
usysdep_exit (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
qreadsys = NULL;
|
|||
|
|
|||
|
while ((z = zsysdep_get_xqt (&zgetsys, &ferr)) != NULL)
|
|||
|
{
|
|||
|
char *zcopy;
|
|||
|
boolean fprocessed;
|
|||
|
const struct ssysteminfo *qusesys;
|
|||
|
|
|||
|
#if ! HAVE_ALLOCA
|
|||
|
/* Clear out any accumulated alloca buffers. */
|
|||
|
(void) alloca (0);
|
|||
|
#endif
|
|||
|
|
|||
|
/* It would be more efficient to pass zdosys down to the
|
|||
|
routines which retrieve execute files. */
|
|||
|
if (zdosys != NULL && strcmp (zdosys, zgetsys) != 0)
|
|||
|
continue;
|
|||
|
|
|||
|
if (strcmp (zgetsys, zLocalname) == 0)
|
|||
|
qusesys = &sLocalsys;
|
|||
|
else
|
|||
|
{
|
|||
|
if (qreadsys == NULL
|
|||
|
|| strcmp (qreadsys->zname, zgetsys) != 0)
|
|||
|
{
|
|||
|
if (fread_system_info (zgetsys, &sreadsys))
|
|||
|
qreadsys = &sreadsys;
|
|||
|
else
|
|||
|
{
|
|||
|
if (! fUnknown_ok)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR,
|
|||
|
"%s: Execute file for unknown system %s",
|
|||
|
z, zgetsys);
|
|||
|
(void) remove (z);
|
|||
|
continue;
|
|||
|
}
|
|||
|
qreadsys = &sUnknown;
|
|||
|
sUnknown.zname = xstrdup (zgetsys);
|
|||
|
}
|
|||
|
|
|||
|
if (! fsysdep_make_spool_dir (qreadsys))
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
qusesys = qreadsys;
|
|||
|
}
|
|||
|
|
|||
|
/* If we've received a signal, get out of the loop. */
|
|||
|
if (FGOT_SIGNAL ())
|
|||
|
break;
|
|||
|
|
|||
|
zcopy = xstrdup (z);
|
|||
|
|
|||
|
ulog_system (qusesys->zname);
|
|||
|
uqdo_xqt_file (zcopy, qusesys, zcmd, &fprocessed);
|
|||
|
ulog_system ((const char *) NULL);
|
|||
|
ulog_user ((const char *) NULL);
|
|||
|
|
|||
|
if (fprocessed)
|
|||
|
fany = TRUE;
|
|||
|
xfree ((pointer) zcopy);
|
|||
|
}
|
|||
|
|
|||
|
usysdep_get_xqt_free ();
|
|||
|
}
|
|||
|
while (fany && ! FGOT_SIGNAL ());
|
|||
|
|
|||
|
(void) fsysdep_unlock_uuxqt (iQunlock_seq, zcmd);
|
|||
|
iQunlock_seq = -1;
|
|||
|
|
|||
|
ulog_close ();
|
|||
|
|
|||
|
if (FGOT_SIGNAL ())
|
|||
|
ferr = TRUE;
|
|||
|
|
|||
|
usysdep_exit (! ferr);
|
|||
|
|
|||
|
/* Avoid errors about not returning a value. */
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
uqusage ()
|
|||
|
{
|
|||
|
fprintf (stderr,
|
|||
|
"Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
|
|||
|
abVersion);
|
|||
|
fprintf (stderr,
|
|||
|
"Usage: uuxqt [-c cmd] [-I file] [-s system] [-x debug]\n");
|
|||
|
fprintf (stderr,
|
|||
|
" -c cmd: Set type of command to execute\n");
|
|||
|
fprintf (stderr,
|
|||
|
" -s system: Execute commands only for named system\n");
|
|||
|
fprintf (stderr,
|
|||
|
" -x debug: Set debugging level (0 for none, 9 is max)\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);
|
|||
|
}
|
|||
|
|
|||
|
/* This is the abort function called when we get a fatal error. */
|
|||
|
|
|||
|
static void
|
|||
|
uqabort ()
|
|||
|
{
|
|||
|
#if ! HAVE_BNU_LOGGING
|
|||
|
/* When using BNU logging, it's a pain to have no system name. */
|
|||
|
ulog_system ((const char *) NULL);
|
|||
|
#endif
|
|||
|
|
|||
|
ulog_user ((const char *) NULL);
|
|||
|
|
|||
|
if (fQunlock_directory)
|
|||
|
(void) fsysdep_unlock_uuxqt_dir ();
|
|||
|
|
|||
|
if (zQunlock_file != NULL)
|
|||
|
(void) fsysdep_unlock_uuxqt_file (zQunlock_file);
|
|||
|
|
|||
|
if (iQunlock_seq >= 0)
|
|||
|
(void) fsysdep_unlock_uuxqt (iQunlock_seq, zQunlock_cmd);
|
|||
|
|
|||
|
ulog_close ();
|
|||
|
|
|||
|
usysdep_exit (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
/* An execute file is a series of lines. The first character of each
|
|||
|
line is a command. The following commands are defined:
|
|||
|
|
|||
|
C command-line
|
|||
|
I standard-input
|
|||
|
O standard-output [ system ]
|
|||
|
F required-file filename-to-use
|
|||
|
R requestor-address
|
|||
|
U user system
|
|||
|
Z (acknowledge if command failed; default)
|
|||
|
N (no acknowledgement on failure)
|
|||
|
n (acknowledge if command succeeded)
|
|||
|
B (return command input on error)
|
|||
|
e (process with sh)
|
|||
|
E (process with exec)
|
|||
|
M status-file
|
|||
|
# comment
|
|||
|
|
|||
|
Unrecognized commands are ignored. We actually do not recognize
|
|||
|
the Z command, since it requests default behaviour. We always send
|
|||
|
mail on failure, unless the N command appears. We never send mail
|
|||
|
on success, unless the n command appears.
|
|||
|
|
|||
|
This code does not currently support the B or M commands. */
|
|||
|
|
|||
|
/* Command arguments. */
|
|||
|
static const char **azQargs;
|
|||
|
/* Command as a complete string. */
|
|||
|
static char *zQcmd;
|
|||
|
/* Standard input file name. */
|
|||
|
static const char *zQinput;
|
|||
|
/* Standard output file name. */
|
|||
|
static const char *zQoutfile;
|
|||
|
/* Standard output system. */
|
|||
|
static const char *zQoutsys;
|
|||
|
/* Number of required files. */
|
|||
|
static int cQfiles;
|
|||
|
/* Names of required files. */
|
|||
|
static char **azQfiles;
|
|||
|
/* Names required files should be renamed to (NULL if original is OK). */
|
|||
|
static char **azQfiles_to;
|
|||
|
/* Requestor address (this is where mail should be sent). */
|
|||
|
static const char *zQrequestor;
|
|||
|
/* User name. */
|
|||
|
static const char *zQuser;
|
|||
|
/* System name. */
|
|||
|
static const char *zQsystem;
|
|||
|
/* This is set by the N flag, meaning that no acknowledgement should
|
|||
|
be mailed on failure. */
|
|||
|
static boolean fQno_ack;
|
|||
|
/* This is set by the n flag, meaning that acknowledgement should be
|
|||
|
mailed if the command succeeded. */
|
|||
|
static boolean fQsuccess_ack;
|
|||
|
/* This is set by the B flag, meaning that command input should be
|
|||
|
mailed to the requestor if an error occurred. */
|
|||
|
static boolean fQsend_input;
|
|||
|
/* This is set by the E flag, meaning that exec should be used to
|
|||
|
execute the command. */
|
|||
|
static boolean fQuse_exec;
|
|||
|
/* The status should be copied to this file on the requesting host. */
|
|||
|
static const char *zQstatus_file;
|
|||
|
#if ALLOW_SH_EXECUTION
|
|||
|
/* This is set by the e flag, meaning that sh should be used to
|
|||
|
execute the command. */
|
|||
|
static boolean fQuse_sh;
|
|||
|
#endif /* ALLOW_SH_EXECUTION */
|
|||
|
|
|||
|
static enum tcmdtabret tqcmd P((int argc, char **argv, pointer pvar,
|
|||
|
const char *zerr));
|
|||
|
static enum tcmdtabret tqout P((int argc, char **argv, pointer pvar,
|
|||
|
const char *zerr));
|
|||
|
static enum tcmdtabret tqfile P((int argc, char **argv, pointer pvar,
|
|||
|
const char *zerr));
|
|||
|
static enum tcmdtabret tquser P((int argc, char **argv, pointer pvar,
|
|||
|
const char *zerr));
|
|||
|
static enum tcmdtabret tqset P((int argc, char **argv, pointer pvar,
|
|||
|
const char *zerr));
|
|||
|
|
|||
|
static struct scmdtab asQcmds[] =
|
|||
|
{
|
|||
|
{ "C", CMDTABTYPE_FN | 0, NULL, tqcmd },
|
|||
|
{ "I", CMDTABTYPE_STRING, (pointer) &zQinput, NULL },
|
|||
|
{ "O", CMDTABTYPE_FN | 0, NULL, tqout },
|
|||
|
{ "F", CMDTABTYPE_FN | 0, NULL, tqfile },
|
|||
|
{ "R", CMDTABTYPE_STRING, (pointer) &zQrequestor, NULL },
|
|||
|
{ "U", CMDTABTYPE_FN | 3, NULL, tquser },
|
|||
|
{ "N", CMDTABTYPE_FN | 1, (pointer) &fQno_ack, tqset },
|
|||
|
{ "n", CMDTABTYPE_FN | 1, (pointer) &fQsuccess_ack, tqset },
|
|||
|
{ "B", CMDTABTYPE_FN | 1, (pointer) &fQsend_input, tqset },
|
|||
|
#if ALLOW_SH_EXECUTION
|
|||
|
{ "e", CMDTABTYPE_FN | 1, (pointer) &fQuse_sh, tqset },
|
|||
|
#endif
|
|||
|
{ "E", CMDTABTYPE_FN | 1, (pointer) &fQuse_exec, tqset },
|
|||
|
{ "M", CMDTABTYPE_STRING, (pointer) &zQstatus_file, NULL },
|
|||
|
{ NULL, 0, NULL, NULL }
|
|||
|
};
|
|||
|
|
|||
|
/* Handle the C command: store off the arguments. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
static enum tcmdtabret
|
|||
|
tqcmd (argc, argv, pvar, zerr)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
pointer pvar;
|
|||
|
const char *zerr;
|
|||
|
{
|
|||
|
int i;
|
|||
|
int clen;
|
|||
|
|
|||
|
if (argc <= 1)
|
|||
|
return CMDTABRET_FREE;
|
|||
|
|
|||
|
azQargs = (const char **) xmalloc (argc * sizeof (char *));
|
|||
|
clen = 0;
|
|||
|
for (i = 1; i < argc; i++)
|
|||
|
{
|
|||
|
azQargs[i - 1] = argv[i];
|
|||
|
clen += strlen (argv[i]) + 1;
|
|||
|
}
|
|||
|
azQargs[i - 1] = NULL;
|
|||
|
|
|||
|
zQcmd = (char *) xmalloc (clen);
|
|||
|
zQcmd[0] = '\0';
|
|||
|
for (i = 1; i < argc - 1; i++)
|
|||
|
{
|
|||
|
strcat (zQcmd, argv[i]);
|
|||
|
strcat (zQcmd, " ");
|
|||
|
}
|
|||
|
strcat (zQcmd, argv[i]);
|
|||
|
|
|||
|
return CMDTABRET_CONTINUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Handle the O command, which may have one or two arguments. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
static enum tcmdtabret
|
|||
|
tqout (argc, argv, pvar, zerr)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
pointer pvar;
|
|||
|
const char *zerr;
|
|||
|
{
|
|||
|
if (argc != 2 && argc != 3)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
|
|||
|
zerr, argv[0]);
|
|||
|
return CMDTABRET_FREE;
|
|||
|
}
|
|||
|
|
|||
|
zQoutfile = argv[1];
|
|||
|
if (argc == 3)
|
|||
|
zQoutsys = argv[2];
|
|||
|
|
|||
|
return CMDTABRET_CONTINUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Handle the F command, which may have one or two arguments. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
static enum tcmdtabret
|
|||
|
tqfile (argc, argv, pvar, zerr)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
pointer pvar;
|
|||
|
const char *zerr;
|
|||
|
{
|
|||
|
if (argc != 2 && argc != 3)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
|
|||
|
zerr, argv[0]);
|
|||
|
return CMDTABRET_FREE;
|
|||
|
}
|
|||
|
|
|||
|
/* If this file is not in the spool directory, just ignore it. */
|
|||
|
if (! fspool_file (argv[1]))
|
|||
|
return CMDTABRET_FREE;
|
|||
|
|
|||
|
++cQfiles;
|
|||
|
azQfiles = (char **) xrealloc ((pointer) azQfiles,
|
|||
|
cQfiles * sizeof (char *));
|
|||
|
azQfiles_to = (char **) xrealloc ((pointer) azQfiles_to,
|
|||
|
cQfiles * sizeof (char *));
|
|||
|
|
|||
|
azQfiles[cQfiles - 1] = xstrdup (argv[1]);
|
|||
|
if (argc == 3)
|
|||
|
azQfiles_to[cQfiles - 1] = xstrdup (argv[2]);
|
|||
|
else
|
|||
|
azQfiles_to[cQfiles - 1] = NULL;
|
|||
|
|
|||
|
return CMDTABRET_FREE;
|
|||
|
}
|
|||
|
|
|||
|
/* Handle the U command, which takes two arguments. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
static enum tcmdtabret
|
|||
|
tquser (argc, argv, pvar, zerr)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
pointer pvar;
|
|||
|
const char *zerr;
|
|||
|
{
|
|||
|
zQuser = argv[1];
|
|||
|
zQsystem = argv[2];
|
|||
|
return CMDTABRET_CONTINUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Handle various commands which just set boolean variables. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
static enum tcmdtabret
|
|||
|
tqset (argc, argv, pvar, zerr)
|
|||
|
int argc;
|
|||
|
char **argv;
|
|||
|
pointer pvar;
|
|||
|
const char *zerr;
|
|||
|
{
|
|||
|
boolean *pf = (boolean *) pvar;
|
|||
|
|
|||
|
*pf = TRUE;
|
|||
|
return CMDTABRET_FREE;
|
|||
|
}
|
|||
|
|
|||
|
/* The execution processing does a lot of things that have to be
|
|||
|
cleaned up. Rather than try to add the appropriate statements
|
|||
|
to each return point, we keep a set of flags indicating what
|
|||
|
has to be cleaned up. The actual clean up is done by the
|
|||
|
function uqcleanup. */
|
|||
|
|
|||
|
#define REMOVE_FILE (01)
|
|||
|
#define REMOVE_NEEDED (02)
|
|||
|
#define FREE_QINPUT (04)
|
|||
|
|
|||
|
/* Process an execute file. The zfile argument is the name of the
|
|||
|
execute file. The qsys argument describes the system it came from.
|
|||
|
The zcmd argument is the name of the command we are executing (from
|
|||
|
the -c option) or NULL if any command is OK. This sets
|
|||
|
*pfprocessed to TRUE if the file is ready to be executed. */
|
|||
|
|
|||
|
static void
|
|||
|
uqdo_xqt_file (zfile, qsys, zcmd, pfprocessed)
|
|||
|
const char *zfile;
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
const char *zcmd;
|
|||
|
boolean *pfprocessed;
|
|||
|
{
|
|||
|
const char *zcmds;
|
|||
|
const char *zabsolute;
|
|||
|
boolean ferr;
|
|||
|
FILE *e;
|
|||
|
int i;
|
|||
|
int iclean;
|
|||
|
const char *zmail;
|
|||
|
const char *zoutput;
|
|||
|
char abtemp[CFILE_NAME_LEN];
|
|||
|
char abdata[CFILE_NAME_LEN];
|
|||
|
const char *zerror;
|
|||
|
struct ssysteminfo soutsys;
|
|||
|
const struct ssysteminfo *qoutsys;
|
|||
|
boolean fshell;
|
|||
|
char *zfullcmd;
|
|||
|
boolean ftemp;
|
|||
|
|
|||
|
*pfprocessed = FALSE;
|
|||
|
|
|||
|
/* If we're not permitted to execute anything for this system,
|
|||
|
we can just clobber the file without even looking at it. */
|
|||
|
zcmds = qsys->zcmds;
|
|||
|
|
|||
|
if (*zcmds == '\0')
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: No commands permitted for system %s",
|
|||
|
zfile, qsys->zname);
|
|||
|
(void) remove (zfile);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* If we are only willing to execute a particular command, and it
|
|||
|
is not one of those accepted by this system, quit now. */
|
|||
|
if (zcmd != NULL
|
|||
|
&& strcmp (zcmds, "ALL") != 0
|
|||
|
&& strstr (zcmds, zcmd) == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
e = fopen (zfile, "r");
|
|||
|
if (e == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
azQargs = NULL;
|
|||
|
zQcmd = NULL;
|
|||
|
zQinput = NULL;
|
|||
|
zQoutfile = NULL;
|
|||
|
zQoutsys = NULL;
|
|||
|
cQfiles = 0;
|
|||
|
azQfiles = NULL;
|
|||
|
azQfiles_to = NULL;
|
|||
|
zQrequestor = NULL;
|
|||
|
zQuser = NULL;
|
|||
|
zQsystem = NULL;
|
|||
|
fQno_ack = FALSE;
|
|||
|
fQsuccess_ack = FALSE;
|
|||
|
fQsend_input = FALSE;
|
|||
|
fQuse_exec = FALSE;
|
|||
|
zQstatus_file = NULL;
|
|||
|
#if ALLOW_SH_EXECUTION
|
|||
|
fQuse_sh = FALSE;
|
|||
|
#endif
|
|||
|
|
|||
|
uprocesscmds (e, (struct smulti_file *) NULL, asQcmds, zfile, 0);
|
|||
|
|
|||
|
(void) fclose (e);
|
|||
|
|
|||
|
iclean = 0;
|
|||
|
|
|||
|
if (azQargs == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: No command given", zfile);
|
|||
|
uqcleanup (zfile, iclean | REMOVE_FILE);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (zcmd != NULL)
|
|||
|
{
|
|||
|
if (strcmp (zcmd, azQargs[0]) != 0)
|
|||
|
{
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* If there is a lock file for this particular command already,
|
|||
|
it means that some other uuxqt is supposed to handle it. */
|
|||
|
if (fsysdep_uuxqt_locked (azQargs[0]))
|
|||
|
{
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Lock this particular file. */
|
|||
|
|
|||
|
if (! fsysdep_lock_uuxqt_file (zfile))
|
|||
|
{
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
zQunlock_file = zfile;
|
|||
|
|
|||
|
if (zQuser != NULL)
|
|||
|
ulog_user (zQuser);
|
|||
|
else if (zQrequestor != NULL)
|
|||
|
ulog_user (zQrequestor);
|
|||
|
else
|
|||
|
ulog_user ("unknown");
|
|||
|
|
|||
|
/* Make sure that all the required files exist, and get their
|
|||
|
full names in the spool directory. */
|
|||
|
|
|||
|
for (i = 0; i < cQfiles; i++)
|
|||
|
{
|
|||
|
const char *zreal;
|
|||
|
|
|||
|
zreal = zsysdep_spool_file_name (qsys, azQfiles[i]);
|
|||
|
if (zreal == NULL)
|
|||
|
{
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
if (! fsysdep_file_exists (zreal))
|
|||
|
{
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
xfree ((pointer) azQfiles[i]);
|
|||
|
azQfiles[i] = xstrdup (zreal);
|
|||
|
}
|
|||
|
|
|||
|
/* See if we need the execute directory, and lock it if we do. */
|
|||
|
|
|||
|
for (i = 0; i < cQfiles; i++)
|
|||
|
{
|
|||
|
int itries;
|
|||
|
|
|||
|
if (azQfiles_to[i] == NULL)
|
|||
|
continue;
|
|||
|
|
|||
|
for (itries = 0; itries < 5; itries++)
|
|||
|
{
|
|||
|
if (fsysdep_lock_uuxqt_dir ())
|
|||
|
break;
|
|||
|
usysdep_sleep (30);
|
|||
|
}
|
|||
|
if (itries >= 5)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "Could not lock execute directory");
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
fQunlock_directory = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
iclean |= REMOVE_FILE | REMOVE_NEEDED;
|
|||
|
*pfprocessed = TRUE;
|
|||
|
|
|||
|
/* Get the address to mail results to. Prepend the system from
|
|||
|
which the execute file originated, since mail addresses are
|
|||
|
relative to it. */
|
|||
|
|
|||
|
zmail = NULL;
|
|||
|
if (zQrequestor != NULL)
|
|||
|
zmail = zQrequestor;
|
|||
|
else if (zQuser != NULL)
|
|||
|
zmail = zQuser;
|
|||
|
if (zmail != NULL
|
|||
|
&& zQsystem != NULL
|
|||
|
#if HAVE_INTERNET_MAIL
|
|||
|
&& strchr (zmail, '@') == NULL
|
|||
|
#endif
|
|||
|
&& strcmp (zQsystem, zLocalname) != 0)
|
|||
|
{
|
|||
|
char *zset;
|
|||
|
|
|||
|
zset = (char *) alloca (strlen (zQsystem) + strlen (zmail) + 2);
|
|||
|
|
|||
|
sprintf (zset, "%s!%s", zQsystem, zmail);
|
|||
|
zmail = zset;
|
|||
|
}
|
|||
|
|
|||
|
/* Get the pathname to execute. */
|
|||
|
|
|||
|
zabsolute = zsysdep_find_command (azQargs[0], zcmds, qsys->zpath,
|
|||
|
&ferr);
|
|||
|
if (zabsolute == NULL)
|
|||
|
{
|
|||
|
if (ferr)
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* Not permitted. Send mail to requestor. */
|
|||
|
|
|||
|
ulog (LOG_ERROR, "Not permitted to execute %s",
|
|||
|
azQargs[0]);
|
|||
|
|
|||
|
if (zmail != NULL && ! fQno_ack)
|
|||
|
{
|
|||
|
const char *az[20];
|
|||
|
|
|||
|
i = 0;
|
|||
|
az[i++] = "Your execution request failed because you are not";
|
|||
|
az[i++] = " permitted to execute\n\t";
|
|||
|
az[i++] = azQargs[0];
|
|||
|
az[i++] = "\non this system.\n";
|
|||
|
az[i++] = "Execution requested was:\n\t";
|
|||
|
az[i++] = zQcmd;
|
|||
|
az[i++] = "\n";
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution failed", i, az);
|
|||
|
}
|
|||
|
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
{
|
|||
|
char *zcopy;
|
|||
|
|
|||
|
zcopy = (char *) alloca (strlen (zabsolute) + 1);
|
|||
|
strcpy (zcopy, zabsolute);
|
|||
|
zabsolute = zcopy;
|
|||
|
}
|
|||
|
|
|||
|
azQargs[0] = zabsolute;
|
|||
|
|
|||
|
#if ! ALLOW_FILENAME_ARGUMENTS
|
|||
|
|
|||
|
/* Check all the arguments to make sure they don't try to specify
|
|||
|
files they are not permitted to access. */
|
|||
|
|
|||
|
for (i = 1; azQargs[i] != NULL; i++)
|
|||
|
{
|
|||
|
if (! fsysdep_xqt_check_file (qsys, azQargs[i]))
|
|||
|
{
|
|||
|
if (zmail != NULL && ! fQno_ack)
|
|||
|
{
|
|||
|
const char *az[20];
|
|||
|
const char *zfailed;
|
|||
|
|
|||
|
zfailed = azQargs[i];
|
|||
|
i = 0;
|
|||
|
az[i++] = "Your execution request failed because you are not";
|
|||
|
az[i++] = " permitted to refer to file\n\t";
|
|||
|
az[i++] = zfailed;
|
|||
|
az[i++] = "\non this system.\n";
|
|||
|
az[i++] = "Execution requested was:\n\t";
|
|||
|
az[i++] = zQcmd;
|
|||
|
az[i++] = "\n";
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution failed", i, az);
|
|||
|
}
|
|||
|
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif /* ! ALLOW_FILENAME_ARGUMENTS */
|
|||
|
|
|||
|
ulog (LOG_NORMAL, "Executing %s (%s)", zfile, zQcmd);
|
|||
|
|
|||
|
if (zQinput != NULL)
|
|||
|
{
|
|||
|
boolean fspool;
|
|||
|
|
|||
|
fspool = fspool_file (zQinput);
|
|||
|
if (fspool)
|
|||
|
zQinput = zsysdep_spool_file_name (qsys, zQinput);
|
|||
|
else
|
|||
|
zQinput = zsysdep_real_file_name (qsys, zQinput,
|
|||
|
(const char *) NULL);
|
|||
|
if (zQinput == NULL)
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
zQinput = xstrdup (zQinput);
|
|||
|
iclean |= FREE_QINPUT;
|
|||
|
|
|||
|
if (! fspool
|
|||
|
&& ! fin_directory_list (qsys, zQinput,
|
|||
|
qsys->zremote_send, TRUE, TRUE,
|
|||
|
(const char *) NULL))
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "Not permitted to read %s", zQinput);
|
|||
|
|
|||
|
if (zmail != NULL && ! fQno_ack)
|
|||
|
{
|
|||
|
const char *az[20];
|
|||
|
|
|||
|
i = 0;
|
|||
|
az[i++] = "Your execution request failed because you are";
|
|||
|
az[i++] = " not permitted to read\n\t";
|
|||
|
az[i++] = zQinput;
|
|||
|
az[i++] = "\non this system.\n";
|
|||
|
az[i++] = "Execution requested was:\n\t";
|
|||
|
az[i++] = zQcmd;
|
|||
|
az[i++] = "\n";
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution failed", i, az);
|
|||
|
}
|
|||
|
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (zQoutfile == NULL)
|
|||
|
{
|
|||
|
zoutput = NULL;
|
|||
|
qoutsys = NULL;
|
|||
|
}
|
|||
|
else if (zQoutsys != NULL
|
|||
|
&& strcmp (zQoutsys, zLocalname) != 0)
|
|||
|
{
|
|||
|
const char *zdata;
|
|||
|
char *zcopy;
|
|||
|
|
|||
|
/* The output file is destined for some other system, so we must
|
|||
|
use a temporary file to catch standard output. */
|
|||
|
|
|||
|
if (strcmp (zQoutsys, qsys->zname) == 0)
|
|||
|
qoutsys = qsys;
|
|||
|
else
|
|||
|
{
|
|||
|
if (! fread_system_info (zQoutsys, &soutsys))
|
|||
|
{
|
|||
|
if (! fUnknown_ok)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR,
|
|||
|
"Can't send standard output to unknown system %s",
|
|||
|
zQoutsys);
|
|||
|
/* We don't send mail to unknown systems, either.
|
|||
|
Maybe we should. */
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
soutsys = sUnknown;
|
|||
|
soutsys.zname = zQoutsys;
|
|||
|
}
|
|||
|
|
|||
|
qoutsys = &soutsys;
|
|||
|
|
|||
|
if (! fsysdep_make_spool_dir (qoutsys))
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
zdata = zsysdep_data_file_name (qoutsys, BDEFAULT_UUX_GRADE, abtemp,
|
|||
|
abdata, (char *) NULL);
|
|||
|
if (zdata == NULL)
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
zcopy = (char *) alloca (strlen (zdata) + 1);
|
|||
|
strcpy (zcopy, zdata);
|
|||
|
zoutput = zcopy;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
boolean fok;
|
|||
|
char *zcopy;
|
|||
|
|
|||
|
qoutsys = NULL;
|
|||
|
|
|||
|
/* If we permitted the standard output to be redirected into
|
|||
|
the spool directory, people could set up phony commands. */
|
|||
|
|
|||
|
if (fspool_file (zQoutfile))
|
|||
|
fok = FALSE;
|
|||
|
else
|
|||
|
{
|
|||
|
zQoutfile = zsysdep_real_file_name (&sLocalsys, zQoutfile,
|
|||
|
(const char *) NULL);
|
|||
|
if (zQoutfile == NULL)
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* Make sure it's OK to receive this file. Note that this
|
|||
|
means that a locally executed uux (which presumably
|
|||
|
requires remote files) will only be able to create files
|
|||
|
in standard directories. If we don't it this way, users
|
|||
|
could clobber files which uucp has access to; still, it
|
|||
|
would be nice to allow them to direct the output to their
|
|||
|
home directory. */
|
|||
|
|
|||
|
fok = fin_directory_list (qsys, zQoutfile, qsys->zremote_receive,
|
|||
|
TRUE, FALSE, (const char *) NULL);
|
|||
|
}
|
|||
|
|
|||
|
if (! fok)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "Not permitted to write to %s", zQoutfile);
|
|||
|
|
|||
|
if (zmail != NULL && ! fQno_ack)
|
|||
|
{
|
|||
|
const char *az[20];
|
|||
|
|
|||
|
i = 0;
|
|||
|
az[i++] = "Your execution request failed because you are";
|
|||
|
az[i++] = " not permitted to write to\n\t";
|
|||
|
az[i++] = zQoutfile;
|
|||
|
az[i++] = "\non this system.\n";
|
|||
|
az[i++] = "Execution requested was:\n\t";
|
|||
|
az[i++] = zQcmd;
|
|||
|
az[i++] = "\n";
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution failed", i, az);
|
|||
|
}
|
|||
|
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
zcopy = (char *) alloca (strlen (zQoutfile) + 1);
|
|||
|
strcpy (zcopy, zQoutfile);
|
|||
|
zQoutfile = zcopy;
|
|||
|
zoutput = zcopy;
|
|||
|
}
|
|||
|
|
|||
|
/* Move the required files to the execution directory if necessary. */
|
|||
|
|
|||
|
for (i = 0; i < cQfiles; i++)
|
|||
|
{
|
|||
|
if (azQfiles_to[i] != NULL)
|
|||
|
{
|
|||
|
const char *zname;
|
|||
|
|
|||
|
/* Move the file to the execute directory. */
|
|||
|
|
|||
|
zname = zsysdep_in_dir (XQTDIR, azQfiles_to[i]);
|
|||
|
if (zname == NULL)
|
|||
|
{
|
|||
|
/* If we get an error, try again later. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
if (! fsysdep_move_file (azQfiles[i], zname, 0, FALSE,
|
|||
|
(const char *) NULL))
|
|||
|
{
|
|||
|
/* If we get an error, try again later. This may not be
|
|||
|
correct, depending on what kind of error we get. */
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* If we just moved the standard input file, adjust the
|
|||
|
file name. */
|
|||
|
if (zQinput != NULL && strcmp (azQfiles[i], zQinput) == 0)
|
|||
|
{
|
|||
|
xfree ((pointer) zQinput);
|
|||
|
zQinput = xstrdup (zname);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if ALLOW_SH_EXECUTION
|
|||
|
fshell = fQuse_sh;
|
|||
|
#else
|
|||
|
fshell = FALSE;
|
|||
|
#endif
|
|||
|
|
|||
|
/* Get a shell command which uses the full path of the command to
|
|||
|
execute. */
|
|||
|
zfullcmd = (char *) alloca (strlen (zQcmd) + strlen (azQargs[0]) + 2);
|
|||
|
*zfullcmd = '\0';
|
|||
|
for (i = 0; azQargs[i] != NULL; i++)
|
|||
|
{
|
|||
|
strcat (zfullcmd, azQargs[i]);
|
|||
|
strcat (zfullcmd, " ");
|
|||
|
}
|
|||
|
zfullcmd[strlen (zfullcmd) - 1] = '\0';
|
|||
|
|
|||
|
if (! fsysdep_execute (qsys,
|
|||
|
zQuser == NULL ? (const char *) "uucp" : zQuser,
|
|||
|
azQargs, zfullcmd, zQinput, zoutput, fshell,
|
|||
|
&zerror, &ftemp))
|
|||
|
{
|
|||
|
if (ftemp)
|
|||
|
{
|
|||
|
ulog (LOG_NORMAL, "Will retry later (%s)", zfile);
|
|||
|
if (zoutput != NULL)
|
|||
|
(void) remove (zoutput);
|
|||
|
if (zerror != NULL)
|
|||
|
(void) remove (zerror);
|
|||
|
uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED));
|
|||
|
*pfprocessed = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ulog (LOG_NORMAL, "Execution failed (%s)", zfile);
|
|||
|
|
|||
|
if (zmail != NULL && ! fQno_ack)
|
|||
|
{
|
|||
|
const char **pz;
|
|||
|
int cgot;
|
|||
|
FILE *eerr;
|
|||
|
int istart;
|
|||
|
|
|||
|
cgot = 20;
|
|||
|
pz = (const char **) xmalloc (cgot * sizeof (const char *));
|
|||
|
i = 0;
|
|||
|
pz[i++] = "Execution request failed:\n\t";
|
|||
|
pz[i++] = zQcmd;
|
|||
|
pz[i++] = "\n";
|
|||
|
|
|||
|
if (zerror == NULL)
|
|||
|
eerr = NULL;
|
|||
|
else
|
|||
|
eerr = fopen (zerror, "r");
|
|||
|
if (eerr == NULL)
|
|||
|
{
|
|||
|
pz[i++] = "There was no output on standard error\n";
|
|||
|
istart = i;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
char *zline;
|
|||
|
|
|||
|
pz[i++] = "Standard error output was:\n";
|
|||
|
istart = i;
|
|||
|
|
|||
|
while ((zline = zfgets (eerr, FALSE)) != NULL)
|
|||
|
{
|
|||
|
if (i >= cgot)
|
|||
|
{
|
|||
|
cgot += 20;
|
|||
|
pz = ((const char **)
|
|||
|
xrealloc ((pointer) pz,
|
|||
|
cgot * sizeof (const char *)));
|
|||
|
}
|
|||
|
pz[i++] = zline;
|
|||
|
}
|
|||
|
|
|||
|
(void) fclose (eerr);
|
|||
|
}
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution failed", i, pz);
|
|||
|
|
|||
|
for (; istart < i; istart++)
|
|||
|
xfree ((pointer) pz[istart]);
|
|||
|
xfree ((pointer) pz);
|
|||
|
}
|
|||
|
|
|||
|
if (qoutsys != NULL)
|
|||
|
(void) remove (zoutput);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (zmail != NULL && fQsuccess_ack)
|
|||
|
{
|
|||
|
const char *az[20];
|
|||
|
|
|||
|
i = 0;
|
|||
|
az[i++] = "\nExecution request succeeded:\n\t";
|
|||
|
az[i++] = zQcmd;
|
|||
|
az[i++] = "\n";
|
|||
|
|
|||
|
(void) fsysdep_mail (zmail, "Execution succeded", i, az);
|
|||
|
}
|
|||
|
|
|||
|
/* Now we may have to uucp the output to some other machine. */
|
|||
|
|
|||
|
if (qoutsys != NULL)
|
|||
|
{
|
|||
|
struct scmd s;
|
|||
|
|
|||
|
/* Fill in the command structure. */
|
|||
|
|
|||
|
s.bcmd = 'S';
|
|||
|
s.pseq = NULL;
|
|||
|
s.zfrom = abtemp;
|
|||
|
s.zto = zQoutfile;
|
|||
|
if (zQuser != NULL)
|
|||
|
s.zuser = zQuser;
|
|||
|
else
|
|||
|
s.zuser = "uucp";
|
|||
|
if (zmail != NULL && fQsuccess_ack)
|
|||
|
s.zoptions = "Cn";
|
|||
|
else
|
|||
|
s.zoptions = "C";
|
|||
|
s.ztemp = abtemp;
|
|||
|
s.imode = 0666;
|
|||
|
if (zmail != NULL && fQsuccess_ack)
|
|||
|
s.znotify = zmail;
|
|||
|
else
|
|||
|
s.znotify = "";
|
|||
|
/* The number of bytes will be filled in when the file is
|
|||
|
actually sent. */
|
|||
|
s.cbytes = -1;
|
|||
|
|
|||
|
(void) zsysdep_spool_commands (qoutsys, BDEFAULT_UUX_GRADE,
|
|||
|
1, &s);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (zerror != NULL)
|
|||
|
(void) remove (zerror);
|
|||
|
|
|||
|
uqcleanup (zfile, iclean);
|
|||
|
}
|
|||
|
|
|||
|
/* Clean up the results of uqdo_xqt_file. */
|
|||
|
|
|||
|
static void
|
|||
|
uqcleanup (zfile, iflags)
|
|||
|
const char *zfile;
|
|||
|
int iflags;
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
|
|||
|
"uqcleanup: %s, %d", zfile, iflags);
|
|||
|
|
|||
|
if (zQunlock_file != NULL)
|
|||
|
{
|
|||
|
(void) fsysdep_unlock_uuxqt_file (zQunlock_file);
|
|||
|
zQunlock_file = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ((iflags & REMOVE_FILE) != 0)
|
|||
|
(void) remove (zfile);
|
|||
|
|
|||
|
if ((iflags & REMOVE_NEEDED) != 0)
|
|||
|
{
|
|||
|
for (i = 0; i < cQfiles; i++)
|
|||
|
{
|
|||
|
if (azQfiles[i] != NULL)
|
|||
|
(void) remove (azQfiles[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((iflags & FREE_QINPUT) != 0)
|
|||
|
xfree ((pointer) zQinput);
|
|||
|
|
|||
|
if (fQunlock_directory)
|
|||
|
{
|
|||
|
(void) fsysdep_unlock_uuxqt_dir ();
|
|||
|
fQunlock_directory = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < cQfiles; i++)
|
|||
|
{
|
|||
|
xfree ((pointer) azQfiles[i]);
|
|||
|
xfree ((pointer) azQfiles_to[i]);
|
|||
|
}
|
|||
|
|
|||
|
xfree ((pointer) azQargs);
|
|||
|
azQargs = NULL;
|
|||
|
|
|||
|
xfree ((pointer) zQcmd);
|
|||
|
zQcmd = NULL;
|
|||
|
|
|||
|
xfree ((pointer) azQfiles);
|
|||
|
azQfiles = NULL;
|
|||
|
|
|||
|
xfree ((pointer) azQfiles_to);
|
|||
|
azQfiles_to = NULL;
|
|||
|
}
|