|
|
1.1 ! root 1: /* ! 2: ** Program to produce reliable locks for shell scripts. ! 3: ** Algorithmn suggested by Peter Honeyman, January 1984, in connection ! 4: ** with HoneyDanBer UUCP. ! 5: ** ! 6: ** Erik E. Fair <ucbvax!fair> ! 7: */ ! 8: ! 9: #include <stdio.h> ! 10: #include <sys/file.h> ! 11: #include <errno.h> ! 12: ! 13: #define LOCK_SET 0 ! 14: #define LOCK_FAIL 1 ! 15: ! 16: #define TRUE 1 ! 17: #define FALSE 0 ! 18: ! 19: int Verbose = FALSE; ! 20: char *Pname; ! 21: char *USAGE = "%s: USAGE: shlock -f file -p pid [-v]\n"; ! 22: char *errmsg(); ! 23: char *tmpfile(); ! 24: ! 25: #define vprintf if (Verbose) printf ! 26: ! 27: extern int errno; ! 28: extern char *rindex(); ! 29: extern char *strcpy(); ! 30: extern char *strcat(); ! 31: ! 32: main(ac,av) ! 33: int ac; ! 34: char *av[]; ! 35: { ! 36: register int x; ! 37: char *file; ! 38: int pid; ! 39: ! 40: Pname = ((Pname = rindex(av[0], '/')) ? Pname + 1 : av[0]); ! 41: ! 42: for(x = 1; x < ac; x++) { ! 43: if (av[x][0] == '-') { ! 44: switch(av[x][1]) { ! 45: case 'v': ! 46: Verbose = TRUE; ! 47: break; ! 48: case 'p': ! 49: if (strlen(av[x]) > 2) { ! 50: pid = atoi(&av[x][2]); ! 51: } else { ! 52: pid = atoi(av[x + 1]); ! 53: x++; ! 54: } ! 55: break; ! 56: case 'f': ! 57: if (strlen(av[x]) > 2) { ! 58: file = &av[x][2]; ! 59: } else { ! 60: file = av[x + 1]; ! 61: x++; ! 62: } ! 63: break; ! 64: default: ! 65: fprintf(stderr, USAGE, Pname); ! 66: exit(LOCK_FAIL); ! 67: } ! 68: } ! 69: } ! 70: if (pid == 0 || file == (char *)NULL) { ! 71: fprintf(stderr, USAGE, Pname); ! 72: exit(LOCK_FAIL); ! 73: } ! 74: if (mklock(file, pid)) ! 75: exit(LOCK_SET); ! 76: exit(LOCK_FAIL); ! 77: } ! 78: ! 79: mklock(file, pid) ! 80: char *file; ! 81: int pid; ! 82: { ! 83: register int fd; ! 84: register int len; ! 85: register char *tmp = tmpfile(file); ! 86: char *buf[BUFSIZ]; ! 87: ! 88: vprintf("%s: attempting to get lock <%s> for process %d\n", Pname, file, pid); ! 89: sprintf(buf, "%d\n", pid); ! 90: len = strlen(buf); ! 91: loop: ! 92: if ((fd = open(tmp, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) { ! 93: switch(errno) { ! 94: case EEXIST: ! 95: vprintf("%s: temporary file %s exists already.\n", Pname, tmp); ! 96: if (unlink(tmp) < 0) { ! 97: fprintf(stderr,"%s: unlink(%s): %s\n", Pname, tmp, errmsg(errno)); ! 98: return(FALSE); ! 99: } ! 100: /* ! 101: ** I hereby profane the god of structured programming ! 102: ** Edsgar Djikstra ! 103: */ ! 104: goto loop; ! 105: default: ! 106: fprintf(stderr,"%s: open(%s): %s\n", Pname, tmp, errmsg(errno)); ! 107: return(FALSE); ! 108: } ! 109: } ! 110: ! 111: /* ! 112: ** Write the PID into the temporary file before attempting to link ! 113: ** to the actual lock file. That way we have a valid lock the instant ! 114: ** the link succeeds. ! 115: */ ! 116: if (write(fd, buf, len) < 0) { ! 117: fprintf(stderr, "%s: write(%s,%d): %s\n", Pname, tmp, pid, errmsg(errno)); ! 118: close(fd); ! 119: return(FALSE); ! 120: } ! 121: close(fd); ! 122: ! 123: loop2: ! 124: if (link(tmp, file) < 0) { ! 125: switch(errno) { ! 126: case EEXIST: ! 127: vprintf("%s: lock <%s> already exists\n", Pname, file); ! 128: if (cklock(file)) { ! 129: vprintf("%s: extant lock is valid\n", Pname); ! 130: if (unlink(tmp) < 0) { ! 131: fprintf(stderr,"%s: unlink(%s): %s\n", Pname, tmp, errmsg(errno)); ! 132: } ! 133: return(FALSE); ! 134: } else { ! 135: vprintf("%s: extant lock is invalid, removing\n", Pname); ! 136: if (unlink(file) < 0) { ! 137: fprintf(stderr,"%s: unlink(%s): %s\n", Pname, file, errmsg(errno)); ! 138: return(FALSE); ! 139: } ! 140: } ! 141: goto loop2; ! 142: default: ! 143: fprintf(stderr,"%s: link(%s, %s): %s\n", Pname, tmp, file, errmsg(errno)); ! 144: return(FALSE); ! 145: } ! 146: } ! 147: if (unlink(tmp) < 0) { ! 148: fprintf(stderr,"%s: unlink(%s): %s\n", Pname, tmp, errmsg(errno)); ! 149: } ! 150: vprintf("%s: got lock <%s>\n", Pname, file); ! 151: return(TRUE); ! 152: } ! 153: ! 154: /* ! 155: ** Check the validity of an existing lock file. ! 156: ** ! 157: ** Read the PID out of the lock ! 158: ** Send a null signal to determine whether that PID still exists ! 159: ** Existence (or not) determines the validity of the lock. ! 160: ** ! 161: ** Two bigs wins to this algorithmn: ! 162: ** ! 163: ** o Locks do not survive crashes of either the system or the ! 164: ** application by any appreciable period of time. ! 165: ** ! 166: ** o No clean up to do if the system or application crashes. ! 167: ** ! 168: */ ! 169: ! 170: cklock(file) ! 171: char *file; ! 172: { ! 173: register int fd = open(file, O_RDONLY); ! 174: register int len; ! 175: char buf[BUFSIZ]; ! 176: ! 177: vprintf("%s: checking extant lock <%s>\n", Pname, file); ! 178: if (fd < 0) { ! 179: fprintf(stderr,"%s: open(%s): %s\n", Pname, file, errmsg(errno)); ! 180: return(TRUE); /* might or might not; conservatism */ ! 181: } ! 182: ! 183: if ((len = read(fd, buf, sizeof(buf))) <= 0) { ! 184: close(fd); ! 185: vprintf("%s: lock file format error\n", Pname); ! 186: return(FALSE); ! 187: } ! 188: close(fd); ! 189: buf[len + 1] = '\0'; ! 190: return(p_exists(atoi(buf))); ! 191: } ! 192: ! 193: /* ! 194: ** Does the PID exist? ! 195: ** Send null signal to find out. ! 196: */ ! 197: ! 198: p_exists(pid) ! 199: int pid; ! 200: { ! 201: vprintf("%s: locking process %d is ", Pname, pid); ! 202: if (kill(pid, 0) < 0) { ! 203: switch(errno) { ! 204: case ESRCH: ! 205: vprintf("dead\n"); ! 206: return(FALSE); /* pid does not exist */ ! 207: case EPERM: ! 208: vprintf("alive\n"); ! 209: return(TRUE); /* pid exists */ ! 210: default: ! 211: vprintf("state unknown: %s\n", errmsg(errno)); ! 212: return(TRUE); /* be conservative */ ! 213: } ! 214: } ! 215: vprintf("alive\n"); ! 216: return(TRUE); /* pid exists */ ! 217: } ! 218: ! 219: char * ! 220: errmsg(n) ! 221: register int n; ! 222: { ! 223: extern int sys_nerr; ! 224: extern char *sys_errlist[]; ! 225: ! 226: return((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error"); ! 227: } ! 228: ! 229: char * ! 230: tmpfile(file) ! 231: char *file; ! 232: { ! 233: register char *cp; ! 234: static char buf[BUFSIZ]; ! 235: char tempname[BUFSIZ]; ! 236: ! 237: if ((cp = rindex(strcpy(buf, file), '/')) != (char *)NULL) { ! 238: *(cp + 1) = '\0'; ! 239: } else ! 240: buf[0] = '\0'; ! 241: sprintf(tempname, "shlock%d", getpid()); ! 242: vprintf("%s: temporary filename: %s\n", Pname, tempname); ! 243: return(strcat(buf, tempname)); ! 244: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.