1 #ifndef lint 2 static char sccsid[] = "@(#)ulockf.c 5.2 (Berkeley) 01/22/85"; 3 #endif 4 5 #include "uucp.h" 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 9 extern time_t time(); 10 11 /* File mode for lock files */ 12 #define LCKMODE 0444 13 14 /* 15 * ulockf - this routine will create a lock file (file). 16 * If one already exists, the create time is checked for 17 * older than the age time (atime). 18 * If it is older, an attempt will be made to unlink it 19 * and create a new one. 20 * 21 * return codes: 0 | FAIL 22 */ 23 24 ulockf(file, atime) 25 register char *file; 26 time_t atime; 27 { 28 struct stat stbuf; 29 time_t ptime; 30 register int ret; 31 static int pid = -1; 32 static char tempfile[NAMESIZE]; 33 34 if (pid < 0) { 35 pid = getpid(); 36 sprintf(tempfile, "%s/LTMP.%d", LOCKDIR, pid); 37 } 38 if (onelock(pid, tempfile, file) == -1) { 39 /* lock file exists */ 40 /* get status to check age of the lock file */ 41 ret = stat(file, &stbuf); 42 if (ret != -1) { 43 time(&ptime); 44 if ((ptime - stbuf.st_ctime) < atime) { 45 /* file not old enough to delete */ 46 return FAIL; 47 } 48 ret = unlink(file); 49 logent(file, "DEAD LOCK"); 50 sleep(5); /* rti!trt: avoid a race */ 51 ret = onelock(pid, tempfile, file); 52 } 53 if (ret != 0) 54 return FAIL; 55 } 56 stlock(file); 57 return SUCCESS; 58 } 59 60 61 #define MAXLOCKS 10 /* maximum number of lock files */ 62 char *Lockfile[MAXLOCKS]; 63 int Nlocks = 0; 64 65 /*** 66 * stlock(name) put name in list of lock files 67 * char *name; 68 * 69 * return codes: none 70 */ 71 72 stlock(name) 73 register char *name; 74 { 75 register char *p; 76 register int i; 77 78 for (i = 0; i < Nlocks; i++) { 79 if (Lockfile[i] == NULL) 80 break; 81 } 82 ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", CNULL, i); 83 if (i >= Nlocks) 84 i = Nlocks++; 85 p = calloc((unsigned)(strlen(name)+1), sizeof (char)); 86 ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0); 87 strcpy(p, name); 88 Lockfile[i] = p; 89 return; 90 } 91 92 93 /* 94 * remove all lock files in list * or name 95 * 96 * return codes: none 97 */ 98 99 rmlock(name) 100 register char *name; 101 { 102 register int i; 103 104 for (i = 0; i < Nlocks; i++) { 105 if (Lockfile[i] == NULL) 106 continue; 107 if (name == NULL || strcmp(name, Lockfile[i]) == SAME) { 108 unlink(Lockfile[i]); 109 free(Lockfile[i]); 110 Lockfile[i] = NULL; 111 } 112 } 113 } 114 115 /* 116 * isalock(name) returns 0 if the name is a lock. 117 * unlock(name) unlocks name if it is a lock. 118 * onelock(pid,tempfile,name) makes lock a name 119 * on behalf of pid. Tempfile must be in the same 120 * file system as name. 121 * lock(pid,tempfile,names) either locks all the 122 * names or none of them. 123 */ 124 isalock(name) 125 char *name; 126 { 127 struct stat xstat; 128 if (stat(name,&xstat) < 0) 129 return 0; 130 if (xstat.st_size != sizeof(int)) 131 return 0; 132 return 1; 133 } 134 unlock(name) 135 char *name; 136 { 137 if (isalock(name)) 138 return unlink(name); 139 else 140 return -1; 141 } 142 onelock(pid,tempfile,name) 143 char *tempfile,*name; 144 { 145 register int fd; 146 #ifdef VMS 147 fd = creat(name, LCKMODE, "1version"); 148 #else !VMS 149 fd = creat(tempfile, LCKMODE); 150 #endif !VMS 151 if (fd<0) 152 return FAIL; 153 write(fd, (char *) &pid, sizeof(int)); 154 close(fd); 155 #ifndef VMS 156 if (link(tempfile, name) < 0) { 157 unlink(tempfile); 158 return FAIL; 159 } 160 unlink(tempfile); 161 #endif 162 return SUCCESS; 163 } 164 165 166 lock(pid, tempfile, names) 167 char *tempfile; 168 register char **names; 169 { 170 register int i, j; 171 172 for(i=0; names[i] != 0; i++) { 173 if (onelock(pid, tempfile, names[i]) == 0) 174 continue; 175 for(j=0; j < i ;j++) 176 unlink(names[j]); 177 return FAIL; 178 } 179 return SUCCESS; 180 } 181 182 #define LOCKPRE "LCK." 183 184 /* 185 * remove a lock file 186 */ 187 delock(s) 188 char *s; 189 { 190 char ln[NAMESIZE]; 191 192 sprintf(ln, "%s/%s.%s", LOCKDIR, LOCKPRE, s); 193 rmlock(ln); 194 } 195 196 /* 197 * create system lock 198 * 199 * return codes: SUCCESS | FAIL 200 */ 201 mlock(sys) 202 char *sys; 203 { 204 char lname[NAMESIZE]; 205 206 sprintf(lname, "%s/%s.%s", LOCKDIR, LOCKPRE, sys); 207 return ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : SUCCESS; 208 } 209 210 /*** 211 * update 'change' time for lock files 212 * 213 * Only update ctime, not mtime or atime. 214 * The 'chmod' method permits cu(I)-like programs 215 * to determine how long uucp has been on the line. 216 * The old "change access, mod, and change time" method 217 * can be had by defining OLDTOUCH 218 * 219 * return code - none 220 */ 221 222 ultouch() 223 { 224 time_t time(); 225 static time_t lasttouch = 0; 226 register int i; 227 struct ut { 228 time_t actime; 229 time_t modtime; 230 } ut; 231 232 ut.actime = time(&ut.modtime); 233 /* Do not waste time touching locking files too often */ 234 /* (But, defend against backward time changes) */ 235 if (ut.actime >= lasttouch && ut.actime < lasttouch+60) 236 return; 237 lasttouch = ut.actime; 238 DEBUG(4, "ultouch\n", 0); 239 240 for (i = 0; i < Nlocks; i++) { 241 if (Lockfile[i] == NULL) 242 continue; 243 #ifdef OLDTOUCH 244 utime(Lockfile[i], &ut); 245 #else !OLDTOUCH 246 chmod(Lockfile[i], LCKMODE); 247 #endif !OLDTOUCH 248 /* 249 * set 'nologinflag' if the file /etc/nologin exists. 250 * This permits graceful shutdown of uucp. 251 */ 252 if (nologinflag == 0 && access(NOLOGIN, 0) == 0) 253 nologinflag = 1; 254 } 255 } 256