1 /*- 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ulockf.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #include "uucp.h" 13 #include <sys/stat.h> 14 #include <errno.h> 15 16 #define LCKMODE 0444 /* File mode for lock files */ 17 #define MAXLOCKS 16 /* Maximum number of lock files */ 18 19 char *Lockfile[MAXLOCKS]; 20 char *LockDirectory = LOCKDIR; 21 int Nlocks = 0; 22 extern int errno; 23 24 /*LINTLIBRARY*/ 25 26 /* 27 * This routine will attempt to create a lock file (file). 28 * It makes sure that the lock file is valid if it already exists. 29 * 30 * return codes: SUCCESS | FAIL 31 */ 32 ulockf(hfile, atime) 33 char *hfile; 34 time_t atime; 35 { 36 register char *p; 37 register int i; 38 static char tempfile[NAMESIZE]; 39 char file[NAMESIZE]; 40 static int pid = -1; 41 42 if (pid < 0) { 43 pid = getpid(); 44 sprintf(tempfile, "%s/LTMP.%d", LockDirectory, pid); 45 } 46 sprintf(file, "%s/LCK..%s", LockDirectory, hfile); 47 i = 0; 48 while (onelock(pid, tempfile, file) == -1) { /* lock file exists */ 49 #if !defined(BSD4_2) && !defined(USG) 50 struct stat stbuf; 51 time_t ptime; 52 /* get status to check age of the lock file */ 53 if (stat(file, &stbuf) == 0) { 54 (void) time(&ptime); 55 if ((ptime - stbuf.st_ctime) < atime) 56 return FAIL; /* file not old enough to delete */ 57 } 58 #else BSD4_2 || USG 59 register int fd; 60 fd = open(file, 0); 61 if (fd >= 0) { 62 int upid, ret; 63 ret = read(fd, &upid, sizeof upid); 64 close(fd); 65 if (ret == sizeof upid && (kill(upid, 0) == 0 66 || errno != ESRCH)) 67 return FAIL; /* process is still running */ 68 } 69 #endif BSD4_2 || USG 70 syslog(LOG_WARNING, "%s: dead lock %s", Rmtname, file); 71 logent(file, "DEAD LOCK"); 72 (void) unlink(file); 73 sleep(5); /* avoid a possible race */ 74 if (i++ >= 5) { 75 syslog(LOG_ERR, "%s: can't get lockfile %s: %m", 76 Rmtname, tempfile); 77 cleanup(FAIL); 78 } 79 } 80 81 for (i = 0; i < Nlocks; i++) { 82 if (Lockfile[i] == NULL) 83 break; 84 } 85 if (i >= MAXLOCKS) { 86 syslog(LOG_ERR, "Too many locks"); 87 cleanup(FAIL); 88 } 89 if (i >= Nlocks) 90 i = Nlocks++; 91 p = malloc((unsigned)(strlen(file)+1)); 92 if (p == NULL) { 93 syslog(LOG_ERR, "malloc failed: %m"); 94 cleanup(FAIL); 95 } 96 strcpy(p, file); 97 Lockfile[i] = p; 98 99 return SUCCESS; 100 } 101 102 /* 103 * remove all lock files in list or name 104 */ 105 rmlock(name) 106 register char *name; 107 { 108 register int i; 109 char file[MAXFULLNAME]; 110 111 if (name != NULL) { 112 sprintf(file, "%s/LCK..%s", LockDirectory, name); 113 name = file; 114 } 115 for (i = 0; i < Nlocks; i++) { 116 if (Lockfile[i] == NULL) 117 continue; 118 if (name == NULL || strcmp(name, Lockfile[i]) == SAME) { 119 unlink(Lockfile[i]); 120 free(Lockfile[i]); 121 Lockfile[i] = NULL; 122 } 123 } 124 } 125 126 /* 127 * makes lock a name on behalf of pid. Tempfile must be in the same 128 * file system as name. 129 */ 130 onelock(pid, tempfile, name) 131 int pid; 132 char *tempfile, *name; 133 { 134 register int fd, ret; 135 #ifdef VMS 136 fd = creat(name, LCKMODE, "1version"); 137 #else !VMS 138 fd = creat(tempfile, LCKMODE); 139 #endif !VMS 140 if (fd < 0) { 141 DEBUG(1,"Can't creat temp file %s ", tempfile); 142 DEBUG(1,"-- errno %d", errno); 143 return FAIL; 144 } 145 ret = write(fd, (char *)&pid, sizeof(int)); 146 (void) close(fd); 147 148 if (ret != sizeof(int)) { 149 DEBUG(1,"Temp file write failed -- errno %d\n", errno); 150 #ifdef VMS 151 (void) unlink(name); 152 #else !VMS 153 (void) unlink(tempfile); 154 #endif !VMS 155 return FAIL; 156 } 157 #ifndef VMS 158 if (link(tempfile, name) < 0) { 159 (void) unlink(tempfile); 160 return FAIL; 161 } 162 unlink(tempfile); 163 #endif !VMS 164 return SUCCESS; 165 } 166 167 #if !defined(BSD4_2) && !defined(USG) 168 /* 169 * update 'change' time for lock files 170 * 171 * Only update ctime, not mtime or atime. 172 * The 'chmod' method permits cu(I)-like programs 173 * to determine how long uucp has been on the line. 174 * The old "change access, mod, and change time" method 175 * can be had by defining OLDTOUCH 176 * 177 * return code - none 178 */ 179 180 ultouch() 181 { 182 static time_t lasttouch = 0; 183 register int i; 184 struct ut { 185 time_t actime; 186 time_t modtime; 187 } ut; 188 189 #ifdef USG 190 time(&Now.time); 191 t1.millitm = 0; 192 #else !USG 193 ftime(&Now); 194 #endif !USG 195 ut.actime = ut.modtime = Now.time; 196 /* Do not waste time touching locking files too often */ 197 /* (But, defend against backward time changes) */ 198 if (ut.actime >= lasttouch && ut.actime < lasttouch+60) 199 return; 200 lasttouch = ut.actime; 201 DEBUG(4, "ultouch\n", 0); 202 203 for (i = 0; i < Nlocks; i++) { 204 if (Lockfile[i] == NULL) 205 continue; 206 #ifdef OLDTOUCH 207 utime(Lockfile[i], &ut); 208 #else !OLDTOUCH 209 chmod(Lockfile[i], LCKMODE); 210 #endif !OLDTOUCH 211 } 212 } 213 #endif !BSD4_2 && ! USG 214