diff --git a/src/include/paths.h b/src/include/paths.h index 6ba951ab..a63c9c5c 100644 --- a/src/include/paths.h +++ b/src/include/paths.h @@ -1,4 +1,4 @@ -/* $OpenBSD: paths.h,v 1.9 1997/08/29 18:05:38 mickey Exp $ */ +/* $OpenBSD: paths.h,v 1.10 1997/11/09 00:29:02 bri Exp $ */ /* $NetBSD: paths.h,v 1.7 1994/10/26 00:56:12 cgd Exp $ */ /* @@ -71,6 +71,7 @@ #define _PATH_BOOTDIR "/usr/mdec/" #define _PATH_DEV "/dev/" #define _PATH_TMP "/tmp/" +#define _PATH_UUCPLOCK "/var/spool/lock/" #define _PATH_VARDB "/var/db/" #define _PATH_VARRUN "/var/run/" #define _PATH_VARTMP "/var/tmp/" diff --git a/src/lib/libutil/Makefile b/src/lib/libutil/Makefile index 4f6c215b..ca526ded 100644 --- a/src/lib/libutil/Makefile +++ b/src/lib/libutil/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.14 1997/06/17 10:10:41 niklas Exp $ +# $OpenBSD: Makefile,v 1.15 1997/11/09 00:29:13 bri Exp $ # $NetBSD: Makefile,v 1.8 1996/05/16 07:03:28 thorpej Exp $ LIB= util @@ -6,11 +6,12 @@ CFLAGS+=-DLIBC_SCCS HDRS= util.h scsi.h SRCS= getmaxpartitions.c getrawpartition.c login.c login_tty.c logout.c \ - logwtmp.c opendev.c passwd.c pty.c readlabel.c scsi.c login_fbtab.c + logwtmp.c opendev.c passwd.c pty.c readlabel.c scsi.c login_fbtab.c \ + uucplock.c # XXX need login_fbtab.3 MAN= getmaxpartitions.3 getrawpartition.3 login.3 opendev.3 openpty.3 \ - pw_init.3 pw_lock.3 readlabelfs.3 scsi.3 pw_getconf.3 + pw_init.3 pw_lock.3 readlabelfs.3 scsi.3 pw_getconf.3 uucplock.3 MLINKS+=login.3 logout.3 MLINKS+=login.3 logwtmp.3 @@ -36,6 +37,9 @@ MLINKS+=scsi.3 SCSIREQ_ERROR.3 MLINKS+=scsi.3 scsi_open.3 MLINKS+=scsi.3 scsi_debug.3 MLINKS+=scsi.3 scsi_debug_output.3 +MLINKS+=uucplock.3 uu_lock.3 +MLINKS+=uucplock.3 uu_unlock.3 +MLINKS+=uucplock.3 uu_lockerr.3 includes: @cd ${.CURDIR}; for i in $(HDRS); do \ diff --git a/src/lib/libutil/shlib_version b/src/lib/libutil/shlib_version index d9961ea9..890c5738 100644 --- a/src/lib/libutil/shlib_version +++ b/src/lib/libutil/shlib_version @@ -1,2 +1,2 @@ major=4 -minor=0 +minor=1 diff --git a/src/lib/libutil/util.h b/src/lib/libutil/util.h index acadd530..9fd98e23 100644 --- a/src/lib/libutil/util.h +++ b/src/lib/libutil/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.6 1997/06/17 10:10:43 niklas Exp $ */ +/* $OpenBSD: util.h,v 1.7 1997/11/09 00:29:14 bri Exp $ */ /* $NetBSD: util.h,v 1.2 1996/05/16 07:00:22 thorpej Exp $ */ /*- @@ -76,6 +76,18 @@ int getmaxpartitions __P((void)); int getrawpartition __P((void)); void login_fbtab __P((char *, uid_t, gid_t)); char *readlabelfs __P((char *, int)); +const char *uu_lockerr __P((int _uu_lockresult)); +int uu_lock __P((const char *_ttyname)); +int uu_unlock __P((const char *_ttyname)); __END_DECLS +#define UU_LOCK_INUSE (1) +#define UU_LOCK_OK (0) +#define UU_LOCK_OPEN_ERR (-1) +#define UU_LOCK_READ_ERR (-2) +#define UU_LOCK_CREAT_ERR (-3) +#define UU_LOCK_WRITE_ERR (-4) +#define UU_LOCK_LINK_ERR (-5) +#define UU_LOCK_TRY_ERR (-6) + #endif /* !_UTIL_H_ */ diff --git a/src/lib/libutil/uucplock.3 b/src/lib/libutil/uucplock.3 new file mode 100644 index 00000000..40eeab60 --- /dev/null +++ b/src/lib/libutil/uucplock.3 @@ -0,0 +1,160 @@ +.\" +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $Id: uucplock.3,v 1.1 1997/11/09 00:29:14 bri Exp $ +.\" " +.Dd March 30, 1997 +.Os +.Dt uucplock 3 +.Sh NAME +.Nm uu_lock , +.Nm uu_unlock , +.Nm uu_lockerr +.Nd acquire and release control of a serial device +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn uu_lock "const char *ttyname" +.Ft int +.Fn uu_unlock "const char *ttyname" +.Ft const char * +.Fn uu_lockerr "int uu_lockresult" +.Pp +Link with +.Va -lutil +on the +.Xr cc 1 +command line. +.Sh DESCRIPTION +The +.Fn uu_lock +function attempts to create a lock file called +.Pa /var/spool/lock/LCK.. +with a suffix given by the passed +.Fa ttyname . +If the file already exists, it is expected to contain the process +id of the locking program. +.Pp +If the file does not already exist, or the owning process given by +the process id found in the lock file is no longer running, +.Fn uu_lock +will write its own process id into the file and return success. +.Pp +.Fn uu_unlock +removes the lockfile created by +.Fn uu_lock +for the given +.Fa ttyname . +Care should be taken that +.Fn uu_lock +was successful before calling +.Fn uu_unlock . +.Pp +.Fn uu_lockerr +returns an error string representing the error +.Fa uu_lockresult , +as returned from +.Fn uu_lock . +.Sh RETURN VALUES +.Fn uu_unlock +returns 0 on success and -1 on failure. +.Pp +.Fn uu_lock +may return any of the following values: +.Pp +.Dv UU_LOCK_INUSE: +The lock is in use by another process. +.Pp +.Dv UU_LOCK_OK: +The lock was successfully created. +.Pp +.Dv UU_LOCK_OPEN_ERR: +The lock file could not be opened via +.Xr open 2 . +.Pp +.Dv UU_LOCK_READ_ERR: +The lock file could not be read via +.Xr read 2 . +.Pp +.Dv UU_LOCK_CREAT_ERR: +Can't create temporary lock file via +.Xr creat 2 . +.Pp +.Dv UU_LOCK_WRITE_ERR: +The current process id could not be written to the lock file via a call to +.Xr write 2 . +.Pp +.Dv UU_LOCK_LINK_ERR: +Can't link temporary lock file via +.Xr link 2 . +.Pp +.Dv UU_LOCK_TRY_ERR: +Locking attempts are failed after 5 tries. +.Pp +If a value of +.Dv UU_LOCK_OK +is passed to +.Fn uu_lockerr , +an empty string is returned. +Otherwise, a string specifying +the reason for failure is returned. +.Fn uu_lockerr +uses the current value of +.Va errno +to determine the exact error. Care should be made not to allow +.Va errno +to be changed between calls to +.Fn uu_lock +and +.Fn uu_lockerr . +.Sh ERRORS +If +.Fn uu_lock +returns one of the four error values above, the global value +.Va errno +can be used to determine the cause. Refer to the respective manual pages +for further details. +.Pp +.Fn uu_unlock +will set the global variable +.Va errno +to reflect the reason that the lock file could not be removed. +Refer to the description of +.Xr unlink 2 +for further details. +.Sh SEE ALSO +.Xr lseek 2 , +.Xr open 2 , +.Xr read 2 , +.Xr write 2 +.Sh BUGS +It is possible that a stale lock is not recognised as such if a new +processes is assigned the same processes id as the program that left +the stale lock. +.Pp +The calling process must have write permissions to the +.Pa /var/spool/lock +directory. There is no mechanism in place to ensure that the +permissions of this directory are the same as those of the +serial devices that might be locked. diff --git a/src/lib/libutil/uucplock.c b/src/lib/libutil/uucplock.c new file mode 100644 index 00000000..5f879df8 --- /dev/null +++ b/src/lib/libutil/uucplock.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: uucplock.c,v 1.1 1997/11/09 00:29:15 bri Exp $ + * + */ + +#ifndef lint +static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +#define MAXTRIES 5 + +#define LOCKTMP "LCKTMP..%d" +#define LOCKFMT "LCK..%s" + +#define GORET(level, val) { err = errno; uuerr = (val); \ + goto __CONCAT(ret, level); } + +/* Forward declarations */ +static int put_pid __P((int fd, pid_t pid)); +static pid_t get_pid __P((int fd,int *err)); + +/* + * uucp style locking routines + */ + +int +uu_lock(ttyname) + const char *ttyname; +{ + int fd, tmpfd, i; + pid_t pid; + char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], + lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + int err, uuerr; + + pid = getpid(); + (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, + pid); + (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, + ttyname); + if ((tmpfd = creat(lcktmpname, 0664)) < 0) + GORET(0, UU_LOCK_CREAT_ERR); + + for (i = 0; i < MAXTRIES; i++) { + if (link (lcktmpname, lckname) < 0) { + if (errno != EEXIST) + GORET(1, UU_LOCK_LINK_ERR); + /* + * file is already locked + * check to see if the process holding the lock + * still exists + */ + if ((fd = open(lckname, O_RDONLY)) < 0) + GORET(1, UU_LOCK_OPEN_ERR); + + if ((pid = get_pid (fd, &err)) == -1) + GORET(2, UU_LOCK_READ_ERR); + + close(fd); + + if (kill(pid, 0) == 0 || errno != ESRCH) + GORET(1, UU_LOCK_INUSE); + /* + * The process that locked the file isn't running, so + * we'll lock it ourselves + */ + (void)unlink(lckname); + } else { + if (!put_pid (tmpfd, pid)) + GORET(3, UU_LOCK_WRITE_ERR); + break; + } + } + GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); + +ret3: + (void)unlink(lckname); + goto ret1; +ret2: + (void)close(fd); +ret1: + (void)close(tmpfd); + (void)unlink(lcktmpname); +ret0: + errno = err; + return uuerr; +} + +int +uu_unlock(ttyname) + const char *ttyname; +{ + char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; + + (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); + return unlink(tbuf); +} + +const char * +uu_lockerr(uu_lockresult) + int uu_lockresult; +{ + static char errbuf[128]; + char *fmt; + + switch (uu_lockresult) { + case UU_LOCK_INUSE: + return "device in use"; + case UU_LOCK_OK: + return ""; + case UU_LOCK_OPEN_ERR: + fmt = "open error: %s"; + break; + case UU_LOCK_READ_ERR: + fmt = "read error: %s"; + break; + case UU_LOCK_CREAT_ERR: + fmt = "creat error: %s"; + break; + case UU_LOCK_WRITE_ERR: + fmt = "write error: %s"; + break; + case UU_LOCK_LINK_ERR: + fmt = "link error: %s"; + break; + case UU_LOCK_TRY_ERR: + fmt = "too many tries: %s"; + break; + default: + fmt = "undefined error: %s"; + break; + } + + (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno)); + return errbuf; +} + +static int +put_pid(fd, pid) + int fd; + pid_t pid; +{ + char buf[32]; + int len; + + len = sprintf (buf, "%10d\n", pid); + return write (fd, buf, len) == len && ftruncate(fd, len); +} + +static pid_t +get_pid(fd, err) + int fd; + int *err; +{ + int bytes_read; + char buf[32]; + pid_t pid; + + bytes_read = read (fd, buf, sizeof (buf) - 1); + if (bytes_read > 0) { + buf[bytes_read] = '\0'; + pid = strtoul (buf, (char **) NULL, 10); + } else { + pid = -1; + *err = bytes_read ? errno : EINVAL; + } + return pid; +}