diff -Naur conserver-8.1.9/configure.in conserver-8.1.9-p/configure.in --- conserver-8.1.9/configure.in Sun May 30 18:50:32 2004 +++ conserver-8.1.9-p/configure.in Fri Aug 6 23:23:02 2004 @@ -16,6 +16,7 @@ AH_TEMPLATE([HAVE_OPENSSL], [have openssl support]) AH_TEMPLATE([HAVE_DMALLOC], [have dmalloc support]) AH_TEMPLATE([HAVE_SA_LEN],[Defined if sa_len member exists in struct sockaddr]) +AH_TEMPLATE([HAVE_MKSTEMP],[have mkstemp]) AH_TEMPLATE([TRUST_REVERSE_DNS],[Defined if we trust reverse DNS]) AH_TEMPLATE([USE_EXTENDED_MESSAGES],[Defined if we produce extended messages]) AH_TEMPLATE([USE_UNIX_DOMAIN_SOCKETS],[Defined if we use Unix domain sockets]) @@ -359,7 +360,13 @@ [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SA_LEN)], [AC_MSG_RESULT(no)]) - +AC_MSG_CHECKING(for mkstemp) +AC_TRY_COMPILE([#include ], + [mkstemp("/tmp/XXXXXX");], + [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_MKSTEMP)], + [AC_MSG_RESULT(no)]) + dnl ### Host specific checks. ###################################### AC_CANONICAL_HOST diff -Naur conserver-8.1.9/conserver/Makefile.in conserver-8.1.9-p/conserver/Makefile.in --- conserver-8.1.9/conserver/Makefile.in Tue Feb 10 01:32:28 2004 +++ conserver-8.1.9-p/conserver/Makefile.in Fri Aug 6 22:11:26 2004 @@ -28,11 +28,11 @@ ### Makefile rules - no user-servicable parts below CONSERVER_OBJS = access.o client.o consent.o group.o main.o master.o \ - readcfg.o fallback.o cutil.o + readcfg.o fallback.o cutil.o locks.o CONSERVER_HDRS = ../config.h $(top_srcdir)/compat.h $(srcdir)/access.h \ $(srcdir)/client.h $(srcdir)/consent.h $(srcdir)/cutil.h \ $(srcdir)/group.h $(srcdir)/main.h $(srcdir)/master.h \ - $(srcdir)/readcfg.h $(srcdir)/version.h + $(srcdir)/readcfg.h $(srcdir)/version.h $(srcdir)/locks.h ALL = conserver convert diff -Naur conserver-8.1.9/conserver/consent.c conserver-8.1.9-p/conserver/consent.c --- conserver-8.1.9/conserver/consent.c Thu Jun 3 23:53:59 2004 +++ conserver-8.1.9-p/conserver/consent.c Sat Aug 7 00:20:34 2004 @@ -49,7 +49,7 @@ #include #include #include - +#include BAUD baud[] = { #if defined(B115200) @@ -655,6 +655,9 @@ close(pCE->execSlaveFD); pCE->execSlaveFD = 0; } + if (pCE->type == DEVICE && pCE->lock == FLAGTRUE) { + rmlocks(pCE->device); + } pCE->fup = 0; pCE->nolog = 0; pCE->autoReUp = 0; @@ -854,6 +857,21 @@ } break; case DEVICE: + if (pCE->lock == FLAGTRUE) { + if (checklock(pCE->device) != NO_LOCK) { + Error("[%s] checklock(%s): device already locked", + pCE->server, pCE->device); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + if (makelock(pCE->device) == FAIL) { + Error("[%s] makelock(%s): could not lock device", + pCE->server, pCE->device); + ConsDown(pCE, FLAGTRUE, FLAGTRUE); + return; + } + /* now we have the lock */ + } if (-1 == (cofile = open(pCE->device, O_RDWR | O_NONBLOCK, 0600))) { diff -Naur conserver-8.1.9/conserver/consent.h conserver-8.1.9-p/conserver/consent.h --- conserver-8.1.9/conserver/consent.h Wed Jun 2 01:45:47 2004 +++ conserver-8.1.9-p/conserver/consent.h Fri Aug 6 22:41:11 2004 @@ -123,6 +123,7 @@ FLAG striphigh; /* strip high-bit of console data */ FLAG autoreinit; /* auto-reinitialize if failed */ FLAG unloved; /* copy "unloved" data to stdout */ + FLAG lock; /* lock the device */ /*** runtime settings ***/ CONSFILE *fdlog; /* the local log file */ diff -Naur conserver-8.1.9/conserver/locks.c conserver-8.1.9-p/conserver/locks.c --- conserver-8.1.9/conserver/locks.c Thu Jan 1 01:00:00 1970 +++ conserver-8.1.9-p/conserver/locks.c Sat Aug 7 00:21:23 2004 @@ -0,0 +1,435 @@ +#ident "$Id$ Copyright (c) Gert Doering / Paul Sutcliffe Jr." + +/* large parts of the code in this module are taken from the + * "getty kit 2.0" by Paul Sutcliffe, Jr., paul@devon.lns.pa.us, + * and are used with permission here. + * SVR4 style locking by Bodo Bauer, bodo@hal.nbg.sub.org. + */ +/* adopted from mgetty 1.1.30 for conserver + * by Sebastian Zagrodzki, s.zagrodzki@net.icm.edu.pl */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* some OSes do include this in stdio.h, others don't... */ +#ifndef EEXIST +#include +#endif + +/* SVR4 uses a different locking mechanism. This is why we need this... */ +#ifdef SVR4 +#include + +#define LCK_NODEV -1 +#define LCK_OPNFAIL -2 +#endif + +#include "locks.h" + +int add_lock_to_list(char *device) +{ + s_ldev *temp_ldev, *ldev, *p_ldev = NULL; + + Debug(2, "add_lock: %s", device); + for (ldev = locked_devices; ldev && strcmp(ldev->name, device); + p_ldev = ldev, ldev = ldev->next); + + if (ldev) { /* we had it already */ + Msg("add_lock: That lock was already on my list"); + return(SUCCESS); + } + + if (!(temp_ldev = (s_ldev *) malloc(sizeof(s_ldev)))) + OutOfMem(); + + if (!(temp_ldev->name = (char *) malloc(strlen(device)+1))) + OutOfMem(); + + strcpy(temp_ldev->name, device); + temp_ldev->next = NULL; + if (p_ldev) + p_ldev->next = temp_ldev; + else + locked_devices = temp_ldev; + return(SUCCESS); +} + +int remove_lock_from_list(char *device) +{ + s_ldev *ldev, *p_ldev = NULL; + + Debug(2, "remove_lock: %s", device); + for (ldev = locked_devices; ldev && strcmp(ldev->name, device); + p_ldev = ldev, ldev = ldev->next); + if (!ldev) { + Msg("remove_lock: That lock wasn't on my list"); + return(SUCCESS); + } + free(ldev->name); + if (p_ldev) + p_ldev->next = ldev->next; + else + locked_devices = ldev->next; + free(ldev); + return(SUCCESS); +} + +int lock_is_on_list(char *device) +{ + s_ldev *ldev; + for (ldev = locked_devices; ldev && strcmp(ldev->name, device); + ldev = ldev->next); + if (!ldev) { + Debug(2, "lock_is_on_list: not found: %s", device); + return(FALSE); + } else { + Debug(2, "lock_is_on_list: FOUND: %s", device); + return(TRUE); + } +} + + +/* + * makelock() - attempt to create a lockfile + * + * Returns FAIL if lock could not be made (line in use). + */ + +int makelock(char *device) +{ + int fd, pid; + char *temp, buf[MAXLINE+1]; + int tries = 0; + char lock[MAXLINE+1]; + + s_ldev *ldev, *temp_ldev; + Debug(2, "makelock: %s", device); + for (ldev = locked_devices; ldev; ldev = ldev->next) { + if (!strcmp(device, locked_devices->name)) { + Msg("We already had a lock"); + return (SUCCESS); + } + } + + if (get_lock_name(lock, device) == NULL) { + Error("Cannot get lock filename"); + return (FAIL); + } + Debug(2, "makelock: lock='%s'", lock); + + /* first make a temp file */ + +#ifdef HAVE_MKSTEMP + /* secure, but not as portable */ + temp=buf; + sprintf(buf, LOCK, "TM.XXXXXX"); + if ((fd = mkstemp(temp)) == FAIL ) { + Error("cannot create tempfile (%s)", temp); + return(FAIL); + } +#else + /* portable, but subject to some problems on some platforms */ +again: + sprintf(buf, LOCK, "TM.XXXXXX"); + temp = mktemp(buf); + unlink(temp); + if ((fd = open(temp, O_CREAT|O_WRONLY|O_EXCL, 0644)) == FAIL) { + Error("cannot create tempfile (%s)", temp); + if ( errno == EEXIST && ++tries < 20 ) goto again; + return(FAIL); + } +#endif + + /* just in case some "umask" is set (errors are ignored) */ + chmod( temp, 0644 ); + + /* put my pid in it */ + if ( lock_write_pid( fd ) == FAIL) + { unlink(temp); return FAIL; } + + /* link it to the lock file */ + + while (link(temp, lock) == FAIL) + { + if (errno != EEXIST ) + { + Error("lock not made: link(temp,lock) failed" ); + } + + if (errno == EEXIST) /* lock file already there */ + { + if ((pid = readlock(lock)) == FAIL) + { + if ( errno == ENOENT ) /* disappeared */ + continue; + else + { + Debug(2, "cannot read lockfile" ); + unlink(temp); + return FAIL; + } + } + + if (pid == getpid()) /* huh? WE locked the line!*/ + { + Msg("we *have* the line!" ); + break; + } + + if ((kill(pid, 0) == FAIL) && errno == ESRCH) + { + /* pid that created lockfile is gone */ + Debug(2, "stale lockfile, created by process %d, ignoring", pid ); + if ( unlink(lock) < 0 && + errno != EINTR && errno != ENOENT ) + { + Error("unlink() failed, giving up" ); + unlink(temp); + return FAIL; + } + continue; + } + + Msg("lock not made: lock file exists (pid=%d)", pid); + } /* if (errno == EEXIST) */ + + (void) unlink(temp); + return(FAIL); + } + + Debug(2, "lock made"); + (void) unlink(temp); + + Msg("Locking device"); + add_lock_to_list(device); + return(SUCCESS); +} + +/* + * checklock() - test for presence of valid lock file + * + * if lockfile found, return PID of process holding it, 0 otherwise + */ + +int checklock (char *device) +{ + int pid; + struct stat st; + char name[MAXLINE+1]; + + if ( get_lock_name( name, device ) == NULL ) + { + Error("cannot get lock name" ); + return NO_LOCK; + } + + if ((stat(name, &st) == FAIL) && errno == ENOENT) + { + Debug(2, "checklock: stat failed, no file"); + return NO_LOCK; + } + + if ((pid = readlock(name)) == FAIL) + { + Msg("checklock: couldn't read lockfile"); + return NO_LOCK; + } + + if (pid == getpid()) + { + Msg("huh? It's *our* lock file!" ); + return NO_LOCK; + } + + if ((kill(pid, 0) == FAIL) && errno == ESRCH) + { + Debug(2, "checklock: no active process has lock, will remove"); + (void) unlink(name); + return NO_LOCK; + } + + Debug(2, "lockfile found, pid=%d", pid ); + + return pid; +} + +/* + * readlock() - read contents of lockfile + * + * Returns pid read or FAIL on error. + * + * private function + */ + +int readlock (char *name) +{ + int fd, pid; + char apid[20]; + int length; + + if ((fd = open(name, O_RDONLY)) == FAIL) + return(FAIL); + + length = read(fd, apid, sizeof(apid)-1); + apid[length]=0; /* make sscanf() happy */ + + pid = 0; + if ( length == sizeof( pid ) || sscanf(apid, "%d", &pid) != 1 || + pid == 0 ) + { + pid = * ( (int *) apid ); +#if LOCKS_BINARY == 0 + Msg("compiled with ascii locks, found binary lock file (length=%d, pid=%d)!", length, pid ); +#endif + } +#if LOCKS_BINARY == 1 + else + { + Msg("compiled with binary locks, found ascii lock file (length=%d, pid=%d)!", length, pid ); + } +#endif + + (void) close(fd); + return(pid); +} + +/* lock_write_pid() + * + * write contents of lock file: my process ID in specified format + * + * private function + */ +int lock_write_pid (int fd) +{ +#if LOCKS_BINARY + int bpid; /* must be 4 bytes wide! */ + bpid = getpid(); + if ( write(fd, &bpid, sizeof(bpid) ) != sizeof(bpid) ) +#else + char apid[16]; + sprintf( apid, "%10d\n", (int) getpid() ); + if ( write(fd, apid, strlen(apid)) != strlen(apid) ) +#endif + { + Error("cannot write PID to (temp) lock file" ); + close(fd); + return(FAIL); + } + close(fd); + return SUCCESS; +} + +/* + * rmlocks() - remove lockfile + * signal handler + */ + +void rmlocks(char *device) +{ + char lock[MAXLINE + 1]; + Debug(2, "rmlocks: %s", device); + get_lock_name(lock, device); + Debug(2, "rmlocks: lock: %s", lock); + if (lock_is_on_list(device)) + { + Msg("Removing lock file" ); + if (unlink(lock) == -1 ) + Error("error removing lock file (huh?!)" ); + /* mark lock file as 'not set' */ + remove_lock_from_list(device); + } +} + +/* get_lock_name() + * + * determine full path + name of the lock file for a given device + */ + +#ifdef SVR4 + +/* + * get_lock_name() - create SVR4 lock file name (Bodo Bauer) + */ + +char *get_lock_name (char* lock, char* fax_tty) +{ + struct stat tbuf; + char ttyname[FILENAME_MAX]; + + Debug(2, "get_lock_name(%s) called", fax_tty); + + if ( strncmp( fax_tty, "/dev/", 5 ) == 0 ) + strcpy( ttyname, fax_tty ); + else + sprintf(ttyname, "/dev/%s", fax_tty); + + Debug(2, "-> ttyname %s", ttyname); + + if (stat(ttyname, &tbuf) < 0) { + if(errno == ENOENT) { + Debug(2, "device does not exist: %s", ttyname); + return(NULL); + } else { + Debug(2, "could not access line: %s", ttyname); + return(NULL); + } + } + + sprintf(lock,"%s/LK.%03u.%03u.%03u", + LOCK_PATH, + major(tbuf.st_dev), + tbuf.st_rdev >> 18, + minor(tbuf.st_rdev)); + + Debug(2, "lock file: %s", lock); + return(lock); +} + +#else /* not SVR4 */ + +char * get_lock_name (char * lock_name, char * device) +{ +#ifdef LOCKS_LOWERCASE + /* sco locking convention -> change all device names to lowercase */ + + char p[MAXLINE+1]; + int i; + if ( ( i = strlen( device ) ) > sizeof(p) ) + { + Error("get_lock_name: device name too long" ); + exit(5); + } + +#ifdef LOCKS_ALL_LOWERCASE + /* convert the full name */ + while ( i >= 0 ) + { + p[i] = tolower( device[i] ); i--; + } +#else + /* convert only the last character */ + strcpy( p, device ); + i--; + p[i] = tolower( p[i] ); +#endif + + device = p; +#endif /* LOCKS_LOWERCASE */ + + /* throw out all directory prefixes */ + if ( strchr( device, '/' ) != NULL ) + device = strrchr( device, '/' ) +1; + + sprintf( lock_name, LOCK, device); + + return lock_name; +} + +#endif /* !SVR4 */ diff -Naur conserver-8.1.9/conserver/locks.h conserver-8.1.9-p/conserver/locks.h --- conserver-8.1.9/conserver/locks.h Thu Jan 1 01:00:00 1970 +++ conserver-8.1.9-p/conserver/locks.h Fri Aug 6 23:12:48 2004 @@ -0,0 +1,30 @@ +#ifndef _locks_h +#define LOCK "/var/lock/LCK..%s" +#define MAXLINE 1024 +#define FALSE (1==0) +#define TRUE (1==1) +#define SUCCESS 0 +#define FAIL -1 +#define NO_LOCK 0 +typedef void RETSIGTYPE; + +int makelock (char *device); +// int makelock_file ( char * lockname ); +int checklock (char *device); +RETSIGTYPE rmlocks (); +// int steal_lock (char * device, int pid ); + + +typedef struct _s_ldev { + char *name; + struct _s_ldev *next; +} s_ldev; + +static s_ldev *locked_devices = NULL; + +int readlock (char *name); +int makelock (char *name); +char *get_lock_name (char *lock_name, char *device); +int lock_write_pid (int fd); + +#endif diff -Naur conserver-8.1.9/conserver/main.c conserver-8.1.9-p/conserver/main.c --- conserver-8.1.9/conserver/main.c Wed Jul 14 07:28:42 2004 +++ conserver-8.1.9-p/conserver/main.c Fri Aug 6 22:38:37 2004 @@ -952,6 +952,9 @@ "DumpDataStructures(): motd=%s, idletimeout=%d, idlestring=%s", EMPTYSTR(pCE->motd), pCE->idletimeout, EMPTYSTR(pCE->idlestring))); + CONDDEBUG((1, + "DumpDataStructures(): lock=%s", + FLAGSTR(pCE->lock))); if (pCE->ro) { CONSENTUSERS *u; for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) { diff -Naur conserver-8.1.9/conserver/readcfg.c conserver-8.1.9-p/conserver/readcfg.c --- conserver-8.1.9/conserver/readcfg.c Wed Jul 14 07:28:42 2004 +++ conserver-8.1.9-p/conserver/readcfg.c Fri Aug 6 22:42:11 2004 @@ -1401,6 +1401,7 @@ c->reinitoncc = FLAGUNKNOWN; c->autoreinit = FLAGUNKNOWN; c->unloved = FLAGUNKNOWN; + c->lock = FLAGUNKNOWN; return; } @@ -1436,6 +1437,8 @@ c->autoreinit = negative ? FLAGFALSE : FLAGTRUE; else if (strcasecmp("unloved", token) == 0) c->unloved = negative ? FLAGFALSE : FLAGTRUE; + else if (strcasecmp("lock", token) == 0) + c->lock = negative ? FLAGFALSE : FLAGTRUE; else if (isMaster) Error("invalid option `%s' [%s:%d]", token, file, line); } @@ -2711,6 +2714,7 @@ pCEmatch->reinitoncc = c->reinitoncc; pCEmatch->autoreinit = c->autoreinit; pCEmatch->unloved = c->unloved; + pCEmatch->lock = c->lock; pCEmatch->inituid = c->inituid; pCEmatch->initgid = c->initgid; while (pCEmatch->aliases != (NAMES *)0) { @@ -2881,6 +2885,8 @@ #endif if (c->ondemand == FLAGUNKNOWN) c->ondemand = FLAGFALSE; + if (c->lock == FLAGUNKNOWN) + c->lock = FLAGFALSE; if (c->reinitoncc == FLAGUNKNOWN) c->reinitoncc = FLAGFALSE; if (c->striphigh == FLAGUNKNOWN) --- conserver-8.1.9-p/conserver.cf/conserver.cf.man Wed Jul 14 07:28:42 2004 +++ conserver-8.1.9/conserver.cf/conserver.cf.man Sat Aug 7 00:34:36 2004 @@ -774,6 +774,11 @@ Default is .BR !ondemand . .TP +.B lock +Lock the device using UUCP-style locks. +Default is +.BR !lock . +.TP .B striphigh Strip the high bit off all data coming from this console and all clients connected to this console before processing occurs.