|
|
1.1 root 1: /*
2: * lock.c
3: *
4: * Provide a locking mechanism for devices that may be used by
5: * UUCP. This is infact used by UUCP.
6: *
7: * Lock files are created in SPOOLDIR with the name LCK..resource. The
8: * contents of the lock file are a decimal representation of the pid of
9: * the process that created the lock.
10: *
11: * For a tty device, the "resource" is a string composed of a
12: * decimal representation of its major number, a decimal point, and
13: * the lower five bits of its minor number. This conversion is done
14: * by gen_res_name().
15: *
16: * Each routine takes a string which names a resource to be locked or
17: * unlocked. The tty routines want the base name of the tty to be locked
18: * (without the "/dev/" part).
19: *
20: * These routines all return 0 on failure and 1 on success.
21: *
22: * It is possible to provide an alternate pid by using one of the "n"
23: * routines. A pid of 0 provided to one of the unlocking routines
24: * is treated as an over-ride--the lock will be removed no matter
25: * what the pid of its creating process.
26: *
27: * Here are the lock/unlock pairs:
28: *
29: * locktty(ttyname) / unlocktty(ttyname)
30: * lockntty(ttyname, pid) / unlockntty(ttyname, pid)
31: * lockit(resource) / lockrm(resource)
32: * nlockit(resource, pid) / locknrm(resource, pid)
33: *
34: * These are for checking for the existence of locks:
35: * lockexist(resource)
36: * lockttyexist(ttyname)
37: */
38:
39: #include <stdio.h>
40: #include <sys/stat.h>
41: #include <unistd.h>
42:
43: static char *gen_res_name();
44:
45: #ifdef UUCP
46: #include "dcp.h"
47: #else
48: #define SPOOLDIR "/usr/spool/uucp"
49: #define LOCKSIG 9 /* Significant Chars of Lockable Resources. */
50: #define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */
51: #endif /* UUCP */
52:
53: #define LOCKDIR SPOOLDIR
54: #define LOCKPRE "LCK.."
55: #define PIDLEN 6 /* Maximum length of string representing a pid. */
56:
57: /* There is a special version of DEVMASK for the PE multiport driver
58: * because of the peculiar way it uses the minor device number. For
59: * all other drivers, the lower 5 bits describe the physical port--
60: * the upper 3 bits give attributes for the port.
61: */
62:
63: #define PE_DRIVER 21 /* Major device number for the PE driver. */
64: #define PE_DEVMASK 0x3f /* PE driver minor device mask. */
65: #define DEVMASK 0x1f /* Minor device mask. */
66:
67:
68: /*
69: * lockit(resource) char *resource;
70: *
71: * Lock the given resource--just like nlockit, but uses the current pid.
72: * Returns (0) if already locked or error in locking.
73: * (1) if all ok, resource locked.
74: */
75: int
76: lockit(resource)
77: char *resource;
78: {
79: return(nlockit(resource, getpid()));
80: } /* lockit() */
81:
82: /*
83: * nlockit(resource, pid) char *resource; int pid;
84: *
85: * Lock the given resource.
86: * Returns (0) if already locked or error in locking.
87: * (1) if all ok, resource locked.
88: */
89: int
90: nlockit(resource, pid)
91: char *resource;
92: int pid;
93: {
94:
95: int lockfd;
96: char lockfn[LOKFLEN];
97: char pidstring[PIDLEN];
98:
99: sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
100: if ( (access(lockfn, F_OK) == 0) ||
101: ((lockfd=creat(lockfn, 0644)) == -1) ) {
102: #ifdef UUCP
103: printmsg(M_DEBUG, "Can't lock: %s", lockfn);
104: #endif /* UUCP */
105: close(lockfd);
106: unlink(lockfn);
107: return(0);
108: }
109: #ifdef UUCP
110: printmsg(M_DEBUG, "Just created lock: %s", lockfn);
111: #endif /* UUCP */
112: sprintf(pidstring, "%d", pid);
113: if (-1 == write(lockfd, pidstring, strlen(pidstring))) {
114: close(lockfd);
115: unlink(lockfn);
116: return(0);
117: }
118: close(lockfd);
119: return(1);
120: } /* nlockit() */
121: /*
122: * lockrm(resource) char *resource;
123: *
124: * Simply remove the lock on the given resource.
125: * Returns (0) if not locked or error in unlocking.
126: * (1) if all ok, resource lock removed.
127: *
128: *
129: * Open the lock file for read operations to try to read the pid
130: * stored in the file. If the open fails, abort. If the read fails,
131: * abort. if the read pid does not match our pid, abort. We will only
132: * remove the lock if our pid matches the pid written to the file.
133: */
134:
135: lockrm(resource)
136: char *resource;
137: {
138: return(locknrm(resource, getpid()));
139: } /* lockrm() */
140:
141:
142: /*
143: * locknrm(resource, pid) char *resource;
144: *
145: * Remove the lock on the given resource, using pid as the process id to
146: * look for.
147: *
148: * Returns (0) if not locked or error in unlocking.
149: * (1) if all ok, resource lock removed.
150: *
151: * Open the lock file for read operations to try to read the pid
152: * stored in the file. If the open fails, abort. If the read fails,
153: * abort. If the read pid does not match our pid, abort. We will only
154: * remove the lock if the passed matches the pid written to the file, or
155: * if the passed pid is
156: */
157:
158: locknrm(resource, pid)
159: char *resource;
160: int pid;
161: {
162: int lockfd; /* pointer to file to read */
163: int chars_read; /* Number of characters read(). */
164:
165: char gotpid[PIDLEN + 1]; /* String value of the pid that should be stored
166: * in the lock file pointed to by *lockfp.
167: */
168: char lockfn[LOKFLEN];
169:
170: if (resource == NULL) {
171: #ifdef UUCP
172: plog(M_CALL, "Unlocking NULL resource.");
173: #endif /* UUCP */
174: return(1);
175: }
176:
177: sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
178:
179: /* open the lock file for read, abort on failure */
180: if(-1 == (lockfd = (open(lockfn, 0)))){
181: #ifdef UUCP
182: printmsg(M_DEBUG, "Error opening lock file for pid verify");
183: plog(M_CALL, "Error opening lock file for pid verify");
184: #endif /* UUCP */
185: close(lockfd);
186: return(0);
187: }
188:
189: /* read the contents of the file. Abort if empty */
190: if ( -1 == (chars_read = read(lockfd, gotpid, PIDLEN))) {
191: #ifdef UUCP
192: printmsg(M_DEBUG, "Lockrm: Error reading lock file for pid verify");
193: plog(M_CALL, "Lockrm: Error reading lock file for pid verify");
194: #endif /* UUCP */
195: close(lockfd);
196: return(0);
197: }
198:
199: gotpid[chars_read] = '\0'; /* NUL terminate the string. */
200: if (pid != 0 && atoi(gotpid) != pid){
201: #ifdef UUCP
202: printmsg(M_DEBUG, "Lockrm: pid verify failed. pid read was %s.",
203: gotpid);
204: plog(M_CALL, "Lockrm: pid verify failed. pid read was %s", gotpid);
205: #endif /* UUCP */
206: close(lockfd);
207: return(0);
208: }else{
209: #ifdef UUCP
210: printmsg(M_DEBUG, "Lockrm: pid verify successful, removing lock.");
211: plog(M_CALL, "Lockrm: pid verify successful, removing lock.");
212: #endif /* UUCP */
213:
214: if (unlink(lockfn) < 0) {
215: #ifdef UUCP
216: printmsg(M_DEBUG, "Lockrm: Error unlocking: %s", lockfn);
217: plog(M_CALL, "Lockrm: Error unlocking: %s", lockfn);
218: #endif /* UUCP */
219: close(lockfd);
220: return(0);
221: }
222: #ifdef UUCP
223: printmsg(M_DEBUG, "Just unlocked: %s", lockfn);
224: #endif /* UUCP */
225: close(lockfd);
226: return(1);
227: }
228: #ifdef UUCP
229: plog(M_CALL, "Unreachable code in locknrm().");
230: #endif /* UUCP */
231: } /* locknrm() */
232:
233: /*
234: * lockexist(resource) char *resource;
235: *
236: * Test for existance of a lock on the given resource.
237: *
238: * Returns: (1) Resource is locked.
239: * (0) Resource is not locked.
240: */
241:
242: lockexist(resource)
243: char *resource;
244: {
245: char lockfn[LOKFLEN];
246:
247: if ( resource == NULL )
248: return(0);
249: sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
250:
251: return (!access(lockfn, F_OK));
252: } /* lockexist() */
253:
254:
255: /*
256: * Attempt to lock a tty device. Takes the name of the tty itself
257: * otherwise behaves like lockit().
258: */
259: locktty(ttyname)
260: char *ttyname;
261: {
262: return(lockntty(ttyname, getpid()));
263: } /* locktty() */
264:
265: /*
266: * Attempt to lock a tty device. Takes the name of the tty itself and
267: * a pid, otherwise behaves like nlockit().
268: */
269: lockntty(ttyname, pid)
270: char *ttyname;
271: int pid;
272: {
273: char resource[LOKFLEN];
274: char filename[LOKFLEN];
275:
276: sprintf(filename, "/dev/%s", ttyname);
277: if (NULL == gen_res_name(filename, resource)){
278: return(0);
279: }
280: return(nlockit(resource, pid));
281:
282: } /* lockntty() */
283:
284: /*
285: * Unlock a tty device. Takes the name of the tty itself,
286: * otherwise behaves like lockrm().
287: */
288: unlocktty(ttyname)
289: char *ttyname;
290: {
291: return(unlockntty(ttyname, getpid()));
292: } /* unlocktty() */
293:
294: /*
295: * Unlock a tty device. Takes the name of the tty itself,
296: * otherwise behaves like locknrm().
297: */
298: unlockntty(ttyname, pid)
299: char *ttyname;
300: int pid;
301: {
302: char resource[LOKFLEN];
303: char filename[LOKFLEN];
304:
305: sprintf(filename, "/dev/%s", ttyname);
306: if (NULL == gen_res_name(filename, resource)){
307: #ifdef UUCP
308: plog(M_CALL, "Can't generate resource for %s.", ttyname);
309: #endif /* UUCP */
310: return(0);
311: }
312: return(locknrm(resource, pid));
313: } /* unlockntty() */
314:
315: /*
316: * lockttyexist(ttyname) char *ttyname;
317: *
318: * Test for existance of a lock on the given tty.
319: *
320: * Returns: (1) Resource is locked.
321: * (0) Resource is not locked.
322: */
323: lockttyexist(ttyname)
324: char *ttyname;
325: {
326: char resource[LOKFLEN];
327: char filename[LOKFLEN];
328:
329: sprintf(filename, "/dev/%s", ttyname);
330: if (NULL == gen_res_name(filename, resource)){
331: return(0); /* Non-existent tty can not be locked :-) */
332: }
333:
334: return(lockexist(resource));
335: } /* lockttyexist() */
336:
337: /*
338: * Generates a resource name for locking, based on the major number
339: * and the lower 4 bits of the minor number of the tty device.
340: *
341: * Builds the name in buff as two "." separated decimal numbers.
342: * Returns NULL on failure, buff on success.
343: */
344: static char *
345: gen_res_name(path, buff)
346: char *path;
347: char *buff;
348: {
349: struct stat sbuf;
350: int status;
351:
352: if (0 != (status = stat(path, &sbuf))) {
353: /* Can't stat the file. */
354: return (NULL);
355: }
356:
357: if (PE_DRIVER == major(sbuf.st_rdev)) {
358: sprintf(buff, "%d.%d", major(sbuf.st_rdev),
359: PE_DEVMASK & minor(sbuf.st_rdev));
360: } else {
361: sprintf(buff, "%d.%d", major(sbuf.st_rdev),
362: DEVMASK & minor(sbuf.st_rdev));
363: }
364:
365: return(buff);
366: } /* gen_res_name */
367:
368:
369: #ifdef PGM
370: static char _version[]="lock version 1.0";
371: /*
372: * executable file to lock and unlock uucp resources.
373: * must be owned by uucp and setuid.
374: */
375: main(argc, argv)
376: int argc;
377: char *argv[];
378: {
379: int c, rc;
380: extern char *optarg;
381: extern int optind;
382: static char umsg[] = "lock [-l dev][-u dev][-t dev]";
383:
384: for (rc = 0; EOF != (c = getopt(argc, argv, "l:u:t:"));) {
385: if (NULL == optarg || !*optarg)
386: usage(umsg);
387: /*
388: * Strip off a possible leading "/dev/".
389: */
390: if (0 == strncmp(optarg, "/dev/", strlen("/dev/") )) {
391: optarg += strlen("/dev/");
392: }
393:
394: switch (c) {
395: case 'l':
396: if (0 == lockntty(optarg, 0)) {
397: fprintf(stderr, "%s locked\n", optarg);
398: rc |= 1;
399: }
400: break;
401: case 'u':
402: unlockntty(optarg, 0);
403: break;
404: case 't':
405: rc |= lockttyexist(optarg);
406: break;
407: default:
408: usage(umsg);
409: }
410: }
411: if (optind < argc)
412: usage(umsg);
413: exit(rc);
414: }
415: #endif
416:
417: #ifdef TEST
418: #include <stdio.h>
419: #define LOCKSIG 9 /* Significant Chars of Lockable Resources. */
420: main(argc, argv)
421: int argc;
422: char *argv[];
423: {
424: char buffer[LOCKSIG + 1];
425: char path[LOKFLEN];
426:
427: if (argc != 2) {
428: fprintf(stderr, "Usage: %s ttyname\n", argv[0]);
429: exit(1);
430: }
431:
432: sprintf(path, "/dev/%s", argv[1]);
433:
434: if (NULL == gen_res_name(path, buffer)) {
435: fprintf(stderr, "%s: Can't stat %s.\n", argv[0], argv[1]);
436: exit(1);
437: }
438:
439: printf("Resource to lock: %s\n", buffer);
440:
441: if (-1 == locktty(argv[1])) {
442: fprintf(stderr, "%s: Can't lock %s.\n", argv[0], argv[1]);
443: exit(1);
444: }
445:
446: printf("I think I've locked %s.\n", argv[1]);
447:
448: if (lockttyexist(argv[1])) {
449: printf("Yep, %s is locked.\n", argv[1]);
450: } else {
451: fprintf(stderr, "%s: Failed to lock %s.\n", argv[0], argv[1]);
452: exit(1);
453: }
454:
455:
456: sprintf(path, "cat /usr/spool/uucp/LCK..%s", buffer);
457: printf("Contents of lock file: ");
458: fflush(stdout);
459: system(path);
460: printf("\n");
461:
462: if (-1 == unlocktty(argv[1])) {
463: fprintf(stderr, "%s: Problem removing lock on %s.\n", argv[0], argv[1]);
464: exit(1);
465: }
466:
467: printf("I think I've unlocked %s.\n", argv[1]);
468:
469: if (lockttyexist(argv[1])) {
470: fprintf(stderr, "%s: Failed to unlock %s.\n", argv[0], argv[1]);
471: exit(1);
472: } else {
473: printf("Successfully unlocked %s.\n", argv[1]);
474: }
475:
476: exit(0);
477: }
478: #endif /* TEST */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.