The system dependent routines to read execute files for Unix,
and to execute programs. These routines are used by uuxqt.
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.
Revision 1.40 1992/03/17 03:15:40 ian
Pass command to fsysdep_execute as first element of argument array
Revision 1.39 1992/03/16 19:44:45 ian
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:06:37 ian
Marty Shannon: added max-uuxqts command
Revision 1.35 1992/03/11 17:04:53 ian
Jon Zeeff: retry execution later if temporary failure
Revision 1.34 1992/03/11 02:09:57 ian
Franc,ois Pinard: retry fork several times before giving up
Revision 1.33 1992/02/29 01:06:59 ian
Chip Salzenberg: recheck file permissions before sending
Revision 1.32 1992/02/27 05:40:54 ian
T. William Wells: detach from controlling terminal, handle signals safely
Revision 1.31 1992/02/25 15:58:29 ian
Bob Denny: don't warn when trying to open a non-directory
Revision 1.30 1992/02/24 20:07:43 ian
John Theus: some systems don't have <fcntl.h>
Revision 1.29 1992/02/24 04:58:47 ian
Only permit files to be received into directories that are world-writeable
Revision 1.28 1992/02/23 19:50:50 ian
Handle READ and WRITE in Permissions correctly
Revision 1.27 1992/02/23 03:26:51 ian
Overhaul to use automatic configure shell script
Revision 1.26 1992/02/18 04:40:06 ian
Michael Nolan: allow full command path from remote, not just basename
Revision 1.25 1992/02/09 03:14:48 ian
Added HAVE_OLD_DIRECTORIES for systems without readdir routines
Revision 1.24 1992/02/08 03:54:18 ian
Include <string.h> only in <uucp.h>, added 1992 copyright
Revision 1.23 1992/01/15 19:42:42 ian
No longer need to define wait status macros here
Revision 1.22 1992/01/15 19:40:35 ian
Mike Park: handle HAVE_UNION_WAIT correctly and completely
Revision 1.21 1992/01/13 06:11:39 ian
David Nugent: can't declare open or fcntl
Revision 1.20 1992/01/04 21:43:24 ian
Chip Salzenberg: added ALLOW_FILENAME_ARGUMENTS to permit them
Revision 1.19 1992/01/04 04:12:54 ian
David J. Fiander: make sure execution arguments are not bad file names
Revision 1.18 1991/12/29 04:04:18 ian
Added a bunch of extern definitions
Revision 1.17 1991/12/29 00:55:23 ian
Monty Solomon: added HAVE_UNION_WAIT
Revision 1.16 1991/12/22 22:14:19 ian
Monty Solomon: added HAVE_UNISTD_H configuration parameter
Revision 1.15 1991/12/21 21:34:14 ian
Moved fsysdep_file_exists from sys5.unx to sys1.unx
Revision 1.14 1991/12/15 01:58:49 ian
Oleg Tabarovsky: don't abandon processing because of an opendir error
Revision 1.13 1991/12/11 04:17:39 ian
Call fsysdep_make_dirs correctly if chdir (XQTDIR) fails
Revision 1.12 1991/12/11 03:59:19 ian
Create directories when necessary; don't just assume they exist
Revision 1.11 1991/12/07 03:41:44 ian
David J. Fiander: if execve fails, fall back on /bin/sh
Revision 1.10 1991/12/01 02:23:12 ian
Niels Baggesen: don't multiply include <unistd.h>
Revision 1.9 1991/11/26 01:45:42 ian
Marty Shannon: configuration option to not include <sys/wait.h>
Revision 1.8 1991/11/22 06:05:57 ian
Gregory Gulik: fix wait status macro definitions
Revision 1.7 1991/11/16 00:35:43 ian
Case constant arguments to opendir
Revision 1.6 1991/11/07 20:52:33 ian
Chip Salzenberg: pass command as single argument to /bin/sh
Revision 1.5 1991/11/07 19:32:28 ian
Chip Salzenberg: allow LOCKDIR, and check that locking process exists
Revision 1.4 1991/09/19 16:15:58 ian
Chip Salzenberg: configuration option for permitting execution via sh
Revision 1.3 1991/09/19 15:51:01 ian
Chip Salzenberg: pass TZ environment variable to execution process
Revision 1.2 1991/09/19 03:06:04 ian
Chip Salzenberg: put BNU temporary files in system's directory
Revision 1.1 1991/09/10 19:45:50 ian
char sys5_unx_rcsid[] = "$Id: sys5.unx,v 1.40 1992/03/17 03:15:40 ian Rel $";
#if USE_STDIO && HAVE_UNISTD_H
#else /* ! HAVE_DIRENT_H */
#endif /* ! HAVE_DIRENT_H */
#endif /* HAVE_OPENDIR */
/* Get a value for EX_TEMPFAIL. */
/* External functions. */
extern int access (), close (), dup2 (), chdir ();
/* Under the V2 or BSD42 spool directory scheme, all execute files are
in the main spool directory. Under the BSD43 scheme, they are all
in the directory X.. Under the BNU scheme, they are in directories
named after systems. Under the ULTRIX scheme, they are in X.
subdirectories of subdirectories of sys. Under the TAYLOR scheme,
they are all in the subdirectory X. of a directory named after
This means that for BNU, ULTRIX or TAYLOR, we have to search
directories of directories. */
#if SPOOLDIR_V2 | SPOOLDIR_BSD42
#if SPOOLDIR_BNU | SPOOLDIR_TAYLOR
/* Static variables for the execute file scan. */
static DIR *qSxqt_topdir;
static const char *zSdir;
/* Initialize the scan for execute files. The function
usysdep_get_xqt_free will clear the data out when we are done with
the system. This returns FALSE on error. */
qSxqt_topdir = opendir ((char *) ZDIR);
if (qSxqt_topdir == NULL)
ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno));
/* Return the name of the next execute file to read and process. If
this returns NULL, *pferr must be checked. If will be TRUE on
error, FALSE if there are no more files. On a successful return
*pzsystem will be set to the system for which the execute file was
zsysdep_get_xqt (pzsystem, pferr)
if (qSxqt_topdir == NULL)
/* This loop continues until we find a file. */
/* This loop continues until we find a subdirectory to read. */
while (qSxqt_dir == NULL)
qtop = readdir (qSxqt_topdir);
(void) closedir (qSxqt_topdir);
/* No system name may start with a dot (this is enforced by
tisystem in sysinf.c). This allows us to quickly skip
impossible directories. */
if (qtop->d_name[0] == '.')
DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
"zsysdep_get_xqt: Found %s in top directory",
zset = (char *) alloca (strlen (qtop->d_name) + sizeof "sys//X.");
sprintf (zset, "sys/%s/X.", qtop->d_name);
zset = (char *) alloca (strlen (qtop->d_name) + sizeof "/X.");
sprintf (zset, "%s/X.", qtop->d_name);
xfree ((pointer) zSsystem);
zSsystem = xstrdup (qtop->d_name);
qSxqt_dir = opendir (zSdir);
ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno));
DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
"zsysdep_get_xqt: Found %s in subdirectory %s",
/* If we've found an execute file, return it. We have to get
the system name, which is easy for BNU or TAYLOR. For other
spool directory schemes, we have to pull it out of the X.
file name; this would be insecure, except that zsfind_file
clobbers the file name to include the real system name. */
#if SPOOLDIR_BNU | SPOOLDIR_TAYLOR
static char *zsys = NULL;
clen = strlen (q->d_name) - 7;
zsys = (char *) xrealloc ((pointer) zsys, clen + 1);
strncpy (zsys, q->d_name + 2, clen);
/* Set *pferr to TRUE in case zsappend returns NULL. */
zret = zsappend (zSdir, q->d_name);
DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
"zsysdep_get_xqt: Returning %s (system %s)",
/* If we've reached the end of the directory, then if we are
using subdirectories loop around to read the next one,
otherwise we are finished. */
/* Free up the results of an execute file scan, when we're done with
if (qSxqt_topdir != NULL)
(void) closedir (qSxqt_topdir);
(void) closedir (qSxqt_dir);
xfree ((pointer) zSsystem);
/* Get the full pathname of the command to execute, given the list of
permitted commands and the allowed path. */
zsysdep_find_command (zcmd, zcmds, zpath, pferr)
if (strcmp (zcmds, "ALL") != 0)
zcopy = (char *) alloca (strlen (zcmds) + 1);
for (ztok = strtok (zcopy, " ");
ztok = strtok ((char *) NULL, " "))
zslash = strrchr (ztok, '/');
if (strcmp (zslash, zcmd) == 0
|| strcmp (ztok, zcmd) == 0)
/* Hack to get two arguments for zsappend. */
return zsappend (ztok, zslash);
/* If we didn't find this command, get out. */
/* We didn't find an absolute pathname, so we must look through
zcopy = (char *) alloca (strlen (zpath) + 1);
for (ztok = strtok (zcopy, " ");
ztok = strtok ((char *) NULL, " "))
zname = zsappend (ztok, zcmd);
if (access (zname, F_OK) == 0)
#if ! ALLOW_FILENAME_ARGUMENTS
/* Check to see whether an argument specifies a file name; if it does,
make sure that the file may legally be sent and/or received. For
Unix, we do not permit any occurrence of "/../" in the name, nor
may it start with "../". Otherwise, if it starts with "/" we check
against the list of permitted files. */
fsysdep_xqt_check_file (qsys, zfile)
const struct ssysteminfo *qsys;
if (strncmp (zfile, "../", sizeof "../" - 1) == 0
|| strstr (zfile, "/../") != NULL
&& (! fin_directory_list (qsys, zfile, qsys->zremote_send, TRUE,
FALSE, (const char *) NULL)
|| (qsys->zcalled_remote_send != NULL
&& ! fin_directory_list (qsys, zfile,
qsys->zcalled_remote_send,
|| ! fin_directory_list (qsys, zfile, qsys->zremote_receive,
TRUE, FALSE, (const char *) NULL)
|| (qsys->zcalled_remote_receive != NULL
&& ! fin_directory_list (qsys, zfile,
qsys->zcalled_remote_receive,
ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
#endif /* ! ALLOW_FILENAME_ARGUMENTS */
/* Invoke the command specified by an execute file. */
fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
const struct ssysteminfo *qsys;
aidescs[0] = open (zinput, O_RDONLY, 0);
ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
if (! ferr && zoutput != NULL)
aidescs[1] = creat (zoutput, IPRIVATE_FILE_MODE);
ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
*pzerror = zstemp_file (qsys);
aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
if (! fsysdep_make_dirs (*pzerror, FALSE))
aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
if (! ferr && aidescs[2] < 0)
ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
if (! fsdirectory_exists (XQTDIR))
/* The fsysdep_make_dirs function needs a trailing slash,
because it only works on file names. */
zcopy = (char *) alloca (strlen (XQTDIR) + 2);
sprintf (zcopy, "%s/", XQTDIR);
if (! fsysdep_make_dirs (zcopy, FALSE))
if (aidescs[0] != SPAWN_NULL)
(void) close (aidescs[0]);
if (aidescs[1] != SPAWN_NULL)
(void) close (aidescs[1]);
if (aidescs[2] != SPAWN_NULL)
(void) close (aidescs[2]);
/* Pass zchdir as XQTDIR, fnosigs as TRUE, fshell as TRUE if we
aren't already using the shell. */
ipid = isspawn (pazargs, aidescs, FALSE, FALSE, XQTDIR, TRUE,
! fshell, qsys->zpath, qsys->zname, zuser);
if (aidescs[0] != SPAWN_NULL)
(void) close (aidescs[0]);
if (aidescs[1] != SPAWN_NULL)
(void) close (aidescs[1]);
if (aidescs[2] != SPAWN_NULL)
(void) close (aidescs[2]);
ulog (LOG_ERROR, "isspawn: %s", strerror (ierr));
istat = iswait ((unsigned long) ipid, "Execution");
if (istat == EX_TEMPFAIL)
/* Lock a uuxqt process. */
isysdep_lock_uuxqt (zcmd)
sprintf (ab, "LCK.XQT.%d", i);
if (fsdo_lock (ab, TRUE))
sprintf (abcmd, "LXQ.%.9s", zcmd);
abcmd[strcspn (abcmd, " \t/")] = '\0';
if (! fsdo_lock (abcmd, TRUE))
(void) fsdo_unlock (ab, TRUE);
/* Unlock a uuxqt process. */
fsysdep_unlock_uuxqt (iseq, zcmd)
sprintf (ab, "LCK.XQT.%d", iseq);
if (! fsdo_unlock (ab, TRUE))
sprintf (ab, "LXQ.%.9s", zcmd);
ab[strcspn (ab, " \t/")] = '\0';
if (! fsdo_unlock (ab, TRUE))
/* See whether a particular uuxqt command is locked (this depends on
the implementation of fsdo_lock). */
fsysdep_uuxqt_locked (zcmd)
sprintf (ab, "LXQ.%.9s", zcmd);
return access (ab, F_OK) == 0;
/* Lock a particular execute file. */
fsysdep_lock_uuxqt_file (zfile)
zcopy = (char *) alloca (strlen (zfile) + 1);
z = strrchr (zcopy, '/');
return fsdo_lock (zcopy, TRUE);
/* Unlock a particular execute file. */
fsysdep_unlock_uuxqt_file (zfile)
zcopy = (char *) alloca (strlen (zfile) + 1);
z = strrchr (zcopy, '/');
return fsdo_unlock (zcopy, TRUE);
/* Lock the execute directory. */
fsysdep_lock_uuxqt_dir ()
return fsdo_lock ("LCK..XQTDIR", TRUE);
/* Unlock the execute directory and clear it out. */
fsysdep_unlock_uuxqt_dir ()
qdir = opendir ((char *) XQTDIR);
while ((qentry = readdir (qdir)) != NULL)
if (strcmp (qentry->d_name, ".") == 0
|| strcmp (qentry->d_name, "..") == 0)
z = zsappend (XQTDIR, qentry->d_name);
return fsdo_unlock ("LCK..XQTDIR", TRUE);