[comp.sources.misc] UUCP lock file cleaner-upper

allbery@ncoast.UUCP (11/02/87)

When uucico core dumps (an all to common occurence on our
system) it leaves an LCK.. file or two lying around. If
this happens at night and you only have one dialout line,
not much traffic moves until someone manually fixes things
up. Uulck is a little program I wrote to zap these stray
lock files. Run it once per hour from cron (I run it just
before our polling rounds at 10 to and 20 after the hour).
It's written for System V, but a BSD port is trivial (almost).


/*
 * @(#)uulck.c 1.1	(ncc!lyndon)
 *
 * Scan the UUCP spool directory for stray lock files
 * that don't belong to a currently running process
 * and remove them.
 *
 * Invoke it from cron, or run it out of your polling
 * scripts. There are no command line parameters.
 *
 * This program is in the public domain. You may copy it, sell
 * it, or do whatever else feels good with it. You also accept
 * any and all consequences of running this software.
 *
 * If you make any enhancements, I would appreciate receiving
 * a copy of them. Enjoy!
 *
 * Lyndon Nerenberg
 * Nexus Computing Inc.
 * {alberta,pyramid,uwvax}!ncc!lyndon
 *
 */

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/dir.h>

#define LOCKDIR	"/usr/spool/uucp/"	/* Need trailing '/'    */
#define LCKPFX		"LCK."
#define EVER		;;

main() {

int		spoolfd, lockfd;	/* One each for spool directory */
					/* and current lock file.       */
int		lockpid;		/* Holds pid from LCK file.     */
int		rc;			/* General purpose return code. */
register int	i;

struct direct	direntry;		/* Storage for directory entry. */

char		lockpath[ sizeof(LOCKDIR) + DIRSIZ + 1];


	spoolfd = open(LOCKDIR, O_RDONLY);

	if (spoolfd == -1) {
		if (isatty(2)) {
			fprintf(stderr, "[%s] ", LOCKDIR);
			perror("LOCKDIR open failed");
		}
		exit(1);
	}

	for (EVER) {

		rc = read(spoolfd, &direntry, sizeof(direntry));

		if (rc == 0)
			break;		/* Finished processing directory*/

		if (rc == -1) {
			if (isatty(2)) {
				fprintf(stderr, "[%s] ", LOCKDIR);
				perror("LOCKDIR read error");
			}
			exit(1);
		}

		if (direntry.d_ino == 0)
			continue;	/* Deleted entry */

		(void) strcpy(lockpath,LOCKDIR);

	/* Build the path string, and make sure it's terminated */

		for (i = 0; i < DIRSIZ; i++)
			lockpath[sizeof(LOCKDIR)+i-1] = direntry.d_name[i];

		lockpath[sizeof(LOCKDIR) + DIRSIZ + 1] = '\0';

		if (strncmp(LCKPFX, direntry.d_name, strlen(LCKPFX)) != 0)
			continue;

		lockfd = open(lockpath, O_RDONLY);

		if (lockfd == -1) {
			if (isatty(2)) {
				fprintf(stderr, "[%s] ", lockpath);
				perror("open failed");
			}
			continue;
		}

		rc = read(lockfd, &lockpid, 4);	/* Grab the process ID */

		if (rc == -1) {
			if (isatty(2)) {
				fprintf(stderr, "[%s] ", lockpath);
				perror("read failed");
			}
			(void) close(lockfd);
			continue;
		}

		if (rc != 4) {
			if (isatty(2))
				fprintf(stderr,
					"read returned %d bytes?!?\n",
					rc);
			(void) close(lockfd);
			continue;
		}

		(void) close(lockfd);	/* Done with the file */

		/* This is probably the ONLY thing I like about Sys V */

		rc = kill(lockpid, 0);

		if (rc == 0)
			continue;	/* Task exists */

		if ((rc == -1) && (errno == ESRCH)) {
			rc = unlink(lockpath);	/* Something died! */
			if ((rc == -1) && isatty(2)) {
				fprintf(stderr, "[%s] ", lockpath);
				perror("unlink failed");
			}
			continue;
		}

		/* We only get here if kill() failed in a strange way */

		if (isatty(2)) {
			fprintf(stderr, "lockpid = %d ", lockpid);
			perror("kill failed");
		}

		continue;
	}

	exit(0);
}