1BSD/exrecover/expreserve.c

Compare this file to the similar file:
Show the results in this format:

#define	FNSIZE 64
/*
 * Expreserve - preserve a file in /usr/preserve
 * Bill Joy UCB November 13, 1977
 *
 * This routine is very naive - it doesn't remove anything from
 * /usr/preserve... this may mean that we will be unable to preserve
 * stuff there... the danger in doing anything with /usr/preserve
 * is that the clock may be screwed up and we may get confused.
 *
 * We are called in two ways - first from the editor with no argumentss
 * and the standard input open on the temp file. Second with an argument
 * to preserve the entire contents of /tmp (root only).
 */

struct stbuff {
	char	major, minor;
	int	inumber;
	int	flags;
	char	nlinks;
	char	uid, gid;
	char	size0;
	int	size1;
	int	addr[8];
	long	actime, modtime;
} stbuff;

int	mask	0377;

main(argc, argv)
	int argc;
	char *argv[];
{
	int tf;
	struct {
		int inum;
		char name[16];
	} dirent;
	char name[30];

	if (argc == 1) {
		if (copyout(0))
			exit(1);
		exit(0);
	}
	if (getuid() & mask) {
		write(2, "NOT super user\n", 15);
		exit(1);
	}
	if (chdir("/tmp") < 0) {
		perror("/tmp");
		exit(1);
	}
	tf = open(".", 0);
	if (tf < 0) {
		perror("/tmp");
		exit(1);
	}
	dirent.name[14] = 0;
	while(read(tf, &dirent, sizeof dirent - 2) == sizeof dirent - 2) {
		if (dirent.inum == 0)
			continue;
#define eq(a, b) strcmp(a, b) == 0
		if (eq(dirent.name, "."))
			continue;
		if (eq(dirent.name, ".."))
			continue;
		if (eq(dirent.name, ".q"))
			continue;
		if (stat(dirent.name, &stbuff))
			continue;
		if ((stbuff.flags & 060000) != 0)
			continue;
		if (dirent.name[0] != 'E' || dirent.name[1] != 'x')
			continue;
		copyout(dirent.name);
	}
	exit(0);
}

char	pattern[]	"/usr/preserve/Exaa`XXXXX";

copyout(name)
	char *name;
{
	int i;
	static char reenter;
	char buf[512];
	struct header {
		int	Atime[2];
		int	Auid;
		int	Alines;
		int	Afname[FNSIZE];
		int	Ablocks[100];
	} header;
	char *cp;

	if (reenter == 0) {
		mkdigits(pattern);
		reenter++;
	}
	if (name != 0) {
		close(0);
		if (open(name, 2) < 0)
			return (-1);
	}
	seek(0, 0, 0);
	if (read(0, &header, sizeof header) != sizeof header) {
format:
		if (name == 0)
			write(2, "Buffer format error\n", 20);
		return (-1);
	}
	if (header.Alines < 0)
		goto format;
	if (header.Ablocks[0] != 1 || header.Ablocks[1] != 2)
		goto format;
	if (name == 0 && header.Auid != (getuid() & mask))
		goto format;
	if (seek(0, 0, 0))
		goto format;
	if (header.Afname[0] == 0) {
		strcpy(header.Afname, "LOST");
		write(0, &header, sizeof header);
		header.Afname[0] = 0;
		seek(0, 0, 0);
	}
	mknext(pattern);
	close(1);
	if (creat(pattern, 0600) < 0) {
		if (name == 0)
			perror(pattern);
		return (1);
	}
	chown(pattern, header.Auid);
	for (;;) {
		i = read(0, buf, 512);
		if (i < 0) {
			if (name)
				perror("Buffer read error");
			unlink(cp);
			return (-1);
		}
		if (i == 0) {
			if (name) {
				unlink(name);
				notify(header.Auid, header.Afname);
			}
			return (0);
		}
		if (write(1, buf, i) != i) {
			if (name == 0)
				perror(pattern);
			unlink(cp);
			return (-1);
		}
	}
}

strcpy(to, from)
	char *to, *from;
{

	while (*to++ = *from++)
		continue;
}

strcmp(a, b)
	register char *a, *b;
{

	while (*a && *b && *a == *b)
		a++, b++;
	if (*a == 0 && *b == 0)
		return (0);
	return (*a - *b);
}

mkdigits(cp)
	char *cp;
{
	register int i, j;

	for (i = getpid(), j = 5, cp =+ strlen(cp); j > 0; i =/ 10, j--)
		*--cp = i % 10 | '0';
}

mknext(cp)
	char *cp;
{
	char *dcp;
	int spbuf[18];

	dcp = cp + strlen(cp) - 1;
	while (digit(*dcp))
		dcp--;
whoops:
	if (dcp[0] == 'z') {
		dcp[0] = 'a';
		if (dcp[-1] == 'z') {
			dcp[-1] = 'a';
			if (dcp[-2] == 'z')
				write(2, "Can't find a name\n", 17);
			dcp[-2]++;
		} else
			dcp[-1]++;
	} else
		dcp[0]++;
	if (stat(cp, spbuf) == 0)
		goto whoops;
}

digit(c)
	char c;
{

	return (c >= '0' && c <= '9');
}

notify(nuid, nfname)
	int nuid;
	char *nfname;
{
	register char *cp;
	char pwbuf[512];
	int pid, pvec[2];
	extern int fout;

	if (getpw(nuid, pwbuf) < 0)
		return;
	if (pipe(pvec) < 0)
		return;
	for (cp = pwbuf; *cp && *cp != ':'; cp++)
		continue;
	*cp = 0;
	pid = fork();
	if (pid < 0)
		return;
	if (pid == 0) {
		close(0);
		close(pvec[1]);
		dup(pvec[0]);
		close(pvec[0]);
		close(1);
		dup(2);
		execl("/bin/mail", "mail", pwbuf, 0);
		execl("/usr/bin/mail", "mail", pwbuf, 0);
		while (read(0, &pwbuf, 512) > 0)
			continue;
		exit(1);
	}
	close(pvec[0]);
	fout = pvec[1];
	if (nfname[0] == 0)
		printf(
"A copy of an editor buffer of yours was saved when the system went down.\n\
No name was associated with this buffer so it has been named \"LOST\".\n"
		);
	else
		printf(
"A copy of an editor buffer of your file \"%s\"\n\
was saved when the system went down.\n",
		nfname);
	printf(
"This buffer can be retrieved using the \"recover\" command of the editor.\n\
For more information enter the editor (edit or ex) and type \"help recover\".\n"
		);
	flush();
	close(pvec[1]);
	wait();
}