summaryrefslogtreecommitdiffstats
path: root/gnu/libexec/uucp/libunix/filnam.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/libexec/uucp/libunix/filnam.c')
-rw-r--r--gnu/libexec/uucp/libunix/filnam.c258
1 files changed, 233 insertions, 25 deletions
diff --git a/gnu/libexec/uucp/libunix/filnam.c b/gnu/libexec/uucp/libunix/filnam.c
index 7dd6626..6f804bb 100644
--- a/gnu/libexec/uucp/libunix/filnam.c
+++ b/gnu/libexec/uucp/libunix/filnam.c
@@ -1,7 +1,7 @@
/* filnam.c
Get names to use for UUCP files.
- Copyright (C) 1991, 1992, 1993 Ian Lance Taylor
+ Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor
This file is part of the Taylor UUCP package.
@@ -17,10 +17,10 @@
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.
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The author of the program may be contacted at ian@airs.com or
- c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
+ c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
*/
#include "uucp.h"
@@ -56,6 +56,23 @@
#define SEEK_SET 0
#endif
+/* We use POSIX style fcntl locks if they are available, unless
+ O_CREAT is not defined. We could use them in the latter case, but
+ the code would have to become more complex to avoid races
+ concerning the use of creat. It is very unlikely that there is any
+ system which does have POSIX style locking but does not have
+ O_CREAT. */
+#if ! HAVE_BROKEN_SETLKW
+#ifdef F_SETLKW
+#ifdef O_CREAT
+#define USE_POSIX_LOCKS 1
+#endif
+#endif
+#endif
+#ifndef USE_POSIX_LOCKS
+#define USE_POSIX_LOCKS 0
+#endif
+
/* External functions. */
#ifndef lseek
extern off_t lseek ();
@@ -83,21 +100,31 @@ fscmd_seq (zsystem, zseq)
const char *zsystem;
char *zseq;
{
- boolean ferr;
+ int cdelay;
char *zfree;
const char *zfile;
int o;
+ boolean flockfile;
int i;
+ boolean fret;
- /* 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);
- }
+ cdelay = 5;
+
+#if ! USE_POSIX_LOCKS
+ {
+ boolean ferr;
+
+ /* Lock the sequence file. */
+ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr))
+ {
+ if (ferr || FGOT_SIGNAL ())
+ return FALSE;
+ sleep (cdelay);
+ if (cdelay < 60)
+ ++cdelay;
+ }
+ }
+#endif
zfree = NULL;
@@ -123,12 +150,12 @@ fscmd_seq (zsystem, zseq)
#endif /* SPOOLDIR_TAYLOR */
#ifdef O_CREAT
- o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE);
+ o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPRIVATE_FILE_MODE);
#else
o = open ((char *) zfile, O_RDWR | O_NOCTTY);
if (o < 0 && errno == ENOENT)
{
- o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ o = creat ((char *) zfile, IPRIVATE_FILE_MODE);
if (o >= 0)
{
(void) close (o);
@@ -143,15 +170,17 @@ fscmd_seq (zsystem, zseq)
{
if (! fsysdep_make_dirs (zfile, FALSE))
{
+#if ! USE_POSIX_LOCKS
(void) fsdo_unlock ("LCK..SEQ", TRUE);
+#endif
return FALSE;
}
#ifdef O_CREAT
o = open ((char *) zfile,
O_RDWR | O_CREAT | O_NOCTTY,
- IPUBLIC_FILE_MODE);
+ IPRIVATE_FILE_MODE);
#else
- o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ o = creat ((char *) zfile, IPRIVATE_FILE_MODE);
if (o >= 0)
{
(void) close (o);
@@ -162,11 +191,79 @@ fscmd_seq (zsystem, zseq)
if (o < 0)
{
ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+#if ! USE_POSIX_LOCKS
(void) fsdo_unlock ("LCK..SEQ", TRUE);
+#endif
return FALSE;
}
}
+#if ! USE_POSIX_LOCKS
+ flockfile = TRUE;
+#else
+ {
+ struct flock slock;
+
+ flockfile = FALSE;
+
+ slock.l_type = F_WRLCK;
+ slock.l_whence = SEEK_SET;
+ slock.l_start = 0;
+ slock.l_len = 0;
+ while (fcntl (o, F_SETLKW, &slock) == -1)
+ {
+ boolean fagain;
+
+ /* Some systems define F_SETLKW, but it does not work. We try
+ to catch those systems at runtime, and revert to using a
+ lock file. */
+ if (errno == EINVAL)
+ {
+ boolean ferr;
+
+ /* Lock the sequence file. */
+ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr))
+ {
+ if (ferr || FGOT_SIGNAL ())
+ {
+ (void) close (o);
+ return FALSE;
+ }
+ sleep (cdelay);
+ if (cdelay < 60)
+ ++cdelay;
+ }
+
+ flockfile = TRUE;
+
+ break;
+ }
+
+ fagain = FALSE;
+ if (errno == ENOMEM)
+ fagain = TRUE;
+#ifdef ENOLCK
+ if (errno == ENOLCK)
+ fagain = TRUE;
+#endif
+#ifdef ENOSPC
+ if (errno == ENOSPC)
+ fagain = TRUE;
+#endif
+ if (fagain)
+ {
+ sleep (cdelay);
+ if (cdelay < 60)
+ ++cdelay;
+ continue;
+ }
+ ulog (LOG_ERROR, "Locking %s: %s", zfile, strerror (errno));
+ (void) close (o);
+ return FALSE;
+ }
+ }
+#endif
+
if (read (o, zseq, CSEQLEN) != CSEQLEN)
strcpy (zseq, "0000");
zseq[CSEQLEN] = '\0';
@@ -199,19 +296,24 @@ fscmd_seq (zsystem, zseq)
}
#endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */
+ fret = TRUE;
+
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));
+ ulog (LOG_ERROR, "lseek or write or close %s: %s",
+ zfile, strerror (errno));
(void) close (o);
- (void) fsdo_unlock ("LCK..SEQ", TRUE);
- return FALSE;
+ fret = FALSE;
}
- (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ if (flockfile)
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+
+ ubuffree (zfree);
- return TRUE;
+ return fret;
}
/* Get the name of a command or data file for a remote system. The
@@ -266,9 +368,9 @@ zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname)
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
+#if SPOOLDIR_SVR4
sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq);
-#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+#else /* ! SPOOLDIR_SVR4 */
#if ! SPOOLDIR_TAYLOR
sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq);
#else /* SPOOLDIR_TAYLOR */
@@ -329,10 +431,41 @@ zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname,
char *zdname;
char *zxname;
{
- return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt,
+ return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt,
ztname, zdname, zxname);
}
+#if SPOOLDIR_TAYLOR
+
+/* Write out a number in base 62 into a given number of characters,
+ right justified with zero fill. This is used by zscmd_file if
+ SPOOLDIR_TAYLOR. */
+
+static void usput62 P((long i, char *, int c));
+
+static void
+usput62 (i, z, c)
+ long i;
+ char *z;
+ int c;
+{
+ for (--c; c >= 0; --c)
+ {
+ int d;
+
+ d = i % 62;
+ i /= 62;
+ if (d < 26)
+ z[c] = 'A' + d;
+ else if (d < 52)
+ z[c] = 'a' + d - 26;
+ else
+ z[c] = '0' + d - 52;
+ }
+}
+
+#endif /* SPOOLDIR_TAYLOR */
+
/* Get a command file name. */
char *
@@ -340,9 +473,84 @@ zscmd_file (qsys, bgrade)
const struct uuconf_system *qsys;
int bgrade;
{
+#if ! SPOOLDIR_TAYLOR
return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL,
bgrade, FALSE, (char *) NULL, (char *) NULL,
(char *) NULL);
+#else
+ char *zname;
+ long isecs, imicros;
+ pid_t ipid;
+
+ /* This file name is never seen by the remote system, so we don't
+ actually need to get a sequence number for it. We just need to
+ get a file name which is unique for this system. We don't try
+ this optimization for other spool directory formats, mainly due
+ to compatibility concerns. It would be possible for HDB and SVR4
+ spool directory formats.
+
+ We get a unique name by combining the process ID and the current
+ time. The file name must start with C.g, where g is the grade.
+ Note that although it is likely that this name will be unique, it
+ is not guaranteed, so the caller must be careful. */
+
+ isecs = ixsysdep_time (&imicros);
+ ipid = getpid ();
+
+ /* We are going to represent the file name as a series of numbers in
+ base 62 (using the alphanumeric characters). The maximum file
+ name length is 14 characters, so we may use 11. We use 3 for the
+ seconds within the day, 3 for the microseconds, and 5 for the
+ process ID. */
+
+ /* Cut the seconds down to a number within a day (maximum value
+ 86399 < 62 ** 3 == 238328). */
+ isecs %= (long) 24 * (long) 60 * (long) 60;
+ /* Divide the microseconds (max 999999) by 5 to make sure they are
+ less than 62 ** 3. */
+ imicros %= 1000000;
+ imicros /= 5;
+
+ while (TRUE)
+ {
+ char ab[15];
+
+ ab[0] = 'C';
+ ab[1] = '.';
+ ab[2] = bgrade;
+ usput62 (isecs, ab + 3, 3);
+ usput62 (imicros, ab + 6, 3);
+ usput62 ((long) ipid, ab + 9, 5);
+ ab[14] = '\0';
+
+ zname = zsfind_file (ab, qsys->uuconf_zname, bgrade);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+
+ /* We hit a duplicate. Move backward in time until we find an
+ available name. Note that there is still a theoretical race
+ condition, since 5 base 62 digits might not be enough for the
+ process ID, and some other process might be running these
+ checks at the same time as we are. The caller must deal with
+ this. */
+ if (imicros == 0)
+ {
+ imicros = (long) 62 * (long) 62 * (long) 62;
+ if (isecs == 0)
+ isecs = (long) 62 * (long) 62 * (long) 62;
+ --isecs;
+ }
+ --imicros;
+ }
+
+ return zname;
+
+#endif
}
/* Return a name for an execute file to be created locally. This is
OpenPOWER on IntegriCloud