/* Merged into Zmailer by Edwin Allum -- and a bit latter with some
   modifications -- to make the compile optional -- by Matti Aarnio */

/*
 * V7-style file locking: try to link a temp file to "file.lock".
 *
 *	dotlock(char *file): returns 0 on success, -1/errno otherwise.
 *	dotunlock(char *file): same
 *
 * By Ken Lalonde, based loosely on code from mush and pine.
 */

#if defined(HAVE_DOTLOCK) /* Well, we DO use DOTLOCK scheme! */

/*
   #include <sys/types.h>
   #include <sys/param.h>
   #include <sys/stat.h>
   #include <sys/time.h>
   #include <fcntl.h>
   #include <errno.h>
 */

#define MAXLOCKAGE	(5*60)	/* locks older than this are broken (secs) */
#define SLEEP		1	/* interval between busy lock checks (secs) */
#define MAXFAIL		5	/* max # checks before we give up */

int
dotlock(file)
	char *file;
{
	char lockname[MAXPATHLEN];
	char temp[MAXPATHLEN];
	struct stat st;
	time_t now;
	int fd, i, fail = 0;
	extern int errno;

	sprintf(lockname, "%s.lock", file);
	sprintf(temp, "%s.L%x.%lx.%x",
		file, getpid(), (long)time((time_t *)0), gethostid());
	unlink(temp);
	for (;;) {
		if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
			return -1;
		fchmod(fd, 0666);
		fstat(fd, &st);
		now = st.st_ctime;	/* fileserver's idea of current time */
		close(fd);
		/* Ignore return value of link, to work around NFS pain */
		link(temp, lockname);
		i = stat(temp, &st);
		unlink(temp);
		if (i == 0 && st.st_nlink == 2)
			return 0;
		/* If the lock is too old, remove it. */
		if (stat(lockname, &st) == 0 && st.st_ctime < now-MAXLOCKAGE &&
		    unlink(lockname) == 0)
			continue;
		if (++fail == MAXFAIL) {
			errno = EBUSY;		/* yuk */
			return -1;
		}
		sleep(SLEEP);
	}
}

int
dotunlock(file)
	char *file;
{
	char lockname[MAXPATHLEN];

	sprintf(lockname, "%s.lock", file);
	return unlink(lockname);
}

/*
 * Solaris 2.x equivalent of gethostid().
 * This should be configured in differently, but for
 * now this #if will do. 
 */
#if defined(sun) && defined(__svr4__)
#include <sys/systeminfo.h>

gethostid()
{
	char buf[1024];

	sysinfo(SI_HW_SERIAL, buf, sizeof buf);
	return atoi(buf);
}
#endif

#else	/* we don't compile this piece.. */
static int foo = 0;
#endif
