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