xref: /onnv-gate/usr/src/cmd/tip/uucplock.c (revision 549:9e644232f978)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
5*549Smuffin 
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
80Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
90Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate  */
11*549Smuffin 
12*549Smuffin #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*549Smuffin 
140Sstevel@tonic-gate /*
150Sstevel@tonic-gate  * defs that come from uucp.h
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate #define	NAMESIZE 40
180Sstevel@tonic-gate #define	FAIL -1
190Sstevel@tonic-gate #define	SAME 0
200Sstevel@tonic-gate #define	SLCKTIME (8*60*60)	/* device timeout (LCK.. files) in seconds */
210Sstevel@tonic-gate #ifdef __STDC__
220Sstevel@tonic-gate #define	ASSERT(e, f, v) if (!(e)) {\
23*549Smuffin 	(void) fprintf(stderr, "AERROR - (%s) ", #e); \
24*549Smuffin 	(void) fprintf(stderr, f, v); \
250Sstevel@tonic-gate 	finish(FAIL); \
260Sstevel@tonic-gate }
270Sstevel@tonic-gate #else
280Sstevel@tonic-gate #define	ASSERT(e, f, v) if (!(e)) {\
29*549Smuffin 	(void) fprintf(stderr, "AERROR - (%s) ", "e"); \
30*549Smuffin 	(void) fprintf(stderr, f, v); \
310Sstevel@tonic-gate 	finish(FAIL); \
320Sstevel@tonic-gate }
330Sstevel@tonic-gate #endif
340Sstevel@tonic-gate #define	SIZEOFPID	10		/* maximum number of digits in a pid */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	LOCKDIR "/var/spool/locks"
370Sstevel@tonic-gate #define	LOCKPRE "LK"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * This code is taken almost directly from uucp and follows the same
410Sstevel@tonic-gate  * conventions.  This is important since uucp and tip should
420Sstevel@tonic-gate  * respect each others locks.
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <sys/types.h>
460Sstevel@tonic-gate #include <sys/stat.h>
470Sstevel@tonic-gate #include <sys/mkdev.h>
480Sstevel@tonic-gate #include <stdio.h>
490Sstevel@tonic-gate #include <errno.h>
500Sstevel@tonic-gate #include <string.h>
51*549Smuffin #include <stdlib.h>
52*549Smuffin #include <time.h>
53*549Smuffin #include <unistd.h>
54*549Smuffin #include <fcntl.h>
55*549Smuffin #include <signal.h>
56*549Smuffin #include <utime.h>
570Sstevel@tonic-gate 
58*549Smuffin static void	stlock(char *);
59*549Smuffin static int	onelock(char *, char *, char *);
60*549Smuffin static int	checkLock(char *);
610Sstevel@tonic-gate 
62*549Smuffin extern void	finish(int);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  *	ulockf(file, atime)
660Sstevel@tonic-gate  *	char *file;
670Sstevel@tonic-gate  *	time_t atime;
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  *	ulockf  -  this routine will create a lock file (file).
700Sstevel@tonic-gate  *	If one already exists, send a signal 0 to the process--if
710Sstevel@tonic-gate  *	it fails, then unlink it and make a new one.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  *	input:
740Sstevel@tonic-gate  *		file - name of the lock file
750Sstevel@tonic-gate  *		atime - is unused, but we keep it for lint compatibility
760Sstevel@tonic-gate  *			with non-ATTSVKILL
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  *	return codes:  0  |  FAIL
790Sstevel@tonic-gate  */
80*549Smuffin /* ARGSUSED */
81*549Smuffin static int
82*549Smuffin ulockf(char *file, time_t atime)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	static char pid[SIZEOFPID+2] = { '\0' }; /* +2 for '\n' and NULL */
850Sstevel@tonic-gate 	static char tempfile[NAMESIZE];
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	if (pid[0] == '\0') {
88*549Smuffin 		(void) sprintf(pid, "%*d\n", SIZEOFPID, (int)getpid());
89*549Smuffin 		(void) snprintf(tempfile, sizeof (tempfile),
90*549Smuffin 		    "%s/LTMP.%d", LOCKDIR, getpid());
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 	if (onelock(pid, tempfile, file) == -1) {
930Sstevel@tonic-gate 		/* lock file exists */
940Sstevel@tonic-gate 		(void) unlink(tempfile);
950Sstevel@tonic-gate 		if (checkLock(file))
960Sstevel@tonic-gate 			return (FAIL);
970Sstevel@tonic-gate 		else {
980Sstevel@tonic-gate 			if (onelock(pid, tempfile, file)) {
990Sstevel@tonic-gate 				(void) unlink(tempfile);
1000Sstevel@tonic-gate 				return (FAIL);
1010Sstevel@tonic-gate 			}
1020Sstevel@tonic-gate 		}
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 	stlock(file);
1050Sstevel@tonic-gate 	return (0);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * check to see if the lock file exists and is still active
1100Sstevel@tonic-gate  * - use kill(pid, 0) - (this only works on ATTSV and some hacked
1110Sstevel@tonic-gate  * BSD systems at this time)
1120Sstevel@tonic-gate  * return:
1130Sstevel@tonic-gate  *	0	-> success (lock file removed - no longer active)
1140Sstevel@tonic-gate  *	FAIL	-> lock file still active
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static int
117*549Smuffin checkLock(char *file)
1180Sstevel@tonic-gate {
119*549Smuffin 	int ret;
1200Sstevel@tonic-gate 	int lpid = -1;
1210Sstevel@tonic-gate 	char alpid[SIZEOFPID+2];	/* +2 for '\n' and NULL */
1220Sstevel@tonic-gate 	int fd;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	fd = open(file, 0);
1250Sstevel@tonic-gate 	if (fd == -1) {
1260Sstevel@tonic-gate 		if (errno == ENOENT)  /* file does not exist -- OK */
1270Sstevel@tonic-gate 			return (0);
1280Sstevel@tonic-gate 		goto unlk;
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 	ret = read(fd, (char *)alpid, SIZEOFPID+1); /* +1 for '\n' */
1310Sstevel@tonic-gate 	(void) close(fd);
1320Sstevel@tonic-gate 	if (ret != (SIZEOFPID+1))
1330Sstevel@tonic-gate 		goto unlk;
1340Sstevel@tonic-gate 	lpid = atoi(alpid);
1350Sstevel@tonic-gate 	if ((ret = kill(lpid, 0)) == 0 || errno == EPERM)
1360Sstevel@tonic-gate 		return (FAIL);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate unlk:
1390Sstevel@tonic-gate 	if (unlink(file) != 0)
1400Sstevel@tonic-gate 		return (FAIL);
1410Sstevel@tonic-gate 	return (0);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate #define	MAXLOCKS 10	/* maximum number of lock files */
1450Sstevel@tonic-gate char *Lockfile[MAXLOCKS];
1460Sstevel@tonic-gate int Nlocks = 0;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  *	stlock(name)	put name in list of lock files
1500Sstevel@tonic-gate  *	char *name;
1510Sstevel@tonic-gate  *
1520Sstevel@tonic-gate  *	return codes:  none
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static void
156*549Smuffin stlock(char *name)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	char *p;
1590Sstevel@tonic-gate 	int i;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	for (i = 0; i < Nlocks; i++) {
1620Sstevel@tonic-gate 		if (Lockfile[i] == NULL)
1630Sstevel@tonic-gate 			break;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 	ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
1660Sstevel@tonic-gate 	if (i >= Nlocks)
1670Sstevel@tonic-gate 		i = Nlocks++;
1680Sstevel@tonic-gate 	p = calloc(strlen(name) + 1, sizeof (char));
1690Sstevel@tonic-gate 	ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
170*549Smuffin 	(void) strcpy(p, name);
1710Sstevel@tonic-gate 	Lockfile[i] = p;
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  *	rmlock(name)	remove all lock files in list
1760Sstevel@tonic-gate  *	char *name;	or name
1770Sstevel@tonic-gate  *
1780Sstevel@tonic-gate  *	return codes: none
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 
181*549Smuffin static void
182*549Smuffin rmlock(char *name)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	int i;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	for (i = 0; i < Nlocks; i++) {
1870Sstevel@tonic-gate 		if (Lockfile[i] == NULL)
1880Sstevel@tonic-gate 			continue;
1890Sstevel@tonic-gate 		if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
190*549Smuffin 			(void) unlink(Lockfile[i]);
1910Sstevel@tonic-gate 			free(Lockfile[i]);
1920Sstevel@tonic-gate 			Lockfile[i] = NULL;
1930Sstevel@tonic-gate 		}
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
197*549Smuffin static int
198*549Smuffin onelock(char *pid, char *tempfile, char *name)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	int fd;
2010Sstevel@tonic-gate 	static int first = 1;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	fd = creat(tempfile, 0444);
2040Sstevel@tonic-gate 	if (fd < 0) {
2050Sstevel@tonic-gate 		if (first) {
2060Sstevel@tonic-gate 			if (errno == EACCES) {
207*549Smuffin 				(void) fprintf(stderr,
2080Sstevel@tonic-gate 			"tip: can't create files in lock file directory %s\n",
2090Sstevel@tonic-gate 				    LOCKDIR);
2100Sstevel@tonic-gate 			} else if (access(LOCKDIR, 0) < 0) {
211*549Smuffin 				(void) fprintf(stderr,
212*549Smuffin 				    "tip: lock file directory %s: ",
2130Sstevel@tonic-gate 				    LOCKDIR);
2140Sstevel@tonic-gate 				perror("");
2150Sstevel@tonic-gate 			}
2160Sstevel@tonic-gate 			first = 0;
2170Sstevel@tonic-gate 		}
2180Sstevel@tonic-gate 		if (errno == EMFILE || errno == ENFILE)
2190Sstevel@tonic-gate 			(void) unlink(tempfile);
2200Sstevel@tonic-gate 		return (-1);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 	/* +1 for '\n' */
2230Sstevel@tonic-gate 	if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) {
224*549Smuffin 		(void) fprintf(stderr,
2250Sstevel@tonic-gate 		    "tip: can't write to files in lock file directory %s: %s\n",
2260Sstevel@tonic-gate 		    LOCKDIR, strerror(errno));
2270Sstevel@tonic-gate 		(void) unlink(tempfile);
2280Sstevel@tonic-gate 		return (-1);
2290Sstevel@tonic-gate 	}
230*549Smuffin 	(void) fchmod(fd, 0444);
231*549Smuffin 	(void) close(fd);
2320Sstevel@tonic-gate 	if (link(tempfile, name) < 0) {
233*549Smuffin 		(void) unlink(tempfile);
2340Sstevel@tonic-gate 		return (-1);
2350Sstevel@tonic-gate 	}
236*549Smuffin 	(void) unlink(tempfile);
2370Sstevel@tonic-gate 	return (0);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  *	delock(sys)	remove a lock file
2420Sstevel@tonic-gate  *	char *sys;
243*549Smuffin  */
244*549Smuffin 
245*549Smuffin void
246*549Smuffin delock(char *sys)
247*549Smuffin {
248*549Smuffin 	struct stat sb;
249*549Smuffin 	char lname[NAMESIZE];
250*549Smuffin 
251*549Smuffin 	if (stat(sys, &sb) < 0)
252*549Smuffin 		return;
253*549Smuffin 	(void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
254*549Smuffin 	    LOCKDIR, LOCKPRE,
255*549Smuffin 	    (unsigned long)major(sb.st_dev),
256*549Smuffin 	    (unsigned long)major(sb.st_rdev),
257*549Smuffin 	    (unsigned long)minor(sb.st_rdev));
258*549Smuffin 	rmlock(lname);
259*549Smuffin }
260*549Smuffin 
261*549Smuffin /*
262*549Smuffin  *	tip_mlock(sys)	create system lock
263*549Smuffin  *	char *sys;
2640Sstevel@tonic-gate  *
2650Sstevel@tonic-gate  *	return codes:  0  |  FAIL
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate 
268*549Smuffin int
269*549Smuffin tip_mlock(char *sys)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	struct stat sb;
2720Sstevel@tonic-gate 	char lname[NAMESIZE];
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	if (stat(sys, &sb) < 0)
2750Sstevel@tonic-gate 		return (FAIL);
276*549Smuffin 	(void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
277*549Smuffin 	    LOCKDIR, LOCKPRE,
278*549Smuffin 	    (unsigned long)major(sb.st_dev),
279*549Smuffin 	    (unsigned long)major(sb.st_rdev),
280*549Smuffin 	    (unsigned long)minor(sb.st_rdev));
2810Sstevel@tonic-gate 	return (ulockf(lname, (time_t)SLCKTIME) < 0 ? FAIL : 0);
2820Sstevel@tonic-gate }
283