NetBSD/gnu/libexec/uucp/config.c
1993-03-21 09:45:37 +00:00

1045 lines
24 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.

/* config.c
Read the configuration file.
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: config.c,v $
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
initial import of 386bsd-0.1 sources
Revision 1.29 1992/03/28 22:06:38 ian
Michael I Bushnell: renamed enum tstatus to avoid header file conflict
Revision 1.28 1992/03/28 21:47:55 ian
David J. MacKenzie: allow backslash to quote newline in config files
Revision 1.27 1992/03/28 04:26:12 ian
David J. MacKenzie: cMaxuuxqts is independent of HAVE_TAYLOR_CONFIG
Revision 1.26 1992/03/18 23:12:37 ian
Handle CMDTABTYPE_FULLSTRING correctly if there are no arguments
Revision 1.25 1992/03/17 01:03:03 ian
Miscellaneous cleanup
Revision 1.24 1992/03/12 19:54:43 ian
Debugging based on types rather than number
Revision 1.23 1992/03/11 22:06:37 ian
Marty Shannon: added max-uuxqts command
Revision 1.22 1992/03/09 05:08:16 ian
Added status for wrong time to call, not used if system can't be called
Revision 1.21 1992/03/04 21:39:04 ian
Local variables in igradecmp have to be integers
Revision 1.20 1992/03/03 06:06:48 ian
T. William Wells: don't complain about missing configuration files
Revision 1.19 1992/02/29 01:06:59 ian
Chip Salzenberg: recheck file permissions before sending
Revision 1.18 1992/02/24 04:58:47 ian
Only permit files to be received into directories that are world-writeable
Revision 1.17 1992/02/08 03:54:18 ian
Include <string.h> only in <uucp.h>, added 1992 copyright
Revision 1.16 1992/01/15 07:06:29 ian
Set configuration directory in Makefile rather than sysdep.h
Revision 1.15 1992/01/14 04:04:17 ian
Chip Salzenberg: strcmp is a macro on AIX
Revision 1.14 1991/12/29 04:04:18 ian
Added a bunch of extern definitions
Revision 1.13 1991/12/29 01:54:46 ian
Terry Gardner: allow a # character to be quoted in a configuration file
Revision 1.12 1991/12/22 20:57:57 ian
Added externs for strcasecmp or strncasecmp
Revision 1.11 1991/12/18 03:54:14 ian
Made error messages to terminal appear more normal
Revision 1.10 1991/12/15 03:42:33 ian
Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
Revision 1.9 1991/12/13 22:43:06 ian
Don't continually allocate and free the list of arguments
Revision 1.8 1991/12/09 18:39:46 ian
Richard Todd: the pushed back line is specific to a particular multi file
Revision 1.7 1991/12/09 16:59:48 ian
Richard Todd: don't warn if special "#" command is unrecognized
Revision 1.6 1991/12/07 18:05:20 ian
Franc,ois Pinard: no limit to number of arguments
Revision 1.5 1991/12/03 02:38:26 ian
Don't treat numbers with leading zeroes as octal
Revision 1.4 1991/12/01 19:35:38 ian
David Nugent: read V2 and BNU files by default even with TAYLOR_CONFIG
Revision 1.3 1991/11/26 02:04:49 ian
Bob Denny: add explicit extern for strcmp and strcasecmp
Revision 1.2 1991/09/19 02:38:21 ian
Chip Salzenberg: V2 and BNU dialcodes files are relative to CONFIGLIB
Revision 1.1 1991/09/10 19:38:34 ian
Initial revision
*/
#include "uucp.h"
#if USE_RCS_ID
char config_rcsid[] = "$Id: config.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
#endif
#include <ctype.h>
#include <errno.h>
#include "system.h"
#include "sysdep.h"
/* Some systems make strcmp a macro, which screws us up since we want
to declare it since we will take its address later. */
#undef strcmp
#undef strncmp
/* External functions. */
extern int strcmp (), strncmp (), strcasecmp (), strncasecmp ();
extern int fclose ();
/* Local functions. */
static void umulti_pushback P((struct smulti_file *, char *));
/* Status strings. These must match enum tstatus_type. */
const char *azStatus[] =
{
"Conversation complete",
"Port unavailable",
"Dial failed",
"Login failed",
"Handshake failed",
"Call failed",
"Talking",
"Wrong time to call"
};
/* Local node name. */
const char *zLocalname;
/* Spool directory. */
const char *zSpooldir = SPOOLDIR;
#if DEBUG > 1
/* Debugging level. */
int iDebug = 0;
/* Debugging file name. */
const char *zDebugfile = DEBUGFILE;
#endif
/* Public directory. */
const char *zPubdir = PUBDIR;
/* Log file name. */
const char *zLogfile = LOGFILE;
/* Statistics file name. */
const char *zStatfile = STATFILE;
/* Dialcode file names. */
char *zDialcodefile;
/* The maximum number of uuxqt processes which may be running at one
time. If this is zero, there is no limit. */
int cMaxuuxqts;
#if HAVE_TAYLOR_CONFIG
/* System file names. */
char *zSysfile;
/* Port file names. */
char *zPortfile;
/* Dialer file names. */
char *zDialfile;
/* Call out login and password file names. */
char *zCallfile;
/* Call in login and password file names. */
char *zPwdfile;
/* Command table used to parse the configuration file. */
static enum tcmdtabret tcadd P((int argc, char **argv, pointer pvar,
const char *zerr));
const struct scmdtab asCmds[] =
{
/* System name. */
{ "nodename", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
{ "hostname", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
{ "uuname", CMDTABTYPE_STRING, (pointer) &zLocalname, NULL },
/* Spool directory. */
{ "spool", CMDTABTYPE_STRING, (pointer) &zSpooldir, NULL },
/* System information files. */
{ "sysfile", CMDTABTYPE_FN | 0, (pointer) &zSysfile, tcadd },
/* Port files. */
{ "portfile", CMDTABTYPE_FN | 0, (pointer) &zPortfile, tcadd },
/* Dial files. */
{ "dialfile", CMDTABTYPE_FN | 0, (pointer) &zDialfile, tcadd },
/* Dialcode files. */
{ "dialcodefile", CMDTABTYPE_FN | 0, (pointer) &zDialcodefile, tcadd },
/* Public directory. */
{ "pubdir", CMDTABTYPE_STRING, (pointer) &zPubdir, NULL },
/* Call out login name and password files. */
{ "callfile", CMDTABTYPE_FN | 0, (pointer) &zCallfile, tcadd },
/* Call in login name and password files. */
{ "passwdfile", CMDTABTYPE_FN | 0, (pointer) &zPwdfile, tcadd },
/* Log file. */
{ "logfile", CMDTABTYPE_STRING, (pointer) &zLogfile, NULL },
/* Statistics file. */
{ "statfile", CMDTABTYPE_STRING, (pointer) &zStatfile, NULL },
#if DEBUG > 1
/* Debugging file. */
{ "debugfile", CMDTABTYPE_STRING, (pointer) &zDebugfile, NULL },
/* Debugging level. */
{ "debug", CMDTABTYPE_FN | 0, (pointer) &iDebug, tidebug_parse },
#endif
/* Command for unknown system. */
{ "unknown", CMDTABTYPE_FN, NULL, tiunknown },
/* Maximum number of uuxqt processes. */
{ "max-uuxqts", CMDTABTYPE_INT, (pointer) &cMaxuuxqts, NULL },
#if HAVE_V2_CONFIG
{ "v2-files", CMDTABTYPE_BOOLEAN, (pointer) &fV2, NULL },
#endif
#if HAVE_BNU_CONFIG
{ "bnu-files", CMDTABTYPE_BOOLEAN, (pointer) &fBnu, NULL },
#endif
/* End marker. */
{ NULL, 0, NULL, NULL }
};
/* Add strings to a string variable, separating with spaces. */
/*ARGSUSED*/
static enum tcmdtabret
tcadd (argc, argv, pvar, zerr)
int argc;
char **argv;
pointer pvar;
const char *zerr;
{
int i;
for (i = 1; i < argc; i++)
uadd_string ((char **) pvar, argv[i], ' ');
return CMDTABRET_FREE;
}
#endif /* HAVE_TAYLOR_CONFIG */
/* Process commands from a stdio file according to a command table.
The character '#' introduces a comment. Exactly one of e and
qmulti must be NULL. If we get the first line of a multi file, we
attempt to process the command "#"; this command will not arise
from a normal command file, and lets the caller take special action
at the start of a new file. If we are reading with zmulti_gets, we
ignore the zerr argument and instead use the name of the file. */
void
uprocesscmds (e, qmulti, qcmds, zerr, iflags)
FILE *e;
struct smulti_file *qmulti;
const struct scmdtab *qcmds;
const char *zerr;
int iflags;
{
while (TRUE)
{
static char **pzargs;
static int calloc_args;
char *zget, *z;
int cargs;
enum tcmdtabret t;
char **pzhold_args;
int chold_alloc_args;
if (e != NULL)
zget = zfgets (e, (iflags & CMDFLAG_BACKSLASH) != 0);
else
{
boolean ffirst;
zget = zmulti_gets (qmulti, &ffirst, &zerr,
(iflags & CMDFLAG_BACKSLASH) != 0);
if (zget != NULL && ffirst)
{
char *zargs;
zargs = (char *) "#";
t = tprocess_one_cmd (1, &zargs, qcmds, zerr,
iflags &~ CMDFLAG_WARNUNRECOG);
if (t == CMDTABRET_EXIT || t == CMDTABRET_FREE_AND_EXIT)
{
umulti_pushback (qmulti, zget);
return;
}
}
}
if (zget == NULL)
return;
/* Any # character not preceeded by a backslash starts a
comment. */
z = zget;
while ((z = strchr (z, '#')) != NULL)
{
if (z == zget || *(z - 1) != '\\')
{
*z = '\0';
break;
}
/* Remove the backslash. */
xmemmove (z - 1, z, strlen (z) + 1);
}
z = zget;
cargs = 0;
while (TRUE)
{
while (*z != '\0' && isspace (BUCHAR (*z)))
z++;
if (*z == '\0')
break;
if (cargs >= calloc_args)
{
calloc_args += 10;
pzargs = (char **) xrealloc ((pointer) pzargs,
calloc_args * sizeof (char *));
}
pzargs[cargs] = z;
++cargs;
while (*z != '\0' && ! isspace (BUCHAR (*z)))
z++;
if (*z == '\0')
break;
*z++ = '\0';
}
if (cargs <= 0)
{
xfree ((pointer) zget);
continue;
}
/* Save off the static variables to allow this function to
be called recursively. */
pzhold_args = pzargs;
chold_alloc_args = calloc_args;
pzargs = NULL;
calloc_args = 0;
t = tprocess_one_cmd (cargs, pzhold_args, qcmds, zerr, iflags);
if (pzargs != NULL)
xfree ((pointer) pzargs);
pzargs = pzhold_args;
calloc_args = chold_alloc_args;
if (t == CMDTABRET_FREE || t == CMDTABRET_FREE_AND_EXIT)
xfree ((pointer) zget);
if (t == CMDTABRET_EXIT || t == CMDTABRET_FREE_AND_EXIT)
return;
}
}
/* Process a single command. */
enum tcmdtabret
tprocess_one_cmd (cargs, azargs, qcmds, zerr, iflags)
int cargs;
char **azargs;
const struct scmdtab *qcmds;
const char *zerr;
int iflags;
{
const struct scmdtab *q;
int (*pfcmp) P((const char *, const char *));
if ((iflags & CMDFLAG_CASESIGNIFICANT) != 0)
pfcmp = strcmp;
else
pfcmp = strcasecmp;
for (q = qcmds; q->zcmd != NULL; q++)
{
int itype;
int callowed;
itype = TTYPE_CMDTABTYPE (q->itype);
if (itype != CMDTABTYPE_PREFIX)
{
if ((*pfcmp) (q->zcmd, azargs[0]) != 0)
continue;
}
else
{
int clen;
clen = strlen (q->zcmd);
if ((iflags & CMDFLAG_CASESIGNIFICANT) != 0)
{
if (strncmp (q->zcmd, azargs[0], clen) != 0)
continue;
}
else
{
if (strncasecmp (q->zcmd, azargs[0], clen) != 0)
continue;
}
}
callowed = CARGS_CMDTABTYPE (q->itype);
if (callowed != 0 && callowed != cargs)
{
if (zerr != NULL)
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
zerr, q->zcmd);
return CMDTABRET_FREE;
}
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_STRING))
{
if (cargs != 1 && cargs != 2)
{
if (zerr != NULL)
ulog (LOG_ERROR, "%s: %s: Wrong number of arguments",
zerr, q->zcmd);
return CMDTABRET_FREE;
}
if (cargs == 1)
*(const char **) q->pvar = "";
else
*(const char **) q->pvar = azargs[1];
return CMDTABRET_CONTINUE;
}
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_INT)
|| itype == TTYPE_CMDTABTYPE (CMDTABTYPE_LONG))
{
long i;
char *zend;
i = strtol (azargs[1], &zend, 10);
if (*zend != '\0')
{
if (zerr != NULL)
ulog (LOG_ERROR, "%s: %s: Bad number", zerr,
q->zcmd);
return CMDTABRET_FREE;
}
if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_INT))
* (int *) q->pvar = (int) i;
else
* (long *) q->pvar = i;
return CMDTABRET_FREE;
}
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_BOOLEAN))
{
char b;
b = azargs[1][0];
if (b == 'y' || b == 'Y' || b == 't' || b == 'T')
* (boolean *) q->pvar = TRUE;
else if (b == 'n' || b == 'N' || b == 'f' || b == 'F')
* (boolean *) q->pvar = FALSE;
else if (zerr != NULL)
ulog (LOG_ERROR, "%s: %s: Bad boolean", zerr,
q->zcmd);
return CMDTABRET_FREE;
}
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_FULLSTRING))
{
int i, clen;
char *zset;
/* Use all the arguments separated by a ' '
character. */
clen = 1;
for (i = 1; i < cargs; i++)
clen += strlen (azargs[i]) + 1;
zset = (char *) xmalloc (clen);
*zset = '\0';
for (i = 1; i < cargs - 1; i++)
{
strcat (zset, azargs[i]);
strcat (zset, " ");
}
if (i < cargs)
strcat (zset, azargs[i]);
* (const char **) q->pvar = zset;
return CMDTABRET_FREE;
}
else if (itype == TTYPE_CMDTABTYPE (CMDTABTYPE_FN)
|| itype == TTYPE_CMDTABTYPE (CMDTABTYPE_PREFIX))
return (*q->ptfn) (cargs, azargs, q->pvar, zerr);
else
{
#if DEBUG > 0
ulog (LOG_FATAL, "tprocess_one_cmd: Can't happen (0x%x)",
itype);
#endif
return CMDTABRET_FREE;
}
}
if ((iflags & CMDFLAG_WARNUNRECOG) != 0
&& zerr != NULL)
ulog (LOG_ERROR, "%s: Unrecognized command %s", zerr, azargs[0]);
return CMDTABRET_FREE;
}
/* Read the configuration file. If we can't open the configuration file,
and we're trying to read the default, don't report an error. This
permits people to not have a configuration file at all if they are
satisfied with the compiled in defaults. */
void
uread_config (zname)
const char *zname;
{
#if HAVE_TAYLOR_CONFIG
FILE *e;
char *zdefault;
zdefault = (char *) alloca (sizeof NEWCONFIGLIB + sizeof CONFIGFILE);
sprintf (zdefault, "%s%s", NEWCONFIGLIB, CONFIGFILE);
/* On UNIX we will be probably be running suid to uucp. We don't want
to let somebody run us and specify some arbitrary file as the
configuration file, since that might let them examine files they
have no access to. */
if (zname != NULL
&& strcmp (zname, zdefault) != 0
&& ! fsysdep_other_config (zname))
{
ulog (LOG_ERROR, "Can't read %s; using %s", zname, zdefault);
zname = zdefault;
}
if (zname == NULL)
zname = zdefault;
e = fopen (zname, "r");
if (e == NULL)
{
if (strcmp (zname, zdefault) != 0)
{
fprintf (stderr, "%s: %s: %s\n", abProgram, zname,
strerror (errno));
/* We haven't yet called usysdep_initialize, so it should be
safe to just exit. */
exit (EXIT_FAILURE);
}
/* Just use defaults. */
}
else
{
uiunknown_start ();
uprocesscmds (e, (struct smulti_file *) NULL, asCmds, zname,
CMDFLAG_BACKSLASH);
(void) fclose (e);
uiunknown_end ();
}
#else /* ! HAVE_TAYLOR_CONFIG */
uiunknown_start ();
uiunknown_end ();
#endif /* ! HAVE_TAYLOR_CONFIG */
if (zLocalname == NULL)
{
zLocalname = zsysdep_local_name ();
if (zLocalname == NULL)
{
fprintf (stderr, "%s: Can't get local node name\n", abProgram);
exit (EXIT_FAILURE);
}
}
uisetup_localsys ();
#if HAVE_TAYLOR_CONFIG
/* Get the defaults for the file names. */
#define SETDEFAULT(z, zfile) \
if (z == NULL) \
{ \
z = (char *) xmalloc (sizeof NEWCONFIGLIB + sizeof zfile - 1); \
strcpy (z, NEWCONFIGLIB); \
strcat (z, zfile); \
if (! fsysdep_file_exists (z)) \
{ \
xfree ((pointer) z); \
z = NULL; \
} \
}
SETDEFAULT (zSysfile, SYSFILE);
SETDEFAULT (zPortfile, PORTFILE);
SETDEFAULT (zDialfile, DIALFILE);
SETDEFAULT (zDialcodefile, DIALCODEFILE);
SETDEFAULT (zPwdfile, PASSWDFILE);
SETDEFAULT (zCallfile, CALLFILE);
#endif /* HAVE_TAYLOR_CONFIG */
#if HAVE_BNU_CONFIG
/* If we are supposed to read standard BNU files, read Sysfiles to
get any nonstandard file names. */
if (fBnu)
ubnu_read_sysfiles ();
#endif /* HAVE_BNU_CONFIG */
/* The format of the dialcodes file is the same for all systems, so
if additional configuration are being used we add the files in
here to save having to do it when the dialcodes file is read. */
#if HAVE_V2_CONFIG
if (fV2)
{
char *z;
z = (char *) alloca (sizeof OLDCONFIGLIB + sizeof V2_DIALCODES);
sprintf (z, "%s%s", OLDCONFIGLIB, V2_DIALCODES);
uadd_string (&zDialcodefile, z, ' ');
}
#endif /* HAVE_V2_CONFIG */
#if HAVE_BNU_CONFIG
if (fBnu)
{
char *z;
z = (char *) alloca (sizeof OLDCONFIGLIB + sizeof BNU_DIALCODES);
sprintf (z, "%s%s", OLDCONFIGLIB, BNU_DIALCODES);
uadd_string (&zDialcodefile, z, ' ');
}
#endif /* HAVE_BNU_CONFIG */
}
/* Add a string to a list of strings separated by a separator
character. */
void
uadd_string (pz, z, bsep)
char **pz;
const char *z;
int bsep;
{
if (*pz == NULL)
*pz = xstrdup (z);
else
{
int clen;
clen = strlen (*pz);
*pz = (char *) xrealloc ((pointer) *pz, clen + strlen (z) + 2);
(*pz)[clen] = (char) bsep;
strcpy (*pz + clen + 1, z);
}
}
#if DEBUG > 1
/* Parse a debugging string. This may be a simple number, which sets
the given number of bits in iDebug, or it may be a series of single
letters. */
static const char * const azDebug_names[] = DEBUG_NAMES;
int
idebug_parse (z)
const char *z;
{
char *zend;
int i, iret;
char *zcopy, *ztok;
i = (int) strtol (z, &zend, 0);
if (*zend == '\0')
{
if (i > 15)
i = 15;
else if (i < 0)
i = 0;
return (1 << i) - 1;
}
zcopy = (char *) alloca (strlen (z) + 1);
strcpy (zcopy, z);
iret = 0;
for (ztok = strtok (zcopy, ",");
ztok != NULL;
ztok = strtok ((char *) NULL, ","))
{
if (strcasecmp (ztok, "all") == 0)
{
iret = DEBUG_MAX;
break;
}
for (i = 0; azDebug_names[i] != NULL; i++)
{
if (strncasecmp (ztok, azDebug_names[i],
strlen (azDebug_names[i])) == 0)
{
iret |= 1 << i;
break;
}
}
if (azDebug_names[i] == NULL)
ulog (LOG_ERROR, "Unrecognized debugging option \"%s\"",
ztok);
}
return iret;
}
/* Parse a debugging string in a configuration file. The pvar
arguments points to the field to set. */
/*ARGSUSED*/
enum tcmdtabret
tidebug_parse (argc, argv, pvar, zerr)
int argc;
char **argv;
pointer pvar;
const char *zerr;
{
int *pidebug = (int *) pvar;
int i;
if (argc == 2 &&
strncasecmp (argv[1], DEBUG_NONE, strlen (DEBUG_NONE)) == 0)
{
*pidebug = 0;
return CMDTABRET_FREE;
}
for (i = 1; i < argc; i++)
*pidebug |= idebug_parse (argv[i]);
return CMDTABRET_FREE;
}
#endif /* DEBUG > 1 */
/* Given a file name that may actually be several file names each
separated with a single space character, we want to be able to read
lines from them as though they were catenated to form a single
file. This set of routines allows us to do that easily, although
only for one set of files at a time. One line can be pushed back,
which can be convenient for the first line of a file. */
struct smulti_file
{
/* Names of next files to open. */
char *z;
/* String to free up when done. */
char *zfree;
/* Current file. */
FILE *e;
/* Current file name. */
char *zname;
/* Next line to return. */
char *znext;
};
struct smulti_file *
qmulti_open (znames)
const char *znames;
{
struct smulti_file *qret;
qret = (struct smulti_file *) xmalloc (sizeof (struct smulti_file));
qret->z = qret->zfree = xstrdup (znames);
qret->zname = NULL;
qret->e = NULL;
qret->znext = NULL;
return qret;
}
/* Read the next line from a multiply opened set of files. */
char *
zmulti_gets (q, pffirst, pzname, fbackslash)
struct smulti_file *q;
boolean *pffirst;
const char **pzname;
boolean fbackslash;
{
if (pffirst != NULL)
*pffirst = FALSE;
if (q->znext != NULL)
{
char *z;
z = q->znext;
q->znext = NULL;
return z;
}
while (TRUE)
{
char *z;
if (q->e != NULL)
{
char *zret;
zret = zfgets (q->e, fbackslash);
if (zret != NULL)
{
if (pzname != NULL)
*pzname = q->zname;
return zret;
}
if (fclose (q->e) != 0)
{
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
q->e = NULL;
return NULL;
}
q->e = NULL;
}
if (*q->z == '\0')
return NULL;
z = q->z;
q->z += strcspn (z, " ");
if (*q->z != '\0')
*q->z++ = '\0';
q->e = fopen (z, "r");
if (q->e == NULL)
{
ulog (LOG_ERROR, "fopen (%s): %s", z, strerror (errno));
return NULL;
}
if (pffirst != NULL)
*pffirst = TRUE;
q->zname = z;
}
}
/* Push back a line so that it is read by the next call to
zmulti_gets. This is sometimes used on the first line of a file in
uprocesscmds. */
static void
umulti_pushback (q, z)
struct smulti_file *q;
char *z;
{
#if DEBUG > 0
if (q->znext != NULL)
ulog (LOG_FATAL, "umulti_pushback: Can't happen");
#endif
q->znext = z;
}
/* Close the multiple file, even though a read is in progress. If
zmulti_gets returns NULL, the files will have been closed. */
boolean
fmulti_close (q)
struct smulti_file *q;
{
boolean fret;
fret = TRUE;
if (q->e != NULL)
{
if (fclose (q->e) != 0)
{
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
fret = FALSE;
}
}
xfree ((pointer) q->zfree);
xfree ((pointer) q);
return fret;
}
/* See whether a file is in a directory list, and make sure the user
has appropriate access. */
boolean
fin_directory_list (qsys, zfile, zdirs, fcheck, freadable, zuser)
const struct ssysteminfo *qsys;
const char *zfile;
const char *zdirs;
boolean fcheck;
boolean freadable;
const char *zuser;
{
char *zcopy;
boolean fmatch;
zcopy = (char *) alloca (strlen (zdirs) + 1);
strcpy (zcopy, zdirs);
fmatch = FALSE;
while (*zcopy != '\0')
{
char *z;
z = zcopy + strcspn (zcopy, " ");
if (*z == '\0')
--z;
else
*z = '\0';
if (*zcopy == '!')
{
if (fsysdep_in_directory (qsys, zfile, zcopy + 1, FALSE,
FALSE, (const char *) NULL))
fmatch = FALSE;
}
else
{
if (fsysdep_in_directory (qsys, zfile, zcopy, fcheck,
freadable, zuser))
fmatch = TRUE;
}
zcopy = z + 1;
}
return fmatch;
}
/* See whether a file is a spool file. Spool file names are specially
crafted to hand around to other UUCP packages. They always begin
with 'C', 'D' or 'X', and the second character is always a period.
The remaining characters are any character that could appear in a
system name. */
boolean
fspool_file (zfile)
const char *zfile;
{
const char *z;
if (*zfile != 'C' && *zfile != 'D' && *zfile != 'X')
return FALSE;
if (zfile[1] != '.')
return FALSE;
for (z = zfile + 2; *z != '\0'; z++)
if (! isalnum (BUCHAR (*z)) && *z != '_' && *z != '-' && *z != '.')
return FALSE;
return TRUE;
}
/* Compare two grades, returning < 0 if the first should be executed
before the second, == 0 if they are the same, and > 0 if the first
should be executed after the second. This code assumes that the
upper case letters appear in sequence and the lower case letters
appear in sequence. */
int
igradecmp (barg1, barg2)
int barg1;
int barg2;
{
int b1, b2;
/* Make sure the arguments are unsigned. */
b1 = (int) BUCHAR (barg1);
b2 = (int) BUCHAR (barg2);
if (isdigit (b1))
{
if (isdigit (b2))
return b1 - b2;
else
return -1;
}
else if (isupper (b1))
{
if (isdigit (b2))
return 1;
else if (isupper (b2))
return b1 - b2;
else
return -1;
}
else
{
if (! islower (b2))
return 1;
else
return b1 - b2;
}
}