aboutsummaryrefslogtreecommitdiffstats
path: root/gnu/libexec/uucp/libunix
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/libexec/uucp/libunix')
-rw-r--r--gnu/libexec/uucp/libunix/MANIFEST76
-rw-r--r--gnu/libexec/uucp/libunix/Makefile22
-rw-r--r--gnu/libexec/uucp/libunix/access.c83
-rw-r--r--gnu/libexec/uucp/libunix/addbas.c50
-rw-r--r--gnu/libexec/uucp/libunix/app3.c29
-rw-r--r--gnu/libexec/uucp/libunix/app4.c33
-rw-r--r--gnu/libexec/uucp/libunix/basnam.c22
-rw-r--r--gnu/libexec/uucp/libunix/bytfre.c19
-rw-r--r--gnu/libexec/uucp/libunix/chmod.c25
-rw-r--r--gnu/libexec/uucp/libunix/cohtty.c244
-rw-r--r--gnu/libexec/uucp/libunix/cusub.c1163
-rw-r--r--gnu/libexec/uucp/libunix/cwd.c55
-rw-r--r--gnu/libexec/uucp/libunix/detach.c165
-rw-r--r--gnu/libexec/uucp/libunix/dirent.c123
-rw-r--r--gnu/libexec/uucp/libunix/dup2.c69
-rw-r--r--gnu/libexec/uucp/libunix/efopen.c132
-rw-r--r--gnu/libexec/uucp/libunix/epopen.c85
-rw-r--r--gnu/libexec/uucp/libunix/exists.c16
-rw-r--r--gnu/libexec/uucp/libunix/filnam.c376
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.c231
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.h31
-rw-r--r--gnu/libexec/uucp/libunix/ftw.c250
-rw-r--r--gnu/libexec/uucp/libunix/getcwd.c59
-rw-r--r--gnu/libexec/uucp/libunix/indir.c133
-rw-r--r--gnu/libexec/uucp/libunix/init.c394
-rw-r--r--gnu/libexec/uucp/libunix/isdir.c18
-rw-r--r--gnu/libexec/uucp/libunix/isfork.c25
-rw-r--r--gnu/libexec/uucp/libunix/iswait.c159
-rw-r--r--gnu/libexec/uucp/libunix/jobid.c101
-rw-r--r--gnu/libexec/uucp/libunix/lcksys.c41
-rw-r--r--gnu/libexec/uucp/libunix/link.c38
-rw-r--r--gnu/libexec/uucp/libunix/locfil.c95
-rw-r--r--gnu/libexec/uucp/libunix/lock.c477
-rw-r--r--gnu/libexec/uucp/libunix/loctim.c25
-rw-r--r--gnu/libexec/uucp/libunix/mail.c85
-rw-r--r--gnu/libexec/uucp/libunix/mkdir.c58
-rw-r--r--gnu/libexec/uucp/libunix/mkdirs.c49
-rw-r--r--gnu/libexec/uucp/libunix/mode.c33
-rw-r--r--gnu/libexec/uucp/libunix/move.c176
-rw-r--r--gnu/libexec/uucp/libunix/opensr.c244
-rw-r--r--gnu/libexec/uucp/libunix/pause.c96
-rw-r--r--gnu/libexec/uucp/libunix/picksb.c230
-rw-r--r--gnu/libexec/uucp/libunix/portnm.c51
-rw-r--r--gnu/libexec/uucp/libunix/proctm.c197
-rw-r--r--gnu/libexec/uucp/libunix/recep.c197
-rw-r--r--gnu/libexec/uucp/libunix/remove.c13
-rw-r--r--gnu/libexec/uucp/libunix/rename.c27
-rw-r--r--gnu/libexec/uucp/libunix/rmdir.c43
-rw-r--r--gnu/libexec/uucp/libunix/run.c75
-rw-r--r--gnu/libexec/uucp/libunix/seq.c126
-rw-r--r--gnu/libexec/uucp/libunix/serial.c2991
-rw-r--r--gnu/libexec/uucp/libunix/signal.c208
-rw-r--r--gnu/libexec/uucp/libunix/sindir.c26
-rw-r--r--gnu/libexec/uucp/libunix/size.c27
-rw-r--r--gnu/libexec/uucp/libunix/sleep.c14
-rw-r--r--gnu/libexec/uucp/libunix/spawn.c398
-rw-r--r--gnu/libexec/uucp/libunix/splcmd.c115
-rw-r--r--gnu/libexec/uucp/libunix/splnam.c19
-rw-r--r--gnu/libexec/uucp/libunix/spool.c420
-rw-r--r--gnu/libexec/uucp/libunix/srmdir.c112
-rw-r--r--gnu/libexec/uucp/libunix/statsb.c572
-rw-r--r--gnu/libexec/uucp/libunix/status.c212
-rw-r--r--gnu/libexec/uucp/libunix/strerr.c22
-rw-r--r--gnu/libexec/uucp/libunix/time.c32
-rw-r--r--gnu/libexec/uucp/libunix/tmpfil.c83
-rw-r--r--gnu/libexec/uucp/libunix/trunc.c157
-rw-r--r--gnu/libexec/uucp/libunix/uacces.c205
-rw-r--r--gnu/libexec/uucp/libunix/ufopen.c218
-rw-r--r--gnu/libexec/uucp/libunix/ultspl.c21
-rw-r--r--gnu/libexec/uucp/libunix/unknwn.c43
-rw-r--r--gnu/libexec/uucp/libunix/uuto.c31
-rw-r--r--gnu/libexec/uucp/libunix/walk.c59
-rw-r--r--gnu/libexec/uucp/libunix/wldcrd.c212
-rw-r--r--gnu/libexec/uucp/libunix/work.c765
-rw-r--r--gnu/libexec/uucp/libunix/xqtfil.c265
-rw-r--r--gnu/libexec/uucp/libunix/xqtsub.c698
76 files changed, 14489 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/libunix/MANIFEST b/gnu/libexec/uucp/libunix/MANIFEST
new file mode 100644
index 000000000000..d64e79922046
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/MANIFEST
@@ -0,0 +1,76 @@
+Makefile.in
+MANIFEST
+access.c
+addbas.c
+app3.c
+app4.c
+basnam.c
+bytfre.c
+chmod.c
+cohtty.c
+cwd.c
+cusub.c
+detach.c
+dirent.c
+dup2.c
+efopen.c
+epopen.c
+exists.c
+filnam.c
+fsusg.c
+fsusg.h
+ftw.c
+getcwd.c
+indir.c
+init.c
+isdir.c
+isfork.c
+iswait.c
+jobid.c
+lcksys.c
+link.c
+locfil.c
+lock.c
+loctim.c
+mail.c
+mkdir.c
+mkdirs.c
+mode.c
+move.c
+opensr.c
+pause.c
+picksb.c
+portnm.c
+proctm.c
+recep.c
+remove.c
+rename.c
+rmdir.c
+run.c
+seq.c
+serial.c
+signal.c
+sindir.c
+size.c
+sleep.c
+splcmd.c
+splnam.c
+spool.c
+spawn.c
+srmdir.c
+statsb.c
+status.c
+strerr.c
+time.c
+tmpfil.c
+trunc.c
+uacces.c
+ufopen.c
+ultspl.c
+unknwn.c
+uuto.c
+walk.c
+wldcrd.c
+work.c
+xqtfil.c
+xqtsub.c
diff --git a/gnu/libexec/uucp/libunix/Makefile b/gnu/libexec/uucp/libunix/Makefile
new file mode 100644
index 000000000000..3a6750b17164
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/Makefile
@@ -0,0 +1,22 @@
+# This subdirectory contains Unix specific support functions.
+# $Id: Makefile,v 1.1 1993/08/05 18:23:34 conklin Exp $
+
+LIB= unix
+SRCS= access.c addbas.c app3.c app4.c basnam.c bytfre.c cwd.c \
+ chmod.c cohtty.c cusub.c detach.c efopen.c epopen.c exists.c \
+ filnam.c fsusg.c indir.c init.c isdir.c isfork.c iswait.c \
+ jobid.c lcksys.c link.c locfil.c lock.c loctim.c mail.c \
+ mkdirs.c mode.c move.c opensr.c pause.c picksb.c portnm.c \
+ proctm.c recep.c run.c seq.c serial.c signal.c sindir.c size.c \
+ sleep.c spawn.c splcmd.c splnam.c spool.c srmdir.c statsb.c \
+ status.c time.c tmpfil.c trunc.c uacces.c ufopen.c ultspl.c \
+ unknwn.c uuto.c walk.c wldcrd.c work.c xqtfil.c xqtsub.c ftw.c
+CFLAGS+= -I$(.CURDIR)/../common_sources \
+ -DOWNER=\"$(owner)\" -DSBINDIR=\"$(sbindir)\"
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libunix/access.c b/gnu/libexec/uucp/libunix/access.c
new file mode 100644
index 000000000000..c2c0eef21084
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/access.c
@@ -0,0 +1,83 @@
+/* access.c
+ Check access to files by the user and by the daemon. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See if the user has access to a file, to prevent the setuid uucp
+ and uux programs handing out unauthorized access. */
+
+boolean
+fsysdep_access (zfile)
+ const char *zfile;
+{
+ if (access (zfile, R_OK) == 0)
+ return TRUE;
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (errno));
+ return FALSE;
+}
+
+/* See if the daemon has access to a file. This is called if a file
+ is not being transferred to the spool directory, since if the
+ daemon does not have access the later transfer will fail. We
+ assume that the daemon will have the same euid (or egid) as the one
+ we are running under. If our uid (gid) and euid (egid) are the
+ same, we assume that we have access. Note that is not important
+ for security, since the check will be (implicitly) done again when
+ the daemon tries to transfer the file. This routine should work
+ whether the UUCP programs are installed setuid or setgid. */
+
+boolean
+fsysdep_daemon_access (zfile)
+ const char *zfile;
+{
+ struct stat s;
+ uid_t ieuid, iuid, iegid, igid;
+ boolean fok;
+
+ ieuid = geteuid ();
+ if (ieuid == 0)
+ return TRUE;
+ iuid = getuid ();
+ iegid = getegid ();
+ igid = getgid ();
+
+ /* If our effective uid and gid are the same as our real uid and
+ gid, we assume the daemon will have access to the file. */
+ if (ieuid == iuid && iegid == igid)
+ return TRUE;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+
+ /* If our euid is not our uid, but it is the file's uid, see if the
+ owner has read access. Otherwise, if our egid is not our gid,
+ but it is the file's gid, see if the group has read access.
+ Otherwise, see if the world has read access. We know from the
+ above check that at least one of our euid and egid are different,
+ so that is the only one we want to check. This check could fail
+ if the UUCP programs were both setuid and setgid, but why would
+ they be? */
+ if (ieuid != iuid && ieuid == s.st_uid)
+ fok = (s.st_mode & S_IRUSR) != 0;
+ else if (iegid != igid && iegid == s.st_gid)
+ fok = (s.st_mode & S_IRGRP) != 0;
+ else
+ fok = (s.st_mode & S_IROTH) != 0;
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "%s: cannot be read by daemon", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/addbas.c b/gnu/libexec/uucp/libunix/addbas.c
new file mode 100644
index 000000000000..8597918a3c95
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/addbas.c
@@ -0,0 +1,50 @@
+/* addbas.c
+ If we have a directory, add in a base name. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* If we have a directory, add a base name. */
+
+char *
+zsysdep_add_base (zfile, zname)
+ const char *zfile;
+ const char *zname;
+{
+ size_t clen;
+ const char *zlook;
+ char *zfree;
+ char *zret;
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "zsysdep_add_base: %s: Can't happen", zfile);
+#endif
+
+ clen = strlen (zfile);
+
+ if (zfile[clen - 1] != '/')
+ {
+ if (! fsysdep_directory (zfile))
+ return zbufcpy (zfile);
+ zfree = NULL;
+ }
+ else
+ {
+ /* Trim out the trailing '/'. */
+ zfree = zbufcpy (zfile);
+ zfree[clen - 1] = '\0';
+ zfile = zfree;
+ }
+
+ zlook = strrchr (zname, '/');
+ if (zlook != NULL)
+ zname = zlook + 1;
+
+ zret = zsysdep_in_dir (zfile, zname);
+ ubuffree (zfree);
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/app3.c b/gnu/libexec/uucp/libunix/app3.c
new file mode 100644
index 000000000000..5c0b58938515
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/app3.c
@@ -0,0 +1,29 @@
+/* app3.c
+ Stick two directories and a file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+char *
+zsappend3 (zdir1, zdir2, zfile)
+ const char *zdir1;
+ const char *zdir2;
+ const char *zfile;
+{
+ size_t cdir1, cdir2, cfile;
+ char *zret;
+
+ cdir1 = strlen (zdir1);
+ cdir2 = strlen (zdir2);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir1 + cdir2 + cfile + 3);
+ memcpy (zret, zdir1, cdir1);
+ memcpy (zret + cdir1 + 1, zdir2, cdir2);
+ memcpy (zret + cdir1 + cdir2 + 2, zfile, cfile);
+ zret[cdir1] = '/';
+ zret[cdir1 + cdir2 + 1] = '/';
+ zret[cdir1 + cdir2 + cfile + 2] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/app4.c b/gnu/libexec/uucp/libunix/app4.c
new file mode 100644
index 000000000000..a3b3787f68fd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/app4.c
@@ -0,0 +1,33 @@
+/* app4.c
+ Stick three directories and a file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+char *
+zsappend4 (zdir1, zdir2, zdir3, zfile)
+ const char *zdir1;
+ const char *zdir2;
+ const char *zdir3;
+ const char *zfile;
+{
+ size_t cdir1, cdir2, cdir3, cfile;
+ char *zret;
+
+ cdir1 = strlen (zdir1);
+ cdir2 = strlen (zdir2);
+ cdir3 = strlen (zdir3);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir1 + cdir2 + cdir3 + cfile + 4);
+ memcpy (zret, zdir1, cdir1);
+ memcpy (zret + cdir1 + 1, zdir2, cdir2);
+ memcpy (zret + cdir1 + cdir2 + 2, zdir3, cdir3);
+ memcpy (zret + cdir1 + cdir2 + cdir3 + 3, zfile, cfile);
+ zret[cdir1] = '/';
+ zret[cdir1 + cdir2 + 1] = '/';
+ zret[cdir1 + cdir2 + cdir3 + 2] = '/';
+ zret[cdir1 + cdir2 + cdir3 + cfile + 3] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/basnam.c b/gnu/libexec/uucp/libunix/basnam.c
new file mode 100644
index 000000000000..c61fcaa8de61
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/basnam.c
@@ -0,0 +1,22 @@
+/* basnam.c
+ Get the base name of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Get the base name of a file name. */
+
+char *
+zsysdep_base_name (zfile)
+ const char *zfile;
+{
+ const char *z;
+
+ z = strrchr (zfile, '/');
+ if (z != NULL)
+ return zbufcpy (z + 1);
+ return zbufcpy (zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/bytfre.c b/gnu/libexec/uucp/libunix/bytfre.c
new file mode 100644
index 000000000000..568eebe0307a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/bytfre.c
@@ -0,0 +1,19 @@
+/* bytfre.c
+ Get the number of bytes free on a file system. */
+
+#include "uucp.h"
+
+#include "system.h"
+#include "sysdep.h"
+#include "fsusg.h"
+
+long
+csysdep_bytes_free (zfile)
+ const char *zfile;
+{
+ struct fs_usage s;
+
+ if (get_fs_usage ((char *) zfile, (char *) NULL, &s) < 0)
+ return -1;
+ return s.fsu_bavail * (long) 512;
+}
diff --git a/gnu/libexec/uucp/libunix/chmod.c b/gnu/libexec/uucp/libunix/chmod.c
new file mode 100644
index 000000000000..cf69f3eb0140
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/chmod.c
@@ -0,0 +1,25 @@
+/* chmod.c
+ Change the mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Change the mode of a file. */
+
+boolean
+fsysdep_change_mode (zfile, imode)
+ const char *zfile;
+ unsigned int imode;
+{
+ if (chmod ((char *) zfile, imode) < 0)
+ {
+ ulog (LOG_ERROR, "chmod (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/cohtty.c b/gnu/libexec/uucp/libunix/cohtty.c
new file mode 100644
index 000000000000..a7aec1cae338
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cohtty.c
@@ -0,0 +1,244 @@
+/* Coherent tty locking support. This file was contributed by Bob
+ Hemedinger <bob@dalek.mwc.com> of Mark Williams Corporation and
+ lightly edited by Ian Lance Taylor. */
+
+/* The bottom part of this file is lock.c.
+ * This is a hacked lock.c. A full lock.c can be found in the libmisc sources
+ * under /usr/src/misc.tar.Z.
+ *
+ * These are for checking for the existence of locks:
+ * lockexist(resource)
+ * lockttyexist(ttyname)
+ */
+
+#include "uucp.h"
+
+#if HAVE_COHERENT_LOCKFILES
+
+/* cohtty.c: Given a serial device name, read /etc/ttys and determine if
+ * the device is already enabled. If it is, disable the
+ * device and return a string so that it can be re-enabled
+ * at the completion of the uucico session as part of the
+ * function that resets the serial device before uucico
+ * terminates.
+ *
+ */
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <access.h>
+
+/* fscoherent_disable_tty() is a COHERENT specific function. It takes the name
+ * of a serial device and then scans /etc/ttys for a match. If it finds one,
+ * it checks the first field of the entry. If it is a '1', then it will disable
+ * the port and set a flag. The flag will be checked later when uucico wants to
+ * reset the serial device to see if the device needs to be re-enabled.
+ */
+
+boolean
+fscoherent_disable_tty (zdevice, pzenable)
+ const char *zdevice;
+ char **pzenable;
+{
+
+
+struct ttyentry{ /* this is an /etc/ttys entry */
+ char enable_disable[1];
+ char remote_local[1];
+ char baud_rate[1];
+ char tty_device[16];
+};
+
+struct ttyentry sought_tty;
+
+int x,y,z; /* dummy */
+FILE * infp; /* this will point to /etc/ttys */
+char disable_command[66]; /* this will be the disable command
+ * passed to the system.
+ */
+char enable_device[16]; /* this will hold our device name
+ * to enable.
+ */
+
+ *pzenable = NULL;
+
+ strcpy(enable_device,""); /* initialize our strings */
+ strcpy(sought_tty.tty_device,"");
+
+ if( (infp = fopen("/etc/ttys","r")) == NULL){
+ ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n");
+ return FALSE;
+ }
+
+ while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){
+ sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0';
+ strcpy(enable_device,sought_tty.tty_device);
+
+ /* we must strip away the suffix to the com port name or
+ * we will never find a match. For example, if we are passed
+ * /dev/com4l to call out with and the port is already enabled,
+ * 9/10 the port enabled will be com4r. After we strip away the
+ * suffix of the port found in /etc/ttys, then we can test
+ * if the base port name appears in the device name string
+ * passed to us.
+ */
+
+ for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){
+ if(isdigit(sought_tty.tty_device[z])){
+ break;
+ }
+ }
+ y = strlen(sought_tty.tty_device);
+ for(x = z+1 ; x <= y; x++){
+ sought_tty.tty_device[x] = '\0';
+ }
+
+
+/* ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */
+ if(strstr(zdevice, sought_tty.tty_device)){
+ if(sought_tty.enable_disable[0] == '1'){
+ ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n",
+ zdevice, sought_tty.tty_device);
+ sprintf(disable_command, "/etc/disable %s",enable_device);
+ {
+ pid_t ipid;
+ const char *azargs[3];
+ int aidescs[3];
+
+ azargs[0] = "/etc/disable";
+ azargs[1] = enable_device;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+ ipid = ixsspawn (azargs, aidescs, TRUE,
+ FALSE,
+ (const char *) NULL, TRUE,
+ TRUE,
+ (const char *) NULL,
+ (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ x = 1;
+ else
+ x = ixswait ((unsigned long) ipid,
+ (const char *) NULL);
+ }
+ *pzenable = zbufalc (sizeof "/dev/"
+ + strlen (enable_device));
+ sprintf(*pzenable,"/dev/%s", enable_device);
+/* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */
+ return(x==0? TRUE : FALSE); /* disable either failed
+ or succeded */
+ }else{
+ return FALSE; /* device in tty entry not enabled */
+ }
+ }
+ }
+ return FALSE; /* no ttys entry found */
+}
+
+/* The following is COHERENT 4.0 specific. It is used to test for any
+ * existing lockfiles on a port which would have been created by init
+ * when a user logs into a port.
+ */
+
+#define LOCKSIG 9 /* Significant Chars of Lockable Resources. */
+#define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */
+
+#define LOCKPRE "LCK.."
+#define PIDLEN 6 /* Maximum length of string representing a pid. */
+
+#ifndef LOCKDIR
+#define LOCKDIR SPOOLDIR
+#endif
+
+/* There is a special version of DEVMASK for the PE multiport driver
+ * because of the peculiar way it uses the minor device number. For
+ * all other drivers, the lower 5 bits describe the physical port--
+ * the upper 3 bits give attributes for the port.
+ */
+
+#define PE_DRIVER 21 /* Major device number for the PE driver. */
+#define PE_DEVMASK 0x3f /* PE driver minor device mask. */
+#define DEVMASK 0x1f /* Minor device mask. */
+
+/*
+ * Generates a resource name for locking, based on the major number
+ * and the lower 4 bits of the minor number of the tty device.
+ *
+ * Builds the name in buff as two "." separated decimal numbers.
+ * Returns NULL on failure, buff on success.
+ */
+static char *
+gen_res_name(path, buff)
+char *path;
+char *buff;
+{
+ struct stat sbuf;
+ int status;
+
+ if (0 != (status = stat(path, &sbuf))) {
+ /* Can't stat the file. */
+ return (NULL);
+ }
+
+ if (PE_DRIVER == major(sbuf.st_rdev)) {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ PE_DEVMASK & minor(sbuf.st_rdev));
+ } else {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ DEVMASK & minor(sbuf.st_rdev));
+ }
+
+ return(buff);
+} /* gen_res_name */
+
+/*
+ * lockexist(resource) char *resource;
+ *
+ * Test for existance of a lock on the given resource.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+
+static boolean
+lockexist(resource)
+const char *resource;
+{
+ char lockfn[LOKFLEN];
+
+ if ( resource == NULL )
+ return(0);
+ sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
+
+ return (!access(lockfn, AEXISTS));
+} /* lockexist() */
+
+/*
+ * lockttyexist(ttyname) char *ttyname;
+ *
+ * Test for existance of a lock on the given tty.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+boolean
+lockttyexist(ttyn)
+const char *ttyn;
+{
+ char resource[LOKFLEN];
+ char filename[LOKFLEN];
+
+ sprintf(filename, "/dev/%s", ttyn);
+ if (NULL == gen_res_name(filename, resource)){
+ return(0); /* Non-existent tty can not be locked :-) */
+ }
+
+ return(lockexist(resource));
+} /* lockttyexist() */
+
+#endif /* HAVE_COHERENT_LOCKFILES */
diff --git a/gnu/libexec/uucp/libunix/cusub.c b/gnu/libexec/uucp/libunix/cusub.c
new file mode 100644
index 000000000000..d1110fd5c7b4
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cusub.c
@@ -0,0 +1,1163 @@
+/* cusub.c
+ System dependent routines for cu.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/05 18:23:44 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+#include "cu.h"
+#include "conn.h"
+#include "prot.h"
+
+#include <errno.h>
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Local variables. */
+
+/* The EOF character, as set by fsysdep_terminal_raw. */
+static char bSeof;
+
+/* The SUSP character, as set by fsysdep_terminal_raw. */
+static char bStstp;
+
+/* Local functions. */
+
+static const char *zsport_line P((const struct uuconf_port *qport));
+static void uscu_child P((struct sconnection *qconn, int opipe));
+static RETSIGTYPE uscu_alarm P((int isig));
+static int cscu_escape P((char *pbcmd, const char *zlocalname));
+static RETSIGTYPE uscu_alarm_kill P((int isig));
+
+/* Return the device name for a port, or NULL if none. */
+
+static const char *
+zsport_line (qport)
+ const struct uuconf_port *qport;
+{
+ const char *zline;
+
+ if (qport == NULL)
+ return NULL;
+
+ switch (qport->uuconf_ttype)
+ {
+ default:
+ case UUCONF_PORTTYPE_STDIN:
+ return NULL;
+ case UUCONF_PORTTYPE_MODEM:
+ zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_DIRECT:
+ zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ return NULL;
+ }
+
+ if (zline == NULL)
+ zline = qport->uuconf_zname;
+ return zline;
+}
+
+/* Check whether the user has legitimate access to a port. */
+
+boolean
+fsysdep_port_access (qport)
+ struct uuconf_port *qport;
+{
+ const char *zline;
+ char *zfree;
+ boolean fret;
+
+ zline = zsport_line (qport);
+ if (zline == NULL)
+ return TRUE;
+
+ zfree = NULL;
+ if (*zline != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree, "/dev/%s", zline);
+ zline = zfree;
+ }
+
+ fret = access (zline, R_OK | W_OK) == 0;
+ ubuffree (zfree);
+ return fret;
+}
+
+/* Return whether the given port is named by the given line. */
+
+boolean
+fsysdep_port_is_line (qport, zline)
+ struct uuconf_port *qport;
+ const char *zline;
+{
+ const char *zpline;
+ char *zfree1, *zfree2;
+ boolean fret;
+
+ zpline = zsport_line (qport);
+ if (zpline == NULL)
+ return FALSE;
+
+ if (strcmp (zline, zpline) == 0)
+ return TRUE;
+
+ zfree1 = NULL;
+ zfree2 = NULL;
+ if (*zline != '/')
+ {
+ zfree1 = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree1, "/dev/%s", zline);
+ zline = zfree1;
+ }
+ if (*zpline != '/')
+ {
+ zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline));
+ sprintf (zfree2, "/dev/%s", zpline);
+ zpline = zfree2;
+ }
+
+ fret = strcmp (zline, zpline) == 0;
+ ubuffree (zfree1);
+ ubuffree (zfree2);
+ return fret;
+}
+
+/* The cu program wants the system dependent layer to handle the
+ details of copying data from the communications port to the
+ terminal. This copying need only be done while executing
+ fsysdep_cu. On Unix, however, we set up a subprocess to do it all
+ the time. This subprocess must be controllable via the
+ fsysdep_cu_copy function.
+
+ We keep a pipe open to the subprocess. When we want it to stop we
+ send it a signal, and then wait for it to write a byte to us over
+ the pipe. */
+
+/* The subprocess pid. */
+static volatile pid_t iSchild;
+
+/* The pipe from the subprocess. */
+static int oSpipe;
+
+/* When we tell the child to stop, it sends this. */
+#define CHILD_STOPPED ('S')
+
+/* When we tell the child to start, it sends this. */
+#define CHILD_STARTED ('G')
+
+/* Initialize the subprocess, and have it start copying data. */
+
+boolean
+fsysdep_cu_init (qconn)
+ struct sconnection *qconn;
+{
+ int ai[2];
+
+ /* Write out anything we may have buffered up during the chat
+ script. We do this before forking the child only to make it easy
+ to move the child into a separate executable. */
+ while (iPrecend != iPrecstart)
+ {
+ char *z;
+ int c;
+
+ z = abPrecbuf + iPrecstart;
+ if (iPrecend > iPrecstart)
+ c = iPrecend - iPrecstart;
+ else
+ c = CRECBUFLEN - iPrecstart;
+
+ iPrecstart = (iPrecstart + c) % CRECBUFLEN;
+
+ while (c > 0)
+ {
+ int cwrote;
+
+ cwrote = write (1, z, c);
+ if (cwrote <= 0)
+ {
+ if (cwrote < 0)
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ c -= cwrote;
+ z += cwrote;
+ }
+ }
+
+ if (pipe (ai) < 0)
+ {
+ ulog (LOG_ERROR, "pipe: %s", strerror (errno));
+ return FALSE;
+ }
+
+ iSchild = ixsfork ();
+ if (iSchild < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (iSchild == 0)
+ {
+ (void) close (ai[0]);
+ uscu_child (qconn, ai[1]);
+ /*NOTREACHED*/
+ }
+
+ (void) close (ai[1]);
+
+ oSpipe = ai[0];
+
+ return TRUE;
+}
+
+/* Copy all data from the terminal to the communications port. If we
+ see an escape character following a newline character, read the
+ next character and return it. */
+
+boolean
+fsysdep_cu (qconn, pbcmd, zlocalname)
+ struct sconnection *qconn;
+ char *pbcmd;
+ const char *zlocalname;
+{
+ boolean fstart;
+ char b;
+ int c;
+
+ fstart = TRUE;
+
+ while (TRUE)
+ {
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+ else
+ {
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ c = read (0, &b, 1);
+
+ usysdep_end_catch ();
+
+ if (c <= 0)
+ break;
+
+ if (fstart && b == *zCuvar_escape)
+ {
+ c = cscu_escape (pbcmd, zlocalname);
+ if (c <= 0)
+ break;
+ if (*pbcmd != b)
+ {
+ write (1, pbcmd, 1);
+
+ /* For Unix, we let the eof character be the same as
+ '.', and we let the suspend character (if any) be the
+ same as 'z'. */
+ if (*pbcmd == bSeof)
+ *pbcmd = '.';
+ if (*pbcmd == bStstp)
+ *pbcmd = 'z';
+ return TRUE;
+ }
+ }
+ if (! fconn_write (qconn, &b, (size_t) 1))
+ return FALSE;
+ fstart = strchr (zCuvar_eol, b) != NULL;
+ }
+
+ if (c < 0)
+ {
+ if (errno != EINTR)
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* I'm not sure what's best in this case. */
+ ulog (LOG_ERROR, "End of file on terminal");
+ return FALSE;
+}
+
+/* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */
+
+volatile sig_atomic_t fScu_alarm;
+
+static RETSIGTYPE
+uscu_alarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm);
+#endif
+
+ fScu_alarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif
+}
+
+/* We've just seen an escape character. We print the host name,
+ optionally after a 1 second delay. We read the next character from
+ the terminal and return it. The 1 second delay on the host name is
+ mostly to be fancy; it lets ~~ look smoother. */
+
+static int
+cscu_escape (pbcmd, zlocalname)
+ char *pbcmd;
+ const char *zlocalname;
+{
+ CATCH_PROTECT int c;
+
+ write (1, zCuvar_escape, 1);
+
+ fScu_alarm = FALSE;
+ usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL);
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ alarm (1);
+ }
+
+ c = 0;
+
+ while (TRUE)
+ {
+ if (fScu_alarm)
+ {
+ char b;
+
+ fScu_alarm = FALSE;
+ b = '[';
+ write (1, &b, 1);
+ write (1, zlocalname, strlen (zlocalname));
+ b = ']';
+ write (1, &b, 1);
+ }
+
+ if (c <= 0)
+ c = read (0, pbcmd, 1);
+ if (c >= 0 || errno != EINTR)
+ {
+ usysdep_end_catch ();
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ return c;
+ }
+ }
+}
+
+/* A SIGALRM handler which does nothing but send a signal to the child
+ process and schedule another alarm. POSIX.1 permits kill and alarm
+ from a signal handler. The reference to static data may or may not
+ be permissible. */
+
+static volatile sig_atomic_t iSsend_sig;
+
+static RETSIGTYPE
+uscu_alarm_kill (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm_kill);
+#endif
+
+ (void) kill (iSchild, iSsend_sig);
+
+ alarm (1);
+}
+
+/* Start or stop copying data from the communications port to the
+ terminal. We send a signal to the child process to tell it what to
+ do. Unfortunately, there are race conditions in the child, so we
+ keep sending it a signal once a second until it responds. We send
+ SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */
+
+boolean
+fsysdep_cu_copy (fcopy)
+ boolean fcopy;
+{
+ int ierr;
+ int c;
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ if (fcopy)
+ iSsend_sig = SIGUSR1;
+ else
+ iSsend_sig = SIGUSR2;
+
+ uscu_alarm_kill (SIGALRM);
+
+ alarm (1);
+
+ while (TRUE)
+ {
+ char b;
+
+ c = read (oSpipe, &b, 1);
+
+#if DEBUG > 1
+ if (c > 0)
+ DEBUG_MESSAGE1 (DEBUG_INCOMING,
+ "fsysdep_cu_copy: Got '%d'", b);
+#endif
+
+ if ((c < 0 && errno != EINTR)
+ || c == 0
+ || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED)))
+ break;
+
+ /* If none of the above conditions were true, then we either got
+ an EINTR error, in which case we probably timed out and the
+ SIGALRM handler resent the signal, or we read the wrong
+ character, in which case we will just read again from the
+ pipe. */
+ }
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ if (c > 0)
+ return TRUE;
+
+ if (c == 0)
+ ulog (LOG_ERROR, "EOF on child pipe");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+
+ return FALSE;
+}
+
+/* Shut down cu by killing the child process. */
+
+boolean
+fsysdep_cu_finish ()
+{
+ (void) close (oSpipe);
+
+ /* We hit the child with SIGTERM, give it two seconds to die, and
+ then send a SIGKILL. */
+ if (kill (iSchild, SIGTERM) < 0)
+ {
+ /* Don't give an error if the child has already died. */
+ if (errno != ESRCH)
+ ulog (LOG_ERROR, "kill: %s", strerror (errno));
+ }
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ iSsend_sig = SIGKILL;
+ alarm (2);
+
+ (void) ixswait ((unsigned long) iSchild, "child");
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ return TRUE;
+}
+
+/* Code for the child process. */
+
+/* This signal handler just records the signal. In this case we only
+ care about which signal we received most recently. */
+
+static volatile sig_atomic_t iSchild_sig;
+
+static RETSIGTYPE
+uscu_child_handler (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_child_handler);
+#endif
+
+ iSchild_sig = isig;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* The child process. This copies the port to the terminal, except
+ when it is stopped by a signal. It would be reasonable to write a
+ separate program for this, probably passing it the port on stdin.
+ This would reduce the memory requirements, since we wouldn't need a
+ second process holding all the configuration stuff, and also let it
+ work reasonably on 680x0 versions of MINIX. */
+
+static void
+uscu_child (qconn, opipe)
+ struct sconnection *qconn;
+ int opipe;
+{
+ CATCH_PROTECT int oport;
+ CATCH_PROTECT boolean fstopped, fgot;
+ CATCH_PROTECT int cwrite;
+ CATCH_PROTECT char abbuf[1024];
+
+ /* It would be nice if we could just use fsserial_read, but that
+ will log signals that we don't want logged. There should be a
+ generic way to extract the file descriptor from the port. */
+ if (qconn->qport == NULL)
+ oport = 0;
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+#if DEBUG > 0
+ default:
+ ulog (LOG_FATAL, "uscu_child: Can't happen");
+ oport = -1;
+ break;
+#endif
+ case UUCONF_PORTTYPE_STDIN:
+ oport = 0;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oport = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL);
+ usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL);
+
+ fstopped = FALSE;
+ fgot = FALSE;
+ iSchild_sig = 0;
+ cwrite = 0;
+
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+
+ while (TRUE)
+ {
+ int isig;
+ int c;
+
+ /* There is a race condition here between checking the signal
+ and receiving a new and possibly different one. This is
+ solved by having the parent resend the signal until it gets a
+ response. */
+ isig = iSchild_sig;
+ iSchild_sig = 0;
+ if (isig != 0)
+ {
+ char b;
+
+ if (isig == SIGTERM)
+ exit (EXIT_SUCCESS);
+
+ if (isig == SIGUSR1)
+ {
+ fstopped = FALSE;
+ b = CHILD_STARTED;
+ }
+ else
+ {
+ fstopped = TRUE;
+ b = CHILD_STOPPED;
+ cwrite = 0;
+ }
+
+ c = write (opipe, &b, 1);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (fstopped)
+ pause ();
+ else if (cwrite > 0)
+ {
+ char *zbuf;
+
+ zbuf = abbuf;
+ while (cwrite > 0)
+ {
+ c = write (1, zbuf, cwrite);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN
+ || errno == EWOULDBLOCK
+ || errno == ENODATA))
+ c = 0;
+
+ if (c < 0 && errno == EINTR)
+ break;
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ cwrite -= c;
+ zbuf += c;
+ }
+ }
+ else
+ {
+ /* On some systems apparently read will return 0 until
+ something has been written to the port. We therefore
+ accept a 0 return until after we have managed to read
+ something. Setting errno to 0 apparently avoids a
+ problem on Coherent. */
+ errno = 0;
+ c = read (oport, abbuf, sizeof abbuf);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if ((c == 0 && fgot)
+ || (c < 0 && errno != EINTR))
+ {
+ /* This can be a normal way to exit, depending on just
+ how the connection is dropped. */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_SUCCESS);
+ }
+ if (c > 0)
+ {
+ fgot = TRUE;
+ cwrite = c;
+ }
+ }
+ }
+}
+
+/* Terminal control routines. */
+
+/* Whether file descriptor 0 is attached to a terminal or not. */
+static boolean fSterm;
+
+/* Whether we are doing local echoing. */
+static boolean fSlocalecho;
+
+/* The original state of the terminal. */
+static sterminal sSterm_orig;
+
+/* The new state of the terminal. */
+static sterminal sSterm_new;
+
+#if ! HAVE_BSD_TTY
+#ifdef SIGTSTP
+/* Whether SIGTSTP is being ignored. */
+static boolean fStstp_ignored;
+#endif
+#endif
+
+/* Set the terminal into raw mode. */
+
+boolean
+fsysdep_terminal_raw (flocalecho)
+ boolean flocalecho;
+{
+ fSlocalecho = flocalecho;
+
+ /* This defaults may be overriden below. */
+ bSeof = '\004';
+ bStstp = '\032';
+
+ if (! fgetterminfo (0, &sSterm_orig))
+ {
+ fSterm = FALSE;
+ return TRUE;
+ }
+
+ fSterm = TRUE;
+
+ sSterm_new = sSterm_orig;
+
+#if HAVE_BSD_TTY
+
+ /* We use CBREAK mode rather than RAW mode, because RAW mode turns
+ off all output processing, which we don't want to do. This means
+ that we have to disable the interrupt characters, which we do by
+ setting them to -1. */
+ bSeof = sSterm_orig.stchars.t_eofc;
+
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ sSterm_new.stchars.t_startc = -1;
+ sSterm_new.stchars.t_stopc = -1;
+ sSterm_new.stchars.t_eofc = -1;
+ sSterm_new.stchars.t_brkc = -1;
+
+ bStstp = sSterm_orig.sltchars.t_suspc;
+
+ sSterm_new.sltchars.t_suspc = -1;
+ sSterm_new.sltchars.t_dsuspc = -1;
+ sSterm_new.sltchars.t_rprntc = -1;
+ sSterm_new.sltchars.t_flushc = -1;
+ sSterm_new.sltchars.t_werasc = -1;
+ sSterm_new.sltchars.t_lnextc = -1;
+
+ if (! flocalecho)
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP);
+ sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM);
+ }
+ else
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO);
+ sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM);
+ }
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ bStstp = sSterm_new.c_cc[VSUSP];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~
+ (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Restore the terminal to its original setting. */
+
+boolean
+fsysdep_terminal_restore ()
+{
+ if (! fSterm)
+ return TRUE;
+
+ if (! fsetterminfo (0, &sSterm_orig))
+ {
+ ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Read a line from the terminal. This will be called after
+ fsysdep_terminal_raw has been called. */
+
+char *
+zsysdep_terminal_line (zprompt)
+ const char *zprompt;
+{
+ CATCH_PROTECT size_t cbuf = 0;
+ CATCH_PROTECT char *zbuf = NULL;
+ CATCH_PROTECT size_t cgot = 0;
+
+ if (zprompt != NULL && *zprompt != '\0')
+ (void) write (1, zprompt, strlen (zprompt));
+
+ /* Forgot about any previous SIGINT or SIGQUIT signals we may have
+ received. We don't worry about the race condition here, since we
+ can't get these signals from the terminal at the moment and it's
+ not too likely that somebody else will be sending them to us. */
+ afSignal[INDEXSIG_SIGINT] = 0;
+ afSignal[INDEXSIG_SIGQUIT] = 0;
+
+ if (! fsysdep_terminal_restore ())
+ return NULL;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ cbuf = 0;
+ zbuf = NULL;
+ cgot = 0;
+ }
+
+ while (TRUE)
+ {
+ char b;
+ int c;
+
+ if (afSignal[INDEXSIG_SIGINT]
+ || afSignal[INDEXSIG_SIGQUIT])
+ {
+ usysdep_end_catch ();
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ /* Return an empty string. */
+ cgot = 0;
+ break;
+ }
+
+ /* There's a race here between checking the signals and calling
+ read. It just means that the user will have to hit ^C more
+ than once. */
+
+ c = read (0, &b, 1);
+ if (c < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+ if (c == 0)
+ {
+ /* I'm not quite sure what to do here. */
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "EOF on terminal");
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ cbuf += 64;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = b;
+
+ ++cgot;
+
+ if (b == '\n')
+ {
+ usysdep_end_catch ();
+ break;
+ }
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ ++cbuf;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = '\0';
+
+ if (! fsysdep_terminal_raw (fSlocalecho))
+ return NULL;
+
+ return zbuf;
+}
+
+/* Write a line to the terminal with a trailing newline. */
+
+boolean
+fsysdep_terminal_puts (zline)
+ const char *zline;
+{
+ char *zalc, *zprint;
+ size_t clen;
+
+ if (zline == NULL)
+ {
+ zalc = zbufalc (2);
+ clen = 0;
+ }
+ else
+ {
+ clen = strlen (zline);
+ zalc = zbufalc (clen + 2);
+ memcpy (zalc, zline, clen);
+ }
+
+ if (fSterm)
+ {
+ zalc[clen] = '\r';
+ ++clen;
+ }
+ zalc[clen] = '\n';
+ ++clen;
+
+ zprint = zalc;
+ while (clen > 0)
+ {
+ int c;
+
+ c = write (1, zprint, clen);
+ if (c <= 0)
+ {
+ ubuffree (zalc);
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ clen -= c;
+ zprint += c;
+ }
+
+ ubuffree (zalc);
+
+ return TRUE;
+}
+
+/* Allow or disallow signals from the terminal. */
+
+boolean
+fsysdep_terminal_signals (faccept)
+ boolean faccept;
+{
+#if HAVE_BSD_TTY
+
+ if (faccept)
+ {
+ sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc;
+ sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc;
+ }
+ else
+ {
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ if (faccept)
+ sSterm_new.c_lflag |= ISIG;
+ else
+ sSterm_new.c_lflag &=~ ISIG;
+
+#ifdef SIGTSTP
+ /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This
+ function will be called with faccept TRUE before it is called
+ with faccept FALSE, so fStstp_ignored will be correctly
+ initialized. */
+ if (faccept)
+ usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored);
+ else if (! fStstp_ignored)
+ usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL);
+#endif
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Start up a command, or possibly just a shell. Optionally attach
+ stdin or stdout to the port. We attach directly to the port,
+ rather than copying the data ourselves. */
+
+boolean
+fsysdep_shell (qconn, zcmd, tcmd)
+ struct sconnection *qconn;
+ const char *zcmd;
+ enum tshell_cmd tcmd;
+{
+ const char *azargs[4];
+ int oread, owrite;
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/bin/sh";
+ if (zcmd == NULL || *zcmd == '\0')
+ azargs[1] = NULL;
+ else
+ {
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+ }
+
+ if (qconn->qport == NULL)
+ {
+ oread = 0;
+ owrite = 1;
+ }
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+ default:
+ oread = owrite = -1;
+ break;
+ case UUCONF_PORTTYPE_STDIN:
+ oread = 0;
+ owrite = 1;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ aidescs[0] = 0;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[0] = oread;
+ if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[1] = owrite;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL,
+ FALSE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, "shell") == 0;
+}
+
+/* Change directories. */
+
+boolean
+fsysdep_chdir (zdir)
+ const char *zdir;
+{
+ if (zdir == NULL || *zdir == '\0')
+ {
+ zdir = getenv ("HOME");
+ if (zdir == NULL)
+ {
+ ulog (LOG_ERROR, "HOME not defined");
+ return FALSE;
+ }
+ }
+ if (chdir (zdir) < 0)
+ {
+ ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Suspend the current process. */
+
+boolean
+fsysdep_suspend ()
+{
+#ifndef SIGTSTP
+ return fsysdep_terminal_puts ("[process suspension not supported]");
+#else
+ return kill (getpid (), SIGTSTP) == 0;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/cwd.c b/gnu/libexec/uucp/libunix/cwd.c
new file mode 100644
index 000000000000..433025db6c3a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cwd.c
@@ -0,0 +1,55 @@
+/* cwd.c
+ Routines dealing with the current working directory. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* See whether running this file through zsysdep_add_cwd would require
+ knowing the current working directory. This is used to avoid
+ determining the cwd if it will not be needed. */
+
+boolean
+fsysdep_needs_cwd (zfile)
+ const char *zfile;
+{
+ return *zfile != '/' && *zfile != '~';
+}
+
+/* Expand a local file, putting relative pathnames in the current
+ working directory. Note that ~/file is placed in the public
+ directory, rather than in the user's home directory. This is
+ consistent with other UUCP packages. */
+
+char *
+zsysdep_local_file_cwd (zfile, zpubdir)
+ const char *zfile;
+ const char *zpubdir;
+{
+ if (*zfile == '/')
+ return zbufcpy (zfile);
+ else if (*zfile == '~')
+ return zsysdep_local_file (zfile, zpubdir);
+ else
+ return zsysdep_add_cwd (zfile);
+}
+
+/* Add the current working directory to a remote file name. */
+
+char *
+zsysdep_add_cwd (zfile)
+ const char *zfile;
+{
+ if (*zfile == '/' || *zfile == '~')
+ return zbufcpy (zfile);
+
+ if (zScwd == NULL)
+ {
+ ulog (LOG_ERROR, "Can't determine current directory");
+ return NULL;
+ }
+
+ return zsysdep_in_dir (zScwd, zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/detach.c b/gnu/libexec/uucp/libunix/detach.c
new file mode 100644
index 000000000000..73144da001d4
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/detach.c
@@ -0,0 +1,165 @@
+/* detach.c
+ Detach from the controlling terminal.
+
+ Copyright (C) 1992, 1993 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef TIOCNOTTY
+#define HAVE_TIOCNOTTY 1
+#else
+#define HAVE_TIOCNOTTY 0
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#if HAVE_BROKEN_SETSID
+#undef HAVE_SETSID
+#define HAVE_SETSID 0
+#endif
+
+/* Detach from the controlling terminal. This is called by uucico if
+ it is calling out to another system, so that it can receive SIGHUP
+ signals from the port it calls out on. It is also called by uucico
+ just before it starts uuxqt, so that uuxqt is completely
+ independent of the terminal. */
+
+void
+usysdep_detach ()
+{
+ pid_t igrp;
+
+ /* Make sure we are not a process group leader. */
+#if HAVE_BSD_PGRP
+ igrp = getpgrp (0);
+#else
+ igrp = getpgrp ();
+#endif
+
+ if (igrp == getpid ())
+ {
+ boolean fignored;
+ pid_t ipid;
+
+ /* Ignore SIGHUP, since our process group leader is about to
+ die. */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored);
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ /* We'll always wind up as a child of process number 1, right?
+ Right? We have to wait for our parent to die before
+ reenabling SIGHUP. */
+ while (getppid () != 1)
+ sleep (1);
+
+ ulog_id (getpid ());
+
+ /* Restore SIGHUP catcher if it wasn't being ignored. */
+ if (! fignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+#if ! HAVE_SETSID && HAVE_TIOCNOTTY
+ /* Lose the original controlling terminal as well as our process
+ group. If standard input has been reopened to /dev/null, this
+ will do no harm. If another port has been opened to become the
+ controlling terminal, it should have been detached when it was
+ closed. */
+ (void) ioctl (0, TIOCNOTTY, (char *) NULL);
+#endif /* ! HAVE_SETSID && HAVE_TIOCNOTTY */
+
+ /* Close stdin, stdout and stderr and reopen them on /dev/null, to
+ make sure we have no connection at all to the terminal. */
+ (void) close (0);
+ (void) close (1);
+ (void) close (2);
+ if (open ((char *) "/dev/null", O_RDONLY) != 0
+ || open ((char *) "/dev/null", O_WRONLY) != 1
+ || open ((char *) "/dev/null", O_WRONLY) != 2)
+ ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno));
+
+#if HAVE_SETSID
+
+ /* Under POSIX the setsid call creates a new session for which we
+ are the process group leader. It also detaches us from our
+ controlling terminal. */
+ if (setsid () < 0)
+ ulog (LOG_ERROR, "setsid: %s", strerror (errno));
+
+#else /* ! HAVE_SETSID */
+
+#if ! HAVE_SETPGRP
+ #error Cannot detach from controlling terminal
+#endif
+
+ /* If we don't have setsid, we must use setpgrp. On an old System V
+ system setpgrp will make us the leader of a new process group and
+ detach the controlling terminal. On an old BSD system the call
+ setpgrp (0, 0) will set our process group to 0 so that we can
+ acquire a new controlling terminal (TIOCNOTTY may or may not have
+ already done that anyhow). */
+#if HAVE_BSD_SETPGRP
+ if (setpgrp (0, 0) < 0)
+#else
+ if (setpgrp () < 0)
+#endif
+ {
+ /* Some systems seem to give EPERM errors inappropriately. */
+ if (errno != EPERM)
+ ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
+ }
+
+#endif /* ! HAVE_SETSID */
+
+ /* At this point we have completely detached from our controlling
+ terminal. The next terminal device we open will probably become
+ our controlling terminal. */
+}
diff --git a/gnu/libexec/uucp/libunix/dirent.c b/gnu/libexec/uucp/libunix/dirent.c
new file mode 100644
index 000000000000..83db496cabbd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dirent.c
@@ -0,0 +1,123 @@
+/* dirent.c
+ Replacements for opendir, readdir and closedir for the original
+ Unix filesystem only.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Simple emulations of opendir/readdir/closedir for systems which
+ have the original format of Unix directories. It's probably better
+ to get Doug Gwyn's public domain set of emulation functions. */
+
+DIR *
+opendir (zdir)
+ const char *zdir;
+{
+ int o;
+ struct stat s;
+ DIR *qret;
+
+ o = open ((char *) zdir, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ return NULL;
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0
+ || fstat (o, &s) < 0)
+ {
+ int isave;
+
+ isave = errno;
+ (void) close (o);
+ errno = isave;
+ return NULL;
+ }
+ if (! S_ISDIR (s.st_mode))
+ {
+ (void) close (o);
+ errno = ENOTDIR;
+ return NULL;
+ }
+ qret = (DIR *) xmalloc (sizeof (DIR));
+ qret->o = o;
+ return qret;
+}
+
+struct dirent *
+readdir (q)
+ DIR *q;
+{
+ struct direct sdir;
+ int cgot;
+
+ do
+ {
+ cgot = read (q->o, &sdir, sizeof (struct direct));
+ if (cgot <= 0)
+ return NULL;
+ if (cgot != sizeof (struct direct))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ while (sdir.d_ino == 0);
+
+ strncpy (q->s.d_name, sdir.d_name, DIRSIZ);
+ q->s.d_name[DIRSIZ] = '\0';
+ return &q->s;
+}
+
+int
+closedir (q)
+ DIR *q;
+{
+ int o;
+
+ o = q->o;
+ xfree (q);
+ return close (o);
+}
diff --git a/gnu/libexec/uucp/libunix/dup2.c b/gnu/libexec/uucp/libunix/dup2.c
new file mode 100644
index 000000000000..6a7359fe92e8
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dup2.c
@@ -0,0 +1,69 @@
+/* dup2.c
+ The Unix dup2 function, for systems which only have dup.
+
+ Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* I basically took this from the emacs 18.57 distribution, although I
+ cleaned it up a bit and made it POSIX compliant. */
+
+int
+dup2 (oold, onew)
+ int oold;
+ int onew;
+{
+ if (oold == onew)
+ return onew;
+ (void) close (onew);
+
+#ifdef F_DUPFD
+ return fcntl (oold, F_DUPFD, onew);
+#else
+ {
+ int onext, oret, isave;
+
+ onext = dup (oold);
+ if (onext == onew)
+ return onext;
+ if (onext < 0)
+ return -1;
+ oret = dup2 (oold, onew);
+ isave = errno;
+ (void) close (onext);
+ errno = isave;
+ return oret;
+ }
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/efopen.c b/gnu/libexec/uucp/libunix/efopen.c
new file mode 100644
index 000000000000..7e360b616876
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/efopen.c
@@ -0,0 +1,132 @@
+/* efopen.c
+ Open a stdio file with appropriate permissions. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_APPEND
+#ifdef FAPPEND
+#define O_APPEND FAPPEND
+#endif
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+FILE *
+esysdep_fopen (zfile, fpublic, fappend, fmkdirs)
+ const char *zfile;
+ boolean fpublic;
+ boolean fappend;
+ boolean fmkdirs;
+{
+ int imode;
+ int o;
+ FILE *e;
+
+ if (fpublic)
+ imode = IPUBLIC_FILE_MODE;
+ else
+ imode = IPRIVATE_FILE_MODE;
+
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = open ((char *) zfile, O_WRONLY | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ o = creat ((char *) zfile, imode);
+#endif /* ! defined (O_CREAT) */
+ }
+
+ if (o < 0)
+ {
+ if (errno == ENOENT && fmkdirs)
+ {
+ if (! fsysdep_make_dirs (zfile, fpublic))
+ return NULL;
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = creat ((char *) zfile, imode);
+#endif
+ }
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ }
+
+#ifndef O_CREAT
+#ifdef O_APPEND
+ if (fappend)
+ {
+ if (fcntl (o, F_SETFL, O_APPEND) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+ }
+#endif /* defined (O_APPEND) */
+#endif /* ! defined (O_CREAT) */
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+
+ if (fappend)
+ e = fdopen (o, (char *) "a");
+ else
+ e = fdopen (o, (char *) "w");
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (o);
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/epopen.c b/gnu/libexec/uucp/libunix/epopen.c
new file mode 100644
index 000000000000..dec1b3999d64
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/epopen.c
@@ -0,0 +1,85 @@
+/* epopen.c
+ A version of popen that goes through ixsspawn.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* A version of popen that goes through ixsspawn. This actually takes
+ an array of arguments rather than a string, and takes a boolean
+ read/write value rather than a string. It sets *pipid to the
+ process ID of the child. */
+
+FILE *
+espopen (pazargs, frd, pipid)
+ const char **pazargs;
+ boolean frd;
+ pid_t *pipid;
+{
+ int aidescs[3];
+ pid_t ipid;
+ FILE *eret;
+
+ if (frd)
+ {
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_READ_PIPE;
+ }
+ else
+ {
+ aidescs[0] = SPAWN_WRITE_PIPE;
+ aidescs[1] = SPAWN_NULL;
+ }
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ return NULL;
+
+ if (frd)
+ eret = fdopen (aidescs[1], (char *) "r");
+ else
+ eret = fdopen (aidescs[0], (char *) "w");
+ if (eret == NULL)
+ {
+ int ierr;
+
+ ierr = errno;
+ (void) close (frd ? aidescs[1] : aidescs[0]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ errno = ierr;
+ return NULL;
+ }
+
+ *pipid = ipid;
+
+ return eret;
+}
diff --git a/gnu/libexec/uucp/libunix/exists.c b/gnu/libexec/uucp/libunix/exists.c
new file mode 100644
index 000000000000..9473922f0d53
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/exists.c
@@ -0,0 +1,16 @@
+/* exists.c
+ Check whether a file exists. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+boolean
+fsysdep_file_exists (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ return stat ((char *) zfile, &s) == 0;
+}
diff --git a/gnu/libexec/uucp/libunix/filnam.c b/gnu/libexec/uucp/libunix/filnam.c
new file mode 100644
index 000000000000..62054767b89a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/filnam.c
@@ -0,0 +1,376 @@
+/* filnam.c
+ Get names to use for UUCP files.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+/* We need a definition for SEEK_SET. */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+#define ZCHARS \
+ "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+/* Local functions. */
+
+static boolean fscmd_seq P((const char *zsystem, char *zseq));
+static char *zsfile_name P((int btype, const char *zsystem,
+ const char *zlocalname, int bgrade,
+ boolean fxqt, char *ztname, char *zdname,
+ char *zxname));
+
+/* Get a new command sequence number (this is not a sequence number to
+ be used for communicating with another system, but a sequence
+ number to be used when generating the name of a command file).
+ The sequence number is placed into zseq, which should be five
+ characters long. */
+
+static boolean
+fscmd_seq (zsystem, zseq)
+ const char *zsystem;
+ char *zseq;
+{
+ boolean ferr;
+ char *zfree;
+ const char *zfile;
+ int o;
+ int i;
+
+ /* Lock the sequence file. This may not be correct for all systems,
+ but it only matters if the system UUCP and this UUCP are running
+ at the same time. */
+ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr))
+ {
+ if (ferr || FGOT_SIGNAL ())
+ return FALSE;
+ sleep (5);
+ }
+
+ zfree = NULL;
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ zfile = "SEQF";
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zfree = zsysdep_in_dir (".Sequence", zsystem);
+ zfile = zfree;
+#endif
+#if SPOOLDIR_ULTRIX
+ if (! fsultrix_has_spool (zsystem))
+ zfile = "sys/DEFAULT/.SEQF";
+ else
+ {
+ zfree = zsappend3 ("sys", zsystem, ".SEQF");
+ zfile = zfree;
+ }
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ zfree = zsysdep_in_dir (zsystem, "SEQF");
+ zfile = zfree;
+#endif /* SPOOLDIR_TAYLOR */
+
+#ifdef O_CREAT
+ o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE);
+#else
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ {
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+ }
+#endif
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zfile, FALSE))
+ {
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_RDWR | O_CREAT | O_NOCTTY,
+ IPUBLIC_FILE_MODE);
+#else
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+#endif
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+ }
+
+ if (read (o, zseq, CSEQLEN) != CSEQLEN)
+ strcpy (zseq, "0000");
+ zseq[CSEQLEN] = '\0';
+
+ /* We must add one to the sequence number and return the new value.
+ On Ultrix, arbitrary characters are allowed in the sequence
+ number. On other systems, the sequence number apparently must be
+ in hex. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_HDB || SPOOLDIR_SVR4
+ i = (int) strtol (zseq, (char **) NULL, 16);
+ ++i;
+ if (i > 0xffff)
+ i = 0;
+ /* The sprintf argument has CSEQLEN built into it. */
+ sprintf (zseq, "%04x", (unsigned int) i);
+#endif
+#if SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ for (i = CSEQLEN - 1; i >= 0; i--)
+ {
+ const char *zdig;
+
+ zdig = strchr (ZCHARS, zseq[i]);
+ if (zdig == NULL || zdig[0] == '\0' || zdig[1] == '\0')
+ zseq[i] = '0';
+ else
+ {
+ zseq[i] = zdig[1];
+ break;
+ }
+ }
+#endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */
+
+ if (lseek (o, (off_t) 0, SEEK_SET) < 0
+ || write (o, zseq, CSEQLEN) != CSEQLEN
+ || close (o) < 0)
+ {
+ ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno));
+ (void) close (o);
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+
+ return TRUE;
+}
+
+/* Get the name of a command or data file for a remote system. The
+ btype argument should be C for a command file or D for a data file.
+ If the grade of a data file is X, it is assumed that this is going
+ to become an execute file on some other system. The zsystem
+ argument is the system that the file will be transferred to. The
+ ztname argument will be set to a file name that could be passed to
+ zsysdep_spool_file_name. The zdname argument, if not NULL, will be
+ set to a data file name appropriate for the remote system. The
+ zxname argument, if not NULL, will be set to the name of an execute
+ file on the remote system. None of the names will be more than 14
+ characters long. */
+
+/*ARGSUSED*/
+static char *
+zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname)
+ int btype;
+ const char *zsystem;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ char abseq[CSEQLEN + 1];
+ char absimple[11 + CSEQLEN];
+ char *zname;
+
+ if (zlocalname == NULL)
+ zlocalname = zSlocalname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zsystem, abseq))
+ return NULL;
+
+ if (btype == 'C')
+ {
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq);
+#else
+ sprintf (absimple, "C.%c%s", bgrade, abseq);
+#endif
+ }
+ else if (btype == 'D')
+ {
+ /* This name doesn't really matter that much; it's just the
+ name we use on the local system. The name we use on the
+ remote system, which we return in zdname, should contain
+ our system name so that remote UUCP's running SPOOLDIR_V2
+ and the like can distinguish while files come from which
+ systems. */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq);
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+#else /* SPOOLDIR_TAYLOR */
+ if (fxqt)
+ sprintf (absimple, "D.X%s", abseq);
+ else
+ sprintf (absimple, "D.%s", abseq);
+#endif /* SPOOLDIR_TAYLOR */
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+ }
+#if DEBUG > 0
+ else
+ ulog (LOG_FATAL, "zsfile_name: Can't happen");
+#endif
+
+ zname = zsfind_file (absimple, zsystem, bgrade);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ if (ztname != NULL)
+ strcpy (ztname, absimple);
+
+ if (zdname != NULL)
+ sprintf (zdname, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ if (zxname != NULL)
+ sprintf (zxname, "X.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ return zname;
+}
+
+/* Return a name to use for a data file to be copied to another
+ system. The name returned will be for a real file. The zlocalname
+ argument is the local name as seen by the remote system, the bgrade
+ argument is the file grade, and the fxqt argument is TRUE if this
+ file will become an execution file. The ztname argument, if not
+ NULL, will be set to a name that could be passed to
+ zsysdep_spool_file_name to get back the return value of this
+ function. The zdname argument, if not NULL, will be set to a name
+ that the file could be given on another system. The zxname
+ argument, if not NULL, will be set to a name for an execute file on
+ another system. */
+
+char *
+zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname,
+ zxname)
+ const struct uuconf_system *qsys;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt,
+ ztname, zdname, zxname);
+}
+
+/* Get a command file name. */
+
+char *
+zscmd_file (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL,
+ bgrade, FALSE, (char *) NULL, (char *) NULL,
+ (char *) NULL);
+}
+
+/* Return a name for an execute file to be created locally. This is
+ used by uux to execute a command locally with remote files. */
+
+char *
+zsysdep_xqt_file_name ()
+{
+ char abseq[CSEQLEN + 1];
+ char absx[11 + CSEQLEN];
+ char *zname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zSlocalname, abseq))
+ return NULL;
+
+ sprintf (absx, "X.%.7sX%s", zSlocalname, abseq);
+
+ zname = zsfind_file (absx, zSlocalname, -1);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ return zname;
+}
diff --git a/gnu/libexec/uucp/libunix/fsusg.c b/gnu/libexec/uucp/libunix/fsusg.c
new file mode 100644
index 000000000000..e2b40a8ad5a5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/fsusg.c
@@ -0,0 +1,231 @@
+/* fsusage.c -- return space usage of mounted filesystems
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ 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, 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.
+
+ This file was modified slightly by Ian Lance Taylor, December 1992,
+ for use with Taylor UUCP. */
+
+#include "uucp.h"
+#include "sysdep.h"
+#include "fsusg.h"
+
+int statfs ();
+
+#if STAT_STATFS2_BSIZE
+#ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */
+#include <sys/vfs.h>
+#endif
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+#include <sys/mount.h>
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if STAT_USTAT /* SVR2 and others. */
+#include <ustat.h>
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+#include <sys/statfs.h>
+#endif
+#ifdef _AIX
+#ifdef _IBMR2 /* AIX RS6000. */
+#include <sys/statfs.h>
+#endif
+#endif
+
+#ifdef _AIX
+#ifdef _I386 /* AIX PS/2. */
+#include <sys/stat.h>
+#include <sys/dustat.h>
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+#include <sys/statvfs.h>
+int statvfs ();
+#endif
+
+#define STAT_NONE 0
+
+#if ! STAT_STATVFS
+#if ! STAT_STATFS2_BSIZE
+#if ! STAT_STATFS2_FSIZE
+#if ! STAT_STATFS2_FS_DATA
+#if ! STAT_STATFS4
+#if ! STAT_USTAT
+#undef STAT_NONE
+#define STAT_NONE 1
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+#if ! STAT_NONE
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding up. */
+
+static long
+adjust_blocks (blocks, fromsize, tosize)
+ long blocks;
+ int fromsize, tosize;
+{
+ if (fromsize == tosize) /* E.g., from 512 to 512. */
+ return blocks;
+ else if (fromsize > tosize) /* E.g., from 2048 to 512. */
+ return blocks * (fromsize / tosize);
+ else /* E.g., from 256 to 512. */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+#endif
+
+/* Fill in the fields of FSP with information about space usage for
+ the filesystem on which PATH resides.
+ DISK is the device on which PATH is mounted, for space-getting
+ methods that need to know it.
+ Return 0 if successful, -1 if not. */
+
+int
+get_fs_usage (path, disk, fsp)
+ char *path, *disk;
+ struct fs_usage *fsp;
+{
+#if STAT_NONE
+ return -1;
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
+ fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
+ fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
+ fsp->fsu_files = fsd.fd_req.gtot;
+ fsp->fsu_ffree = fsd.fd_req.gfree;
+#endif
+
+#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+#define convert_blocks(b) (b)
+#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
+#define f_bavail f_bfree
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+ struct statvfs fsd;
+
+ if (statvfs (path, &fsd) < 0)
+ return -1;
+ /* f_frsize isn't guaranteed to be supported. */
+#define convert_blocks(b) \
+ adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+#endif
+
+#if STAT_USTAT
+ {
+ struct stat sstat;
+ struct ustat s;
+
+ if (stat (path, &sstat) < 0
+ || ustat (sstat.st_dev, &s) < 0)
+ return -1;
+ fsp->fsu_blocks = -1;
+ fsp->fsu_bfree = f_tfree;
+ fsp->fsu_bavail = f_tfree;
+ fsp->fsu_files = -1;
+ fsp->fsu_ffree = -1;
+ }
+#endif
+
+#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */
+#if ! STAT_USTAT
+#if ! STAT_NONE
+ fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
+ fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
+ fsp->fsu_files = fsd.f_files;
+ fsp->fsu_ffree = fsd.f_ffree;
+#endif
+#endif
+#endif
+
+ return 0;
+}
+
+#ifdef _AIX
+#ifdef _I386
+/* AIX PS/2 does not supply statfs. */
+
+int
+statfs (path, fsb)
+ char *path;
+ struct statfs *fsb;
+{
+ struct stat stats;
+ struct dustat fsd;
+
+ if (stat (path, &stats))
+ return -1;
+ if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+ return -1;
+ fsb->f_type = 0;
+ fsb->f_bsize = fsd.du_bsize;
+ fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+ fsb->f_bfree = fsd.du_tfree;
+ fsb->f_bavail = fsd.du_tfree;
+ fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
+ fsb->f_ffree = fsd.du_tinode;
+ fsb->f_fsid.val[0] = fsd.du_site;
+ fsb->f_fsid.val[1] = fsd.du_pckno;
+ return 0;
+}
+#endif
+#endif /* _AIX && _I386 */
diff --git a/gnu/libexec/uucp/libunix/fsusg.h b/gnu/libexec/uucp/libunix/fsusg.h
new file mode 100644
index 000000000000..8d4d054cb5ac
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/fsusg.h
@@ -0,0 +1,31 @@
+/* fsusage.h -- declarations for filesystem space usage info
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ 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, 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.
+
+ This files was modified slightly by Ian Lance Taylor for use with
+ Taylor UUCP. */
+
+/* Space usage statistics for a filesystem. Blocks are 512-byte. */
+struct fs_usage
+{
+ long fsu_blocks; /* Total blocks. */
+ long fsu_bfree; /* Free blocks available to superuser. */
+ long fsu_bavail; /* Free blocks available to non-superuser. */
+ long fsu_files; /* Total file nodes. */
+ long fsu_ffree; /* Free file nodes. */
+};
+
+extern int get_fs_usage P((char *path, char *disk, struct fs_usage *fsp));
diff --git a/gnu/libexec/uucp/libunix/ftw.c b/gnu/libexec/uucp/libunix/ftw.c
new file mode 100644
index 000000000000..c3372b53ca48
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ftw.c
@@ -0,0 +1,250 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ian Lance Taylor (ian@airs.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/* Traverse one level of a directory tree. */
+
+static int
+ftw_dir (dirs, level, descriptors, dir, len, func)
+ DIR **dirs;
+ int level;
+ int descriptors;
+ char *dir;
+ size_t len;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+{
+ int got;
+ struct dirent *entry;
+
+ got = 0;
+
+ errno = 0;
+
+ while ((entry = readdir (dirs[level])) != NULL)
+ {
+ size_t namlen;
+ struct stat s;
+ int flag, ret, newlev;
+
+ ++got;
+
+ namlen = strlen (entry->d_name);
+ if (entry->d_name[0] == '.'
+ && (namlen == 1 ||
+ (namlen == 2 && entry->d_name[1] == '.')))
+ {
+ errno = 0;
+ continue;
+ }
+
+ if (namlen + len + 1 > PATH_MAX)
+ {
+#ifdef ENAMETOOLONG
+ errno = ENAMETOOLONG;
+#else
+ errno = ENOMEM;
+#endif
+ return -1;
+ }
+
+ dir[len] = '/';
+ memcpy ((dir + len + 1), entry->d_name, namlen + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ newlev = (level + 1) % descriptors;
+
+ if (dirs[newlev] != NULL)
+ closedir (dirs[newlev]);
+
+ dirs[newlev] = opendir (dir);
+ if (dirs[newlev] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (dir, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, newlev, descriptors, dir,
+ namlen + len + 1, func);
+ if (dirs[newlev] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[newlev]);
+ errno = save;
+ dirs[newlev] = NULL;
+ }
+ }
+
+ if (ret != 0)
+ return ret;
+
+ if (dirs[level] == NULL)
+ {
+ int skip;
+
+ dir[len] = '\0';
+ dirs[level] = opendir (dir);
+ if (dirs[level] == NULL)
+ return -1;
+ skip = got;
+ while (skip-- != 0)
+ {
+ errno = 0;
+ if (readdir (dirs[level]) == NULL)
+ return errno == 0 ? 0 : -1;
+ }
+ }
+
+ errno = 0;
+ }
+
+ return errno == 0 ? 0 : -1;
+}
+
+/* Call a function on every element in a directory tree. */
+
+int
+ftw (dir, func, descriptors)
+ const char *dir;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+ int descriptors;
+{
+ DIR **dirs;
+ int c;
+ DIR **p;
+ size_t len;
+ char buf[PATH_MAX + 1];
+ struct stat s;
+ int flag, ret;
+
+ if (descriptors <= 0)
+ descriptors = 1;
+
+ dirs = (DIR **) malloc (descriptors * sizeof (DIR *));
+ if (dirs == NULL)
+ return -1;
+ c = descriptors;
+ p = dirs;
+ while (c-- != 0)
+ *p++ = NULL;
+
+ len = strlen (dir);
+ memcpy (buf, dir, len + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ dirs[0] = opendir (dir);
+ if (dirs[0] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (buf, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
+ if (dirs[0] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[0]);
+ errno = save;
+ }
+ }
+
+ free ((pointer) dirs);
+ return ret;
+}
diff --git a/gnu/libexec/uucp/libunix/getcwd.c b/gnu/libexec/uucp/libunix/getcwd.c
new file mode 100644
index 000000000000..d3623bd2cd82
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/getcwd.c
@@ -0,0 +1,59 @@
+/* getcwd.c
+ Replacement for the getcwd function that just calls /bin/pwd. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+char *
+getcwd (zbuf, cbuf)
+ char *zbuf;
+ size_t cbuf;
+{
+ const char *azargs[2];
+ FILE *e;
+ pid_t ipid;
+ int cread;
+ int ierr;
+
+ azargs[0] = PWD_PROGRAM;
+ azargs[1] = NULL;
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ return NULL;
+
+ ierr = 0;
+
+ cread = fread (zbuf, sizeof (char), cbuf, e);
+ if (cread == 0)
+ ierr = errno;
+
+ (void) fclose (e);
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ ierr = EACCES;
+ cread = 0;
+ }
+
+ if (cread != 0)
+ {
+ if (zbuf[cread - 1] == '\n')
+ zbuf[cread - 1] = '\0';
+ else
+ {
+ ierr = ERANGE;
+ cread = 0;
+ }
+ }
+
+ if (cread == 0)
+ {
+ errno = ierr;
+ return NULL;
+ }
+
+ return zbuf;
+}
diff --git a/gnu/libexec/uucp/libunix/indir.c b/gnu/libexec/uucp/libunix/indir.c
new file mode 100644
index 000000000000..2484ec23f85d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/indir.c
@@ -0,0 +1,133 @@
+/* indir.c
+ See if a file is in a directory.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See whether a file is in a directory, and optionally check access. */
+
+boolean
+fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser)
+ const char *zfile;
+ const char *zdir;
+ boolean fcheck;
+ boolean freadable;
+ const char *zuser;
+{
+ size_t c;
+ char *zcopy, *zslash;
+ struct stat s;
+
+ if (*zfile != '/')
+ return FALSE;
+ c = strlen (zdir);
+ if (c > 0 && zdir[c - 1] == '/')
+ c--;
+ if (strncmp (zfile, zdir, c) != 0
+ || (zfile[c] != '/' && zfile[c] != '\0'))
+ return FALSE;
+ if (strstr (zfile + c, "/../") != NULL)
+ return FALSE;
+
+ /* If we're not checking access, get out now. */
+ if (! fcheck)
+ return TRUE;
+
+ zcopy = zbufcpy (zfile);
+
+ /* Start checking directories after zdir. Otherwise, we would
+ require that all directories down to /usr/spool/uucppublic be
+ publically searchable; they probably are but it should not be a
+ requirement. */
+ zslash = zcopy + c;
+ do
+ {
+ char b;
+ struct stat shold;
+
+ b = *zslash;
+ *zslash = '\0';
+
+ shold = s;
+ if (stat (zcopy, &s) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If this is the top directory, any problems will be caught
+ later when we try to open it. */
+ if (zslash == zcopy + c)
+ {
+ ubuffree (zcopy);
+ return TRUE;
+ }
+
+ /* Go back and check the last directory for read or write
+ access. */
+ s = shold;
+ break;
+ }
+
+ /* If this is not a directory, get out of the loop. */
+ if (! S_ISDIR (s.st_mode))
+ break;
+
+ /* Make sure the directory is searchable. */
+ if (! fsuser_access (&s, X_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If we've reached the end of the string, get out. */
+ if (b == '\0')
+ break;
+
+ *zslash = b;
+ }
+ while ((zslash = strchr (zslash + 1, '/')) != NULL);
+
+ /* At this point s holds a stat on the last component of the path.
+ We must check it for readability or writeability. */
+ if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ ubuffree (zcopy);
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/init.c b/gnu/libexec/uucp/libunix/init.c
new file mode 100644
index 000000000000..d4a137762813
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/init.c
@@ -0,0 +1,394 @@
+/* init.c
+ Initialize the system dependent routines.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#if ! HAVE_GETHOSTNAME && HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+/* Use getcwd in preference to getwd; if we have neither, we will be
+ using a getcwd replacement. */
+#if HAVE_GETCWD
+#undef HAVE_GETWD
+#define HAVE_GETWD 0
+#else /* ! HAVE_GETCWD */
+#if ! HAVE_GETWD
+#undef HAVE_GETCWD
+#define HAVE_GETCWD 1
+#endif /* ! HAVE_GETWD */
+#endif /* ! HAVE_GETCWD */
+
+#if HAVE_GETWD
+/* Get a value for MAXPATHLEN. */
+#if HAVE_SYS_PARAMS_H
+#include <sys/params.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else /* ! defined (PATH_MAX) */
+#define MAXPATHLEN 1024
+#endif /* ! defined (PATH_MAX) */
+#endif /* ! defined (MAXPATHLEN) */
+#endif /* HAVE_GETWD */
+
+/* External functions. */
+#ifndef getlogin
+extern char *getlogin ();
+#endif
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+#if HAVE_GETCWD
+#ifndef getcwd
+extern char *getcwd ();
+#endif
+#endif
+#if HAVE_GETWD
+#ifndef getwd
+extern char *getwd ();
+#endif
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Initialize the system dependent routines. We will probably be running
+ suid to uucp, so we make sure that nothing is obviously wrong. We
+ save the login name since we will be losing the real uid. */
+static char *zSlogin;
+
+/* The UUCP spool directory. */
+const char *zSspooldir;
+
+/* The UUCP lock directory. */
+const char *zSlockdir;
+
+/* The local UUCP name. */
+const char *zSlocalname;
+
+/* We save the current directory since we will do a chdir to the
+ spool directory. */
+char *zScwd;
+
+/* The maximum length of a system name is controlled by the type of spool
+ directory we use. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+size_t cSysdep_max_name_len = 7;
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+size_t cSysdep_max_name_len = 14;
+#endif
+#if SPOOLDIR_TAYLOR
+#if HAVE_LONG_FILE_NAMES
+size_t cSysdep_max_name_len = 255;
+#else /* ! HAVE_LONG_FILE_NAMES */
+size_t cSysdep_max_name_len = 14;
+#endif /* ! HAVE_LONG_FILE_NAMES */
+#endif /* SPOOLDIR_TAYLOR */
+
+/* Initialize the system dependent routines. */
+
+void
+usysdep_initialize (puuconf,iflags)
+ pointer puuconf;
+ int iflags;
+{
+ int cdescs;
+ int o;
+ int iuuconf;
+ char *z;
+ struct passwd *q;
+
+ ulog_id (getpid ());
+
+ /* Close everything but stdin, stdout and stderr. */
+#if HAVE_GETDTABLESIZE
+ cdescs = getdtablesize ();
+#else
+#if HAVE_SYSCONF
+ cdescs = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ cdescs = OPEN_MAX;
+#else
+#ifdef NOFILE
+ cdescs = NOFILE;
+#else
+ cdescs = 20;
+#endif /* ! defined (NOFILE) */
+#endif /* ! defined (OPEN_MAX) */
+#endif /* ! HAVE_SYSCONF */
+#endif /* ! HAVE_GETDTABLESIZE */
+
+ for (o = 3; o < cdescs; o++)
+ (void) close (o);
+
+ /* Make sure stdin, stdout and stderr are open. */
+ if (fcntl (0, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_RDONLY, 0) != 0)
+ exit (EXIT_FAILURE);
+ if (fcntl (1, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 1)
+ exit (EXIT_FAILURE);
+ if (fcntl (2, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 2)
+ exit (EXIT_FAILURE);
+
+ iuuconf = uuconf_spooldir (puuconf, &zSspooldir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_lockdir (puuconf, &zSlockdir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_localname (puuconf, &zSlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+#if HAVE_GETHOSTNAME
+ char ab[256];
+
+ if (gethostname (ab, sizeof ab - 1) < 0)
+ ulog (LOG_FATAL, "gethostname: %s", strerror (errno));
+ ab[sizeof ab - 1] = '\0';
+ ab[strcspn (ab, ".")] = '\0';
+ zSlocalname = zbufcpy (ab);
+#else /* ! HAVE_GETHOSTNAME */
+#if HAVE_UNAME
+ struct utsname s;
+
+ if (uname (&s) < 0)
+ ulog (LOG_FATAL, "uname: %s", strerror (errno));
+ zSlocalname = zbufcpy (s.nodename);
+#else /* ! HAVE_UNAME */
+ ulog (LOG_FATAL, "Don't know how to get local node name");
+#endif /* ! HAVE_UNAME */
+#endif /* ! HAVE_GETHOSTNAME */
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ /* We always set our file modes to exactly what we want. */
+ umask (0);
+
+ /* Get the login name, making sure that it matches the uid. Many
+ systems truncate the getlogin return value to 8 characters, but
+ keep the full name in the password file, so we prefer the name in
+ the password file. */
+ z = getenv ("LOGNAME");
+ if (z == NULL)
+ z = getenv ("USER");
+ if (z == NULL)
+ z = getlogin ();
+ if (z == NULL)
+ q = NULL;
+ else
+ {
+ q = getpwnam (z);
+ if (q != NULL)
+ z = q->pw_name;
+ }
+ if (q == NULL || q->pw_uid != getuid ())
+ {
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ z = NULL;
+ else
+ z = q->pw_name;
+ }
+ if (z != NULL)
+ zSlogin = zbufcpy (z);
+
+ /* On some old systems, an suid program run by root is started with
+ an euid of 0. If this happens, we look up the uid we should have
+ and set ourselves to it manually. This means that on such a
+ system root will not be able to uucp or uux files that are not
+ readable by uucp. */
+ if ((iflags & INIT_SUID) != 0
+ && geteuid () == 0)
+ {
+ q = getpwnam (OWNER);
+ if (q != NULL)
+ setuid (q->pw_uid);
+ }
+
+ if ((iflags & INIT_GETCWD) != 0)
+ {
+ const char *zenv;
+ struct stat senv, sdot;
+
+ /* Get the current working directory. We have to get it now,
+ since we're about to do a chdir. We use PWD if it's defined
+ and if it really names the working directory, since if it's
+ not the same as whatever getcwd returns it's probably more
+ appropriate. */
+ zenv = getenv ("PWD");
+ if (zenv != NULL
+ && stat ((char *) zenv, &senv) == 0
+ && stat ((char *) ".", &sdot) == 0
+ && senv.st_ino == sdot.st_ino
+ && senv.st_dev == sdot.st_dev)
+ zScwd = zbufcpy (zenv);
+ else
+ {
+
+#if HAVE_GETCWD
+ {
+ size_t c;
+
+ c = 128;
+ while (TRUE)
+ {
+ zScwd = (char *) xmalloc (c);
+ if (getcwd (zScwd, c) != NULL)
+ break;
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ if (errno != ERANGE)
+ break;
+ c <<= 1;
+ }
+ }
+#endif /* HAVE_GETCWD */
+
+#if HAVE_GETWD
+ zScwd = (char *) xmalloc (MAXPATHLEN);
+ if (getwd (zScwd) == NULL)
+ {
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ }
+#endif /* HAVE_GETWD */
+
+ if (zScwd != NULL)
+ zScwd = (char *) xrealloc ((pointer) zScwd,
+ strlen (zScwd) + 1);
+ }
+ }
+
+ if ((iflags & INIT_NOCHDIR) == 0)
+ {
+ /* Connect to the spool directory, and create it if it doesn't
+ exist. */
+ if (chdir (zSspooldir) < 0)
+ {
+ if (errno == ENOENT
+ && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0)
+ ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir,
+ strerror (errno));
+ if (chdir (zSspooldir) < 0)
+ ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir,
+ strerror (errno));
+ }
+ }
+}
+
+/* Exit the program. */
+
+void
+usysdep_exit (fsuccess)
+ boolean fsuccess;
+{
+ exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/* This is called when a non-standard configuration file is used, to
+ make sure the program doesn't hand out privileged file access.
+ This means that to test non-standard configuration files, you
+ should be logged in as uucp. This is called before
+ usysdep_initialize. It ensures that someone can't simply use an
+ alternate configuration file to steal UUCP transfers from other
+ systems. This will still permit people to set up their own
+ configuration file and pretend to be whatever system they choose.
+ The only real security is to use a high level of protection on the
+ modem ports. */
+
+/*ARGSUSED*/
+boolean fsysdep_other_config (z)
+ const char *z;
+{
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ return TRUE;
+}
+
+/* Get the node name to use if it was not specified in the configuration
+ file. */
+
+const char *
+zsysdep_localname ()
+{
+ return zSlocalname;
+}
+
+/* Get the login name. We actually get the login name in
+ usysdep_initialize, because after that we may switch away from the
+ real uid. */
+
+const char *
+zsysdep_login_name ()
+{
+ if (zSlogin == NULL)
+ ulog (LOG_FATAL, "Can't get login name");
+ return zSlogin;
+}
diff --git a/gnu/libexec/uucp/libunix/isdir.c b/gnu/libexec/uucp/libunix/isdir.c
new file mode 100644
index 000000000000..fc95e5275a82
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/isdir.c
@@ -0,0 +1,18 @@
+/* isdir.c
+ See whether a file exists and is a directory. */
+
+#include "uucp.h"
+
+#include "system.h"
+#include "sysdep.h"
+
+boolean
+fsysdep_directory (z)
+ const char *z;
+{
+ struct stat s;
+
+ if (stat ((char *) z, &s) < 0)
+ return FALSE;
+ return S_ISDIR (s.st_mode);
+}
diff --git a/gnu/libexec/uucp/libunix/isfork.c b/gnu/libexec/uucp/libunix/isfork.c
new file mode 100644
index 000000000000..f067d07552cd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/isfork.c
@@ -0,0 +1,25 @@
+/* isfork.c
+ Retry fork several times before giving up. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+pid_t
+ixsfork ()
+{
+ int i;
+ pid_t iret;
+
+ for (i = 0; i < 10; i++)
+ {
+ iret = fork ();
+ if (iret >= 0 || errno != EAGAIN)
+ return iret;
+ sleep (5);
+ }
+
+ return iret;
+}
diff --git a/gnu/libexec/uucp/libunix/iswait.c b/gnu/libexec/uucp/libunix/iswait.c
new file mode 100644
index 000000000000..d2610aa1f8bd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/iswait.c
@@ -0,0 +1,159 @@
+/* iswait.c
+ Wait for a process to finish.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/* We use a typedef wait_status for wait (waitpid, wait4) to put
+ results into. We define the POSIX examination functions we need if
+ they are not already defined (if they aren't defined, I assume that
+ we have a standard wait status). */
+
+#if HAVE_UNION_WAIT
+typedef union wait wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(u) ((u).w_termsig == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(u) ((u).w_retcode)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(u) ((u).w_termsig)
+#endif
+#else /* ! HAVE_UNION_WAIT */
+typedef int wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(i) (((i) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(i) ((i) & 0x7f)
+#endif
+#endif /* ! HAVE_UNION_WAIT */
+
+/* Wait for a particular process to finish. The ipid argument should
+ be pid_t, but then we couldn't have a prototype. If the zreport
+ argument is not NULL, then a wait error will be logged, and if the
+ exit status is non-zero it will be logged with zreport as the
+ header of the log message. If the zreport argument is NULL, no
+ errors will be logged. This function returns the exit status if
+ the process exited normally, or -1 on error or if the process was
+ killed by a signal (I don't just always return the exit status
+ because then the calling code would have to prepared to handle
+ union wait status vs. int status, and none of the callers care
+ which signal killed the program anyhow).
+
+ This functions keeps waiting until the process finished, even if it
+ is interrupted by a signal. I think this is right for all uses.
+ The controversial one would be when called from uuxqt to wait for a
+ requested process. Hitting uuxqt with SIGKILL will approximate the
+ actions taken if we return from here with an error anyhow. If we
+ do get a signal, we call ulog with a NULL argument to get it in the
+ log file at about the right time. */
+
+int
+ixswait (ipid, zreport)
+ unsigned long ipid;
+ const char *zreport;
+{
+ wait_status istat;
+
+#if HAVE_WAITPID
+ while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "waitpid: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAITPID */
+#if HAVE_WAIT4
+ while (wait4 ((pid_t) ipid, (pointer) &istat, 0,
+ (struct rusage *) NULL) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait4: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAIT4 */
+ pid_t igot;
+
+ /* We could theoretically get the wrong child here if we're in some
+ kind of weird pipeline, so we don't give any error messages for
+ it. */
+ while ((igot = wait ((pointer) &istat)) != (pid_t) ipid)
+ {
+ if (igot < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ }
+#endif /* ! HAVE_WAIT4 */
+#endif /* ! HAVE_WAITPID */
+
+ DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d",
+ WIFEXITED (istat) ? "Exit status" : "Signal",
+ WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat));
+
+ if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0)
+ return 0;
+
+ if (zreport != NULL)
+ {
+ if (! WIFEXITED (istat))
+ ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat));
+ else
+ ulog (LOG_ERROR, "%s: Exit status %d", zreport,
+ WEXITSTATUS (istat));
+ }
+
+ if (WIFEXITED (istat))
+ return WEXITSTATUS (istat);
+ else
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/jobid.c b/gnu/libexec/uucp/libunix/jobid.c
new file mode 100644
index 000000000000..7f22f1d37d75
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/jobid.c
@@ -0,0 +1,101 @@
+/* jobid.c
+ Convert file names to jobids and vice versa.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Translate a file name and an associated system into a job id.
+ These job ids are used by uustat. We use the system name attached
+ to the grade and sequence number. This won't work correctly if the
+ file name was actually created by some other version of uucp that
+ uses a different length for the sequence number. Too bad. */
+
+char *
+zsfile_to_jobid (qsys, zfile, bgrade)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ int bgrade;
+{
+ size_t clen;
+ char *zret;
+
+ clen = strlen (qsys->uuconf_zname);
+ zret = zbufalc (clen + CSEQLEN + 2);
+ memcpy (zret, qsys->uuconf_zname, clen);
+ zret[clen] = bgrade;
+ memcpy (zret + clen + 1, zfile + strlen (zfile) - CSEQLEN, CSEQLEN + 1);
+ return zret;
+}
+
+/* Turn a job id back into a file name. */
+
+char *
+zsjobid_to_file (zid, pzsystem, pbgrade)
+ const char *zid;
+ char **pzsystem;
+ char *pbgrade;
+{
+ size_t clen;
+ const char *zend;
+ char *zsys;
+ char abname[CSEQLEN + 11];
+ char *zret;
+
+ clen = strlen (zid);
+ if (clen <= CSEQLEN)
+ {
+ ulog (LOG_ERROR, "%s: Bad job id", zid);
+ return NULL;
+ }
+
+ zend = zid + clen - CSEQLEN - 1;
+
+ zsys = zbufalc (clen - CSEQLEN);
+ memcpy (zsys, zid, clen - CSEQLEN - 1);
+ zsys[clen - CSEQLEN - 1] = '\0';
+
+ /* This must correspond to zsfile_name. */
+#if ! SPOOLDIR_TAYLOR
+ sprintf (abname, "C.%.7s%s", zsys, zend);
+#else
+ sprintf (abname, "C.%s", zend);
+#endif
+
+ zret = zsfind_file (abname, zsys, *zend);
+
+ if (zret != NULL && pzsystem != NULL)
+ *pzsystem = zsys;
+ else
+ ubuffree (zsys);
+
+ if (pbgrade != NULL)
+ *pbgrade = *zend;
+
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/lcksys.c b/gnu/libexec/uucp/libunix/lcksys.c
new file mode 100644
index 000000000000..4ece16afe7b5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/lcksys.c
@@ -0,0 +1,41 @@
+/* lcksys.c
+ Lock and unlock a remote system. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Lock a remote system. */
+
+boolean
+fsysdep_lock_system (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *z;
+ boolean fret;
+
+ z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
+ sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
+ fret = fsdo_lock (z, FALSE, (boolean *) NULL);
+ ubuffree (z);
+ return fret;
+}
+
+/* Unlock a remote system. */
+
+boolean
+fsysdep_unlock_system (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *z;
+ boolean fret;
+
+ z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
+ sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
+ fret = fsdo_unlock (z, FALSE);
+ ubuffree (z);
+ return fret;
+}
diff --git a/gnu/libexec/uucp/libunix/link.c b/gnu/libexec/uucp/libunix/link.c
new file mode 100644
index 000000000000..4550c76c94d9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/link.c
@@ -0,0 +1,38 @@
+/* link.c
+ Link two files. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_link (zfrom, zto, pfworked)
+ const char *zfrom;
+ const char *zto;
+ boolean *pfworked;
+{
+ *pfworked = FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, TRUE))
+ return FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ }
+ if (errno == EXDEV)
+ return TRUE;
+ ulog (LOG_ERROR, "link (%s, %s): %s", zfrom, zto, strerror (errno));
+ return FALSE;
+}
diff --git a/gnu/libexec/uucp/libunix/locfil.c b/gnu/libexec/uucp/libunix/locfil.c
new file mode 100644
index 000000000000..0e05af9bcee9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/locfil.c
@@ -0,0 +1,95 @@
+/* locfil.c
+ Expand a file name on the local 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <pwd.h>
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Turn a file name into an absolute path, by doing tilde expansion
+ and moving any other type of file into the public directory. */
+
+char *
+zsysdep_local_file (zfile, zpubdir)
+ const char *zfile;
+ const char *zpubdir;
+{
+ const char *zdir;
+
+ if (*zfile == '/')
+ return zbufcpy (zfile);
+
+ if (*zfile != '~')
+ zdir = zpubdir;
+ else
+ {
+ if (zfile[1] == '\0')
+ return zbufcpy (zpubdir);
+
+ if (zfile[1] == '/')
+ {
+ zdir = zpubdir;
+ zfile += 2;
+ }
+ else
+ {
+ size_t cuserlen;
+ char *zcopy;
+ struct passwd *q;
+
+ ++zfile;
+ cuserlen = strcspn ((char *) zfile, "/");
+ zcopy = zbufalc (cuserlen + 1);
+ memcpy (zcopy, zfile, cuserlen);
+ zcopy[cuserlen] = '\0';
+
+ q = getpwnam (zcopy);
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "User %s not found", zcopy);
+ ubuffree (zcopy);
+ return NULL;
+ }
+ ubuffree (zcopy);
+
+ if (zfile[cuserlen] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ zdir = q->pw_dir;
+ zfile += cuserlen + 1;
+ }
+ }
+
+ return zsysdep_in_dir (zdir, zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/lock.c b/gnu/libexec/uucp/libunix/lock.c
new file mode 100644
index 000000000000..d823213017b6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/lock.c
@@ -0,0 +1,477 @@
+/* lock.c
+ Lock and unlock a file name.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/05 18:24:06 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* Lock something. If the fspooldir argument is TRUE, the argument is
+ a file name relative to the spool directory; otherwise the argument
+ is a simple file name which should be created in the system lock
+ directory (under HDB this is /etc/locks). */
+
+boolean
+fsdo_lock (zlock, fspooldir, pferr)
+ const char *zlock;
+ boolean fspooldir;
+ boolean *pferr;
+{
+ char *zfree;
+ const char *zpath, *zslash;
+ size_t cslash;
+ pid_t ime;
+ char *ztempfile;
+ char abtempfile[sizeof "TMP1234567890"];
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cwrote;
+ const char *zerr;
+ boolean fret;
+
+ if (pferr != NULL)
+ *pferr = TRUE;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ ime = getpid ();
+
+ /* We do the actual lock by creating a file and then linking it to
+ the final file name we want. This avoids race conditions due to
+ one process checking the file before we have finished writing it,
+ and also works even if we are somehow running as root.
+
+ First, create the file in the right directory (we must create the
+ file in the same directory since otherwise we might attempt a
+ cross-device link). */
+ zslash = strrchr (zpath, '/');
+ if (zslash == NULL)
+ cslash = 0;
+ else
+ cslash = zslash - zpath + 1;
+
+ sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
+ ztempfile = zbufalc (cslash + sizeof abtempfile);
+ memcpy (ztempfile, zpath, cslash);
+ memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
+
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (ztempfile, FALSE))
+ {
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno));
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ zerr = NULL;
+ if (cwrote < 0)
+ zerr = "write";
+ if (close (o) < 0)
+ zerr = "close";
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno));
+ (void) remove (ztempfile);
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+
+ /* Now try to link the file we just created to the lock file that we
+ want. If it fails, try reading the existing file to make sure
+ the process that created it still exists. We do this in a loop
+ to make it easy to retry if the old locking process no longer
+ exists. */
+ fret = TRUE;
+ if (pferr != NULL)
+ *pferr = FALSE;
+ o = -1;
+ zerr = NULL;
+
+ while (link (ztempfile, zpath) != 0)
+ {
+ int cgot;
+ int ipid;
+ boolean freadonly;
+
+ fret = FALSE;
+
+ if (errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath,
+ strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ break;
+ }
+
+ freadonly = FALSE;
+ o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno == EACCES)
+ {
+ freadonly = TRUE;
+ o = open ((char *) zpath, O_RDONLY, 0);
+ }
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /* The file was presumably removed between the link
+ and the open. Try the link again. */
+ fret = TRUE;
+ continue;
+ }
+ zerr = "open";
+ break;
+ }
+ }
+
+ /* The race starts here. See below for a discussion. */
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ /* On NFS, the link might have actually succeeded even though we
+ got a failure return. This can happen if the original
+ acknowledgement was lost or delayed and the operation was
+ retried. In this case the pid will be our own. This
+ introduces a rather improbable race condition: if a stale
+ lock was left with our process ID in it, and another process
+ just did the kill, below, but has not yet changed the lock
+ file to hold its own process ID, we could start up and make
+ it all the way to here and think we have the lock. I'm not
+ going to worry about this possibility. */
+ if (ipid == ime)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* If the process still exists, we will get EPERM rather than
+ ESRCH. We then return FALSE to indicate that we cannot make
+ the lock. */
+ if (kill (ipid, 0) == 0 || errno == EPERM)
+ break;
+
+ ulog (LOG_ERROR, "Found stale lock %s held by process %d",
+ zpath, ipid);
+
+ /* This is a stale lock, created by a process that no longer
+ exists.
+
+ Now we could remove the file (and, if the file mode disallows
+ writing, that's what we have to do), but we try to avoid
+ doing so since it causes a race condition. If we remove the
+ file, and are interrupted any time after we do the read until
+ we do the remove, another process could get in, open the
+ file, find that it was a stale lock, remove the file and
+ create a new one. When we regained control we would remove
+ the file the other process just created.
+
+ These files are being generated partially for the benefit of
+ cu, and it would be nice to avoid the race however cu avoids
+ it, so that the programs remain compatible. Unfortunately,
+ nobody seems to know how cu avoids the race, or even if it
+ tries to avoid it at all.
+
+ There are a few ways to avoid the race. We could use kernel
+ locking primitives, but they may not be available. We could
+ link to a special file name, but if that file were left lying
+ around then no stale lock could ever be broken (Henry Spencer
+ would think this was a good thing).
+
+ Instead I've implemented the following procedure: seek to the
+ start of the file, write our pid into it, sleep for five
+ seconds, and then make sure our pid is still there. Anybody
+ who checks the file while we're asleep will find our pid
+ there and fail the lock. The only race will come from
+ another process which has done the read by the time we do our
+ write. That process will then have five seconds to do its
+ own write. When we wake up, we'll notice that our pid is no
+ longer in the file, and retry the lock from the beginning.
+
+ This relies on the atomicity of write(2). If it possible for
+ the writes of two processes to be interleaved, the two
+ processes could livelock. POSIX unfortunately leaves this
+ case explicitly undefined; however, given that the write is
+ of less than a disk block, it's difficult to imagine an
+ interleave occurring.
+
+ Note that this is still a race. If it takes the second
+ process more than five seconds to do the kill, the lseek, and
+ the write, both processes will think they have the lock.
+ Perhaps the length of time to sleep should be configurable.
+ Even better, perhaps I should add a configuration option to
+ use a permanent lock file, which eliminates any race and
+ forces the installer to be aware of the existence of the
+ permanent lock file.
+
+ We stat the file after the sleep, to make sure some other
+ program hasn't deleted it for us. */
+ if (freadonly)
+ {
+ (void) close (o);
+ o = -1;
+ (void) remove (zpath);
+ continue;
+ }
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ if (cwrote < 0)
+ {
+ zerr = "write";
+ break;
+ }
+
+ (void) sleep (5);
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ if (ipid == ime)
+ {
+ struct stat sfile, sdescriptor;
+
+ /* It looks like we have the lock. Do the final stat
+ check. */
+ if (stat ((char *) zpath, &sfile) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ zerr = "stat";
+ break;
+ }
+ /* Loop around and try again. */
+ }
+ else
+ {
+ if (fstat (o, &sdescriptor) < 0)
+ {
+ zerr = "fstat";
+ break;
+ }
+
+ if (sfile.st_ino == sdescriptor.st_ino
+ && sfile.st_dev == sdescriptor.st_dev)
+ {
+ /* Close the file before assuming we've succeeded to
+ pick up any trailing errors. */
+ if (close (o) < 0)
+ {
+ zerr = "close";
+ break;
+ }
+
+ o = -1;
+
+ /* We have the lock. */
+ fret = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Loop around and try the lock again. We keep doing this until
+ the lock file holds a pid that exists. */
+ (void) close (o);
+ o = -1;
+ fret = TRUE;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ }
+
+ if (o >= 0)
+ (void) close (o);
+
+ ubuffree (zfree);
+
+ /* It would be nice if we could leave the temporary file around for
+ future calls, but considering that we create lock files in
+ various different directories it's probably more trouble than
+ it's worth. */
+ if (remove (ztempfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
+
+ ubuffree (ztempfile);
+
+ return fret;
+}
+
+/* Unlock something. The fspooldir argument is as in fsdo_lock. */
+
+boolean
+fsdo_unlock (zlock, fspooldir)
+ const char *zlock;
+ boolean fspooldir;
+{
+ char *zfree;
+ const char *zpath;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ if (remove (zpath) == 0
+ || errno == ENOENT)
+ {
+ ubuffree (zfree);
+ return TRUE;
+ }
+ else
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+}
diff --git a/gnu/libexec/uucp/libunix/loctim.c b/gnu/libexec/uucp/libunix/loctim.c
new file mode 100644
index 000000000000..da5f32e2d273
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/loctim.c
@@ -0,0 +1,25 @@
+/* loctim.c
+ Turn a time epoch into a struct tm. This is trivial on Unix. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef localtime
+extern struct tm *localtime ();
+#endif
+
+void
+usysdep_localtime (itime, q)
+ long itime;
+ struct tm *q;
+{
+ time_t i;
+
+ i = (time_t) itime;
+ *q = *localtime (&i);
+}
diff --git a/gnu/libexec/uucp/libunix/mail.c b/gnu/libexec/uucp/libunix/mail.c
new file mode 100644
index 000000000000..74c1aa95adc6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mail.c
@@ -0,0 +1,85 @@
+/* mail.c
+ Send mail to a user.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifndef ctime
+extern char *ctime ();
+#endif
+
+/* Mail a message to a user. */
+
+boolean
+fsysdep_mail (zto, zsubject, cstrs, paz)
+ const char *zto;
+ const char *zsubject;
+ int cstrs;
+ const char **paz;
+{
+ const char *az[3];
+ FILE *e;
+ pid_t ipid;
+ time_t itime;
+ int i;
+
+ az[0] = MAIL_PROGRAM;
+ az[1] = zto;
+ az[2] = NULL;
+
+ e = espopen (az, FALSE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM,
+ strerror (errno));
+ return FALSE;
+ }
+
+ fprintf (e, "Subject: %s\n", zsubject);
+ fprintf (e, "To: %s\n", zto);
+
+ fprintf (e, "\n");
+
+ (void) time (&itime);
+ /* Remember that ctime includes a \n, so this skips a line. */
+ fprintf (e, "Message from UUCP on %s %s\n", zSlocalname,
+ ctime (&itime));
+
+ for (i = 0; i < cstrs; i++)
+ fputs (paz[i], e);
+
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, MAIL_PROGRAM) == 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdir.c b/gnu/libexec/uucp/libunix/mkdir.c
new file mode 100644
index 000000000000..f59ad5dfd6e6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdir.c
@@ -0,0 +1,58 @@
+/* mkdir.c
+ Create a directory. We must go through a subsidiary program to
+ force our real uid to be the uucp owner before invoking the setuid
+ /bin/mkdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+mkdir (zdir, imode)
+ const char *zdir;
+ int imode;
+{
+ struct stat s;
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ /* Make sure the directory does not exist, since we will otherwise
+ get the wrong errno value. */
+ if (stat (zdir, &s) == 0)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ /* /bin/mkdir will create the directory with mode 777, so we set our
+ umask to get the mode we want. */
+ (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO));
+
+ azargs[0] = UUDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
+ TRUE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ (void) umask (0);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdirs.c b/gnu/libexec/uucp/libunix/mkdirs.c
new file mode 100644
index 000000000000..a4e0b67bb8c3
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdirs.c
@@ -0,0 +1,49 @@
+/* mkdirs.c
+ Create any directories needed for a file name. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_make_dirs (zfile, fpublic)
+ const char *zfile;
+ boolean fpublic;
+{
+ char *zcopy, *z;
+ int imode;
+
+ zcopy = zbufcpy (zfile);
+
+ if (fpublic)
+ imode = IPUBLIC_DIRECTORY_MODE;
+ else
+ imode = IDIRECTORY_MODE;
+
+ for (z = zcopy; *z != '\0'; z++)
+ {
+ if (*z == '/' && z != zcopy)
+ {
+ *z = '\0';
+ if (! fsysdep_directory (zcopy))
+ {
+ if (mkdir (zcopy, imode) != 0)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
+ strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ }
+ *z = '/';
+ }
+ }
+
+ ubuffree (zcopy);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/mode.c b/gnu/libexec/uucp/libunix/mode.c
new file mode 100644
index 000000000000..53f74ec81c3e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mode.c
@@ -0,0 +1,33 @@
+/* mode.c
+ Get the Unix file mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+unsigned int
+ixsysdep_file_mode (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return 0;
+ }
+
+#if S_IRWXU != 0700
+ #error Files modes need to be translated
+#endif
+
+ /* We can't return 0, since that indicate an error. */
+ if ((s.st_mode & 0777) == 0)
+ return 0400;
+
+ return s.st_mode & 0777;
+}
diff --git a/gnu/libexec/uucp/libunix/move.c b/gnu/libexec/uucp/libunix/move.c
new file mode 100644
index 000000000000..ccfe6d4d728d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/move.c
@@ -0,0 +1,176 @@
+/* move.c
+ Move a 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* Move (rename) a file from one name to another. This routine will
+ optionally create necessary directories, and fpublic indicates
+ whether the new directories should be publically accessible or not.
+ If fcheck is true, it will try to determine whether the named user
+ has write access to the new file. */
+
+boolean
+fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
+ const char *zorig;
+ const char *zto;
+ boolean fmkdirs;
+ boolean fpublic;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ int o;
+
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "fsysdep_move_file: Moving %s to %s", zorig, zto);
+
+ /* Optionally make sure that zuser has write access on the
+ directory. */
+ if (fcheck)
+ {
+ char *zcopy;
+ char *zslash;
+
+ zcopy = zbufcpy (zto);
+ zslash = strrchr (zcopy, '/');
+ if (zslash == zcopy)
+ zslash[1] = '\0';
+ else
+ *zslash = '\0';
+
+ if (stat (zcopy, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ if (! fsuser_access (&s, W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ ubuffree (zcopy);
+
+ /* A malicious user now has a few milliseconds to change a
+ symbolic link to a directory uucp has write permission on but
+ the user does not (the obvious choice being /usr/lib/uucp).
+ The only certain method I can come up with to close this race
+ is to fork an suid process which takes on the users identity
+ and does the actual copy. This is sufficiently high overhead
+ that I'm not going to do it. */
+ }
+
+ /* We try to use rename to move the file. */
+
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+ }
+
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to copy the
+ file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ /* If we can't link across devices, we must copy the file by hand. */
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto,
+ strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Copy the file. */
+ if (stat ((char *) zorig, &s) < 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Make sure the file gets the right mode by creating it before we
+ call fcopy_file. */
+ (void) remove (zto);
+ o = creat ((char *) zto, s.st_mode);
+ if (o < 0)
+ {
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ o = creat ((char *) zto, s.st_mode);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+ }
+ (void) close (o);
+
+ if (! fcopy_file (zorig, zto, fpublic, fmkdirs))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ if (remove (zorig) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno));
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/opensr.c b/gnu/libexec/uucp/libunix/opensr.c
new file mode 100644
index 000000000000..3a8ca7a8b8ac
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/opensr.c
@@ -0,0 +1,244 @@
+/* opensr.c
+ Open files for sending and receiving.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Open a file to send to another system, and return the mode and
+ the size. */
+
+openfile_t
+esysdep_open_send (qsys, zfile, fcheck, zuser)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ openfile_t e;
+ int o;
+
+ if (fsysdep_directory (zfile))
+ {
+ ulog (LOG_ERROR, "%s: is a directory", zfile);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fopen (zfile, BINREAD);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ o = fileno (e);
+#else
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ if (e == -1)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return -1;
+ }
+ o = e;
+#endif
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (fstat (o, &s) == -1)
+ {
+ ulog (LOG_ERROR, "fstat: %s", strerror (errno));
+ s.st_mode = 0666;
+ }
+
+ /* We have to recheck the file permission, although we probably
+ checked it already, because otherwise there would be a window in
+ which somebody could change the contents of a symbolic link to
+ point to some file which was only readable by uucp. */
+ if (fcheck)
+ {
+ if (! fsuser_access (&s, R_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+ }
+
+ return e;
+}
+
+/* Get a temporary file name to receive into. We use the ztemp
+ argument to pick the file name, so that we relocate the file if the
+ transmission is aborted. */
+
+char *
+zsysdep_receive_temp (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Temp", qsys->uuconf_zname, ztemp);
+ else
+ return zstemp_file (qsys);
+}
+
+/* Open a temporary file to receive into. This should, perhaps, check
+ that we have write permission on the receiving directory, but it
+ doesn't. */
+
+openfile_t
+esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+ const char *zreceive;
+ long *pcrestart;
+{
+ int o;
+ openfile_t e;
+
+ /* If we used the ztemp argument in zsysdep_receive_temp, above,
+ then we will have a name consistent across conversations. In
+ that case, we may have already received some portion of this
+ file. */
+ o = -1;
+ *pcrestart = -1;
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ {
+ o = open ((char *) zreceive, O_WRONLY);
+ if (o >= 0)
+ {
+ struct stat s;
+
+ /* For safety, we insist on the file being less than 1 week
+ old. This can still catch people, unfortunately. I
+ don't know of any good solution to the problem of old
+ files hanging around. If anybody has a file they want
+ restarted, and they know about this issue, they can touch
+ it to bring it up to date. */
+ if (fstat (o, &s) < 0
+ || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL))
+ {
+ (void) close (o);
+ o = -1;
+ }
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "esysdep_open_receive: Reusing %s",
+ zreceive);
+ *pcrestart = (long) s.st_size;
+ }
+ }
+ }
+
+ if (o < 0)
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zreceive, FALSE))
+ return EFILECLOSED;
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zreceive, strerror (errno));
+ return EFILECLOSED;
+ }
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+#else
+ e = o;
+#endif
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/pause.c b/gnu/libexec/uucp/libunix/pause.c
new file mode 100644
index 000000000000..e774e0897bf2
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/pause.c
@@ -0,0 +1,96 @@
+/* pause.c
+ Pause for half a second. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+/* Pick a timing routine to use. I somewhat arbitrarily picked usleep
+ above nap above napms above poll above select. */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#undef HAVE_SELECT
+#define HAVE_SELECT 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+#if HAVE_SELECT
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_POLL
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#if ! HAVE_STROPTS_H && ! HAVE_POLL_H
+/* We need a definition for struct pollfd, although it doesn't matter
+ what it contains. */
+struct pollfd
+{
+ int idummy;
+};
+#endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */
+#endif /* HAVE_POLL */
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER
+#include <time.h>
+#endif
+#endif
+
+void
+usysdep_pause ()
+{
+#if HAVE_NAPMS
+ napms (500);
+#endif /* HAVE_NAPMS */
+#if HAVE_NAP
+#if HAVE_HUNDREDTHS_NAP
+ nap (50L);
+#else
+ nap (500L);
+#endif /* ! HAVE_HUNDREDTHS_NAP */
+#endif /* HAVE_NAP */
+#if HAVE_USLEEP
+ usleep (500 * (long) 1000);
+#endif /* HAVE_USLEEP */
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ /* We need to pass an unused pollfd structure because poll checks
+ the address before checking the number of elements. */
+ poll (&sdummy, 0, 500);
+#endif /* HAVE_POLL */
+#if HAVE_SELECT
+ struct timeval s;
+
+ s.tv_sec = 0;
+ s.tv_usec = 500 * (long) 1000;
+ select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
+#if ! USE_SELECT_TIMER && ! HAVE_POLL
+ sleep (1);
+#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
+#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
+}
diff --git a/gnu/libexec/uucp/libunix/picksb.c b/gnu/libexec/uucp/libunix/picksb.c
new file mode 100644
index 000000000000..4d8cc4b2f3b6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/picksb.c
@@ -0,0 +1,230 @@
+/* picksb.c
+ System dependent routines for uupick.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char picksb_rcsid[] = "$Id: picksb.c,v 1.1 1993/08/05 18:24:15 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+
+/* Local variables. */
+
+/* Directory of ~/receive/USER. */
+static DIR *qStopdir;
+
+/* Name of ~/receive/USER. */
+static char *zStopdir;
+
+/* Directory of ~/receive/USER/SYSTEM. */
+static DIR *qSsysdir;
+
+/* Name of system. */
+static char *zSsysdir;
+
+/* Prepare to get a list of all the file to uupick for this user. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_init (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ const char *zuser;
+
+ zuser = zsysdep_login_name ();
+
+ zStopdir = (char *) xmalloc (strlen (zpubdir)
+ + sizeof "/receive/"
+ + strlen (zuser));
+ sprintf (zStopdir, "%s/receive/%s", zpubdir, zuser);
+
+ qStopdir = opendir (zStopdir);
+ if (qStopdir == NULL && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zStopdir,
+ strerror (errno));
+ return FALSE;
+ }
+
+ qSsysdir = NULL;
+
+ return TRUE;
+}
+
+/* Return the next file from the uupick directories. */
+
+/*ARGSUSED*/
+char *
+zsysdep_uupick (zsysarg, zpubdir, pzfrom, pzfull)
+ const char *zsysarg;
+ const char *zpubdir;
+ char **pzfrom;
+ char **pzfull;
+{
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ while (qSsysdir == NULL)
+ {
+ const char *zsystem;
+ char *zdir;
+
+ if (qStopdir == NULL)
+ return NULL;
+
+ if (zsysarg != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ zsystem = zsysarg;
+ }
+ else
+ {
+ do
+ {
+ qentry = readdir (qStopdir);
+ if (qentry == NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ return NULL;
+ }
+ }
+ while (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0);
+
+ zsystem = qentry->d_name;
+ }
+
+ zdir = zbufalc (strlen (zStopdir) + strlen (zsystem) + sizeof "/");
+ sprintf (zdir, "%s/%s", zStopdir, zsystem);
+
+ qSsysdir = opendir (zdir);
+ if (qSsysdir == NULL)
+ {
+ if (errno != ENOENT && errno != ENOTDIR)
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ }
+ else
+ {
+ ubuffree (zSsysdir);
+ zSsysdir = zbufcpy (zsystem);
+ }
+
+ ubuffree (zdir);
+ }
+
+ qentry = readdir (qSsysdir);
+ if (qentry == NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ continue;
+ }
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+
+ *pzfrom = zbufcpy (zSsysdir);
+ *pzfull = zsappend3 (zStopdir, zSsysdir, qentry->d_name);
+ return zbufcpy (qentry->d_name);
+ }
+}
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_free (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ xfree ((pointer) zStopdir);
+ if (qStopdir != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ }
+ ubuffree (zSsysdir);
+ zSsysdir = NULL;
+ if (qSsysdir != NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ }
+
+ return TRUE;
+}
+
+/* Expand a local file name for uupick. */
+
+char *
+zsysdep_uupick_local_file (zfile)
+ const char *zfile;
+{
+ struct passwd *q;
+
+ /* If this does not start with a simple ~, pass it to
+ zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd
+ only uses the zpubdir argument if the file starts with a simple
+ ~, so it doesn't really matter what we pass for zpubdir. */
+ if (zfile[0] != '~'
+ || (zfile[1] != '/' && zfile[1] != '\0'))
+ return zsysdep_local_file_cwd (zfile, (const char *) NULL);
+
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "Can't get home directory");
+ return NULL;
+ }
+
+ if (zfile[1] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ return zsysdep_in_dir (q->pw_dir, zfile + 2);
+}
diff --git a/gnu/libexec/uucp/libunix/portnm.c b/gnu/libexec/uucp/libunix/portnm.c
new file mode 100644
index 000000000000..9eda4ab012ba
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/portnm.c
@@ -0,0 +1,51 @@
+/* portnm.c
+ Get the port name of stdin. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_TCP
+#if HAVE_SYS_TYPES_TCP_H
+#include <sys/types.tcp.h>
+#endif
+#include <sys/socket.h>
+#endif
+
+#ifndef ttyname
+extern char *ttyname ();
+#endif
+
+/* Get the port name of standard input. I assume that Unix systems
+ generally support ttyname. If they don't, this function can just
+ return NULL. It uses getsockname to see whether standard input is
+ a TCP connection. */
+
+const char *
+zsysdep_port_name (ftcp_port)
+ boolean *ftcp_port;
+{
+ const char *z;
+
+ *ftcp_port = FALSE;
+
+#if HAVE_TCP
+ {
+ size_t clen;
+ struct sockaddr s;
+
+ clen = sizeof (struct sockaddr);
+ if (getsockname (0, &s, &clen) == 0)
+ *ftcp_port = TRUE;
+ }
+#endif /* HAVE_TCP */
+
+ z = ttyname (0);
+ if (z == NULL)
+ return NULL;
+ if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
+ return z + sizeof "/dev/" - 1;
+ else
+ return z;
+}
diff --git a/gnu/libexec/uucp/libunix/proctm.c b/gnu/libexec/uucp/libunix/proctm.c
new file mode 100644
index 000000000000..55cf96f0c972
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/proctm.c
@@ -0,0 +1,197 @@
+/* proctm.c
+ Get the time spent in the process.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+/* Prefer gettimeofday to ftime to times. */
+
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+#undef HAVE_TIMES
+#define HAVE_TIMES 0
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#undef HAVE_FTIME
+#define HAVE_FTIME 0
+#endif
+
+#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY)
+#include <time.h>
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+
+#if HAVE_FTIME
+#include <sys/timeb.h>
+#endif
+
+#if HAVE_TIMES
+
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+
+#if TIMES_DECLARATION_OK
+/* We use a macro to protect this because times really returns clock_t
+ and on some systems, such as Ultrix 4.0, clock_t is int. We don't
+ leave it out entirely because on some systems, such as System III,
+ the declaration is necessary for correct compilation. */
+#ifndef times
+extern long times ();
+#endif
+#endif /* TIMES_DECLARATION_OK */
+
+#ifdef _SC_CLK_TCK
+#define HAVE_SC_CLK_TCK 1
+#else
+#define HAVE_SC_CLK_TCK 0
+#endif
+
+/* TIMES_TICK may have been set in policy.h, or we may be able to get
+ it using sysconf. If neither is the case, try to find a useful
+ definition from the system header files. */
+#if TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK)
+#ifdef CLK_TCK
+#undef TIMES_TICK
+#define TIMES_TICK CLK_TCK
+#else /* ! defined (CLK_TCK) */
+#ifdef HZ
+#undef TIMES_TICK
+#define TIMES_TICK HZ
+#endif /* defined (HZ) */
+#endif /* ! defined (CLK_TCK) */
+#endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */
+
+#endif /* HAVE_TIMES */
+
+#ifndef time
+extern time_t time ();
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Get the time in seconds and microseconds; this need only work
+ within the process when called from the system independent code.
+ It is also called by ixsysdep_time. */
+
+long
+ixsysdep_process_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY
+ struct timeval stime;
+ struct timezone stz;
+
+ (void) gettimeofday (&stime, &stz);
+ if (pimicros != NULL)
+ *pimicros = (long) stime.tv_usec;
+ return (long) stime.tv_sec;
+#endif /* HAVE_GETTIMEOFDAY */
+
+#if HAVE_FTIME
+ static boolean fbad;
+
+ if (! fbad)
+ {
+ struct timeb stime;
+ static struct timeb slast;
+
+ (void) ftime (&stime);
+
+ /* On some systems, such as SCO 3.2.2, ftime can go backwards in
+ time. If we detect this, we switch to using time. */
+ if (slast.time != 0
+ && (stime.time < slast.time
+ || (stime.time == slast.time &&
+ stime.millitm < slast.millitm)))
+ fbad = TRUE;
+ else
+ {
+ slast = stime;
+ if (pimicros != NULL)
+ *pimicros = (long) stime.millitm * (long) 1000;
+ return (long) stime.time;
+ }
+ }
+
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* HAVE_FTIME */
+
+#if HAVE_TIMES
+ struct tms s;
+ long i;
+ static int itick;
+
+ if (itick == 0)
+ {
+#if TIMES_TICK == 0
+#if HAVE_SYSCONF && HAVE_SC_CLK_TCK
+ itick = (int) sysconf (_SC_CLK_TCK);
+#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+ const char *z;
+
+ z = getenv ("HZ");
+ if (z != NULL)
+ itick = (int) strtol (z, (char **) NULL, 10);
+
+ /* If we really couldn't get anything, just use 60. */
+ if (itick == 0)
+ itick = 60;
+#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+#else /* TIMES_TICK != 0 */
+ itick = TIMES_TICK;
+#endif /* TIMES_TICK == 0 */
+ }
+
+ i = (long) times (&s);
+ if (pimicros != NULL)
+ *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick);
+ return i / (long) itick;
+#endif /* HAVE_TIMES */
+
+#if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */
+}
diff --git a/gnu/libexec/uucp/libunix/recep.c b/gnu/libexec/uucp/libunix/recep.c
new file mode 100644
index 000000000000..84a211a7a946
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/recep.c
@@ -0,0 +1,197 @@
+/* recep.c
+ See whether a file has already been received.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+static char *zsreceived_name P((const struct uuconf_system *qsys,
+ const char *ztemp));
+
+/* These routines are used to see whether we have already received a
+ file in a previous UUCP connection. It is possible for the
+ acknowledgement of a received file to be lost. The sending system
+ will then now know that the file was correctly received, and will
+ send it again. This can be a problem particularly with protocols
+ which support channels, since they may send several small files in
+ a single window, all of which may be received correctly although
+ the sending system never sees the acknowledgement. If these files
+ involve an execution, the execution will happen twice, which will
+ be bad.
+
+ We use a simple system. For each file we want to remember, we
+ create an empty file names .Received/SYS/TEMP, where SYS is the
+ name of the system and TEMP is the name of the temporary file used
+ by the sender. If no temporary file is used by the sender, we
+ don't remember that we received the file. This is not perfect, but
+ execution files will always have a temporary file, so the most
+ important case is handled. Also, any file received from Taylor
+ UUCP 1.04 or greater will always have a temporary file. */
+
+/* Return the name we are going use for the marker, or NULL if we have
+ no name. */
+
+static char *
+zsreceived_name (qsys, ztemp)
+ const struct uuconf_system *qsys;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Received", qsys->uuconf_zname, ztemp);
+ else
+ return NULL;
+}
+
+/* Remember that we have already received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_remember_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ int o;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (fsysdep_make_dirs (zfile, TRUE))
+ {
+ ubuffree (zfile);
+ return FALSE;
+ }
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ }
+
+ ubuffree (zfile);
+
+ /* We don't have to actually put anything in the file; we just use
+ the name. This is more convenient than keeping a file with a
+ list of names. */
+ if (close (o) < 0)
+ {
+ ulog (LOG_ERROR, "fsysdep_remember_reception: close: %s",
+ strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* See if we have already received a file. Note that don't delete the
+ marker file here, because we need to know that the sending system
+ has received our denial first. This function returns TRUE if the
+ file has already been received, FALSE if it has not. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_already_received (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ struct stat s;
+ boolean fret;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return FALSE;
+ if (stat (zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+
+ /* Ignore the file (return FALSE) if it is over one week old. */
+ fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL);
+
+ if (fret)
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s",
+ zfile);
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Forget that we have received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_forget_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ if (remove (zfile) < 0
+ && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/remove.c b/gnu/libexec/uucp/libunix/remove.c
new file mode 100644
index 000000000000..b695888ffaa3
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/remove.c
@@ -0,0 +1,13 @@
+/* remove.c
+ Remove a file (Unix specific implementation). */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+int
+remove (z)
+ const char *z;
+{
+ return unlink (z);
+}
diff --git a/gnu/libexec/uucp/libunix/rename.c b/gnu/libexec/uucp/libunix/rename.c
new file mode 100644
index 000000000000..0947ef5cfaeb
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rename.c
@@ -0,0 +1,27 @@
+/* rename.c
+ Rename a file to a new name (Unix specific implementation). */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* This implementation will not work on directories, but fortunately
+ we never want to rename directories. */
+
+int
+rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
diff --git a/gnu/libexec/uucp/libunix/rmdir.c b/gnu/libexec/uucp/libunix/rmdir.c
new file mode 100644
index 000000000000..12a7b9e4507c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rmdir.c
@@ -0,0 +1,43 @@
+/* rmdir.c
+ Remove a directory on a system which doesn't have the rmdir system
+ call. This is only called by uupick, which is not setuid, so we
+ don't have to worry about the problems of invoking the setuid
+ /bin/rmdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+rmdir (zdir)
+ const char *zdir;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = RMDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ TRUE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EBUSY;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/run.c b/gnu/libexec/uucp/libunix/run.c
new file mode 100644
index 000000000000..e21919628372
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/run.c
@@ -0,0 +1,75 @@
+/* run.c
+ Run a program.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Start up a new program and end the current one. We don't have to
+ worry about SIGHUP because the current process is either not a
+ process group leader (uucp, uux) or it does not have a controlling
+ terminal (uucico). */
+
+boolean
+fsysdep_run (zprogram, zarg1, zarg2)
+ const char *zprogram;
+ const char *zarg1;
+ const char *zarg2;
+{
+ char *zlib;
+ const char *azargs[4];
+ int aidescs[3];
+ pid_t ipid;
+
+ zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram));
+ sprintf (zlib, "%s/%s", SBINDIR, zprogram);
+
+ azargs[0] = zlib;
+ azargs[1] = zarg1;
+ azargs[2] = zarg2;
+ azargs[3] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ /* We pass fsetuid and fshell as TRUE, which permits uucico and
+ uuxqt to be replaced by (non-setuid) shell scripts. */
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ ubuffree (zlib);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/seq.c b/gnu/libexec/uucp/libunix/seq.c
new file mode 100644
index 000000000000..2e01233022a9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/seq.c
@@ -0,0 +1,126 @@
+/* seq.c
+ Get and increment the conversation sequence number for a 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Get the current conversation sequence number for a remote system,
+ and increment it for next time. The conversation sequence number
+ is kept in a file named for the system in the directory .Sequence
+ in the spool directory. This is not compatible with other versions
+ of UUCP, but it makes more sense to me. The sequence file is only
+ used if specified in the information for that system. */
+
+long
+ixsysdep_get_sequence (qsys)
+ const struct uuconf_system *qsys;
+{
+ FILE *e;
+ char *zname;
+ struct stat s;
+ long iseq;
+
+ /* This will only be called when the system is locked anyhow, so there
+ is no need to use a separate lock for the conversation sequence
+ file. */
+ zname = zsysdep_in_dir (".Sequence", qsys->uuconf_zname);
+
+ iseq = 0;
+ if (stat (zname, &s) == 0)
+ {
+ boolean fok;
+ char *zline;
+ size_t cline;
+
+ /* The file should only be readable and writable by uucp. */
+ if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ {
+ ulog (LOG_ERROR,
+ "Bad file protection for conversation sequence file");
+ ubuffree (zname);
+ return -1;
+ }
+
+ e = fopen (zname, "r+");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return -1;
+ }
+
+ ubuffree (zname);
+
+ fok = TRUE;
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ fok = FALSE;
+ else
+ {
+ char *zend;
+
+ iseq = strtol (zline, &zend, 10);
+ if (zend == zline)
+ fok = FALSE;
+ }
+
+ xfree ((pointer) zline);
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "Bad format for conversation sequence file");
+ (void) fclose (e);
+ return -1;
+ }
+
+ rewind (e);
+ }
+ else
+ {
+ e = esysdep_fopen (zname, FALSE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return -1;
+ }
+
+ ++iseq;
+
+ fprintf (e, "%ld", iseq);
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return -1;
+ }
+
+ return iseq;
+}
diff --git a/gnu/libexec/uucp/libunix/serial.c b/gnu/libexec/uucp/libunix/serial.c
new file mode 100644
index 000000000000..cee90fcc7bb3
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/serial.c
@@ -0,0 +1,2991 @@
+/* serial.c
+ The serial port communication routines for Unix.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char serial_rcsid[] = "$Id: serial.c,v 1.3 1994/02/07 23:47:51 ache Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "conn.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_TLI
+#if HAVE_TIUSER_H
+#include <tiuser.h>
+#else /* ! HAVE_TIUSER_H */
+#if HAVE_XTI_H
+#include <xti.h>
+#endif /* HAVE_XTI_H */
+#endif /* ! HAVE_TIUSER_H */
+#endif /* HAVE_TLI */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_BSD_TTY
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY
+#include <time.h>
+#endif
+#endif
+
+#if HAVE_STRIP_BUG && HAVE_BSD_TTY
+#include <termio.h>
+#endif
+
+#if HAVE_SVR4_LOCKFILES
+/* Get the right definitions for major and minor. */
+#if MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif /* MAJOR_IN_MKDEV */
+#if MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif /* MAJOR_IN_SYSMACROS */
+#if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS
+#ifndef major
+#define major(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef minor
+#define minor(i) ((i) & 0xff)
+#endif
+#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
+#endif /* HAVE_SVR4_LOCKFILES */
+
+/* Get definitions for both O_NONBLOCK and O_NDELAY. */
+#ifndef O_NDELAY
+#ifdef FNDELAY
+#define O_NDELAY FNDELAY
+#else /* ! defined (FNDELAY) */
+#define O_NDELAY 0
+#endif /* ! defined (FNDELAY) */
+#endif /* ! defined (O_NDELAY) */
+
+#ifndef O_NONBLOCK
+#ifdef FNBLOCK
+#define O_NONBLOCK FNBLOCK
+#else /* ! defined (FNBLOCK) */
+#define O_NONBLOCK 0
+#endif /* ! defined (FNBLOCK) */
+#endif /* ! defined (O_NONBLOCK) */
+
+#if O_NDELAY == 0 && O_NONBLOCK == 0
+ #error No way to do nonblocking I/O
+#endif
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Make sure we have a definition for MAX_INPUT. */
+#ifndef MAX_INPUT
+#define MAX_INPUT (256)
+#endif
+
+/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
+ Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
+ terminal before we know that it is unlocked. */
+#ifdef TIOCSINUSE
+#define HAVE_TIOCSINUSE 1
+#else
+#ifdef TIOCEXCL
+#define HAVE_TIOCEXCL 1
+#endif
+#endif
+
+#if HAVE_TLI
+extern int t_errno;
+extern char *t_errlist[];
+extern int t_nerr;
+#endif
+
+/* Determine bits to clear for the various terminal control fields for
+ HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */
+#if HAVE_SYSV_TERMIO
+#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
+ | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
+ | IXON | IXANY | IXOFF)
+#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
+ | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
+ | VTDLY | FFDLY)
+#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
+ | ECHONL | NOFLSH)
+#endif
+#if HAVE_POSIX_TERMIOS
+#ifdef IMAXBEL
+#define CI_ADD1 IMAXBEL
+#else
+#define CI_ADD1 0
+#endif
+#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
+ | INLCR | INPCK | ISTRIP | IXOFF | IXON \
+ | PARMRK | CI_ADD1)
+#define ICLEAR_OFLAG (OPOST)
+#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#ifdef PENDIN
+#define CL_ADD1 PENDIN
+#else
+#define CL_ADD1 0
+#endif
+#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
+ | ISIG | NOFLSH | TOSTOP | CL_ADD1)
+#endif
+
+/* Local functions. */
+
+static RETSIGTYPE usalarm P((int isig));
+static boolean fsserial_init P((struct sconnection *qconn,
+ const struct sconncmds *qcmds,
+ const char *zdevice));
+static void usserial_free P((struct sconnection *qconn));
+static boolean fsserial_lockfile P((boolean flok,
+ const struct sconnection *));
+static boolean fsserial_lock P((struct sconnection *qconn,
+ boolean fin));
+static boolean fsserial_unlock P((struct sconnection *qconn));
+static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsdirect_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsblock P((struct ssysdep_conn *q, boolean fblock));
+static boolean fsserial_close P((struct ssysdep_conn *q));
+static boolean fsstdin_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsmodem_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsdirect_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsserial_reset P((struct sconnection *qconn));
+static boolean fsstdin_reset P((struct sconnection *qconn));
+static boolean fsstdin_read P((struct sconnection *qconn,
+ char *zbuf, size_t *pclen, size_t cmin,
+ int ctimeout, boolean freport));
+static boolean fsstdin_write P((struct sconnection *qconn,
+ const char *zwrite, size_t cwrite));
+static boolean fsserial_break P((struct sconnection *qconn));
+static boolean fsstdin_break P((struct sconnection *qconn));
+static boolean fsserial_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsstdin_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsmodem_carrier P((struct sconnection *qconn,
+ boolean fcarrier));
+static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
+static boolean fsstdin_chat P((struct sconnection *qconn,
+ char **pzprog));
+static long isserial_baud P((struct sconnection *qconn));
+
+/* The command table for standard input ports. */
+
+static const struct sconncmds sstdincmds =
+{
+ usserial_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ fsstdin_open,
+ fsstdin_close,
+ fsstdin_reset,
+ NULL, /* pfdial */
+ fsstdin_read,
+ fsstdin_write,
+ fsysdep_conn_io,
+ fsstdin_break,
+ fsstdin_set,
+ NULL, /* pfcarrier */
+ fsstdin_chat,
+ isserial_baud
+};
+
+/* The command table for modem ports. */
+
+static const struct sconncmds smodemcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsmodem_open,
+ fsmodem_close,
+ fsserial_reset,
+ fmodem_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ fsmodem_carrier,
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* The command table for direct ports. */
+
+static const struct sconncmds sdirectcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsdirect_open,
+ fsdirect_close,
+ fsserial_reset,
+ NULL, /* pfdial */
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* If the system will let us set both O_NDELAY and O_NONBLOCK, we do
+ so. This is because some ancient drivers on some systems appear to
+ look for one but not the other. Some other systems will give an
+ EINVAL error if we attempt to set both, so we use a static global
+ to hold the value we want to set. If we get EINVAL, we change the
+ global and try again (if some system gives an error other than
+ EINVAL, the code will have to be modified). */
+static int iSunblock = O_NDELAY | O_NONBLOCK;
+
+/* This code handles SIGALRM. See the discussion above
+ fsysdep_conn_read. Normally we ignore SIGALRM, but the handler
+ will temporarily be set to this function, which should set fSalarm
+ and then either longjmp or schedule another SIGALRM. fSalarm is
+ never referred to outside of this file, but we don't make it static
+ to try to fool compilers which don't understand volatile. */
+
+volatile sig_atomic_t fSalarm;
+
+static RETSIGTYPE
+usalarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, usalarm);
+#endif
+
+ fSalarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ longjmp (sSjmp_buf, 1);
+#else
+ alarm (1);
+#endif
+}
+
+/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
+ SIGPIPE and another to restore the original state. When these
+ functions are called (in fsysdep_modem_close) SIGHUP is being
+ ignored. The routines are isblocksigs, which returns a value of
+ type HELD_SIG_MASK and usunblocksigs which takes a single argument
+ of type HELD_SIG_MASK. */
+
+#if HAVE_SIGPROCMASK
+
+/* Use the POSIX sigprocmask call. */
+
+#define HELD_SIG_MASK sigset_t
+
+static sigset_t isblocksigs P((void));
+
+static sigset_t
+isblocksigs ()
+{
+ sigset_t sblock, sold;
+
+ /* These expressions need an extra set of parentheses to avoid a bug
+ in SCO 3.2.2. */
+ (void) (sigemptyset (&sblock));
+ (void) (sigaddset (&sblock, SIGINT));
+ (void) (sigaddset (&sblock, SIGQUIT));
+ (void) (sigaddset (&sblock, SIGTERM));
+ (void) (sigaddset (&sblock, SIGPIPE));
+
+ (void) sigprocmask (SIG_BLOCK, &sblock, &sold);
+ return sold;
+}
+
+#define usunblocksigs(s) \
+ ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
+
+#else /* ! HAVE_SIGPROCMASK */
+#if HAVE_SIGBLOCK
+
+/* Use the BSD sigblock and sigsetmask calls. */
+
+#define HELD_SIG_MASK int
+
+#ifndef sigmask
+#define sigmask(i) (1 << ((i) - 1))
+#endif
+
+#define isblocksigs() \
+ sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
+ | sigmask (SIGTERM) | sigmask (SIGPIPE))
+
+#define usunblocksigs(i) ((void) sigsetmask (i))
+
+#else /* ! HAVE_SIGBLOCK */
+
+#if HAVE_SIGHOLD
+
+/* Use the SVR3 sighold and sigrelse calls. */
+
+#define HELD_SIG_MASK int
+
+static int isblocksigs P((void));
+
+static int
+isblocksigs ()
+{
+ sighold (SIGINT);
+ sighold (SIGQUIT);
+ sighold (SIGTERM);
+ sighold (SIGPIPE);
+ return 0;
+}
+
+static void usunblocksigs P((int));
+
+/*ARGSUSED*/
+static void
+usunblocksigs (i)
+ int i;
+{
+ sigrelse (SIGINT);
+ sigrelse (SIGQUIT);
+ sigrelse (SIGTERM);
+ sigrelse (SIGPIPE);
+}
+
+#else /* ! HAVE_SIGHOLD */
+
+/* We have no way to block signals. This system will suffer from a
+ race condition in fsysdep_modem_close. */
+
+#define HELD_SIG_MASK int
+
+#define isblocksigs() 0
+
+#define usunblocksigs(i)
+
+#endif /* ! HAVE_SIGHOLD */
+#endif /* ! HAVE_SIGBLOCK */
+#endif /* ! HAVE_SIGPROCMASK */
+
+/* Initialize a connection for use on a serial port. */
+
+static boolean
+fsserial_init (qconn, qcmds, zdevice)
+ struct sconnection *qconn;
+ const struct sconncmds *qcmds;
+ const char *zdevice;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ if (zdevice == NULL
+ && qconn->qport != NULL
+ && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ zdevice = qconn->qport->uuconf_zname;
+ if (zdevice == NULL)
+ q->zdevice = NULL;
+ else if (*zdevice == '/')
+ q->zdevice = zbufcpy (zdevice);
+ else
+ {
+ size_t clen;
+
+ clen = strlen (zdevice);
+ q->zdevice = zbufalc (sizeof "/dev/" + clen);
+ memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1);
+ memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen);
+ q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
+ }
+ q->o = -1;
+ q->ftli = FALSE;
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = qcmds;
+ return TRUE;
+}
+
+/* Initialize a connection for use on standard input. */
+
+boolean
+fsysdep_stdin_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sstdincmds, (const char *) NULL);
+}
+
+/* Initialize a connection for use on a modem port. */
+
+boolean
+fsysdep_modem_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &smodemcmds,
+ qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
+}
+
+/* Initialize a connection for use on a direct port. */
+
+boolean
+fsysdep_direct_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sdirectcmds,
+ qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
+}
+
+/* Free up a serial port. */
+
+static void
+usserial_free (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ ubuffree (qsysdep->zdevice);
+ xfree ((pointer) qsysdep);
+ qconn->psysdep = NULL;
+}
+
+/* This routine is used for both locking and unlocking. It is the
+ only routine which knows how to translate a device name into the
+ name of a lock file. If it can't figure out a name, it does
+ nothing and returns TRUE. */
+
+static boolean
+fsserial_lockfile (flok, qconn)
+ boolean flok;
+ const struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+ char *zalc;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qconn->qport == NULL)
+ z = NULL;
+ else
+ z = qconn->qport->uuconf_zlockname;
+ zalc = NULL;
+ if (z == NULL)
+ {
+#if ! HAVE_SVR4_LOCKFILES
+ {
+ const char *zbase;
+ size_t clen;
+
+ zbase = strrchr (qsysdep->zdevice, '/') + 1;
+ clen = strlen (zbase);
+ zalc = zbufalc (sizeof "LCK.." + clen);
+ memcpy (zalc, "LCK..", sizeof "LCK.." - 1);
+ memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1);
+#if HAVE_SCO_LOCKFILES
+ {
+ char *zl;
+
+ for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++)
+ if (isupper (*zl))
+ *zl = tolower (*zl);
+ }
+#endif
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+#if HAVE_SVR4_LOCKFILES
+ {
+ struct stat s;
+
+ if (stat (qsysdep->zdevice, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ zalc = zbufalc (sizeof "LK.123.123.123");
+ sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
+ major (s.st_rdev), minor (s.st_rdev));
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+ z = strrchr (qsysdep->zdevice, '/') + 1;
+#endif /* ! HAVE_SVR4_LOCKFILES */
+#endif /* ! HAVE_SVR4_LOCKFILES */
+ }
+
+ if (flok)
+ fret = fsdo_lock (z, FALSE, (boolean *) NULL);
+ else
+ fret = fsdo_unlock (z, FALSE);
+
+#if HAVE_COHERENT_LOCKFILES
+ if (fret)
+ {
+ if (flok)
+ {
+ if (lockttyexist (z))
+ {
+ ulog (LOG_NORMAL, "%s: port already locked", z+5);
+ fret = FALSE;
+ }
+ else
+ fret = !(fscoherent_disable_tty (z, &qsysdep->zenable));
+ }
+ else
+ {
+ fret = TRUE;
+ if (qsysdep->zenable != NULL)
+ {
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/etc/enable";
+ azargs[1] = qsysdep->zenable;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE,
+ (const char *) NULL, TRUE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s",
+ qsysdep->zenable, strerror (errno));
+ fret = FALSE;
+ }
+ else
+ {
+ if (ixswait ((unsigned long) ipid, (const char *) NULL)
+ == 0)
+ fret = TRUE;
+ else
+ fret = FALSE;
+ }
+ ubuffree (qsysdep->zenable);
+ qsysdep->zenable = NULL;
+ }
+ }
+ }
+#endif /* HAVE_COHERENT_LOCKFILES */
+
+ ubuffree (zalc);
+ return fret;
+}
+
+/* If we can mark a modem line in use, then when we lock a port we
+ must open it and mark it in use. We can't wait until the actual
+ open because we can't fail out if it is locked then. */
+
+static boolean
+fsserial_lock (qconn, fin)
+ struct sconnection *qconn;
+ boolean fin;
+{
+ if (! fsserial_lockfile (TRUE, qconn))
+ return FALSE;
+
+#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
+ /* Open the line and try to mark it in use. */
+ {
+ struct ssysdep_conn *qsysdep;
+ int iflag;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (fin)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag);
+ if (qsysdep->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ qsysdep->o = open (qsysdep->zdevice,
+ O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (qsysdep->o < 0)
+ {
+ if (errno != EBUSY)
+ ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+ }
+
+#if HAVE_TIOCSINUSE
+ /* If we can't mark it in use, return FALSE to indicate that the
+ lock failed. */
+ if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0)
+ {
+ if (errno != EALREADY)
+ ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+#endif
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (qsysdep->o, TIOCSCTTY, 0);
+#endif
+ }
+#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
+
+ return TRUE;
+}
+
+/* Unlock a modem or direct port. */
+
+static boolean
+fsserial_unlock (qconn)
+ struct sconnection *qconn;
+{
+ boolean fret;
+ struct ssysdep_conn *qsysdep;
+
+ fret = TRUE;
+
+ /* The file may have been opened by fsserial_lock, so close it here
+ if necessary. */
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qsysdep->o >= 0)
+ {
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ if (close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->o = -1;
+ }
+
+ if (! fsserial_lockfile (FALSE, qconn))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Open a serial line. This sets the terminal settings. We begin in
+ seven bit mode and let the protocol change if necessary. */
+
+#if HAVE_POSIX_TERMIOS
+typedef speed_t baud_code;
+#else
+typedef int baud_code;
+#endif
+
+static struct sbaud_table
+{
+ baud_code icode;
+ long ibaud;
+} asSbaud_table[] =
+{
+ { B50, 50 },
+ { B75, 75 },
+ { B110, 110 },
+ { B134, 134 },
+ { B150, 150 },
+ { B200, 200 },
+ { B300, 300 },
+ { B600, 600 },
+ { B1200, 1200 },
+ { B1800, 1800 },
+ { B2400, 2400 },
+ { B4800, 4800 },
+ { B9600, 9600 },
+#ifdef B19200
+ { B19200, 19200 },
+#else /* ! defined (B19200) */
+#ifdef EXTA
+ { EXTA, 19200 },
+#endif /* EXTA */
+#endif /* ! defined (B19200) */
+#ifdef B38400
+ { B38400, 38400 },
+#else /* ! defined (B38400) */
+#ifdef EXTB
+ { EXTB, 38400 },
+#endif /* EXTB */
+#endif /* ! defined (B38400) */
+#ifdef B57600
+ { B57600, 57600 },
+#endif
+#ifdef B76800
+ { B76800, 76800 },
+#endif
+#ifdef B115200
+ { B115200, 115200 },
+#endif
+ { B0, 0 }
+};
+
+#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+/* Hold the MIN value for the terminal to avoid setting it
+ unnecessarily. */
+static int cSmin;
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+static boolean
+fsserial_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+ baud_code ib;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (q->zdevice != NULL)
+ ulog_device (strrchr (q->zdevice, '/') + 1);
+ else
+ {
+ const char *zport;
+ boolean fdummy;
+
+#if DEBUG > 0
+ if (qconn->qport != NULL &&
+ qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ ulog (LOG_FATAL, "fsserial_open: Can't happen");
+#endif
+ zport = zsysdep_port_name (&fdummy);
+ if (zport != NULL)
+ ulog_device (zport);
+ }
+
+ ib = B0;
+ if (ibaud != 0)
+ {
+ int i;
+
+ for (i = 0; i < CBAUD_TABLE; i++)
+ if (asSbaud_table[i].ibaud == ibaud)
+ break;
+ if (i >= CBAUD_TABLE)
+ {
+ ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
+ return FALSE;
+ }
+ ib = asSbaud_table[i].icode;
+ }
+
+ /* The port may have already been opened by the locking routine. */
+ if (q->o < 0)
+ {
+ int iflag;
+
+ if (fwait)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ q->o = open (q->zdevice, O_RDWR | iflag);
+ if (q->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ q->o = open (q->zdevice, O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (q->o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ return FALSE;
+ }
+ }
+
+ /* Get the port flags, and make sure the ports are blocking. */
+
+ q->iflags = fcntl (q->o, F_GETFL, 0);
+ if (q->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ q->istdout_flags = -1;
+
+ if (! fgetterminfo (q->o, &q->sorig))
+ {
+ q->fterminal = FALSE;
+ return TRUE;
+ }
+
+ q->fterminal = TRUE;
+
+ q->snew = q->sorig;
+
+#if HAVE_BSD_TTY
+
+ q->snew.stty.sg_flags = RAW | ANYP;
+ if (ibaud == 0)
+ ib = q->snew.stty.sg_ospeed;
+ else
+ {
+ q->snew.stty.sg_ispeed = ib;
+ q->snew.stty.sg_ospeed = ib;
+ }
+
+ /* We don't want to receive any interrupt characters. */
+ q->snew.stchars.t_intrc = -1;
+ q->snew.stchars.t_quitc = -1;
+ q->snew.stchars.t_eofc = -1;
+ q->snew.stchars.t_brkc = -1;
+ q->snew.sltchars.t_suspc = -1;
+ q->snew.sltchars.t_rprntc = -1;
+ q->snew.sltchars.t_dsuspc = -1;
+ q->snew.sltchars.t_flushc = -1;
+ q->snew.sltchars.t_werasc = -1;
+ q->snew.sltchars.t_lnextc = -1;
+
+#ifdef NTTYDISC
+ /* We want to use the ``new'' terminal driver so that we can use the
+ local mode bits to control XON/XOFF. */
+ {
+ int iparam;
+
+ if (ioctl (q->o, TIOCGETD, &iparam) >= 0
+ && iparam != NTTYDISC)
+ {
+ iparam = NTTYDISC;
+ (void) ioctl (q->o, TIOCSETD, &iparam);
+ }
+ }
+#endif
+
+#ifdef TIOCHPCL
+ /* When the file is closed, hang up the line. This is a safety
+ measure in case the program crashes. */
+ (void) ioctl (q->o, TIOCHPCL, 0);
+#endif
+
+#ifdef TIOCFLUSH
+ {
+ int iparam;
+
+ /* Flush pending input. */
+#ifdef FREAD
+ iparam = FREAD;
+#else
+ iparam = 0;
+#endif
+ (void) ioctl (q->o, TIOCFLUSH, &iparam);
+ }
+#endif /* TIOCFLUSH */
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ if (ibaud == 0)
+ ib = q->snew.c_cflag & CBAUD;
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ if (!fwait)
+ q->snew.c_cflag |= CLOCAL;
+ q->snew.c_cflag |= (ib | ISET_CFLAG);
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+#ifdef TCFLSH
+ /* Flush pending input. */
+ (void) ioctl (q->o, TCFLSH, 0);
+#endif
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ if (ibaud == 0)
+ ib = cfgetospeed (&q->snew);
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ if (!fwait)
+ q->snew.c_cflag |= CLOCAL;
+ q->snew.c_cflag |= ISET_CFLAG;
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+ (void) cfsetospeed (&q->snew, ib);
+ (void) cfsetispeed (&q->snew, ib);
+
+ /* Flush pending input. */
+ (void) tcflush (q->o, TCIFLUSH);
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (q->o, TIOCSCTTY, 0);
+#endif
+
+ if (ibaud != 0)
+ q->ibaud = ibaud;
+ else
+ {
+ int i;
+
+ q->ibaud = (long) 1200;
+ for (i = 0; i < CBAUD_TABLE; i++)
+ {
+ if (asSbaud_table[i].icode == ib)
+ {
+ q->ibaud = asSbaud_table[i].ibaud;
+ break;
+ }
+ }
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsserial_open: Baud rate is %ld", q->ibaud);
+ }
+
+ return TRUE;
+}
+
+/* Open a standard input port. The code alternates q->o between 0 and
+ 1 as appropriate. It is always 0 before any call to fsblock. */
+
+static boolean
+fsstdin_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+ q->o = 0;
+ if (! fsserial_open (qconn, ibaud, fwait))
+ return FALSE;
+ q->istdout_flags = fcntl (1, F_GETFL, 0);
+ if (q->istdout_flags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Open a modem port. */
+
+static boolean
+fsmodem_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Open a direct port. */
+
+static boolean
+fsdirect_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Change the blocking status of the port. We keep track of the
+ current blocking status to avoid calling fcntl unnecessarily; fcntl
+ turns out to be surprisingly expensive, at least on Ultrix. */
+
+static boolean
+fsblock (qs, fblock)
+ struct ssysdep_conn *qs;
+ boolean fblock;
+{
+ int iwant;
+ int isys;
+
+ if (fblock)
+ iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->iflags | iSunblock;
+
+ if (iwant == qs->iflags)
+ return TRUE;
+
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ if (isys < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ iwant = qs->iflags | O_NONBLOCK;
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ }
+#endif
+ if (isys < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ }
+
+ qs->iflags = iwant;
+
+ if (qs->istdout_flags >= 0)
+ {
+ if (fblock)
+ iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->istdout_flags | iSunblock;
+
+ if (fcntl (1, F_SETFL, iwant) < 0)
+ {
+ /* We don't bother to fix up iSunblock here, since we
+ succeeded above. */
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+
+ qs->istdout_flags = iwant;
+ }
+
+ return TRUE;
+}
+
+/* Close a serial port. */
+
+static boolean
+fsserial_close (q)
+ struct ssysdep_conn *q;
+{
+ if (q->o >= 0)
+ {
+ /* Use a 30 second timeout to avoid hanging while draining
+ output. */
+ if (q->fterminal)
+ {
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (q->o, &q->sorig);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we timed out, use the non draining call. Hopefully
+ this can't hang. */
+ if (fSalarm)
+ (void) fsetterminfo (q->o, &q->sorig);
+ }
+
+#ifdef TIOCNOTTY
+ /* We don't want this as our controlling terminal any more, so
+ get rid of it. This is necessary because we don't want to
+ open /dev/tty, since that can confuse the serial port locking
+ on some computers. */
+ (void) ioctl (q->o, TIOCNOTTY, (char *) NULL);
+#endif
+
+ (void) close (q->o);
+ q->o = -1;
+
+ /* Sleep to give the terminal a chance to settle, in case we are
+ about to call out again. */
+ sleep (2);
+ }
+
+ return TRUE;
+}
+
+/* Close a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ (void) close (1);
+ (void) close (2);
+ qsysdep->o = 0;
+ return fsserial_close (qsysdep);
+}
+
+/* Close a modem port. */
+
+static boolean
+fsmodem_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+ struct uuconf_dialer sdialer;
+ const struct uuconf_chat *qchat;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ fret = TRUE;
+
+ /* Figure out the dialer so that we can run the complete or abort
+ chat scripts. */
+ if (qdialer == NULL)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ {
+ const char *zdialer;
+ int iuuconf;
+
+ zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
+ iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
+ if (iuuconf == UUCONF_SUCCESS)
+ qdialer = &sdialer;
+ else
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ }
+ }
+ else
+ qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
+ }
+
+ /* Get the complete or abort chat script to use. */
+ qchat = NULL;
+ if (qdialer != NULL)
+ {
+ if (fsuccess)
+ qchat = &qdialer->uuconf_scomplete;
+ else
+ qchat = &qdialer->uuconf_sabort;
+ }
+
+ if (qchat != NULL
+ && (qchat->uuconf_pzprogram != NULL
+ || qchat->uuconf_pzchat != NULL))
+ {
+ boolean fsighup_ignored;
+ HELD_SIG_MASK smask;
+ int i;
+ sig_atomic_t afhold[INDEXSIG_COUNT];
+
+ /* We're no longer interested in carrier. */
+ (void) fsmodem_carrier (qconn, FALSE);
+
+ /* The port I/O routines check whether any signal has been
+ received, and abort if one has. While we are closing down
+ the modem, we don't care if we received a signal in the past,
+ but we do care if we receive a new signal (otherwise it would
+ be difficult to kill a uucico which was closing down a
+ modem). We never care if we get SIGHUP at this point. So we
+ turn off SIGHUP, remember what signals we've already seen,
+ and clear our notion of what signals we've seen. We have to
+ block the signals while we remember and clear the array,
+ since we might otherwise miss a signal which occurred between
+ the copy and the clear (old systems can't block signals; they
+ will just have to suffer the race). */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
+ smask = isblocksigs ();
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ {
+ afhold[i] = afSignal[i];
+ afSignal[i] = FALSE;
+ }
+ usunblocksigs (smask);
+
+ if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL,
+ (const struct uuconf_dialer *) NULL, (const char *) NULL,
+ FALSE, qconn->qport->uuconf_zname,
+ qsysdep->ibaud))
+ fret = FALSE;
+
+ /* Restore the old signal array and the SIGHUP handler. It is
+ not necessary to block signals here, since all we are doing
+ is exactly what the signal handler itself would do if the
+ signal occurred. */
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ if (afhold[i])
+ afSignal[i] = TRUE;
+ if (! fsighup_ignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+ if (qdialer != NULL
+ && qdialer == &sdialer)
+ (void) uuconf_dialer_free (puuconf, &sdialer);
+
+#if ! HAVE_RESET_BUG
+ /* Reset the terminal to make sure we drop DTR. It should be
+ dropped when we close the descriptor, but that doesn't seem to
+ happen on some systems. Use a 30 second timeout to avoid hanging
+ while draining output. */
+ if (qsysdep->fterminal)
+ {
+#if HAVE_BSD_TTY
+ qsysdep->snew.stty.sg_ispeed = B0;
+ qsysdep->snew.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ (void) cfsetospeed (&qsysdep->snew, B0);
+#endif
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* Let the port settle. */
+ sleep (2);
+ }
+#endif /* ! HAVE_RESET_BUG */
+
+ if (! fsserial_close (qsysdep))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Close a direct port. */
+
+/*ARGSUSED*/
+static boolean
+fsdirect_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
+}
+
+/* Reset a serial port by hanging up. */
+
+static boolean
+fsserial_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+ sterminal sbaud;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ sbaud = q->snew;
+
+#if HAVE_BSD_TTY
+ sbaud.stty.sg_ispeed = B0;
+ sbaud.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ if (cfsetospeed (&sbaud, B0) < 0)
+ {
+ ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno));
+ return FALSE;
+ }
+#endif
+
+ if (! fsetterminfodrain (q->o, &sbaud))
+ {
+ ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ /* Give the terminal a chance to settle. */
+ sleep (2);
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Reset a standard input port. */
+
+static boolean
+fsstdin_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_reset (qconn);
+}
+
+/* Begin dialing out on a modem port. This opens the dialer device if
+ there is one. */
+
+boolean
+fsysdep_modem_begin_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+#ifdef TIOCMODEM
+ /* If we can tell the modem to obey modem control, do so. */
+ {
+ int iperm;
+
+ iperm = 0;
+ (void) ioctl (qsysdep->o, TIOCMODEM, &iperm);
+ }
+#endif /* TIOCMODEM */
+
+ /* If we supposed to toggle DTR, do so. */
+
+ if (qdial->uuconf_fdtr_toggle)
+ {
+#ifdef TIOCCDTR
+ (void) ioctl (qsysdep->o, TIOCCDTR, 0);
+ sleep (2);
+ (void) ioctl (qsysdep->o, TIOCSDTR, 0);
+#else /* ! defined (TIOCCDTR) */
+ (void) fconn_reset (qconn);
+#endif /* ! defined (TIOCCDTR) */
+
+ if (qdial->uuconf_fdtr_toggle_wait)
+ sleep (2);
+ }
+
+ if (! fsmodem_carrier (qconn, FALSE))
+ return FALSE;
+
+ /* Open the dial device if there is one. */
+ z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device;
+ if (z != NULL)
+ {
+ char *zfree;
+ int o;
+
+ qsysdep->ohold = qsysdep->o;
+
+ zfree = NULL;
+ if (*z != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (z));
+ sprintf (zfree, "/dev/%s", z);
+ z = zfree;
+ }
+
+ o = open ((char *) z, O_RDWR | O_NOCTTY);
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+ ubuffree (zfree);
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return FALSE;
+ }
+
+ qsysdep->o = o;
+ }
+
+ return TRUE;
+}
+
+/* Tell the port to require or not require carrier. On BSD this uses
+ TIOCCAR and TIOCNCAR, which I assume are generally supported (it
+ can also use the LNOMDM bit supported by IS68K Unix). On System V
+ it resets or sets CLOCAL. We only require carrier if the port
+ supports it. This will only be called with fcarrier TRUE if the
+ dialer supports carrier. */
+
+static boolean
+fsmodem_carrier (qconn, fcarrier)
+ struct sconnection *qconn;
+ boolean fcarrier;
+{
+ register struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ if (fcarrier)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier)
+ {
+#ifdef TIOCCAR
+ /* Tell the modem to pay attention to carrier. */
+ if (ioctl (q->o, TIOCCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into nonlocal mode. */
+ q->snew.c_cflag &=~ CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+ }
+ else
+ {
+#ifdef TIOCNCAR
+ /* Tell the modem to ignore carrier. */
+ if (ioctl (q->o, TIOCNCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCNCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIS, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into local mode (ignore carrier) to start the chat
+ script. */
+ q->snew.c_cflag |= CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+
+#if HAVE_CLOCAL_BUG
+ /* On SCO and AT&T UNIX PC you have to reopen the port. */
+ {
+ int onew;
+
+ onew = open (q->zdevice, O_RDWR);
+ if (onew < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno));
+ return FALSE;
+ }
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (onew);
+ return FALSE;
+ }
+
+ (void) close (q->o);
+ q->o = onew;
+ }
+#endif /* HAVE_CLOCAL_BUG */
+
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+
+ return TRUE;
+}
+
+/* Finish dialing out on a modem by closing any dialer device and waiting
+ for carrier. */
+
+boolean
+fsysdep_modem_end_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
+ {
+ (void) close (q->o);
+ q->o = q->ohold;
+ }
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier
+ && qdial->uuconf_fcarrier)
+ {
+ /* Tell the port that we need carrier. */
+ if (! fsmodem_carrier (qconn, TRUE))
+ return FALSE;
+
+#ifdef TIOCWONLINE
+
+ /* We know how to wait for carrier, so do so. */
+
+ /* If we already got a signal, just quit now. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* This bit of code handles signals just like fsysdep_conn_read
+ does. See that function for a longer explanation. */
+
+ /* Use fsysdep_catch to handle a longjmp from the signal
+ handler. */
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ /* Start catching SIGALRM; normally we ignore it. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (qdial->uuconf_ccarrier_wait);
+
+ /* We really don't care if we get an error, since that will
+ probably just mean that TIOCWONLINE isn't supported in
+ which case there's nothing we can do anyhow. If we get
+ SIGINT we want to keep waiting for carrier, because
+ SIGINT just means don't start any new sessions. We don't
+ handle SIGINT correctly if we do a longjmp in the signal
+ handler; too bad. */
+ while (ioctl (q->o, TIOCWONLINE, 0) < 0
+ && errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ if (FGOT_QUIT_SIGNAL () || fSalarm)
+ break;
+ }
+ }
+
+ /* Turn off the pending SIGALRM and ignore SIGALARM again. */
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we got a random signal, just return FALSE. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* If we timed out, give an error. */
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR, "Timed out waiting for carrier");
+ return FALSE;
+ }
+
+#endif /* TIOCWONLINE */
+ }
+
+ return TRUE;
+}
+
+/* Read data from a connection, with a timeout. This routine handles
+ all types of connections, including TLI.
+
+ This function should return when we have read cmin characters or
+ the timeout has occurred. We have to work a bit to get Unix to do
+ this efficiently on a terminal. The simple implementation
+ schedules a SIGALRM signal and then calls read; if there is a
+ single character available, the call to read will return
+ immediately, so there must be a loop which terminates when the
+ SIGALRM is delivered or the correct number of characters has been
+ read. This can be very inefficient with a fast CPU or a low baud
+ rate (or both!), since each call to read may return only one or two
+ characters.
+
+ Under POSIX or System V, we can specify a minimum number of
+ characters to read, so there is no serious trouble.
+
+ Under BSD, we figure out how many characters we have left to read,
+ how long it will take for them to arrive at the current baud rate,
+ and sleep that long.
+
+ Doing this with a timeout and avoiding all possible race conditions
+ get very hairy, though. Basically, we're going to schedule a
+ SIGALRM for when the timeout expires. I don't really want to do a
+ longjmp in the SIGALRM handler, though, because that may lose data.
+ Therefore, I have the signal handler set a variable. However, this
+ means that there will be a span of time between the time the code
+ checks the variable and the time it calls the read system call; if
+ the SIGALRM occurs during that time, the read might hang forever.
+ To avoid this, the SIGALRM handler not only sets a global variable,
+ it also schedules another SIGALRM for one second in the future
+ (POSIX specifies that a signal handler is permitted to safely call
+ alarm). To avoid getting a continual sequence of SIGALRM
+ interrupts, we change the signal handler to ignore SIGALRM when
+ we're about to exit the function. This means that every time we
+ execute fsysdep_conn_read we make at least five system calls. It's
+ the best I've been able to come up with, though.
+
+ When fsysdep_conn_read finishes, there will be no SIGALRM scheduled
+ and SIGALRM will be ignored. */
+
+boolean
+fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ CATCH_PROTECT size_t cwant;
+ boolean fret;
+ register struct ssysdep_conn * const q
+ = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwant = *pclen;
+ *pclen = 0;
+
+ /* Guard against a bad timeout. We return TRUE when a timeout
+ expires. It is possible to get a negative timeout here because
+ the calling code does not check user supplied timeouts for
+ plausibility. */
+ if (ctimeout <= 0)
+ return TRUE;
+
+ /* We want to do a blocking read. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ fSalarm = FALSE;
+
+ /* We're going to set up an alarm signal to last for the entire
+ read. If the read system call cannot be interrupted, the signal
+ handler will do a longjmp causing fsysdep_catch (a macro) to
+ return FALSE. We handle that here. If read can be interrupted,
+ fsysdep_catch will be defined to TRUE. */
+ if (fsysdep_catch ())
+ {
+ /* Prepare to catch SIGALRM and schedule the signal. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ alarm (ctimeout);
+ }
+ else
+ {
+ /* We caught a signal. We don't actually have to do anything,
+ as all the appropriate checks are made at the start of the
+ following loop. */
+ }
+
+ fret = FALSE;
+
+ while (TRUE)
+ {
+ int cgot;
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* If we can tell the terminal not to return until we have a
+ certain number of characters, do so. */
+ if (q->fterminal)
+ {
+ int csetmin;
+
+ /* I'm not that confident about setting MIN to values larger
+ than 127, although up to 255 would probably work. */
+ if (cmin < 127)
+ csetmin = cmin;
+ else
+ csetmin = 127;
+
+ if (csetmin != cSmin)
+ {
+ q->snew.c_cc[VMIN] = csetmin;
+ while (! fsetterminfo (q->o, &q->snew))
+ {
+ if (errno != EINTR
+ || FGOT_QUIT_SIGNAL ())
+ {
+ int ierr;
+
+ /* We turn off the signal before reporting the
+ error to minimize any problems with
+ interrupted system calls. */
+ ierr = errno;
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
+ strerror (ierr));
+ return FALSE;
+ }
+
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR,
+ "Timed out when setting MIN to %d; retrying",
+ csetmin);
+ fSalarm = FALSE;
+ alarm (ctimeout);
+ }
+ }
+ cSmin = csetmin;
+ }
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+ /* If we've received a signal, get out now. */
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+
+ /* If we've already gotten a SIGALRM, get out with whatever
+ we've accumulated. */
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* Right here is the race condition which we avoid by having the
+ SIGALRM handler schedule another SIGALRM. */
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zbuf, cwant, &iflags);
+ if (cgot < 0 && t_errno != TSYSERR)
+ {
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zbuf, cwant);
+
+ /* If the read returned an error, check for signals. */
+ if (cgot < 0)
+ {
+ if (errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+ }
+
+ /* If read returned an error, get out. We just ignore EINTR
+ here, since it must be from some signal we don't care about.
+ If the read returned 0 then the line must have been hung up
+ (normally we would have received SIGHUP, but we can't count
+ on that). We turn off the signals before calling ulog to
+ reduce problems with interrupted system calls. */
+ if (cgot <= 0)
+ {
+ if (cgot < 0 && errno == EINTR)
+ cgot = 0;
+ else
+ {
+ int ierr;
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ {
+ if (cgot == 0)
+ ulog (LOG_ERROR, "Line disconnected");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+ }
+
+ return FALSE;
+ }
+ }
+
+ cwant -= cgot;
+ if (cgot >= cmin)
+ cmin = 0;
+ else
+ cmin -= cgot;
+ zbuf += cgot;
+ *pclen += cgot;
+
+ /* If we have enough data, get out now. */
+ if (cmin == 0)
+ {
+ fret = TRUE;
+ break;
+ }
+
+#if HAVE_BSD_TTY
+ /* We still want more data, so sleep long enough for the rest of
+ it to arrive. We don't this for System V or POSIX because
+ setting MIN is good enough (we can't sleep longer than it
+ takes to get MAX_INPUT characters anyhow).
+
+ The baud rate is approximately 10 times the number of
+ characters which will arrive in one second, so the number of
+ milliseconds to sleep ==
+ characters * (milliseconds / character) ==
+ characters * (1000 * (seconds / character)) ==
+ characters * (1000 * (1 / (baud / 10))) ==
+ characters * (10000 / baud)
+
+ We arbitrarily reduce the sleep amount by 10 milliseconds to
+ attempt to account for the amount of time it takes to set up
+ the sleep. This is how long it takes to get half a character
+ at 19200 baud. We then don't bother to sleep for less than
+ 10 milliseconds. We don't sleep if the read was interrupted.
+
+ We use select to sleep. It would be easy to use poll as
+ well, but it's unlikely that any system with BSD ttys would
+ have poll but not select. Using select avoids hassles with
+ the pending SIGALRM; if it hits the select will be
+ interrupted, and otherwise the select will not affect it. */
+
+#if ! HAVE_SELECT
+ #error This code requires select; feel free to extend it
+#endif
+
+ if (q->fterminal && cmin > 1 && cgot > 0)
+ {
+ int csleepchars;
+ int isleep;
+
+ /* We don't try to read all the way up to MAX_INPUT,
+ since that might drop a character. */
+ if (cmin <= MAX_INPUT - 10)
+ csleepchars = cmin;
+ else
+ csleepchars = MAX_INPUT - 10;
+
+ isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
+ isleep -= 10;
+
+ if (isleep > 10)
+ {
+ struct timeval s;
+
+ s.tv_sec = isleep / 1000;
+ s.tv_usec = (isleep % 1000) * 1000;
+
+ /* Some versions of select take a pointer to an int,
+ while some take a pointer to an fd_set. I just cast
+ the arguments to a generic pointer, and assume that
+ any machine which distinguishes int * from fd_set *
+ (I would be amazed if there are any such machines)
+ have an appropriate prototype somewhere or other. */
+ (void) select (0, (pointer) NULL, (pointer) NULL,
+ (pointer) NULL, &s);
+
+ /* Here either the select finished sleeping or we got a
+ SIGALRM. If the latter occurred, fSalarm was set to
+ TRUE; it will be checked at the top of the loop. */
+ }
+ }
+#endif /* HAVE_BSD_TTY */
+ }
+
+ /* Turn off the pending SIGALRM and return. */
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ return fret;
+}
+
+/* Read from a stdin port. */
+
+static boolean
+fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
+}
+
+/* Write data to a connection. This routine handles all types of
+ connections, including TLI. */
+
+boolean
+fsysdep_conn_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *q;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ /* We want blocking writes here. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ czero = 0;
+
+ while (cwrite > 0)
+ {
+ int cdid;
+
+ /* Loop until we don't get an interrupt. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cwrite, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cwrite);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We were interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is lost.
+ If we fail to write anything ten times in a row, we
+ assume that this has happened. This is hacked in like
+ this because there seems to be no reliable way to tell
+ exactly why the write returned 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ czero = 0;
+
+ cwrite -= cdid;
+ zwrite += cdid;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Write to a stdin port. */
+
+static boolean
+fsstdin_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ if (! fsblock (qsysdep, TRUE))
+ return FALSE;
+ qsysdep->o = 1;
+ return fsysdep_conn_write (qconn, zwrite, cwrite);
+}
+
+/* The fsysdep_conn_io routine is supposed to both read and write data
+ until it has either filled its read buffer or written out all the
+ data it was given. This lets us write out large packets without
+ losing incoming data. It handles all types of connections,
+ including TLI. */
+
+boolean
+fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t *pcwrite;
+ char *zread;
+ size_t *pcread;
+{
+ struct ssysdep_conn *q;
+ size_t cwrite, cread;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwrite = *pcwrite;
+ *pcwrite = 0;
+ cread = *pcread;
+ *pcread = 0;
+
+ czero = 0;
+
+ while (TRUE)
+ {
+ int cgot, cdid;
+ size_t cdo;
+
+ /* This used to always use nonblocking writes, but it turns out
+ that some systems don't support them on terminals.
+
+ The current algorithm is:
+ loop:
+ unblocked read
+ if read buffer full, return
+ if nothing to write, return
+ if HAVE_UNBLOCKED_WRITES
+ write all data
+ else
+ write up to SINGLE_WRITE bytes
+ if all data written, return
+ if no data written
+ blocked write of up to SINGLE_WRITE bytes
+
+ This algorithm should work whether the system supports
+ unblocked writes on terminals or not. If the system supports
+ unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
+ call write more often than it needs to. If the system does
+ not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
+ then the write may hang so long that incoming data is lost.
+ This is actually possible at high baud rates on any system
+ when a blocking write is done; there is no solution, except
+ hardware handshaking. */
+
+ /* If we are running on standard input, we switch the file
+ descriptors by hand. */
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ /* Do an unblocked read. */
+ if (! fsblock (q, FALSE))
+ return FALSE;
+
+ /* Loop until we get something (error or data) other than an
+ acceptable EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zread, cread, &iflags);
+ if (cgot < 0)
+ {
+ if (t_errno == TNODATA)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zread, cread);
+
+ if (cgot >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cgot < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ return FALSE;
+ }
+ cgot = 0;
+ }
+
+ cread -= cgot;
+ zread += cgot;
+ *pcread += cgot;
+
+ /* If we've filled the read buffer, or we have nothing left to
+ write, return out. */
+ if (cread == 0 || cwrite == 0)
+ return TRUE;
+
+ /* The port is currently unblocked. Do a write. */
+ cdo = cwrite;
+
+#if ! HAVE_UNBLOCKED_WRITES
+ if (q->fterminal && cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+#endif
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0)
+ {
+ if (t_errno == TFLOW)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid > 0)
+ {
+ /* We wrote some data. If we wrote everything, return out.
+ Otherwise loop around and do another read. */
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+
+ if (cwrite == 0)
+ return TRUE;
+
+ czero = 0;
+ }
+ else
+ {
+ /* We didn't write any data. Do a blocking write. */
+
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ cdo = cwrite;
+ if (cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsysdep_conn_io: Blocking write of %lud",
+ (unsigned long) cdo);
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is
+ lost. If we fail to write anything ten times in a
+ row, we assume that this has happened. This is
+ hacked in like this because there seems to be no
+ reliable way to tell exactly why the write returned
+ 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+ czero = 0;
+ }
+ }
+ }
+}
+
+/* Send a break character to a serial port. */
+
+static boolean
+fsserial_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+#if HAVE_BSD_TTY
+ (void) ioctl (q->o, TIOCSBRK, 0);
+ sleep (2);
+ (void) ioctl (q->o, TIOCCBRK, 0);
+ return TRUE;
+#endif /* HAVE_BSD_TTY */
+#if HAVE_SYSV_TERMIO
+ (void) ioctl (q->o, TCSBRK, 0);
+ return TRUE;
+#endif /* HAVE_SYSV_TERMIO */
+#if HAVE_POSIX_TERMIOS
+ return tcsendbreak (q->o, 0) == 0;
+#endif /* HAVE_POSIX_TERMIOS */
+}
+
+/* Send a break character to a stdin port. */
+
+static boolean
+fsstdin_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 1;
+ return fsserial_break (qconn);
+}
+
+/* Change the setting of a serial port. */
+
+/*ARGSUSED*/
+static boolean
+fsserial_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ register struct ssysdep_conn *q;
+ boolean fchanged, fdo;
+ int iset = 0;
+ int iclear = 0;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ fchanged = FALSE;
+
+ /* Set the parity for output characters. */
+
+#if HAVE_BSD_TTY
+
+ /* This will also cause parity detection on input characters. */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+#if HAVE_PARITY_BUG
+ /* The Sony NEWS mishandles this for some reason. */
+ iset = 0;
+ iclear = ANYP;
+#else
+ iset = ANYP;
+ iclear = 0;
+#endif
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = EVENP;
+ iclear = ODDP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = ODDP;
+ iclear = EVENP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+ iset = CS8;
+ iclear = PARENB | PARODD | (CSIZE &~ CS8);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = PARENB | CS7;
+ iclear = PARODD | (CSIZE &~ CS7);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = PARENB | PARODD | CS7;
+ iclear = CSIZE &~ CS7;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_cflag & iset) != iset
+ || (q->snew.c_cflag & iclear) != 0)
+ {
+ q->snew.c_cflag |= iset;
+ q->snew.c_cflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set whether input characters are stripped to seven bits. */
+
+#if HAVE_BSD_TTY
+
+#ifdef LPASS8
+ {
+ int i;
+
+ i = LPASS8;
+ if (tstrip == STRIPSETTING_EIGHTBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+ }
+ else if (tstrip == STRIPSETTING_SEVENBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIC, &i);
+ }
+ }
+#endif
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tstrip)
+ {
+ case STRIPSETTING_DEFAULT:
+ break;
+ case STRIPSETTING_EIGHTBITS:
+ iset = 0;
+ iclear = ISTRIP;
+ fdo = TRUE;
+ break;
+ case STRIPSETTING_SEVENBITS:
+ iset = ISTRIP;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set XON/XOFF handshaking. */
+
+#if HAVE_BSD_TTY
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = RAW;
+ iclear = TANDEM | CBREAK;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+ iset = CBREAK | TANDEM;
+ iclear = RAW;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = 0;
+ iclear = IXON | IXOFF;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+#ifdef CRTSCTS
+#if HAVE_POSIX_TERMIOS
+ /* This is system dependent, but I haven't figured out a good
+ way around it yet. If we are doing hardware flow control, we
+ don't send XON/XOFF characters but we do recognize them. */
+ if ((q->snew.c_cflag & CRTSCTS) != 0)
+ {
+ iset = IXON;
+ iclear = IXOFF;
+ fdo = TRUE;
+ break;
+ }
+#endif /* HAVE_POSIX_TERMIOS */
+#endif /* defined (CRTSCTS) */
+ iset = IXON | IXOFF;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (fchanged)
+ {
+ if (! fsetterminfodrain (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't change terminal settings: %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+#if HAVE_BSD_TTY
+ if (txonxoff == XONXOFF_ON
+ && (q->snew.stty.sg_flags & ANYP) == ANYP)
+ {
+ int i;
+
+ /* At least on Ultrix, we seem to have to set LLITOUT and
+ LPASS8. This shouldn't foul things up anywhere else. As far
+ as I can tell, this has to be done after setting the terminal
+ into cbreak mode, not before. */
+#ifndef LLITOUT
+#define LLITOUT 0
+#endif
+#ifndef LPASS8
+#define LPASS8 0
+#endif
+#ifndef LAUTOFLOW
+#define LAUTOFLOW 0
+#endif
+ i = LLITOUT | LPASS8 | LAUTOFLOW;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+
+#if HAVE_STRIP_BUG
+ /* Ultrix 4.0 has a peculiar problem: setting CBREAK always
+ causes input characters to be stripped. I hope this does not
+ apply to other BSD systems. It is possible to work around
+ this by using the termio call. I wish this sort of stuff was
+ not necessary!!! */
+ {
+ struct termio s;
+
+ if (ioctl (q->o, TCGETA, &s) >= 0)
+ {
+ s.c_iflag &=~ ISTRIP;
+ (void) ioctl (q->o, TCSETA, &s);
+ }
+ }
+#endif /* HAVE_STRIP_BUG */
+ }
+#endif /* HAVE_BSD_TTY */
+
+ return TRUE;
+}
+
+/* Change settings of a stdin port. */
+
+static boolean
+fsstdin_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_set (qconn, tparity, tstrip, txonxoff);
+}
+
+/* Run a chat program. */
+
+static boolean
+fsrun_chat (oread, owrite, pzprog)
+ int oread;
+ int owrite;
+ char **pzprog;
+{
+ int aidescs[3];
+ FILE *e;
+ pid_t ipid;
+ char *z;
+ size_t c;
+
+ aidescs[0] = oread;
+ aidescs[1] = owrite;
+ aidescs[2] = SPAWN_READ_PIPE;
+
+ /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the
+ responsibility of maintaing security on the chat program. */
+ ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE,
+ (const char *) NULL, FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
+ return FALSE;
+ }
+
+ e = fdopen (aidescs[2], (char *) "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (aidescs[2]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* The FILE e now is attached to stderr of the program. Forward
+ every line the program outputs to the log file. */
+ z = NULL;
+ c = 0;
+ while (getline (&z, &c, e) > 0)
+ {
+ size_t clen;
+
+ clen = strlen (z);
+ if (z[clen - 1] == '\n')
+ z[clen - 1] = '\0';
+ if (*z != '\0')
+ ulog (LOG_NORMAL, "chat: %s", z);
+ }
+
+ xfree ((pointer) z);
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, "Chat program") == 0;
+}
+
+/* Run a chat program on a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ return fsrun_chat (0, 1, pzprog);
+}
+
+/* Run a chat program on any general type of connection. */
+
+boolean
+fsysdep_conn_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
+}
+
+/* Return baud rate of a serial port. */
+
+static long
+isserial_baud (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return qsysdep->ibaud;
+}
diff --git a/gnu/libexec/uucp/libunix/signal.c b/gnu/libexec/uucp/libunix/signal.c
new file mode 100644
index 000000000000..33e24a724574
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/signal.c
@@ -0,0 +1,208 @@
+/* signal.c
+ Signal handling routines.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Signal handling routines. When we catch a signal, we want to set
+ the appropriate elements of afSignal and afLog_signal to TRUE. If
+ we are on a system which restarts system calls, we may also want to
+ longjmp out. On a system which does not restart system calls,
+ these signal handling routines are well-defined by ANSI C. */
+
+#if HAVE_RESTARTABLE_SYSCALLS
+volatile sig_atomic_t fSjmp;
+volatile jmp_buf sSjmp_buf;
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+
+/* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be
+ set in the sigaction structure to force system calls to be
+ interrupted. */
+#ifndef SA_INTERRUPT
+#define SA_INTERRUPT 0
+#endif
+
+/* The SVR3 sigset function can be called just like signal, unless
+ system calls are restarted which is extremely unlikely; we prevent
+ this case in sysh.unx. */
+#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC
+#define signal sigset
+#endif
+
+/* The sigvec structure changed from 4.2BSD to 4.3BSD. These macros
+ make the 4.3 code backward compatible. */
+#ifndef SV_INTERRUPT
+#define SV_INTERRUPT 0
+#endif
+#if ! HAVE_SIGVEC_SV_FLAGS
+#define sv_flags sv_onstack
+#endif
+
+/* Catch a signal. Reinstall the signal handler if necessary, set the
+ appropriate variables, and do a longjmp if necessary. */
+
+RETSIGTYPE
+ussignal (isig)
+ int isig;
+{
+ int iindex;
+
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, ussignal);
+#endif
+
+ switch (isig)
+ {
+ default: iindex = INDEXSIG_SIGHUP; break;
+#ifdef SIGINT
+ case SIGINT: iindex = INDEXSIG_SIGINT; break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM: iindex = INDEXSIG_SIGTERM; break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break;
+#endif
+ }
+
+ afSignal[iindex] = TRUE;
+ afLog_signal[iindex] = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* Prepare to catch a signal. This is basically the ANSI C routine
+ signal, but it uses sigaction or sigvec instead if they are
+ available. If fforce is FALSE, we do not set the signal if it is
+ currently being ignored. If pfignored is not NULL and fforce is
+ FALSE, then *pfignored will be set to TRUE if the signal was
+ previously being ignored (if fforce is TRUE the value returned in
+ *pfignored is meaningless). If we can't change the signal handler
+ we give a fatal error. */
+
+void
+usset_signal (isig, pfn, fforce, pfignored)
+ int isig;
+ RETSIGTYPE (*pfn) P((int));
+ boolean fforce;
+ boolean *pfignored;
+{
+#if HAVE_SIGACTION
+
+ struct sigaction s;
+
+ if (! fforce)
+ {
+ (void) (sigemptyset (&s.sa_mask));
+ if (sigaction (isig, (struct sigaction *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+ if (s.sa_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sa_handler = pfn;
+ (void) (sigemptyset (&s.sa_mask));
+ s.sa_flags = SA_INTERRUPT;
+
+ if (sigaction (isig, &s, (struct sigaction *) NULL) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGACTION */
+#if HAVE_SIGVEC
+
+ struct sigvec s;
+
+ if (! fforce)
+ {
+ if (sigvec (isig, (struct sigvec *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+ if (s.sv_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sv_handler = pfn;
+ s.sv_mask = 0;
+ s.sv_flags = SV_INTERRUPT;
+
+ if (sigvec (isig, &s, (struct sigvec *) NULL) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGVEC */
+
+ if (! fforce)
+ {
+ if (signal (isig, SIG_IGN) == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ (void) signal (isig, pfn);
+
+#endif /* ! HAVE_SIGVEC */
+#endif /* ! HAVE_SIGACTION */
+}
+
+/* The routine called by the system independent code, which always
+ uses the same signal handler. */
+
+void
+usysdep_signal (isig)
+ int isig;
+{
+ usset_signal (isig, ussignal, FALSE, (boolean *) NULL);
+}
diff --git a/gnu/libexec/uucp/libunix/sindir.c b/gnu/libexec/uucp/libunix/sindir.c
new file mode 100644
index 000000000000..d98750818915
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/sindir.c
@@ -0,0 +1,26 @@
+/* sindir.c
+ Stick a directory and file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+char *
+zsysdep_in_dir (zdir, zfile)
+ const char *zdir;
+ const char *zfile;
+{
+ size_t cdir, cfile;
+ char *zret;
+
+ cdir = strlen (zdir);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir + cfile + 2);
+ memcpy (zret, zdir, cdir);
+ memcpy (zret + cdir + 1, zfile, cfile);
+ zret[cdir] = '/';
+ zret[cdir + cfile + 1] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/size.c b/gnu/libexec/uucp/libunix/size.c
new file mode 100644
index 000000000000..8d021db3cd5c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/size.c
@@ -0,0 +1,27 @@
+/* size.c
+ Get the size in bytes of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+long
+csysdep_size (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno == ENOENT)
+ return -1;
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return -2;
+ }
+
+ return s.st_size;
+}
diff --git a/gnu/libexec/uucp/libunix/sleep.c b/gnu/libexec/uucp/libunix/sleep.c
new file mode 100644
index 000000000000..b232f9674ff0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/sleep.c
@@ -0,0 +1,14 @@
+/* sleep.c
+ Sleep for a number of seconds. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+void
+usysdep_sleep (c)
+ int c;
+{
+ (void) sleep (c);
+}
diff --git a/gnu/libexec/uucp/libunix/spawn.c b/gnu/libexec/uucp/libunix/spawn.c
new file mode 100644
index 000000000000..7ab080d1a9ca
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/spawn.c
@@ -0,0 +1,398 @@
+/* spawn.c
+ Spawn a program securely.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef environ
+extern char **environ;
+#endif
+
+/* Spawn a child in a fairly secure fashion. This returns the process
+ ID of the child or -1 on error. It takes far too many arguments:
+
+ pazargs -- arguments (element 0 is command)
+ aidescs -- file descriptors for stdin, stdout and stderr
+ fkeepuid -- TRUE if euid should be left unchanged
+ fkeepenv -- TRUE if environment should be left unmodified
+ zchdir -- directory to chdir to
+ fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT
+ fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC
+ zpath -- value for environment variable PATH
+ zuu_machine -- value for environment variable UU_MACHINE
+ zuu_user -- value for environment variable UU_USER
+
+ The aidescs array is three elements long. 0 is stdin, 1 is stdout
+ and 2 is stderr. The array may contain either file descriptor
+ numbers to dup appropriately, or one of the following:
+
+ SPAWN_NULL -- set descriptor to /dev/null
+ SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read
+ SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write
+
+ If fkeepenv is FALSE, a standard environment is created. The
+ environment arguments (zpath, zuu_machine and zuu_user) are only
+ used if fkeepenv is FALSE; any of them may be NULL.
+
+ This routine expects that all file descriptors have been set to
+ close-on-exec, so it doesn't have to worry about closing them
+ explicitly. It sets the close-on-exec flag for the new pipe
+ descriptors it returns. */
+
+pid_t
+ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
+ zpath, zuu_machine, zuu_user)
+ const char **pazargs;
+ int aidescs[3];
+ boolean fkeepuid;
+ boolean fkeepenv;
+ const char *zchdir;
+ boolean fnosigs;
+ boolean fshell;
+ const char *zpath;
+ const char *zuu_machine;
+ const char *zuu_user;
+{
+ char *zshcmd;
+ int i;
+ char *azenv[9];
+ char **pazenv;
+ boolean ferr;
+ int ierr = 0;
+ int onull;
+ int aichild_descs[3];
+ int cpar_close;
+ int aipar_close[4];
+ int cchild_close;
+ int aichild_close[3];
+ pid_t iret = 0;
+ const char *zcmd;
+
+ /* If we might have to use the shell, allocate enough space for the
+ quoted command before forking. Otherwise the allocation would
+ modify the data segment and we could not safely use vfork. */
+ zshcmd = NULL;
+ if (fshell)
+ {
+ size_t clen;
+
+ clen = 0;
+ for (i = 0; pazargs[i] != NULL; i++)
+ clen += strlen (pazargs[i]);
+ zshcmd = zbufalc (2 * clen + i);
+ }
+
+ /* Set up a standard environment. This is again done before forking
+ because it will modify the data segment. */
+ if (fkeepenv)
+ pazenv = environ;
+ else
+ {
+ const char *zterm, *ztz;
+ char *zspace;
+ int ienv;
+
+ if (zpath == NULL)
+ zpath = CMDPATH;
+
+ azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath));
+ sprintf (azenv[0], "PATH=%s", zpath);
+ zspace = azenv[0] + sizeof "PATH=" - 1;
+ while ((zspace = strchr (zspace, ' ')) != NULL)
+ *zspace = ':';
+
+ azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir));
+ sprintf (azenv[1], "HOME=%s", zSspooldir);
+
+ zterm = getenv ("TERM");
+ if (zterm == NULL)
+ zterm = "unknown";
+ azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm));
+ sprintf (azenv[2], "TERM=%s", zterm);
+
+ azenv[3] = zbufcpy ("SHELL=/bin/sh");
+
+ azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER));
+ sprintf (azenv[4], "USER=%s", OWNER);
+
+ ienv = 5;
+
+ ztz = getenv ("TZ");
+ if (ztz != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz));
+ sprintf (azenv[ienv], "TZ=%s", ztz);
+ ++ienv;
+ }
+
+ if (zuu_machine != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_MACHINE="
+ + strlen (zuu_machine));
+ sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine);
+ ++ienv;
+ }
+
+ if (zuu_user != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_USER="
+ + strlen (zuu_user));
+ sprintf (azenv[ienv], "UU_USER=%s", zuu_user);
+ ++ienv;
+ }
+
+ azenv[ienv] = NULL;
+ pazenv = azenv;
+ }
+
+ /* Set up any needed pipes. */
+
+ ferr = FALSE;
+ onull = -1;
+ cpar_close = 0;
+ cchild_close = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aidescs[i] == SPAWN_NULL)
+ {
+ if (onull < 0)
+ {
+ onull = open ((char *) "/dev/null", O_RDWR);
+ if (onull < 0
+ || fcntl (onull, F_SETFD,
+ fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ (void) close (onull);
+ ferr = TRUE;
+ break;
+ }
+ aipar_close[cpar_close] = onull;
+ ++cpar_close;
+ }
+ aichild_descs[i] = onull;
+ }
+ else if (aidescs[i] != SPAWN_READ_PIPE
+ && aidescs[i] != SPAWN_WRITE_PIPE)
+ aichild_descs[i] = aidescs[i];
+ else
+ {
+ int aipipe[2];
+
+ if (pipe (aipipe) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+
+ if (aidescs[i] == SPAWN_READ_PIPE)
+ {
+ aidescs[i] = aipipe[0];
+ aichild_close[cchild_close] = aipipe[0];
+ aichild_descs[i] = aipipe[1];
+ aipar_close[cpar_close] = aipipe[1];
+ }
+ else
+ {
+ aidescs[i] = aipipe[1];
+ aichild_close[cchild_close] = aipipe[1];
+ aichild_descs[i] = aipipe[0];
+ aipar_close[cpar_close] = aipipe[0];
+ }
+
+ ++cpar_close;
+ ++cchild_close;
+
+ if (fcntl (aidescs[i], F_SETFD,
+ fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+ }
+ }
+
+#if DEBUG > 1
+ if (! ferr && FDEBUGGING (DEBUG_EXECUTE))
+ {
+ ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]);
+ for (i = 1; pazargs[i] != NULL; i++)
+ ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]);
+ ulog (LOG_DEBUG_END, "%s", "");
+ }
+#endif
+
+ if (! ferr)
+ {
+ /* This should really be vfork if available. */
+ iret = ixsfork ();
+ if (iret < 0)
+ {
+ ferr = TRUE;
+ ierr = errno;
+ }
+ }
+
+ if (ferr)
+ {
+ for (i = 0; i < cchild_close; i++)
+ (void) close (aichild_close[i]);
+ iret = -1;
+ }
+
+ if (iret != 0)
+ {
+ /* The parent. Close the child's ends of the pipes and return
+ the process ID, or an error. */
+ for (i = 0; i < cpar_close; i++)
+ (void) close (aipar_close[i]);
+ ubuffree (zshcmd);
+ if (! fkeepenv)
+ {
+ char **pz;
+
+ for (pz = azenv; *pz != NULL; pz++)
+ ubuffree (*pz);
+ }
+ errno = ierr;
+ return iret;
+ }
+
+ /* The child. */
+
+#ifdef STDIN_FILENO
+#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2
+ #error The following code makes invalid assumptions
+#endif
+#endif
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aichild_descs[i] != i)
+ (void) dup2 (aichild_descs[i], i);
+ /* This should only be necessary if aichild_descs[i] == i, but
+ some systems copy the close-on-exec flag for a dupped
+ descriptor, which is wrong according to POSIX. */
+ (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC);
+ }
+
+ zcmd = pazargs[0];
+ pazargs[0] = strrchr (zcmd, '/');
+ if (pazargs[0] == NULL)
+ pazargs[0] = zcmd;
+ else
+ ++pazargs[0];
+
+ if (! fkeepuid)
+ {
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ }
+
+ if (zchdir != NULL)
+ (void) chdir (zchdir);
+
+ if (fnosigs)
+ {
+#ifdef SIGHUP
+ (void) signal (SIGHUP, SIG_IGN);
+#endif
+#ifdef SIGINT
+ (void) signal (SIGINT, SIG_IGN);
+#endif
+#ifdef SIGQUIT
+ (void) signal (SIGQUIT, SIG_IGN);
+#endif
+ }
+
+ (void) execve ((char *) zcmd, (char **) pazargs, pazenv);
+
+ /* The exec failed. If permitted, try using /bin/sh to execute a
+ shell script. */
+
+ if (errno == ENOEXEC && fshell)
+ {
+ char *zto;
+ const char *azshargs[4];
+
+ pazargs[0] = zcmd;
+ zto = zshcmd;
+ for (i = 0; pazargs[i] != NULL; i++)
+ {
+ const char *zfrom;
+
+ for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++)
+ {
+ /* Some versions of /bin/sh appear to have a bug such
+ that quoting a '/' sometimes causes an error. I
+ don't know exactly when this happens (I can recreate
+ it on Ultrix 4.0), but in any case it is harmless to
+ not quote a '/'. */
+ if (*zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom;
+ }
+ *zto++ = ' ';
+ }
+ *(zto - 1) = '\0';
+
+ azshargs[0] = "sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zshcmd;
+ azshargs[3] = NULL;
+
+ (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv);
+ }
+
+ _exit (EXIT_FAILURE);
+
+ /* Avoid compiler warning. */
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/splcmd.c b/gnu/libexec/uucp/libunix/splcmd.c
new file mode 100644
index 000000000000..9f6616a36dd0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/splcmd.c
@@ -0,0 +1,115 @@
+/* splcmd.c
+ Spool a command.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+/* Given a set of commands to execute for a remote system, create a
+ command file holding them. This creates a single command file
+ holding all the commands passed in. It returns a jobid. */
+
+char *
+zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ int ccmds;
+ const struct scmd *pascmds;
+{
+ char *z;
+ FILE *e;
+ int i;
+ const struct scmd *q;
+ char *zjobid;
+
+#if DEBUG > 0
+ if (! UUCONF_GRADE_LEGAL (bgrade))
+ ulog (LOG_FATAL, "Bad grade %d", bgrade);
+#endif
+
+ z = zscmd_file (qsys, bgrade);
+ if (z == NULL)
+ return NULL;
+
+ e = esysdep_fopen (z, FALSE, FALSE, TRUE);
+ if (e == NULL)
+ {
+ ubuffree (z);
+ return NULL;
+ }
+
+ for (i = 0, q = pascmds; i < ccmds; i++, q++)
+ {
+ switch (q->bcmd)
+ {
+ case 'S':
+ fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify == NULL ? (const char *) "" : q->znotify);
+ break;
+ case 'R':
+ fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'X':
+ fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'E':
+ fprintf (e, "E %s %s %s -%s %s 0%o %s 0 %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify, q->zcmd);
+ break;
+ default:
+ ulog (LOG_ERROR,
+ "zsysdep_spool_commands: Unrecognized type %d",
+ q->bcmd);
+ (void) fclose (e);
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+ }
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+
+ zjobid = zsfile_to_jobid (qsys, z, bgrade);
+ if (zjobid == NULL)
+ (void) remove (z);
+ ubuffree (z);
+ return zjobid;
+}
diff --git a/gnu/libexec/uucp/libunix/splnam.c b/gnu/libexec/uucp/libunix/splnam.c
new file mode 100644
index 000000000000..06ce3605ce5f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/splnam.c
@@ -0,0 +1,19 @@
+/* splnam.c
+ Get the full name of a file in the spool directory. */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Get the real name of a spool file. */
+
+char *
+zsysdep_spool_file_name (qsys, zfile, pseq)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ pointer pseq;
+{
+ return zsfind_file (zfile, qsys->uuconf_zname, bsgrade (pseq));
+}
diff --git a/gnu/libexec/uucp/libunix/spool.c b/gnu/libexec/uucp/libunix/spool.c
new file mode 100644
index 000000000000..a3e50f7747f1
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/spool.c
@@ -0,0 +1,420 @@
+/* spool.c
+ Find a file in the spool directory.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/05 18:24:31 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* There are several types of files that go in the spool directory,
+ and they go into various different subdirectories. Whenever the
+ system name LOCAL appears below, it means whatever the local system
+ name is.
+
+ Command files
+ These contain instructions for uucico indicating what files to transfer
+ to and from what systems. Each line of a work file is a command
+ beginning with S, R or X.
+ #if ! SPOOLDIR_TAYLOR
+ They are named C.ssssssgqqqq, where ssssss is the system name to
+ transfer to or from, g is the grade and qqqq is the sequence number.
+ #if SPOOLDIR_V2
+ They are put in the spool directory.
+ #elif SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ They are put in the directory "C.".
+ #elif SPOOLDIR_HDB
+ They are put in a directory named for the system for which they were
+ created.
+ #elif SPOOLDIR_ULTRIX
+ If the directory sys/ssssss exists, they are put in the directory
+ sys/ssssss/C; otherwise, they are put in the directory sys/DEFAULT/C.
+ #endif
+ #elif SPOOLDIR_SVR4
+ They are put in the directory sys/g, where sys is the system name
+ and g is the grade.
+ #endif
+ #else SPOOLDIR_TAYLOR
+ They are named C.gqqqq, where g is the grade and qqqq is the sequence
+ number, and are placed in the directory ssssss/C. where ssssss is
+ the system name to transfer to or from.
+ #endif
+
+ Data files
+ There are files to be transferred to other systems. Some files to
+ be transferred may not be in the spool directory, depending on how
+ uucp was invoked. Data files are named in work files, so it is
+ never necessary to look at them directly (except to remove old ones);
+ it is only necessary to create them. These means that the many
+ variations in naming are inconsequential.
+ #if ! SPOOLDIR_TAYLOR
+ They are named D.ssssssgqqqq where ssssss is a system name (which
+ may be LOCAL for locally initiated transfers or a remote system for
+ remotely initiated transfers, except that HDB appears to use the
+ system the file is being transferred to), g is the grade and qqqq
+ is the sequence number. Some systems use a trailing subjob ID
+ number, but we currently do not. The grade is not important, and
+ some systems do not use it. If the data file is to become an
+ execution file on another system the grade (if present) will be
+ 'X'. Otherwise Ultrix appears to use 'b'; the uux included with
+ gnuucp 1.0 appears to use 'S'; SCO does not appear to use a grade,
+ although it does use a subjob ID number.
+ #if SPOOLDIR_V2
+ They are put in the spool directory.
+ #elif SPOOLDIR_BSD42
+ If the name begins with D.LOCAL, the file is put in the directory
+ D.LOCAL. Otherwise the file is put in the directory D..
+ #elif SPOOLDIR_BSD43
+ If the name begins with D.LOCALX, the file is put in the directory
+ D.LOCALX. Otherwise if the name begins with D.LOCAL, the file is
+ put in the directory D.LOCAL Otherwise the file is put in the
+ directory "D.".
+ #elif SPOOLDIR_HDB
+ They are put in a directory named for the system for which they
+ were created.
+ #elif SPOOLDIR_ULTRIX
+ Say the file is being transferred to system REMOTE. If the
+ directory sys/REMOTE exists, then if the file begins with D.LOCALX
+ it is put in sys/REMOTE/D.LOCALX, if the file begins with D.LOCAL
+ it is put in sys/REMOTE/D.LOCAL, and otherwise it is put in
+ "sys/REMOTE/D.". If the directory sys/REMOTE does not exist, the
+ same applies except that DEFAULT is used instead of REMOTE.
+ #elif SPOOLDIR_SVR4
+ They are put in the directory sys/g, where sys is the system name
+ and g is the grade.
+ #endif
+ #else SPOOLDIR_TAYLOR
+ If the file is to become an executable file on another system it is
+ named D.Xqqqq, otherwise it is named D.qqqq where in both cases
+ qqqq is a sequence number. If the corresponding C. file is in
+ directory ssssss/C., a D.X file is placed in ssssss/D.X and a D.
+ file is placed in "ssssss/D.".
+ #endif
+
+ Execute files
+ These are files that specify programs to be executed. They are
+ created by uux, perhaps as run on another system. These names are
+ important, because a file transfer done to an execute file name
+ causes an execution to occur. The name is X.ssssssgqqqq, where
+ ssssss is the requesting system, g is the grade, and qqqq is a
+ sequence number.
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ These files are placed in the spool directory.
+ #elif SPOOLDIR_BSD43
+ These files are placed in the directory X..
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ These files are put in a directory named for the system for which
+ the files were created.
+ #elif SPOOLDIR_ULTRIX
+ If there is a spool directory (sys/ssssss) for the requesting
+ system, the files are placed in sys/ssssss/X.; otherwise, the files
+ are placed in "sys/DEFAULT/X.".
+ #elif SPOOLDIR_TAYLOR
+ The system name is automatically truncated to seven characters when
+ a file is created. The files are placed in the subdirectory X. of
+ a directory named for the system for which the files were created.
+ #endif
+
+ Temporary receive files
+ These are used when receiving files from another system. They are
+ later renamed to the final name. The actual name is unimportant,
+ although it generally begins with TM..
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ These files are placed in the spool directory.
+ #elif SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ These files are placed in the directory .Temp.
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ These files are placed in a directory named for the system for
+ which they were created.
+ #endif
+
+ System status files
+ These are used to record when the last call was made to the system
+ and what the status is. They are used to prevent frequent recalls
+ to a system which is not responding. I will not attempt to
+ recreate the format of these exactly, since they are not all that
+ important. They will be put in the directory .Status, as in HDB,
+ and they use the system name as the name of the file.
+
+ Sequence file
+ This is used to generate a unique sequence number. It contains an
+ ASCII number.
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ The file is named SEQF and is kept in the spool directory.
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ A separate sequence file is kept for each system in the directory
+ .Sequence with the name of the system.
+ #elif SPOOLDIR_ULTRIX
+ Each system with a file sys/ssssss has a sequence file in
+ sys/ssssss/.SEQF. Other systems use sys/DEFAULT/.SEQF.
+ #else SPOOLDIR_TAYLOR
+ A sequence file named SEQF is kept in the directory ssssss for each
+ system.
+ #endif
+ */
+
+/* Given the name of a file as specified in a UUCP command, and the
+ system for which this file has been created, return where to find
+ it in the spool directory. The file will begin with C. (a command
+ file), D. (a data file) or X. (an execution file). Under
+ SPOOLDIR_SVR4 we need to know the grade of the file created by the
+ local system; this is the bgrade argument, which is -1 for a file
+ from a remote system. */
+
+/*ARGSUSED*/
+char *
+zsfind_file (zsimple, zsystem, bgrade)
+ const char *zsimple;
+ const char *zsystem;
+ int bgrade;
+{
+ if (! fspool_file (zsimple))
+ {
+ ulog (LOG_ERROR, "Unrecognized file name %s", zsimple);
+ return NULL;
+ }
+
+#if ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR
+ if (*zsimple == 'X')
+ {
+ size_t clen;
+
+ /* Files beginning with X. are execute files. It is important
+ for security reasons that we know the system which created
+ the X. file. This is easy under SPOOLDIR_HDB or
+ SPOOLDIR_SVR4 SPOOLDIR_TAYLOR, because the file will be in a
+ directory named for the system. Under other schemes, we must
+ get the system name from the X. file name. To prevent
+ security violations, we set the system name directly here;
+ this will cause problems if the maximum file name length is
+ too short, but hopefully no problem will occur since any
+ System V systems will be using HDB or SVR4 or TAYLOR. */
+ clen = strlen (zsimple);
+ if (clen <= 7 || strncmp (zsimple + 2, zsystem, clen - 7) != 0)
+ {
+ static char *zbuf;
+ static size_t cbuf;
+ size_t cwant;
+
+ cwant = strlen (zsystem) + 8;
+ if (cwant > cbuf)
+ {
+ zbuf = (char *) xrealloc ((pointer) zbuf, cwant);
+ cbuf = cwant;
+ }
+ sprintf (zbuf, "X.%s%s", zsystem,
+ clen < 5 ? zsimple : zsimple + clen - 5);
+ zsimple = zbuf;
+ }
+ }
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR */
+
+#if SPOOLDIR_V2
+ /* V2 never uses subdirectories. */
+ return zbufcpy (zsimple);
+#endif /* SPOOLDIR_V2 */
+
+#if SPOOLDIR_HDB
+ /* HDB always uses the system name as a directory. */
+ return zsysdep_in_dir (zsystem, zsimple);
+#endif /* SPOOLDIR_HDB */
+
+#if SPOOLDIR_SVR4
+ /* SVR4 uses grade directories within the system directory for local
+ command and data files. */
+ if (bgrade < 0 || *zsimple == 'X')
+ return zsysdep_in_dir (zsystem, zsimple);
+ else
+ {
+ char abgrade[2];
+
+ abgrade[0] = bgrade;
+ abgrade[1] = '\0';
+ return zsappend3 (zsystem, abgrade, zsimple);
+ }
+#endif /* SPOOLDIR_SVR4 */
+
+#if ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4
+ switch (*zsimple)
+ {
+ case 'C':
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ return zsysdep_in_dir ("C.", zsimple);
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_ULTRIX
+ if (fsultrix_has_spool (zsystem))
+ return zsappend4 ("sys", zsystem, "C.", zsimple);
+ else
+ return zsappend4 ("sys", "DEFAULT", "C.", zsimple);
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ return zsappend3 (zsystem, "C.", zsimple);
+#endif /* SPOOLDIR_TAYLOR */
+
+ case 'D':
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ {
+ size_t c;
+ boolean ftruncated;
+
+ /* D.LOCAL in D.LOCAL/, others in D./. If BSD43, D.LOCALX in
+ D.LOCALX/. */
+ ftruncated = TRUE;
+ if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0)
+ {
+ c = strlen (zSlocalname);
+ ftruncated = FALSE;
+ }
+ else if (strncmp (zsimple + 2, zSlocalname, 7) == 0)
+ c = 7;
+ else if (strncmp (zsimple + 2, zSlocalname, 6) == 0)
+ c = 6;
+ else
+ c = 0;
+#if SPOOLDIR_BSD43
+ if (c > 0 && zsimple[c + 2] == 'X')
+ c++;
+#endif /* SPOOLDIR_BSD43 */
+ if (c > 0)
+ {
+ char *zalloc;
+
+ zalloc = zbufalc (c + 3);
+ memcpy (zalloc, zsimple, c + 2);
+ zalloc[c + 2] = '\0';
+
+ /* If we truncated the system name, and there is no existing
+ directory with the truncated name, then just use D.. */
+ if (! ftruncated || fsysdep_directory (zalloc))
+ {
+ char *zret;
+
+ zret = zsysdep_in_dir (zalloc, zsimple);
+ ubuffree (zalloc);
+ return zret;
+ }
+ ubuffree (zalloc);
+ }
+ return zsysdep_in_dir ("D.", zsimple);
+ }
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_ULTRIX
+ {
+ size_t c;
+ boolean ftruncated;
+ char *zfree;
+ const char *zdir;
+ char *zret;
+
+ /* D.LOCALX in D.LOCALX/, D.LOCAL in D.LOCAL/, others in D./. */
+ ftruncated = TRUE;
+ if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0)
+ {
+ c = strlen (zSlocalname);
+ ftruncated = FALSE;
+ }
+ else if (strncmp (zsimple + 2, zSlocalname, 7) == 0)
+ c = 7;
+ else if (strncmp (zsimple + 2, zSlocalname, 6) == 0)
+ c = 6;
+ else
+ c = 0;
+ if (c > 0 && zsimple[c + 2] == 'X')
+ ++c;
+ if (c > 0)
+ {
+ zfree = zbufalc (c + 3);
+ memcpy (zfree, zsimple, c + 2);
+ zfree[c + 2] = '\0';
+ zdir = zfree;
+
+ /* If we truncated the name, and there is no directory for
+ the truncated name, then don't use it. */
+ if (ftruncated)
+ {
+ char *zlook;
+
+ zlook = zsappend3 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ zdir);
+ if (! fsysdep_directory (zlook))
+ zdir = "D.";
+ ubuffree (zlook);
+ }
+ }
+ else
+ {
+ zfree = NULL;
+ zdir = "D.";
+ }
+
+ zret = zsappend4 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ zdir,
+ zsimple);
+ ubuffree (zfree);
+ return zret;
+ }
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ if (zsimple[2] == 'X')
+ return zsappend3 (zsystem, "D.X", zsimple);
+ else
+ return zsappend3 (zsystem, "D.", zsimple);
+#endif /* SPOOLDIR_TAYLOR */
+
+
+ case 'X':
+#if SPOOLDIR_BSD42
+ return zbufcpy (zsimple);
+#endif
+#if SPOOLDIR_BSD43
+ return zsysdep_in_dir ("X.", zsimple);
+#endif
+#if SPOOLDIR_ULTRIX
+ return zsappend4 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ "X.",
+ zsimple);
+#endif
+#if SPOOLDIR_TAYLOR
+ return zsappend3 (zsystem, "X.", zsimple);
+#endif
+ }
+
+ /* This is just to avoid warnings; it will never be executed. */
+ return NULL;
+#endif /* ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+}
diff --git a/gnu/libexec/uucp/libunix/srmdir.c b/gnu/libexec/uucp/libunix/srmdir.c
new file mode 100644
index 000000000000..28487ef30970
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/srmdir.c
@@ -0,0 +1,112 @@
+/* srmdir.c
+ Remove a directory and all its contents.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int isremove_dir P((const char *, const struct stat *, int));
+
+/* Keep a list of directories to be removed. */
+
+struct sdirlist
+{
+ struct sdirlist *qnext;
+ char *zdir;
+};
+
+static struct sdirlist *qSdirlist;
+
+/* Remove a directory and all files in it. */
+
+boolean
+fsysdep_rmdir (zdir)
+ const char *zdir;
+{
+ boolean fret;
+ struct sdirlist *q;
+
+ qSdirlist = NULL;
+
+ fret = TRUE;
+ if (ftw ((char *) zdir, isremove_dir, 5) != 0)
+ {
+ ulog (LOG_ERROR, "ftw: %s", strerror (errno));
+ fret = FALSE;
+ }
+
+ q = qSdirlist;
+ while (q != NULL)
+ {
+ struct sdirlist *qnext;
+
+ if (rmdir (q->zdir) != 0)
+ {
+ ulog (LOG_ERROR, "rmdir (%s): %s", q->zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (q->zdir);
+ qnext = q->qnext;
+ xfree ((pointer) q);
+ q = qnext;
+ }
+
+ return fret;
+}
+
+/* Remove a file in a directory. */
+
+/*ARGSUSED*/
+static int
+isremove_dir (zfile, qstat, iflag)
+ const char *zfile;
+ const struct stat *qstat;
+ int iflag;
+{
+ if (iflag == FTW_D || iflag == FTW_DNR)
+ {
+ struct sdirlist *q;
+
+ q = (struct sdirlist *) xmalloc (sizeof (struct sdirlist));
+ q->qnext = qSdirlist;
+ q->zdir = zbufcpy (zfile);
+ qSdirlist = q;
+ }
+ else
+ {
+ if (remove (zfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/statsb.c b/gnu/libexec/uucp/libunix/statsb.c
new file mode 100644
index 000000000000..aa17f9e9df07
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/statsb.c
@@ -0,0 +1,572 @@
+/* statsb.c
+ System dependent routines for uustat.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/05 18:24:34 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+/* Local functions. */
+
+static int ussettime P((const char *z, time_t inow));
+static boolean fskill_or_rejuv P((pointer puuconf, const char *zid,
+ boolean fkill));
+
+/* See whether the user is permitted to kill arbitrary jobs. This is
+ true only for root and uucp. We check for uucp by seeing if the
+ real user ID and the effective user ID are the same; this works
+ because we should be suid to uucp, so our effective user ID will
+ always be uucp while our real user ID will be whoever ran the
+ program. */
+
+boolean
+fsysdep_privileged ()
+{
+ uid_t iuid;
+
+ iuid = getuid ();
+ return iuid == 0 || iuid == geteuid ();
+}
+
+/* Set file access time to the present. On many systems this could be
+ done by passing NULL to utime, but on some that doesn't work. This
+ routine is not time critical, so we never rely on NULL. */
+
+static int
+ussettime(z, inow)
+ const char *z;
+ time_t inow;
+{
+#if HAVE_UTIME_H
+ struct utimbuf s;
+
+ s.actime = inow;
+ s.modtime = inow;
+ return utime ((char *) z, &s);
+#else
+ time_t ai[2];
+
+ ai[0] = inow;
+ ai[1] = inow;
+ return utime ((char *) z, ai);
+#endif
+}
+
+/* Kill a job, given the jobid. */
+
+boolean
+fsysdep_kill_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, TRUE);
+}
+
+/* Rejuvenate a job, given the jobid. */
+
+boolean
+fsysdep_rejuvenate_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, FALSE);
+}
+
+/* Kill or rejuvenate a job, given the jobid. */
+
+static boolean
+fskill_or_rejuv (puuconf, zid, fkill)
+ pointer puuconf;
+ const char *zid;
+ boolean fkill;
+{
+ char *zfile;
+ char *zsys;
+ char bgrade;
+ time_t inow = 0;
+ int iuuconf;
+ struct uuconf_system ssys;
+ FILE *e;
+ boolean fret;
+ char *zline;
+ size_t cline;
+ int isys;
+
+ zfile = zsjobid_to_file (zid, &zsys, &bgrade);
+ if (zfile == NULL)
+ return FALSE;
+
+ if (! fkill)
+ inow = time ((time_t *) NULL);
+
+ iuuconf = uuconf_system_info (puuconf, zsys, &ssys);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ if (! funknown_system (puuconf, zsys, &ssys))
+ {
+ ulog (LOG_ERROR, "%s: Bad job id", zid);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ e = fopen (zfile, "r");
+ if (e == NULL)
+ {
+ if (errno == ENOENT)
+ ulog (LOG_ERROR, "%s: Job not found", zid);
+ else
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ /* Now we have to read through the file to identify any temporary
+ files. */
+ fret = TRUE;
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ struct scmd s;
+
+ if (! fparse_cmd (zline, &s))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s", zfile);
+ fret = FALSE;
+ continue;
+ }
+
+ /* You are only permitted to delete a job if you submitted it or
+ if you are root or uucp. */
+ if (strcmp (s.zuser, zsysdep_login_name ()) != 0
+ && ! fsysdep_privileged ())
+ {
+ ulog (LOG_ERROR, "%s: Not submitted by you", zid);
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ if (s.bcmd == 'S' || s.bcmd == 'E')
+ {
+ char *ztemp;
+
+ ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade);
+ if (ztemp == NULL)
+ fret = FALSE;
+ else
+ {
+ if (fkill)
+ isys = remove (ztemp);
+ else
+ isys = ussettime (ztemp, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s",
+ fkill ? "remove" : "utime", ztemp,
+ strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (ztemp);
+ }
+ }
+ }
+
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zsys);
+
+ if (fkill)
+ isys = remove (zfile);
+ else
+ isys = ussettime (zfile, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime",
+ zfile, strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Get the time a work job was queued. */
+
+long
+ixsysdep_work_time (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ char *zjobid, *zfile;
+ long iret;
+
+ zjobid = zsysdep_jobid (qsys, pseq);
+ zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL);
+ if (zfile == NULL)
+ return 0;
+ ubuffree (zjobid);
+ iret = ixsysdep_file_time (zfile);
+ ubuffree (zfile);
+ return iret;
+}
+
+/* Get the time a file was created (actually, the time it was last
+ modified). */
+
+long
+ixsysdep_file_time (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return ixsysdep_time ((long *) NULL);
+ }
+
+ return (long) s.st_mtime;
+}
+
+/* Start getting the status files. */
+
+boolean
+fsysdep_all_status_init (phold)
+ pointer *phold;
+{
+ DIR *qdir;
+
+ qdir = opendir ((char *) ".Status");
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno));
+ return FALSE;
+ }
+
+ *phold = (pointer) qdir;
+ return TRUE;
+}
+
+/* Get the next status file. */
+
+char *
+zsysdep_all_status (phold, pferr, qstat)
+ pointer phold;
+ boolean *pferr;
+ struct sstatus *qstat;
+{
+ DIR *qdir = (DIR *) phold;
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ errno = 0;
+ qentry = readdir (qdir);
+ if (qentry == NULL)
+ {
+ if (errno == 0)
+ *pferr = FALSE;
+ else
+ {
+ ulog (LOG_ERROR, "readdir: %s", strerror (errno));
+ *pferr = TRUE;
+ }
+ return NULL;
+ }
+
+ if (qentry->d_name[0] != '.')
+ {
+ struct uuconf_system ssys;
+
+ /* Hack seriously; fsysdep_get_status only looks at the
+ zname element of the qsys argument, so if we fake that we
+ can read the status file. This should really be done
+ differently. */
+ ssys.uuconf_zname = qentry->d_name;
+ if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL))
+ return zbufcpy (qentry->d_name);
+
+ /* If fsysdep_get_status fails, it will output an error
+ message. We just continue with the next entry, so that
+ most of the status files will be displayed. */
+ }
+ }
+}
+
+/* Finish getting the status file. */
+
+void
+usysdep_all_status_free (phold)
+ pointer phold;
+{
+ DIR *qdir = (DIR *) phold;
+
+ (void) closedir (qdir);
+}
+
+/* Get the status of all processes holding lock files. We do this by
+ invoking ps after we've figured out the process entries to use. */
+
+boolean
+fsysdep_lock_status ()
+{
+ DIR *qdir;
+ struct dirent *qentry;
+ int calc;
+ int *pai;
+ int cgot;
+ int aidescs[3];
+ char *zcopy, *ztok;
+ int cargs, iarg;
+ char **pazargs;
+
+ qdir = opendir ((char *) zSlockdir);
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno));
+ return FALSE;
+ }
+
+ /* We look for entries that start with "LCK.." and ignore everything
+ else. This won't find all possible lock files, but it should
+ find all the locks on terminals and systems. */
+
+ calc = 0;
+ pai = NULL;
+ cgot = 0;
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *zname;
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cread;
+ int ierr;
+ int ipid;
+
+ if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
+ continue;
+
+ zname = zsysdep_in_dir (zSlockdir, qentry->d_name);
+ o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ continue;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cread = read (o, &i, sizeof i);
+#else
+ cread = read (o, ab, sizeof ab - 1);
+#endif
+
+ ierr = errno;
+ (void) close (o);
+
+ if (cread < 0)
+ {
+ ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr));
+ ubuffree (zname);
+ continue;
+ }
+
+ ubuffree (zname);
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cread] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ printf ("%s: %d\n", qentry->d_name, ipid);
+
+ if (cgot >= calc)
+ {
+ calc += 10;
+ pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int));
+ }
+
+ pai[cgot] = ipid;
+ ++cgot;
+ }
+
+ if (cgot == 0)
+ return TRUE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ /* Parse PS_PROGRAM into an array of arguments. */
+ zcopy = zbufcpy (PS_PROGRAM);
+
+ cargs = 0;
+ for (ztok = strtok (zcopy, " \t");
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"))
+ ++cargs;
+
+ pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *));
+
+ memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM);
+ for (ztok = strtok (zcopy, " \t"), iarg = 0;
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"), ++iarg)
+ pazargs[iarg] = ztok;
+ pazargs[iarg] = NULL;
+
+#if ! HAVE_PS_MULTIPLE
+ /* We have to invoke ps multiple times. */
+ {
+ int i;
+ char *zlast, *zset;
+
+ zlast = pazargs[cargs - 1];
+ zset = zbufalc (strlen (zlast) + 20);
+ for (i = 0; i < cgot; i++)
+ {
+ pid_t ipid;
+
+ sprintf (zset, "%s%d", zlast, pai[i]);
+ pazargs[cargs - 1] = zset;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ }
+ ubuffree (zset);
+ }
+#else
+ {
+ char *zlast;
+ int i;
+ pid_t ipid;
+
+ zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1);
+ strcpy (zlast, pazargs[cargs - 1]);
+ for (i = 0; i < cgot; i++)
+ {
+ char ab[20];
+
+ sprintf (ab, "%d", pai[i]);
+ strcat (zlast, ab);
+ if (i + 1 < cgot)
+ strcat (zlast, ",");
+ }
+ pazargs[cargs - 1] = zlast;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ ubuffree (zlast);
+ }
+#endif
+
+ ubuffree (zcopy);
+ xfree ((pointer) pazargs);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/status.c b/gnu/libexec/uucp/libunix/status.c
new file mode 100644
index 000000000000..f403068a7094
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/status.c
@@ -0,0 +1,212 @@
+/* status.c
+ Routines to get and set the status for a 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+
+/* If we are using HDB spool layout, store status using HDB status
+ values. SVR4 is a variant of HDB. */
+
+#define MAP_STATUS 1
+
+static const int aiMapstatus[] =
+{
+ 0, 13, 7, 6, 4, 20, 3, 2
+};
+#define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0]))
+
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+#define MAP_STATUS 0
+
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+/* Get the status of a system. This assumes that we are in the spool
+ directory. */
+
+boolean
+fsysdep_get_status (qsys, qret, pfnone)
+ const struct uuconf_system *qsys;
+ struct sstatus *qret;
+ boolean *pfnone;
+{
+ char *zname;
+ FILE *e;
+ char *zline;
+ char *zend, *znext;
+ boolean fbad;
+ int istat;
+
+ if (pfnone != NULL)
+ *pfnone = FALSE;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return FALSE;
+ }
+ zline = NULL;
+ }
+ else
+ {
+ size_t cline;
+
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ {
+ xfree ((pointer) zline);
+ zline = NULL;
+ }
+ (void) fclose (e);
+ }
+
+ if (zline == NULL)
+ {
+ /* There is either no status file for this system, or it's been
+ truncated, so fake a good status. */
+ qret->ttype = STATUS_COMPLETE;
+ qret->cretries = 0;
+ qret->ilast = 0;
+ qret->cwait = 0;
+ if (pfnone != NULL)
+ *pfnone = TRUE;
+ ubuffree (zname);
+ return TRUE;
+ }
+
+ /* It turns out that scanf is not used much in this program, so for
+ the benefit of small computers we avoid linking it in. This is
+ basically
+
+ sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries,
+ &qret->ilast, &qret->cwait);
+
+ except that it's done with strtol. */
+
+ fbad = FALSE;
+ istat = (int) strtol (zline, &zend, 10);
+ if (zend == zline)
+ fbad = TRUE;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map system dependent status
+ values on to our status values. */
+ {
+ int i;
+
+ for (i = 0; i < CMAPENTRIES; ++i)
+ {
+ if (aiMapstatus[i] == istat)
+ {
+ istat = i;
+ break;
+ }
+ }
+ }
+#endif /* MAP_STATUS */
+
+ if (istat < 0 || istat >= (int) STATUS_VALUES)
+ istat = (int) STATUS_COMPLETE;
+ qret->ttype = (enum tstatus_type) istat;
+ znext = zend;
+ qret->cretries = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->ilast = strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->cwait = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+
+ xfree ((pointer) zline);
+
+ if (fbad)
+ {
+ ulog (LOG_ERROR, "%s: Bad status file format", zname);
+ ubuffree (zname);
+ return FALSE;
+ }
+
+ ubuffree (zname);
+
+ return TRUE;
+}
+
+/* Set the status of a remote system. This assumes the system is
+ locked when this is called, and that the program is in the spool
+ directory. */
+
+boolean
+fsysdep_set_status (qsys, qset)
+ const struct uuconf_system *qsys;
+ const struct sstatus *qset;
+{
+ char *zname;
+ FILE *e;
+ int istat;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+
+ e = esysdep_fopen (zname, TRUE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return FALSE;
+ istat = (int) qset->ttype;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map istat onto a system
+ dependent number. */
+ if (istat >= 0 && istat < CMAPENTRIES)
+ istat = aiMapstatus[istat];
+#endif /* MAP_STATUS */
+
+ fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries,
+ qset->ilast, qset->cwait, azStatus[(int) qset->ttype],
+ qsys->uuconf_zname);
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/strerr.c b/gnu/libexec/uucp/libunix/strerr.c
new file mode 100644
index 000000000000..d2a6c2128d04
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/strerr.c
@@ -0,0 +1,22 @@
+/* strerr.c
+ Return a string for a Unix errno value. */
+
+#include "uucp.h"
+
+#include <errno.h>
+
+#ifndef sys_nerr
+extern int sys_nerr;
+#endif
+#ifndef sys_errlist
+extern char *sys_errlist[];
+#endif
+
+char *
+strerror (ierr)
+ int ierr;
+{
+ if (ierr >= 0 && ierr < sys_nerr)
+ return sys_errlist[ierr];
+ return (char *) "unknown error";
+}
diff --git a/gnu/libexec/uucp/libunix/time.c b/gnu/libexec/uucp/libunix/time.c
new file mode 100644
index 000000000000..d0462433a7dd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/time.c
@@ -0,0 +1,32 @@
+/* time.c
+ Get the current time. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Get the time in seconds since the epoch, with optional
+ microseconds. We use ixsysdep_process_time to get the microseconds
+ if it will work (it won't if it uses times, since that returns a
+ time based only on the process). */
+
+long
+ixsysdep_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+ return ixsysdep_process_time (pimicros);
+#else
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/tmpfil.c b/gnu/libexec/uucp/libunix/tmpfil.c
new file mode 100644
index 000000000000..2dac0024388a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/tmpfil.c
@@ -0,0 +1,83 @@
+/* tmpfil.c
+ Get a temporary file name.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#define ZDIGS \
+ "0123456789abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
+#define CDIGS (sizeof ZDIGS - 1)
+
+/*ARGSUSED*/
+char *
+zstemp_file (qsys)
+ const struct uuconf_system *qsys;
+{
+ static int icount;
+ const char *const zdigs = ZDIGS;
+ char ab[14];
+ pid_t ime;
+ int iset;
+
+ ab[0] = 'T';
+ ab[1] = 'M';
+ ab[2] = '.';
+
+ ime = getpid ();
+ iset = 3;
+ while (ime > 0 && iset < 10)
+ {
+ ab[iset] = zdigs[ime % CDIGS];
+ ime /= CDIGS;
+ ++iset;
+ }
+
+ ab[iset] = '.';
+ ++iset;
+
+ ab[iset] = zdigs[icount / CDIGS];
+ ++iset;
+ ab[iset] = zdigs[icount % CDIGS];
+ ++iset;
+
+ ab[iset] = '\0';
+
+ ++icount;
+ if (icount >= CDIGS * CDIGS)
+ icount = 0;
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ return zbufcpy (ab);
+#endif
+#if SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ return zsysdep_in_dir (".Temp", ab);
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ return zsysdep_in_dir (qsys->uuconf_zname, ab);
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/trunc.c b/gnu/libexec/uucp/libunix/trunc.c
new file mode 100644
index 000000000000..c93e82e39403
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/trunc.c
@@ -0,0 +1,157 @@
+/* trunc.c
+ Truncate a file to zero length. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+/* Truncate a file to zero length. If this fails, it closes and
+ removes the file. We support a number of different means of
+ truncation, which is probably a waste of time since this function
+ is currently only called when the 'f' protocol resends a file. */
+
+#if HAVE_FTRUNCATE
+#undef HAVE_LTRUNC
+#define HAVE_LTRUNC 0
+#endif
+
+#if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC
+#ifdef F_CHSIZE
+#define HAVE_F_CHSIZE 1
+#else /* ! defined (F_CHSIZE) */
+#ifdef F_FREESP
+#define HAVE_F_FREESP 1
+#endif /* defined (F_FREESP) */
+#endif /* ! defined (F_CHSIZE) */
+#endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */
+
+openfile_t
+esysdep_truncate (e, zname)
+ openfile_t e;
+ const char *zname;
+{
+ int o;
+
+#if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP
+ int itrunc;
+
+ if (! ffilerewind (e))
+ {
+ ulog (LOG_ERROR, "rewind: %s", strerror (errno));
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ o = fileno (e);
+#else
+ o = e;
+#endif
+
+#if HAVE_FTRUNCATE
+ itrunc = ftruncate (o, 0);
+#endif
+#if HAVE_LTRUNC
+ itrunc = ltrunc (o, (long) 0, SEEK_SET);
+#endif
+#if HAVE_F_CHSIZE
+ itrunc = fcntl (o, F_CHSIZE, (off_t) 0);
+#endif
+#if HAVE_F_FREESP
+ /* This selection is based on an implementation of ftruncate by
+ kucharsk@Solbourne.com (William Kucharski). */
+ {
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = 0;
+ fl.l_type = F_WRLCK;
+
+ itrunc = fcntl (o, F_FREESP, &fl);
+ }
+#endif
+
+ if (itrunc != 0)
+ {
+#if HAVE_FTRUNCATE
+ ulog (LOG_ERROR, "ftruncate: %s", strerror (errno));
+#endif
+#ifdef HAVE_LTRUNC
+ ulog (LOG_ERROR, "ltrunc: %s", strerror (errno));
+#endif
+#ifdef HAVE_F_CHSIZE
+ ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno));
+#endif
+#ifdef HAVE_F_FREESP
+ ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno));
+#endif
+
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+ return e;
+#else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+ (void) ffileclose (e);
+ (void) remove (zname);
+
+ o = creat ((char *) zname, IPRIVATE_FILE_MODE);
+
+ if (o == -1)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zname, strerror (errno));
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno));
+ (void) close (o);
+ (void) remove (zname);
+ return NULL;
+ }
+#else /* ! USE_STDIO */
+ e = o;
+#endif /* ! USE_STDIO */
+
+ return e;
+#endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+}
diff --git a/gnu/libexec/uucp/libunix/uacces.c b/gnu/libexec/uucp/libunix/uacces.c
new file mode 100644
index 000000000000..c92c78eae354
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/uacces.c
@@ -0,0 +1,205 @@
+/* uacces.c
+ Check access to a file by user name.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#if HAVE_GETGRENT
+#include <grp.h>
+#if GETGRENT_DECLARATION_OK
+#ifndef getgrent
+extern struct group *getgrent ();
+#endif
+#endif
+#endif /* HAVE_GETGRENT */
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Do access(2) on a stat structure, except that the user name is
+ provided. If the user name in zuser is NULL, require the file to
+ be accessible to the world. Return TRUE if access is permitted,
+ FALSE otherwise. This does not log an error message. */
+
+boolean
+fsuser_access (q, imode, zuser)
+ const struct stat *q;
+ int imode;
+ const char *zuser;
+{
+ static char *zuser_hold;
+ static uid_t iuid_hold;
+ static gid_t igid_hold;
+ static int cgroups_hold;
+ static gid_t *paigroups_hold;
+ int ir, iw, ix, iand;
+
+ if (imode == F_OK)
+ return TRUE;
+
+ if (zuser != NULL)
+ {
+ /* We keep static variables around for the last user we did, to
+ avoid looking up a user multiple times. */
+ if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0)
+ {
+ struct passwd *qpwd;
+
+ if (zuser_hold != NULL)
+ {
+ ubuffree (zuser_hold);
+ zuser_hold = NULL;
+ cgroups_hold = 0;
+ xfree ((pointer) paigroups_hold);
+ paigroups_hold = NULL;
+ }
+
+ qpwd = getpwnam ((char *) zuser);
+ if (qpwd == NULL)
+ {
+ /* Check this as a remote request. */
+ zuser = NULL;
+ }
+ else
+ {
+#if HAVE_GETGRENT
+ struct group *qg;
+#endif
+
+ zuser_hold = zbufcpy (zuser);
+
+ iuid_hold = qpwd->pw_uid;
+ igid_hold = qpwd->pw_gid;
+
+#if HAVE_GETGRENT
+ /* Get the list of groups for this user. This is
+ definitely more appropriate for BSD than for System
+ V. It may just be a waste of time, and perhaps it
+ should be configurable. */
+ setgrent ();
+ while ((qg = getgrent ()) != NULL)
+ {
+ const char **pz;
+
+ if (qg->gr_gid == igid_hold)
+ continue;
+ for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++)
+ {
+ if ((*pz)[0] == *zuser
+ && strcmp (*pz, zuser) == 0)
+ {
+ paigroups_hold = ((gid_t *)
+ (xrealloc
+ ((pointer) paigroups_hold,
+ ((cgroups_hold + 1)
+ * sizeof (gid_t)))));
+ paigroups_hold[cgroups_hold] = qg->gr_gid;
+ ++cgroups_hold;
+ break;
+ }
+ }
+ }
+ endgrent ();
+#endif
+ }
+ }
+ }
+
+
+ /* Now do the actual access check. */
+
+ if (zuser != NULL)
+ {
+ /* The superuser can do anything. */
+ if (iuid_hold == 0)
+ return TRUE;
+
+ /* If this is the uid we're running under, there's no point to
+ checking access further, because when we actually try the
+ operation the system will do the checking for us. */
+ if (iuid_hold == geteuid ())
+ return TRUE;
+ }
+
+ ir = S_IROTH;
+ iw = S_IWOTH;
+ ix = S_IXOTH;
+
+ if (zuser != NULL)
+ {
+ if (iuid_hold == q->st_uid)
+ {
+ ir = S_IRUSR;
+ iw = S_IWUSR;
+ ix = S_IXUSR;
+ }
+ else
+ {
+ boolean fgroup;
+
+ fgroup = FALSE;
+ if (igid_hold == q->st_gid)
+ fgroup = TRUE;
+ else
+ {
+ int i;
+
+ for (i = 0; i < cgroups_hold; i++)
+ {
+ if (paigroups_hold[i] == q->st_gid)
+ {
+ fgroup = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fgroup)
+ {
+ ir = S_IRGRP;
+ iw = S_IWGRP;
+ ix = S_IXGRP;
+ }
+ }
+ }
+
+ iand = 0;
+ if ((imode & R_OK) != 0)
+ iand |= ir;
+ if ((imode & W_OK) != 0)
+ iand |= iw;
+ if ((imode & X_OK) != 0)
+ iand |= ix;
+
+ return (q->st_mode & iand) == iand;
+}
diff --git a/gnu/libexec/uucp/libunix/ufopen.c b/gnu/libexec/uucp/libunix/ufopen.c
new file mode 100644
index 000000000000..5a7b6f22b0d0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ufopen.c
@@ -0,0 +1,218 @@
+/* ufopen.c
+ Open a file with the permissions of the invoking user.
+
+ Copyright (C) 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Local functions. */
+
+static boolean fsuser_perms P((uid_t *pieuid));
+static boolean fsuucp_perms P((long ieuid));
+
+/* Switch to permissions of the invoking user. */
+
+static boolean
+fsuser_perms (pieuid)
+ uid_t *pieuid;
+{
+ uid_t ieuid, iuid;
+
+ ieuid = geteuid ();
+ iuid = getuid ();
+ if (pieuid != NULL)
+ *pieuid = ieuid;
+
+#if HAVE_SETREUID
+ /* Swap the effective user id and the real user id. We can then
+ swap them back again when we want to return to the uucp user's
+ permissions. */
+ if (setreuid (ieuid, iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) ieuid, (long) iuid, strerror (errno));
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set the effective user id to the real user id. Since the
+ effective user id is saved (it's the saved setuid) we will able
+ to set back to it later. If the real user id is root we will not
+ be able to switch back and forth, so don't even try. */
+ if (iuid != 0)
+ {
+ if (setuid (iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno));
+ return FALSE;
+ }
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* There's no way to switch between real permissions and effective
+ permissions. Just try to open the file with the uucp
+ permissions. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Restore the uucp permissions. */
+
+/*ARGSUSED*/
+static boolean
+fsuucp_perms (ieuid)
+ long ieuid;
+{
+#if HAVE_SETREUID
+ /* Swap effective and real user id's back to what they were. */
+ if (! fsuser_perms ((uid_t *) NULL))
+ return FALSE;
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set ourselves back to our original effective user id. */
+ if (setuid ((uid_t) ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno));
+ /* Is this error message helpful or confusing? */
+ if (errno == EPERM)
+ ulog (LOG_ERROR,
+ "Probably HAVE_SAVED_SETUID in policy.h should be set to 0");
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* We didn't switch, no need to switch back. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Open a file with the permissions of the invoking user. Ignore the
+ fbinary argument since Unix has no distinction between text and
+ binary files. */
+
+/*ARGSUSED*/
+openfile_t
+esysdep_user_fopen (zfile, frd, fbinary)
+ const char *zfile;
+ boolean frd;
+ boolean fbinary;
+{
+ uid_t ieuid;
+ openfile_t e;
+ const char *zerr;
+ int o = 0;
+
+ if (! fsuser_perms (&ieuid))
+ return EFILECLOSED;
+
+ zerr = NULL;
+
+#if USE_STDIO
+ e = fopen (zfile, frd ? "r" : "w");
+ if (e == NULL)
+ zerr = "fopen";
+ else
+ o = fileno (e);
+#else
+ if (frd)
+ {
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ zerr = "open";
+ }
+ else
+ {
+ e = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ zerr = "creat";
+ }
+ if (e >= 0)
+ {
+ o = e;
+ zerr = NULL;
+ }
+#endif
+
+ if (! fsuucp_perms ((long) ieuid))
+ {
+ if (ffileisopen (e))
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zfile, strerror (errno));
+#if ! HAVE_SETREUID
+ /* Are these error messages helpful or confusing? */
+#if HAVE_SAVED_SETUID
+ if (errno == EACCES && getuid () == 0)
+ ulog (LOG_ERROR,
+ "The superuser may only transfer files that are readable by %s",
+ OWNER);
+#else
+ if (errno == EACCES)
+ ulog (LOG_ERROR,
+ "You may only transfer files that are readable by %s", OWNER);
+#endif
+#endif /* ! HAVE_SETREUID */
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/ultspl.c b/gnu/libexec/uucp/libunix/ultspl.c
new file mode 100644
index 000000000000..34921d228046
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ultspl.c
@@ -0,0 +1,21 @@
+/* ultspl.c
+ See whether there is an Ultrix spool directory for a system. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+boolean
+fsultrix_has_spool (zsystem)
+ const char *zsystem;
+{
+ char *z;
+ boolean fret;
+
+ z = zsysdep_in_dir ("sys", zsystem);
+ fret = fsysdep_directory (z);
+ ubuffree (z);
+ return fret;
+}
diff --git a/gnu/libexec/uucp/libunix/unknwn.c b/gnu/libexec/uucp/libunix/unknwn.c
new file mode 100644
index 000000000000..76f53459475e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/unknwn.c
@@ -0,0 +1,43 @@
+/* unknwn.c
+ Check remote.unknown shell script. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Run the remote.unknown shell script. If it succeeds, we return
+ FALSE because that means that the system is not permitted to log
+ in. If the execution fails, we return TRUE. */
+
+boolean
+fsysdep_unknown_caller (zscript, zsystem)
+ const char *zscript;
+ const char *zsystem;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = zscript;
+ azargs[1] = zsystem;
+ azargs[2] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL, FALSE,
+ TRUE, (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, (const char *) NULL) != 0;
+}
diff --git a/gnu/libexec/uucp/libunix/uuto.c b/gnu/libexec/uucp/libunix/uuto.c
new file mode 100644
index 000000000000..debba9d6fd01
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/uuto.c
@@ -0,0 +1,31 @@
+/* uuto.c
+ Translate a destination for uuto. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Translate a uuto destination for Unix. */
+
+char *
+zsysdep_uuto (zdest, zlocalname)
+ const char *zdest;
+ const char *zlocalname;
+{
+ const char *zexclam;
+ char *zto;
+
+ zexclam = strrchr (zdest, '!');
+ if (zexclam == NULL)
+ return NULL;
+ zto = (char *) zbufalc (zexclam - zdest
+ + sizeof "!~/receive///"
+ + strlen (zexclam)
+ + strlen (zlocalname));
+ memcpy (zto, zdest, (size_t) (zexclam - zdest));
+ sprintf (zto + (zexclam - zdest), "!~/receive/%s/%s/",
+ zexclam + 1, zlocalname);
+ return zto;
+}
diff --git a/gnu/libexec/uucp/libunix/walk.c b/gnu/libexec/uucp/libunix/walk.c
new file mode 100644
index 000000000000..ab96123127dd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/walk.c
@@ -0,0 +1,59 @@
+/* walk.c
+ Walk a directory tree. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int iswalk_dir P((const char *zname, const struct stat *qstat,
+ int iflag));
+
+/* Walk a directory tree. */
+
+static size_t cSlen;
+static void (*puSfn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+static pointer pSinfo;
+
+boolean
+usysdep_walk_tree (zdir, pufn, pinfo)
+ const char *zdir;
+ void (*pufn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+ pointer pinfo;
+{
+ cSlen = strlen (zdir) + 1;
+ puSfn = pufn;
+ pSinfo = pinfo;
+ return ftw ((char *) zdir, iswalk_dir, 5) == 0;
+}
+
+/* Pass a file found in the directory tree to the system independent
+ function. */
+
+/*ARGSUSED*/
+static int
+iswalk_dir (zname, qstat, iflag)
+ const char *zname;
+ const struct stat *qstat;
+ int iflag;
+{
+ char *zcopy;
+
+ if (iflag != FTW_F)
+ return 0;
+
+ zcopy = zbufcpy (zname + cSlen);
+
+ (*puSfn) (zname, zcopy, pSinfo);
+
+ ubuffree (zcopy);
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/wldcrd.c b/gnu/libexec/uucp/libunix/wldcrd.c
new file mode 100644
index 000000000000..cfbd15eb848a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/wldcrd.c
@@ -0,0 +1,212 @@
+/* wldcrd.c
+ Expand wildcards.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_GLOB && ! HAVE_GLOB_H
+#undef HAVE_GLOB
+#define HAVE_GLOB 0
+#endif
+
+#if HAVE_GLOB
+#include <glob.h>
+#endif
+
+/* Local variables to hold the wildcard in progress. */
+
+#if HAVE_GLOB
+static glob_t sSglob;
+static int iSglob;
+#else
+static char *zSwildcard_alloc;
+static char *zSwildcard;
+#endif
+
+/* Start getting a wildcarded file spec. Use the glob function if it
+ is available, and otherwise use the shell. */
+
+boolean
+fsysdep_wildcard_start (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ if (glob (zfile, 0, (int (*) ()) NULL, &sSglob) != 0)
+ sSglob.gl_pathc = 0;
+ iSglob = 0;
+ return TRUE;
+
+#else /* ! HAVE_GLOB */
+
+ char *zcmd, *zto;
+ const char *zfrom;
+ size_t c;
+ const char *azargs[4];
+ FILE *e;
+ pid_t ipid;
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+
+ zcmd = zbufalc (sizeof ECHO_PROGRAM + sizeof " " + 2 * strlen (zfile));
+ memcpy (zcmd, ECHO_PROGRAM, sizeof ECHO_PROGRAM - 1);
+ zto = zcmd + sizeof ECHO_PROGRAM - 1;
+ *zto++ = ' ';
+ zfrom = zfile;
+ while (*zfrom != '\0')
+ {
+ /* To avoid shell trickery, we quote all characters except
+ letters, digits, and wildcard specifiers. We don't quote '/'
+ to avoid an Ultrix sh bug. */
+ if (! isalnum (*zfrom)
+ && *zfrom != '*'
+ && *zfrom != '?'
+ && *zfrom != '['
+ && *zfrom != ']'
+ && *zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom++;
+ }
+ *zto = '\0';
+
+ azargs[0] = "/bin/sh";
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+
+ ubuffree (zcmd);
+
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen: %s", strerror (errno));
+ return FALSE;
+ }
+
+ zSwildcard_alloc = NULL;
+ c = 0;
+ if (getline (&zSwildcard_alloc, &c, e) <= 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ }
+
+ if (ixswait ((unsigned long) ipid, ECHO_PROGRAM) != 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ return FALSE;
+ }
+
+ if (zSwildcard_alloc == NULL)
+ return FALSE;
+
+ DEBUG_MESSAGE1 (DEBUG_EXECUTE,
+ "fsysdep_wildcard_start: got \"%s\"",
+ zSwildcard_alloc);
+
+ zSwildcard = zSwildcard_alloc;
+
+ return TRUE;
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Get the next wildcard spec. */
+
+/*ARGSUSED*/
+char *
+zsysdep_wildcard (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+ char *zret;
+
+ if (iSglob >= sSglob.gl_pathc)
+ return NULL;
+ zret = zbufcpy (sSglob.gl_pathv[iSglob]);
+ ++iSglob;
+ return zret;
+
+#else /* ! HAVE_GLOB */
+
+ char *zret;
+
+ if (zSwildcard_alloc == NULL || zSwildcard == NULL)
+ return NULL;
+
+ zret = zSwildcard;
+
+ while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+
+ if (*zSwildcard != '\0')
+ {
+ *zSwildcard = '\0';
+ ++zSwildcard;
+ while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+ }
+
+ if (*zSwildcard == '\0')
+ zSwildcard = NULL;
+
+ return zbufcpy (zret);
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Finish up getting wildcard specs. */
+
+boolean
+fsysdep_wildcard_end ()
+{
+#if HAVE_GLOB
+ globfree (&sSglob);
+ return TRUE;
+#else /* ! HAVE_GLOB */
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+ return TRUE;
+#endif /* ! HAVE_GLOB */
+}
diff --git a/gnu/libexec/uucp/libunix/work.c b/gnu/libexec/uucp/libunix/work.c
new file mode 100644
index 000000000000..8744347aeb44
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/work.c
@@ -0,0 +1,765 @@
+/* work.c
+ Routines to read command files.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char work_rcsid[] = "$Id: work.c,v 1.1 1993/08/05 18:24:45 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Local functions. */
+
+static char *zswork_directory P((const char *zsystem));
+static boolean fswork_file P((const char *zsystem, const char *zfile,
+ char *pbgrade));
+static int iswork_cmp P((constpointer pkey, constpointer pdatum));
+
+/* These functions can support multiple actions going on at once.
+ This allows the UUCP package to send and receive multiple files at
+ the same time. This is a very flexible feature, but I'm not sure
+ it will actually be used all that much.
+
+ The ssfile structure holds a command file name and all the lines
+ read in from that command file. The union within the ssline
+ structure initially holds a line from the file and then holds a
+ pointer back to the ssfile structure; a pointer to this union is
+ used as a sequence pointer. The ztemp entry of the ssline
+ structure holds the name of a temporary file to delete, if any. */
+
+#define CFILELINES (10)
+
+struct ssline
+{
+ char *zline;
+ struct ssfile *qfile;
+ char *ztemp;
+};
+
+struct ssfile
+{
+ char *zfile;
+ int clines;
+ int cdid;
+ struct ssline aslines[CFILELINES];
+};
+
+/* Static variables for the work scan. */
+
+static char **azSwork_files;
+static size_t cSwork_files;
+static size_t iSwork_file;
+static struct ssfile *qSwork_file;
+
+/* Given a system name, return a directory to search for work. */
+
+static char *
+zswork_directory (zsystem)
+ const char *zsystem;
+{
+#if SPOOLDIR_V2
+ return zbufcpy (".");
+#endif /* SPOOLDIR_V2 */
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ return zbufcpy ("C.");
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ return zbufcpy (zsystem);
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_ULTRIX
+ return zsappend3 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ "C.");
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ return zsysdep_in_dir (zsystem, "C.");
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* See whether a file name from the directory returned by
+ zswork_directory is really a command for a particular system.
+ Return the command grade. */
+
+/*ARGSUSED*/
+static boolean
+fswork_file (zsystem, zfile, pbgrade)
+ const char *zsystem;
+ const char *zfile;
+ char *pbgrade;
+{
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+ int cfilesys, csys;
+
+ /* The file name should be C.ssssssgqqqq, where g is exactly one
+ letter and qqqq is exactly four numbers. The system name may be
+ truncated to six or seven characters. The system name of the
+ file must match the system name we're looking for, since there
+ could be work files for several systems in one directory. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ csys = strlen (zsystem);
+ cfilesys = strlen (zfile) - 7;
+ if (csys != cfilesys
+ && (csys < 6 || (cfilesys != 6 && cfilesys != 7)))
+ return FALSE;
+ *pbgrade = zfile[cfilesys + 2];
+ return strncmp (zfile + 2, zsystem, cfilesys) == 0;
+#endif /* V2 || BSD42 || BSD43 || ULTRIX */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ int clen;
+
+ /* The HDB file name should be C.ssssssgqqqq where g is exactly one
+ letter and qqqq is exactly four numbers or letters. We don't
+ check the system name, because it is guaranteed by the directory
+ we are looking in and some versions of uucp set it to the local
+ system rather than the remote one. I'm not sure of the exact
+ format of the SVR4 file name, but it does not include the grade
+ at all. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ clen = strlen (zfile);
+ if (clen < 7)
+ return FALSE;
+#if ! SPOOLDIR_SVR4
+ *pbgrade = zfile[clen - 5];
+#endif
+ return TRUE;
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_TAYLOR
+ /* We don't keep the system name in the file name, since that
+ forces truncation. Our file names are always C.gqqqq. */
+ *pbgrade = zfile[2];
+ return (zfile[0] == 'C'
+ && zfile[1] == '.'
+ && strlen (zfile) == 7);
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* A comparison function to look through the list of file names. */
+
+static int
+iswork_cmp (pkey, pdatum)
+ constpointer pkey;
+ constpointer pdatum;
+{
+ const char * const *pzkey = (const char * const *) pkey;
+ const char * const *pzdatum = (const char * const *) pdatum;
+
+ return strcmp (*pzkey, *pzdatum);
+}
+
+/* See whether there is any work to do for a particular system. */
+
+boolean
+fsysdep_has_work (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ qdir = opendir ((char *) zdir);
+ if (qdir == NULL)
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0')
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ ubuffree (zsub);
+ if (qdir == NULL)
+ continue;
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bgrade;
+
+ if (fswork_file (qsys->uuconf_zname, qentry->d_name, &bgrade))
+ {
+ closedir (qdir);
+#if SPOOLDIR_SVR4
+ closedir (qgdir);
+#endif
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+ return FALSE;
+}
+
+/* Initialize the work scan. We have to read all the files in the
+ work directory, so that we can sort them by work grade. The bgrade
+ argument is the minimum grade to consider. We don't want to return
+ files that we have already considered; usysdep_get_work_free will
+ clear the data out when we are done with the system. This returns
+ FALSE on error. */
+
+#define CWORKFILES (10)
+
+boolean
+fsysdep_get_work_init (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+ size_t chad;
+ size_t callocated;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+
+ qdir = opendir (zdir);
+ if (qdir == NULL)
+ {
+ boolean fret;
+
+ if (errno == ENOENT)
+ fret = TRUE;
+ else
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (zdir);
+ return fret;
+ }
+
+ chad = cSwork_files;
+ callocated = cSwork_files;
+
+ /* Sort the files we already know about so that we can check the new
+ ones with bsearch. It would be faster to use a hash table, and
+ the code should be probably be changed. The sort done at the end
+ of this function does not suffice because it only includes the
+ files added last time, and does not sort the entire array. Some
+ (bad) qsort implementations are very slow when given a sorted
+ array, which causes particularly bad effects here. */
+ if (chad > 0)
+ qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp);
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0'
+ || UUCONF_GRADE_CMP (bgrade, qgentry->d_name[0]) < 0)
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ if (qdir == NULL)
+ {
+ if (errno != ENOTDIR && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zsub,
+ strerror (errno));
+ ubuffree (zsub);
+ return FALSE;
+ }
+ ubuffree (zsub);
+ continue;
+ }
+ ubuffree (zsub);
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bfilegrade;
+ char *zname;
+
+#if ! SPOOLDIR_SVR4
+ zname = zbufcpy (qentry->d_name);
+#else
+ zname = zsysdep_in_dir (qgentry->d_name, qentry->d_name);
+ bfilegrade = qgentry->d_name[0];
+#endif
+
+ if (! fswork_file (qsys->uuconf_zname, qentry->d_name,
+ &bfilegrade)
+ || UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0
+ || (azSwork_files != NULL
+ && bsearch ((pointer) &zname,
+ (pointer) azSwork_files,
+ chad, sizeof (char *),
+ iswork_cmp) != NULL))
+ ubuffree (zname);
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "fsysdep_get_work_init: Found %s",
+ zname);
+
+ if (cSwork_files >= callocated)
+ {
+ callocated += CWORKFILES;
+ azSwork_files =
+ (char **) xrealloc ((pointer) azSwork_files,
+ callocated * sizeof (char *));
+ }
+
+ azSwork_files[cSwork_files] = zname;
+ ++cSwork_files;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+
+ /* Sorting the files alphabetically will get the grades in the
+ right order, since all the file prefixes are the same. */
+
+ if (cSwork_files > chad)
+ qsort ((pointer) (azSwork_files + chad), cSwork_files - chad,
+ sizeof (char *), iswork_cmp);
+
+ return TRUE;
+}
+
+/* Get the next work entry for a system. This must parse the next
+ line in the next work file. The type of command is set into
+ qcmd->bcmd; if there are no more commands we call
+ fsysdep_get_work_init to rescan, in case any came in since the last
+ call. If there are still no commands, qcmd->bcmd is set to 'H'.
+ Each field in the structure is set to point to a spot in an
+ malloced string. The only time we use the grade here is when
+ calling fsysdep_get_work_init to rescan. */
+
+boolean
+fsysdep_get_work (qsys, bgrade, qcmd)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ struct scmd *qcmd;
+{
+ char *zdir;
+
+ if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines)
+ qSwork_file = NULL;
+
+ if (azSwork_files == NULL)
+ {
+ qcmd->bcmd = 'H';
+ return TRUE;
+ }
+
+ zdir = NULL;
+
+ /* This loop continues until a line is returned. */
+ while (TRUE)
+ {
+ /* This loop continues until a file is opened and read in. */
+ while (qSwork_file == NULL)
+ {
+ FILE *e;
+ struct ssfile *qfile;
+ int iline, callocated;
+ char *zline;
+ size_t cline;
+ char *zname;
+
+ /* Read all the lines of a command file into memory. */
+ do
+ {
+ if (iSwork_file >= cSwork_files)
+ {
+ /* Rescan the work directory. */
+ if (! fsysdep_get_work_init (qsys, bgrade))
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+ if (iSwork_file >= cSwork_files)
+ {
+ qcmd->bcmd = 'H';
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+ if (zdir == NULL)
+ {
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ }
+
+ zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]);
+
+ ++iSwork_file;
+
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname,
+ strerror (errno));
+ ubuffree (zname);
+ }
+ }
+ while (e == NULL);
+
+ qfile = (struct ssfile *) xmalloc (sizeof (struct ssfile));
+ callocated = CFILELINES;
+ iline = 0;
+
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ if (iline >= callocated)
+ {
+ /* The sizeof (struct ssfile) includes CFILELINES
+ entries already, so using callocated * sizeof
+ (struct ssline) will give us callocated *
+ CFILELINES entries. */
+ qfile =
+ ((struct ssfile *)
+ xrealloc ((pointer) qfile,
+ (sizeof (struct ssfile) +
+ (callocated * sizeof (struct ssline)))));
+ callocated += CFILELINES;
+ }
+ qfile->aslines[iline].zline = zbufcpy (zline);
+ qfile->aslines[iline].qfile = NULL;
+ qfile->aslines[iline].ztemp = NULL;
+ iline++;
+ }
+
+ xfree ((pointer) zline);
+
+ if (fclose (e) != 0)
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+
+ if (iline == 0)
+ {
+ /* There were no lines in the file; this is a poll file,
+ for which we return a 'P' command. */
+ qfile->aslines[0].zline = zbufcpy ("P");
+ qfile->aslines[0].qfile = NULL;
+ qfile->aslines[0].ztemp = NULL;
+ iline = 1;
+ }
+
+ qfile->zfile = zname;
+ qfile->clines = iline;
+ qfile->cdid = 0;
+ qSwork_file = qfile;
+ }
+
+ /* This loop continues until all the lines from the current file
+ are used up, or a line is returned. */
+ while (TRUE)
+ {
+ int iline;
+
+ if (qSwork_file->cdid >= qSwork_file->clines)
+ {
+ /* We don't want to free qSwork_file here, since it must
+ remain until all the lines have been completed. It
+ is freed in fsysdep_did_work. */
+ qSwork_file = NULL;
+ /* Go back to the main loop which finds another file. */
+ break;
+ }
+
+ iline = qSwork_file->cdid;
+ ++qSwork_file->cdid;
+
+ /* Now parse the line into a command. */
+ if (! fparse_cmd (qSwork_file->aslines[iline].zline, qcmd))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s",
+ qSwork_file->zfile);
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ continue;
+ }
+
+ qSwork_file->aslines[iline].qfile = qSwork_file;
+ qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]);
+
+ if (qcmd->bcmd == 'S' || qcmd->bcmd == 'E')
+ {
+ char *zreal;
+
+ zreal = zsysdep_spool_file_name (qsys, qcmd->ztemp,
+ qcmd->pseq);
+ if (zreal == NULL)
+ {
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ ubuffree (zdir);
+ return FALSE;
+ }
+ qSwork_file->aslines[iline].ztemp = zreal;
+ }
+
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+}
+
+/* When a command has been complete, fsysdep_did_work is called. The
+ sequence entry was set above to be the address of an aslines
+ structure whose pfile entry points to the ssfile corresponding to
+ this file. We can then check whether all the lines have been
+ completed (they will have been if the pfile entry is NULL) and
+ remove the file if they have been. This means that we only remove
+ a command file if we manage to complete every transfer it specifies
+ in a single UUCP session. I don't know if this is how regular UUCP
+ works. */
+
+boolean
+fsysdep_did_work (pseq)
+ pointer pseq;
+{
+ struct ssfile *qfile;
+ struct ssline *qline;
+ int i;
+
+ qline = (struct ssline *) pseq;
+
+ ubuffree (qline->zline);
+ qline->zline = NULL;
+
+ qfile = qline->qfile;
+ qline->qfile = NULL;
+
+ /* Remove the temporary file, if there is one. It really doesn't
+ matter if this fails, and not checking the return value lets us
+ attempt to remove D.0 or whatever an unused temporary file is
+ called without complaining. */
+ if (qline->ztemp != NULL)
+ {
+ (void) remove (qline->ztemp);
+ ubuffree (qline->ztemp);
+ qline->ztemp = NULL;
+ }
+
+ /* If not all the lines have been returned from fsysdep_get_work,
+ we can't remove the file yet. */
+ if (qfile->cdid < qfile->clines)
+ return TRUE;
+
+ /* See whether all the commands have been completed. */
+ for (i = 0; i < qfile->clines; i++)
+ if (qfile->aslines[i].qfile != NULL)
+ return TRUE;
+
+ /* All commands have finished. */
+ if (remove (qfile->zfile) != 0)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", qfile->zfile,
+ strerror (errno));
+ return FALSE;
+ }
+
+ ubuffree (qfile->zfile);
+ xfree ((pointer) qfile);
+
+ if (qfile == qSwork_file)
+ qSwork_file = NULL;
+
+ return TRUE;
+}
+
+/* Free up the results of a work scan, when we're done with this
+ system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_work_free (qsys)
+ const struct uuconf_system *qsys;
+{
+ if (azSwork_files != NULL)
+ {
+ size_t i;
+
+ for (i = 0; i < cSwork_files; i++)
+ ubuffree ((pointer) azSwork_files[i]);
+ xfree ((pointer) azSwork_files);
+ azSwork_files = NULL;
+ cSwork_files = 0;
+ iSwork_file = 0;
+ }
+ if (qSwork_file != NULL)
+ {
+ int i;
+
+ ubuffree (qSwork_file->zfile);
+ for (i = 0; i < qSwork_file->cdid; i++)
+ {
+ ubuffree (qSwork_file->aslines[i].zline);
+ ubuffree (qSwork_file->aslines[i].ztemp);
+ }
+ for (i = qSwork_file->cdid; i < qSwork_file->clines; i++)
+ ubuffree (qSwork_file->aslines[i].zline);
+ xfree ((pointer) qSwork_file);
+ qSwork_file = NULL;
+ }
+}
+
+/* Save the temporary file used by a send command, and return an
+ informative message to mail to the requestor. This is called when
+ a file transfer failed, to make sure that the potentially valuable
+ file is not completely lost. */
+
+const char *
+zsysdep_save_temp_file (pseq)
+ pointer pseq;
+{
+ struct ssline *qline = (struct ssline *) pseq;
+ char *zto, *zslash;
+ size_t cwant;
+ static char *zbuf;
+ static int cbuf;
+
+ if (! fsysdep_file_exists (qline->ztemp))
+ return NULL;
+
+ zslash = strrchr (qline->ztemp, '/');
+ if (zslash == NULL)
+ zslash = qline->ztemp;
+ else
+ ++zslash;
+
+ zto = zbufalc (sizeof PRESERVEDIR + sizeof "/" + strlen (zslash));
+ sprintf (zto, "%s/%s", PRESERVEDIR, zslash);
+
+ if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE,
+ (const char *) NULL))
+ {
+ ubuffree (zto);
+ return "Could not move file to preservation directory";
+ }
+
+ cwant = sizeof "File saved as\n\t/" + strlen (zSspooldir) + strlen (zto);
+ if (cwant > cbuf)
+ {
+ ubuffree (zbuf);
+ zbuf = zbufalc (cwant);
+ cbuf = cwant;
+ }
+
+ sprintf (zbuf, "File saved as\n\t%s/%s", zSspooldir, zto);
+ ubuffree (zto);
+ return zbuf;
+}
+
+/* Get the jobid of a work file. This is needed by uustat. */
+
+char *
+zsysdep_jobid (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ return zsfile_to_jobid (qsys, ((struct ssline *) pseq)->qfile->zfile,
+ bsgrade (pseq));
+}
+
+/* Get the grade of a work file. The pseq argument can be NULL when
+ this is called from zsysdep_spool_file_name, and simply means that
+ this is a remote file; returning -1 will cause zsfind_file to do
+ the right thing. */
+
+char
+bsgrade (pseq)
+ pointer pseq;
+{
+ const char *zfile;
+ char bgrade;
+
+ if (pseq == NULL)
+ return -1;
+
+ zfile = ((struct ssline *) pseq)->qfile->zfile;
+
+#if ! SPOOLDIR_SVR4
+ bgrade = zfile[strlen (zfile) - CSEQLEN - 1];
+#else
+ bgrade = *(strchr (zfile, '/') + 1);
+#endif
+
+ return bgrade;
+}
diff --git a/gnu/libexec/uucp/libunix/xqtfil.c b/gnu/libexec/uucp/libunix/xqtfil.c
new file mode 100644
index 000000000000..9edb40f23fef
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtfil.c
@@ -0,0 +1,265 @@
+/* xqtfil.c
+ Routines to read execute files.
+
+ 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.1 1993/08/05 18:24:46 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* 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 HDB or SVR4 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 the system.
+
+ This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search
+ directories of directories. */
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42
+#define ZDIR "."
+#define SUBDIRS 0
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+#define ZDIR "."
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_ULTRIX
+#define ZDIR "sys"
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_BSD43
+#define ZDIR "X."
+#define SUBDIRS 0
+#endif
+
+/* Static variables for the execute file scan. */
+
+static DIR *qSxqt_topdir;
+#if ! SUBDIRS
+static const char *zSdir;
+#else /* SUBDIRS */
+static char *zSdir;
+static DIR *qSxqt_dir;
+static char *zSsystem;
+#endif /* SUBDIRS */
+
+/* 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. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_get_xqt_init ()
+{
+ usysdep_get_xqt_free ();
+
+ qSxqt_topdir = opendir ((char *) ZDIR);
+ if (qSxqt_topdir == NULL)
+ {
+ if (errno == ENOENT)
+ return TRUE;
+ ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* 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
+ created. */
+
+char *
+zsysdep_get_xqt (pzsystem, pferr)
+ char **pzsystem;
+ boolean *pferr;
+{
+ *pferr = FALSE;
+
+ if (qSxqt_topdir == NULL)
+ return NULL;
+
+ /* This loop continues until we find a file. */
+ while (TRUE)
+ {
+ DIR *qdir;
+ struct dirent *q;
+
+#if ! SUBDIRS
+ zSdir = ZDIR;
+ qdir = qSxqt_topdir;
+#else /* SUBDIRS */
+ /* This loop continues until we find a subdirectory to read. */
+ while (qSxqt_dir == NULL)
+ {
+ struct dirent *qtop;
+
+ qtop = readdir (qSxqt_topdir);
+ if (qtop == NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ return NULL;
+ }
+
+ /* 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] == '.')
+ continue;
+
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in top directory",
+ qtop->d_name);
+
+ ubuffree (zSdir);
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zSdir = zbufcpy (qtop->d_name);
+#endif
+#if SPOOLDIR_ULTRIX
+ zSdir = zsappend3 ("sys", qtop->d_name, "X.");
+#endif
+#if SPOOLDIR_TAYLOR
+ zSdir = zsysdep_in_dir (qtop->d_name, "X.");
+#endif
+
+ ubuffree (zSsystem);
+ zSsystem = zbufcpy (qtop->d_name);
+
+ qSxqt_dir = opendir (zSdir);
+
+ if (qSxqt_dir == NULL
+ && errno != ENOTDIR
+ && errno != ENOENT)
+ ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno));
+ }
+
+ qdir = qSxqt_dir;
+#endif /* SUBDIRS */
+
+ q = readdir (qdir);
+
+#if DEBUG > 1
+ if (q != NULL)
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in subdirectory %s",
+ q->d_name, zSdir);
+#endif
+
+ /* If we've found an execute file, return it. We have to get
+ the system name, which is easy for HDB 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 (q != NULL
+ && q->d_name[0] == 'X'
+ && q->d_name[1] == '.')
+ {
+ char *zret;
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+ *pzsystem = zbufcpy (zSsystem);
+#else
+ {
+ size_t clen;
+
+ clen = strlen (q->d_name) - 7;
+ *pzsystem = zbufalc (clen + 1);
+ memcpy (*pzsystem, q->d_name + 2, clen);
+ (*pzsystem)[clen] = '\0';
+ }
+#endif
+
+ zret = zsysdep_in_dir (zSdir, q->d_name);
+#if DEBUG > 1
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Returning %s (system %s)",
+ zret, *pzsystem);
+#endif
+ return zret;
+ }
+
+ /* 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. */
+ if (q == NULL)
+ {
+ (void) closedir (qdir);
+#if SUBDIRS
+ qSxqt_dir = NULL;
+ continue;
+#else
+ qSxqt_topdir = NULL;
+ return NULL;
+#endif
+ }
+ }
+}
+
+/* Free up the results of an execute file scan, when we're done with
+ this system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_xqt_free ()
+{
+ if (qSxqt_topdir != NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ }
+#if SUBDIRS
+ if (qSxqt_dir != NULL)
+ {
+ (void) closedir (qSxqt_dir);
+ qSxqt_dir = NULL;
+ }
+ ubuffree (zSdir);
+ zSdir = NULL;
+ ubuffree (zSsystem);
+ zSsystem = NULL;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/xqtsub.c b/gnu/libexec/uucp/libunix/xqtsub.c
new file mode 100644
index 000000000000..87b558b83086
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtsub.c
@@ -0,0 +1,698 @@
+/* xqtsub.c
+ System dependent functions used only 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 1993/08/05 18:24:47 conklin Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Get a value for EX_TEMPFAIL. */
+
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_TEMPFAIL
+#define EX_TEMPFAIL 75
+#endif
+
+/* Get the full pathname of the command to execute, given the list of
+ permitted commands and the allowed path. */
+
+char *
+zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
+ const char *zcmd;
+ char **pzcmds;
+ char **pzpath;
+ boolean *pferr;
+{
+ char **pz;
+
+ *pferr = FALSE;
+
+ for (pz = pzcmds; *pz != NULL; pz++)
+ {
+ char *zslash;
+
+ if (strcmp (*pz, "ALL") == 0)
+ break;
+
+ zslash = strrchr (*pz, '/');
+ if (zslash != NULL)
+ ++zslash;
+ else
+ zslash = *pz;
+ if (strcmp (zslash, zcmd) == 0
+ || strcmp (*pz, zcmd) == 0)
+ {
+ /* If we already have an absolute path, we can get out
+ immediately. */
+ if (**pz == '/')
+ return zbufcpy (*pz);
+ break;
+ }
+ }
+
+ /* If we didn't find this command, get out. */
+ if (*pz == NULL)
+ return NULL;
+
+ /* We didn't find an absolute pathname, so we must look through
+ the path. */
+ for (pz = pzpath; *pz != NULL; pz++)
+ {
+ char *zname;
+ struct stat s;
+
+ zname = zsysdep_in_dir (*pz, zcmd);
+ if (stat (zname, &s) == 0)
+ return zname;
+ }
+
+ *pferr = FALSE;
+ return NULL;
+}
+
+/* Expand a local filename for uuxqt. This is special because uuxqt
+ only wants to expand filenames that start with ~ (it does not want
+ to prepend the current directory to other names) and if the ~ is
+ double, it is turned into a single ~. This returns NULL to
+ indicate that no change was required; it has no way to return
+ error. */
+
+char *
+zsysdep_xqt_local_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ if (*zfile != '~')
+ return NULL;
+ if (zfile[1] == '~')
+ {
+ size_t clen;
+ char *zret;
+
+ clen = strlen (zfile);
+ zret = zbufalc (clen);
+ memcpy (zret, zfile + 1, clen);
+ return zret;
+ }
+ return zsysdep_local_file (zfile, qsys->uuconf_zpubdir);
+}
+
+#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. */
+
+boolean
+fsysdep_xqt_check_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ size_t clen;
+
+ clen = strlen (zfile);
+ if ((clen == sizeof "../" - 1
+ && strcmp (zfile, "../") == 0)
+ || (clen >= sizeof "/.." - 1
+ && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
+ || strstr (zfile, "/../") != NULL
+ || (*zfile == '/'
+ && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL)
+ || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL))))
+ {
+ ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* ! ALLOW_FILENAME_ARGUMENTS */
+
+/* Invoke the command specified by an execute file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
+ fshell, iseq, pzerror, pftemp)
+ const struct uuconf_system *qsys;
+ const char *zuser;
+ const char **pazargs;
+ const char *zfullcmd;
+ const char *zinput;
+ const char *zoutput;
+ boolean fshell;
+ int iseq;
+ char **pzerror;
+ boolean *pftemp;
+{
+ int aidescs[3];
+ boolean ferr;
+ pid_t ipid;
+ int ierr;
+ char abxqtdir[sizeof XQTDIR + 4];
+ const char *zxqtdir;
+ int istat;
+ char *zpath;
+#if ALLOW_SH_EXECUTION
+ const char *azshargs[4];
+#endif
+
+ *pzerror = NULL;
+ *pftemp = FALSE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ferr = FALSE;
+
+ if (zinput != NULL)
+ {
+ aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
+ if (aidescs[0] < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[0], F_SETFD,
+ fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr && zoutput != NULL)
+ {
+ aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
+ if (aidescs[1] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[1], F_SETFD,
+ fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr)
+ {
+ *pzerror = zstemp_file (qsys);
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ if (aidescs[2] < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (*pzerror, FALSE))
+ {
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ }
+ if (! ferr && aidescs[2] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ }
+ if (! ferr
+ && fcntl (aidescs[2], F_SETFD,
+ fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (ferr)
+ {
+ 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]);
+ ubuffree (*pzerror);
+ return FALSE;
+ }
+
+#if ALLOW_SH_EXECUTION
+ if (fshell)
+ {
+ azshargs[0] = "/bin/sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zfullcmd;
+ azshargs[3] = NULL;
+ pazargs = azshargs;
+ }
+#else
+ fshell = FALSE;
+#endif
+
+ if (qsys->uuconf_pzpath == NULL)
+ zpath = NULL;
+ else
+ {
+ size_t c;
+ char **pz;
+
+ c = 0;
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ c += strlen (*pz) + 1;
+ zpath = zbufalc (c);
+ *zpath = '\0';
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ {
+ strcat (zpath, *pz);
+ if (pz[1] != NULL)
+ strcat (zpath, ":");
+ }
+ }
+
+ /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
+ aren't already using the shell. */
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE,
+ ! fshell, zpath, qsys->uuconf_zname, zuser);
+
+ ierr = errno;
+
+ ubuffree (zpath);
+
+ 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]);
+
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
+ *pftemp = TRUE;
+ return FALSE;
+ }
+
+ istat = ixswait ((unsigned long) ipid, "Execution");
+
+ if (istat == EX_TEMPFAIL)
+ *pftemp = TRUE;
+
+ return istat == 0;
+}
+
+/* Lock a uuxqt process. */
+
+int
+ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ int i;
+
+ if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
+ cmaxuuxqts = 9999;
+ for (i = 0; i < cmaxuuxqts; i++)
+ {
+ sprintf (ab, "LCK.XQT.%d", i);
+ if (fsdo_lock (ab, TRUE, (boolean *) NULL))
+ break;
+ }
+ if (i >= cmaxuuxqts)
+ return -1;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
+ {
+ (void) fsdo_unlock (ab, TRUE);
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+/* Unlock a uuxqt process. */
+
+boolean
+fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
+ int iseq;
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ boolean fret;
+
+ fret = TRUE;
+
+ sprintf (ab, "LCK.XQT.%d", iseq);
+ if (! fsdo_unlock (ab, TRUE))
+ fret = FALSE;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_unlock (abcmd, TRUE))
+ fret = FALSE;
+ }
+
+ return fret;
+}
+
+/* See whether a particular uuxqt command is locked (this depends on
+ the implementation of fsdo_lock). */
+
+boolean
+fsysdep_uuxqt_locked (zcmd)
+ const char *zcmd;
+{
+ char ab[sizeof "LXQ.123456789"];
+ struct stat s;
+
+ sprintf (ab, "LXQ.%.9s", zcmd);
+ return stat (ab, &s) == 0;
+}
+
+/* Lock a particular execute file. */
+
+boolean
+fsysdep_lock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Unlock a particular execute file. */
+
+boolean
+fsysdep_unlock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_unlock (zcopy, TRUE);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Lock the execute directory. Since we use a different directory
+ depending on which LCK.XQT.dddd file we got, there is actually no
+ need to create a lock file. We do make sure that the directory
+ exists, though. */
+
+boolean
+fsysdep_lock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (mkdir (zxqtdir, S_IRWXU) < 0
+ && errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Unlock the execute directory and clear it out. The lock is
+ actually the LCK.XQT.dddd file, so we don't unlock it, but we do
+ remove all the files. */
+
+boolean
+fsysdep_unlock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ DIR *qdir;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ qdir = opendir ((char *) zxqtdir);
+ if (qdir != NULL)
+ {
+ struct dirent *qentry;
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *z;
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+ z = zsysdep_in_dir (zxqtdir, qentry->d_name);
+ if (remove (z) < 0)
+ {
+ int ierr;
+
+ ierr = errno;
+ if (! fsysdep_directory (z))
+ ulog (LOG_ERROR, "remove (%s): %s", z,
+ strerror (ierr));
+ else
+ (void) fsysdep_rmdir (z);
+ }
+ ubuffree (z);
+ }
+
+ closedir (qdir);
+ }
+
+ return TRUE;
+}
+
+/* Move files into the execution directory. */
+
+boolean
+fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
+ int cfiles;
+ const char *const *pzfrom;
+ const char *const *pzto;
+ boolean fto;
+ int iseq;
+ char **pzinput;
+{
+ char *zinput;
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ int i;
+
+ if (pzinput == NULL)
+ zinput = NULL;
+ else
+ zinput = *pzinput;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ for (i = 0; i < cfiles; i++)
+ {
+ const char *zfrom, *zto;
+ char *zfree;
+
+ if (pzto[i] == NULL)
+ continue;
+
+ zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
+
+ zfrom = pzfrom[i];
+ zto = zfree;
+
+ if (zinput != NULL && strcmp (zinput, zfrom) == 0)
+ {
+ *pzinput = zbufcpy (zto);
+ zinput = NULL;
+ }
+
+ if (! fto)
+ {
+ const char *ztemp;
+
+ ztemp = zfrom;
+ zfrom = zto;
+ zto = ztemp;
+ (void) chmod (zfrom, IPRIVATE_FILE_MODE);
+ }
+
+ if (rename (zfrom, zto) < 0)
+ {
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to
+ copy the file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
+ strerror (errno));
+ ubuffree (zfree);
+ break;
+ }
+
+ if (! fcopy_file (zfrom, zto, FALSE, FALSE))
+ {
+ ubuffree (zfree);
+ break;
+ }
+ if (remove (zfrom) < 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfrom,
+ strerror (errno));
+ }
+
+ if (fto)
+ (void) chmod (zto, IPUBLIC_FILE_MODE);
+
+ ubuffree (zfree);
+ }
+
+ if (i < cfiles)
+ {
+ if (fto)
+ (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
+ (char **) NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}