|
|
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.