From: Andrew Moore Date: Fri, 18 Jun 1993 02:06:57 +0000 (+0000) Subject: Upgrade elvispreserve to version 1.7 X-Git-Tag: FreeBSD-release/1.1~2688 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/e4b163b1bca2e4bfd8a658fbc99f30a7c503136d Upgrade elvispreserve to version 1.7 --- diff --git a/libexec/elvispreserve/Makefile b/libexec/elvispreserve/Makefile index 67e1ab03ee..3d868c9d7d 100644 --- a/libexec/elvispreserve/Makefile +++ b/libexec/elvispreserve/Makefile @@ -1,6 +1,8 @@ PROG= elvispreserve -CFLAGS= -I${.CURDIR}/../../usr.bin/elvis +CFLAGS+=-I${.CURDIR}/../../usr.bin/elvis +BINOWN= root +BINMODE=4755 MAN8=elvispreserve.0 .include diff --git a/libexec/elvispreserve/elvispreserve.8 b/libexec/elvispreserve/elvispreserve.8 index 9c7e74f974..ae4cdfbe5b 100644 --- a/libexec/elvispreserve/elvispreserve.8 +++ b/libexec/elvispreserve/elvispreserve.8 @@ -33,14 +33,14 @@ if your operating system normally supports mail. .SH FILES .IP /tmp/elv* The temporary file that \fIelvis\fP was using when it died. -.IP /usr/preserve/p* +.IP /var/preserve/p* The text that is preserved by \fIelvispreserve\fP. -.IP /usr/preserve/Index +.IP /var/preserve/Index A text file which lists the names of all preserved files, and the names -of the /usr/preserve/p* files which contain their preserved text. +of the /var/preserve/p* files which contain their preserved text. .SH BUGS .PP -Due to the permissions on the /usr/preserve directory, on UNIX systems +Due to the permissions on the /var/preserve directory, on UNIX systems \fIelvispreserve\fP must be run as superuser. This is accomplished by making the \fIelvispreserve\fP executable be owned by "root" and turning on its "set user id" bit. diff --git a/libexec/elvispreserve/elvispreserve.c b/libexec/elvispreserve/elvispreserve.c index b9e72725e1..f5a76e40b6 100644 --- a/libexec/elvispreserve/elvispreserve.c +++ b/libexec/elvispreserve/elvispreserve.c @@ -53,6 +53,17 @@ #include "config.h" #include "vi.h" +/* We include ctype.c here (instead of including just ctype.h and linking + * with ctype.o) because on some systems ctype.o will have been compiled in + * "large model" and the elvprsv program is to be compiled in "small model" + * You can't mix models. By including ctype.c here, we can avoid linking + * with ctype.o. + */ +#include "ctype.c" + +void preserve P_((char *, char *)); +void main P_((int, char **)); + #if AMIGA BLK tmpblk; # include "amiwild.c" @@ -121,7 +132,7 @@ void preserve(tname, when) || read(infd, name.c, BLKSIZE) != BLKSIZE) { /* something wrong with the file - sorry */ - fprintf(stderr, "%s: trucated header blocks\n", tname); + fprintf(stderr, "%s: truncated header blocks\n", tname); close(infd); return; } @@ -138,6 +149,16 @@ void preserve(tname, when) return; } + /* If there are no text blocks in the file, then we must've never + * really started editing. Discard the file. + */ + if (hdr.n[1] == 0) + { + close(infd); + unlink(tname); + return; + } + if (rewrite_now) { /* we don't need to open the index file */ @@ -147,7 +168,8 @@ void preserve(tname, when) for (i = 1; i < MAXBLKS && hdr.n[i]; i++) { lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); - if (read(infd, buf.c, BLKSIZE) != BLKSIZE) + if (read(infd, buf.c, BLKSIZE) != BLKSIZE + || buf.c[0] == '\0') { /* messed up header */ fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); @@ -172,9 +194,12 @@ void preserve(tname, when) if (!index) { perror(PRSVINDEX); - exit(1); + exit(2); } + /* should be at the end of the file already, but MAKE SURE */ + fseek(index, 0L, 2); + /* create the recovery file in the PRESVDIR directory */ #if AMIGA prsvdir = &PRSVDIR[strlen(PRSVDIR) - 1]; @@ -199,7 +224,8 @@ void preserve(tname, when) for (i = 1; i < MAXBLKS && hdr.n[i]; i++) { lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); - if (read(infd, buf.c, BLKSIZE) != BLKSIZE) + if (read(infd, buf.c, BLKSIZE) != BLKSIZE + || buf.c[0] == '\0') { /* messed up header */ fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); @@ -242,7 +268,7 @@ void preserve(tname, when) } } -main(argc, argv) +void main(argc, argv) int argc; char **argv; { @@ -251,10 +277,11 @@ main(argc, argv) #if MSDOS || TOS /* expand any wildcards in the command line */ + _ct_init(""); argv = wildexpand(&argc, argv); #endif - /* do we have a "when" argument? */ + /* do we have a "-c", "-R", or "-when elvis died" argument? */ i = 1; if (argc >= i + 1 && !strcmp(argv[i], "-R")) { diff --git a/libexec/elvispreserve/prsvunix.c b/libexec/elvispreserve/prsvunix.c new file mode 100644 index 0000000000..be954c2715 --- /dev/null +++ b/libexec/elvispreserve/prsvunix.c @@ -0,0 +1,226 @@ +/* prsvunix.c */ + +/* This file contains the UNIX-specific parts of the "elvprsv" program. */ + +#if OSK +#define ELVPRSV +#include "osk.c" +#else +#include +#include +#endif +#ifndef __STDC__ +/* some older systems don't declare this in pwd.h, I guess. */ +extern struct passwd *getpwuid(); +#endif + +#if ANY_UNIX /* { */ +/* Since elvprsv runs as SUID-root, we need a *secure* version of popen() */ +#define popen safe_popen +#define pclose safe_pclose + +/* This function is similar to the standard popen() function, except for... + * 1) It doesn't use the shell, for security reasons. + * 2) Shell services are not supported, including quoting. + * 3) The mode can only be "w". "r" is not supported. + * 4) No more than 9 arguments can be given, including the command. + */ +/*ARGSUSED*/ +static FILE *safe_popen(cmd, mode) + char *cmd; /* the filename of the program to be run */ + char *mode; /* "w", ignored */ +{ + char path[100];/* full pathname of argv[0] */ + char *argv[10];/* the arguments */ + int r0w1[2];/* the pipe fd's */ + int i; + FILE *fp; + + /* parse the arguments */ + for (i = 0; i < 9 && *cmd; i++) + { + /* remember where this arg starts */ + argv[i] = cmd; + + /* move to the end of the argument */ + do + { + cmd++; + } while (*cmd && *cmd != ' '); + + /* then mark end of arg & skip to next */ + while (*cmd && *cmd == ' ') + { + *cmd++ = '\0'; + } +printf("argv[%d]=\"%s\"\n", i, argv[i]); + } + argv[i] = (char *)0; + + /* make the pipe */ + if (pipe(r0w1) < 0) + { +perror("pipe()"); + return (FILE *)0; /* pipe failed */ + } + + switch (fork()) + { + case -1: /* error */ +perror("fork()"); + return (FILE *)0; + + case 0: /* child */ + /* close the "write" end of the pipe */ + close(r0w1[1]); + + /* redirect stdin to come from the "read" end of the pipe */ + close(0); + dup(r0w1[0]); + close(r0w1[0]); + + /* exec the shell to run the command */ + if (*argv[0] != '/') + { + /* no path, try "/bin/argv[0]" */ + strcpy(path, "/bin/"); + strcat(path, argv[0]); + execv(path, argv); +perror(path); + + /* if that failed, then try "/usr/bin/argv[0]" */ + strcpy(path, "/usr/bin/"); + strcat(path, argv[0]); + execv(path, argv); +perror(path); + } + else + { + /* full pathname given, so use it */ + execv(argv[0], argv); +perror(argv[0]); + } + + /* if we get here, exec failed */ + exit(1); + + default: /* parent */ + /* close the "read" end of the pipe */ + close(r0w1[0]); + + /* convert the "write" fd into a (FILE *) */ + fp = fdopen(r0w1[1], "w"); + return fp; + } + /*NOTREACHED*/ +} + + +/* This function closes the pipe opened by popen(), and returns 0 for success */ +static int safe_pclose(fp) + FILE *fp; /* value returned by popen() */ +{ + int status; + + /* close the file, and return the defunct child's exit status */ + fclose(fp); + wait(&status); + return status; +} +#endif /* } ANY UNIX */ + + +/* This variable is used to add extra error messages for mail sent to root */ +char *ps; + +/* This function returns the login name of the owner of a file */ +char *ownername(filename) + char *filename; /* name of a file */ +{ + struct stat st; + struct passwd *pw; + + /* stat the file, to get its uid */ + if (stat(filename, &st) < 0) + { + ps = "stat() failed"; + return "root"; + } + + /* get the /etc/passwd entry for that user */ + pw = getpwuid(st.st_uid); + if (!pw) + { + ps = "uid not found in password file"; + return "root"; + } + + /* return the user's name */ + return pw->pw_name; +} + + +/* This function sends a mail message to a given user, saying that a file + * has been preserved. + */ +void mail(user, file, when) + char *user; /* name of user who should receive the mail */ + char *file; /* name of original text file that was preserved */ + char *when; /* description of why the file was preserved */ +{ + char cmd[80];/* buffer used for constructing a "mail" command */ + FILE *m; /* stream used for giving text to the "mail" program */ + char *base; /* basename of the file */ + + /* separate the directory name from the basename. */ + for (base = file + strlen(file); --base > file && *base != SLASH; ) + { + } + if (*base == SLASH) + { + *base++ = '\0'; + } + + /* for anonymous buffers, pretend the name was "foo" */ + if (!strcmp(base, "*")) + { + base = "foo"; + } + + /* open a pipe to the "mail" program */ +#if OSK + sprintf(cmd, "mail \"-s=%s preserved!\" %s", base, user); +#else /* ANY_UNIX */ + sprintf(cmd, "mail -s Graceland %s", user); +#endif + m = popen(cmd, "w"); + if (!m) + { + perror(cmd); + /* Can't send mail! Hope the user figures it out. */ + return; + } + + /* Tell the user that the file was preserved */ + fprintf(m, "A version of your file \"%s%c%s\"\n", file, SLASH, base); + fprintf(m, "was preserved when %s.\n", when); + fprintf(m, "To recover this file, do the following:\n"); + fprintf(m, "\n"); +#if OSK + fprintf(m, " chd %s\n", file); +#else /* ANY_UNIX */ + fprintf(m, " cd %s\n", file); +#endif + fprintf(m, " elvisrecover %s\n", base); + fprintf(m, "\n"); + fprintf(m, "With fond wishes for a speedy recovery,\n"); + fprintf(m, " Elvis\n"); + if (ps) + { + fprintf(m, "\nP.S. %s\n", ps); + ps = (char *)0; + } + + /* close the stream */ + pclose(m); +}