10Sstevel@tonic-gate /*
2*2590Ssn199410 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
5549Smuffin
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 */
11549Smuffin
12549Smuffin #pragma ident "%Z%%M% %I% %E% SMI"
13549Smuffin
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)) {\
23549Smuffin (void) fprintf(stderr, "AERROR - (%s) ", #e); \
24549Smuffin (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)) {\
29549Smuffin (void) fprintf(stderr, "AERROR - (%s) ", "e"); \
30549Smuffin (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>
51549Smuffin #include <stdlib.h>
52549Smuffin #include <time.h>
53549Smuffin #include <unistd.h>
54549Smuffin #include <fcntl.h>
55549Smuffin #include <signal.h>
56549Smuffin #include <utime.h>
570Sstevel@tonic-gate
58549Smuffin static void stlock(char *);
59549Smuffin static int onelock(char *, char *, char *);
60549Smuffin static int checkLock(char *);
610Sstevel@tonic-gate
62549Smuffin 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 */
80549Smuffin /* ARGSUSED */
81549Smuffin static int
ulockf(char * file,time_t atime)82549Smuffin 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*2590Ssn199410 (void) snprintf(pid, sizeof (pid), "%*d\n", SIZEOFPID,
89*2590Ssn199410 (int)getpid());
90549Smuffin (void) snprintf(tempfile, sizeof (tempfile),
91549Smuffin "%s/LTMP.%d", LOCKDIR, getpid());
920Sstevel@tonic-gate }
930Sstevel@tonic-gate if (onelock(pid, tempfile, file) == -1) {
940Sstevel@tonic-gate /* lock file exists */
950Sstevel@tonic-gate (void) unlink(tempfile);
960Sstevel@tonic-gate if (checkLock(file))
970Sstevel@tonic-gate return (FAIL);
980Sstevel@tonic-gate else {
990Sstevel@tonic-gate if (onelock(pid, tempfile, file)) {
1000Sstevel@tonic-gate (void) unlink(tempfile);
1010Sstevel@tonic-gate return (FAIL);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate stlock(file);
1060Sstevel@tonic-gate return (0);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate * check to see if the lock file exists and is still active
1110Sstevel@tonic-gate * - use kill(pid, 0) - (this only works on ATTSV and some hacked
1120Sstevel@tonic-gate * BSD systems at this time)
1130Sstevel@tonic-gate * return:
1140Sstevel@tonic-gate * 0 -> success (lock file removed - no longer active)
1150Sstevel@tonic-gate * FAIL -> lock file still active
1160Sstevel@tonic-gate */
1170Sstevel@tonic-gate static int
checkLock(char * file)118549Smuffin checkLock(char *file)
1190Sstevel@tonic-gate {
120549Smuffin int ret;
1210Sstevel@tonic-gate int lpid = -1;
1220Sstevel@tonic-gate char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
1230Sstevel@tonic-gate int fd;
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate fd = open(file, 0);
1260Sstevel@tonic-gate if (fd == -1) {
1270Sstevel@tonic-gate if (errno == ENOENT) /* file does not exist -- OK */
1280Sstevel@tonic-gate return (0);
1290Sstevel@tonic-gate goto unlk;
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate ret = read(fd, (char *)alpid, SIZEOFPID+1); /* +1 for '\n' */
1320Sstevel@tonic-gate (void) close(fd);
1330Sstevel@tonic-gate if (ret != (SIZEOFPID+1))
1340Sstevel@tonic-gate goto unlk;
1350Sstevel@tonic-gate lpid = atoi(alpid);
1360Sstevel@tonic-gate if ((ret = kill(lpid, 0)) == 0 || errno == EPERM)
1370Sstevel@tonic-gate return (FAIL);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate unlk:
1400Sstevel@tonic-gate if (unlink(file) != 0)
1410Sstevel@tonic-gate return (FAIL);
1420Sstevel@tonic-gate return (0);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate #define MAXLOCKS 10 /* maximum number of lock files */
1460Sstevel@tonic-gate char *Lockfile[MAXLOCKS];
1470Sstevel@tonic-gate int Nlocks = 0;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * stlock(name) put name in list of lock files
1510Sstevel@tonic-gate * char *name;
1520Sstevel@tonic-gate *
1530Sstevel@tonic-gate * return codes: none
1540Sstevel@tonic-gate */
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate static void
stlock(char * name)157549Smuffin stlock(char *name)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate char *p;
1600Sstevel@tonic-gate int i;
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate for (i = 0; i < Nlocks; i++) {
1630Sstevel@tonic-gate if (Lockfile[i] == NULL)
1640Sstevel@tonic-gate break;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i);
1670Sstevel@tonic-gate if (i >= Nlocks)
1680Sstevel@tonic-gate i = Nlocks++;
1690Sstevel@tonic-gate p = calloc(strlen(name) + 1, sizeof (char));
1700Sstevel@tonic-gate ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name);
171549Smuffin (void) strcpy(p, name);
1720Sstevel@tonic-gate Lockfile[i] = p;
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * rmlock(name) remove all lock files in list
1770Sstevel@tonic-gate * char *name; or name
1780Sstevel@tonic-gate *
1790Sstevel@tonic-gate * return codes: none
1800Sstevel@tonic-gate */
1810Sstevel@tonic-gate
182549Smuffin static void
rmlock(char * name)183549Smuffin rmlock(char *name)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate int i;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate for (i = 0; i < Nlocks; i++) {
1880Sstevel@tonic-gate if (Lockfile[i] == NULL)
1890Sstevel@tonic-gate continue;
1900Sstevel@tonic-gate if (name == NULL || strcmp(name, Lockfile[i]) == SAME) {
191549Smuffin (void) unlink(Lockfile[i]);
1920Sstevel@tonic-gate free(Lockfile[i]);
1930Sstevel@tonic-gate Lockfile[i] = NULL;
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
198549Smuffin static int
onelock(char * pid,char * tempfile,char * name)199549Smuffin onelock(char *pid, char *tempfile, char *name)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate int fd;
2020Sstevel@tonic-gate static int first = 1;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate fd = creat(tempfile, 0444);
2050Sstevel@tonic-gate if (fd < 0) {
2060Sstevel@tonic-gate if (first) {
2070Sstevel@tonic-gate if (errno == EACCES) {
208549Smuffin (void) fprintf(stderr,
2090Sstevel@tonic-gate "tip: can't create files in lock file directory %s\n",
2100Sstevel@tonic-gate LOCKDIR);
2110Sstevel@tonic-gate } else if (access(LOCKDIR, 0) < 0) {
212549Smuffin (void) fprintf(stderr,
213549Smuffin "tip: lock file directory %s: ",
2140Sstevel@tonic-gate LOCKDIR);
2150Sstevel@tonic-gate perror("");
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate first = 0;
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate if (errno == EMFILE || errno == ENFILE)
2200Sstevel@tonic-gate (void) unlink(tempfile);
2210Sstevel@tonic-gate return (-1);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate /* +1 for '\n' */
2240Sstevel@tonic-gate if (write(fd, pid, SIZEOFPID+1) != (SIZEOFPID+1)) {
225549Smuffin (void) fprintf(stderr,
2260Sstevel@tonic-gate "tip: can't write to files in lock file directory %s: %s\n",
2270Sstevel@tonic-gate LOCKDIR, strerror(errno));
2280Sstevel@tonic-gate (void) unlink(tempfile);
2290Sstevel@tonic-gate return (-1);
2300Sstevel@tonic-gate }
231549Smuffin (void) fchmod(fd, 0444);
232549Smuffin (void) close(fd);
2330Sstevel@tonic-gate if (link(tempfile, name) < 0) {
234549Smuffin (void) unlink(tempfile);
2350Sstevel@tonic-gate return (-1);
2360Sstevel@tonic-gate }
237549Smuffin (void) unlink(tempfile);
2380Sstevel@tonic-gate return (0);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate * delock(sys) remove a lock file
2430Sstevel@tonic-gate * char *sys;
244549Smuffin */
245549Smuffin
246549Smuffin void
delock(char * sys)247549Smuffin delock(char *sys)
248549Smuffin {
249549Smuffin struct stat sb;
250549Smuffin char lname[NAMESIZE];
251549Smuffin
252549Smuffin if (stat(sys, &sb) < 0)
253549Smuffin return;
254549Smuffin (void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
255549Smuffin LOCKDIR, LOCKPRE,
256549Smuffin (unsigned long)major(sb.st_dev),
257549Smuffin (unsigned long)major(sb.st_rdev),
258549Smuffin (unsigned long)minor(sb.st_rdev));
259549Smuffin rmlock(lname);
260549Smuffin }
261549Smuffin
262549Smuffin /*
263549Smuffin * tip_mlock(sys) create system lock
264549Smuffin * char *sys;
2650Sstevel@tonic-gate *
2660Sstevel@tonic-gate * return codes: 0 | FAIL
2670Sstevel@tonic-gate */
2680Sstevel@tonic-gate
269549Smuffin int
tip_mlock(char * sys)270549Smuffin tip_mlock(char *sys)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate struct stat sb;
2730Sstevel@tonic-gate char lname[NAMESIZE];
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate if (stat(sys, &sb) < 0)
2760Sstevel@tonic-gate return (FAIL);
277549Smuffin (void) snprintf(lname, sizeof (lname), "%s/%s.%3.3lu.%3.3lu.%3.3lu",
278549Smuffin LOCKDIR, LOCKPRE,
279549Smuffin (unsigned long)major(sb.st_dev),
280549Smuffin (unsigned long)major(sb.st_rdev),
281549Smuffin (unsigned long)minor(sb.st_rdev));
2820Sstevel@tonic-gate return (ulockf(lname, (time_t)SLCKTIME) < 0 ? FAIL : 0);
2830Sstevel@tonic-gate }
284