diff options
Diffstat (limited to 'gnu/libexec/uucp/libunix/filnam.c')
-rw-r--r-- | gnu/libexec/uucp/libunix/filnam.c | 258 |
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 |