Upgrade elvispreserve to version 1.7
authorAndrew Moore <alm@FreeBSD.org>
Fri, 18 Jun 1993 02:06:57 +0000 (02:06 +0000)
committerAndrew Moore <alm@FreeBSD.org>
Fri, 18 Jun 1993 02:06:57 +0000 (02:06 +0000)
libexec/elvispreserve/Makefile
libexec/elvispreserve/elvispreserve.8
libexec/elvispreserve/elvispreserve.c
libexec/elvispreserve/prsvunix.c [new file with mode: 0644]

index 67e1ab0..3d868c9 100644 (file)
@@ -1,6 +1,8 @@
 
 PROG=  elvispreserve
 
 PROG=  elvispreserve
-CFLAGS=        -I${.CURDIR}/../../usr.bin/elvis
+CFLAGS+=-I${.CURDIR}/../../usr.bin/elvis
+BINOWN=        root
+BINMODE=4755
 MAN8=elvispreserve.0
 
 .include <bsd.prog.mk>
 MAN8=elvispreserve.0
 
 .include <bsd.prog.mk>
index 9c7e74f..ae4cdfb 100644 (file)
@@ -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.
 .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.
 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
 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
 .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.
 \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.
index b9e7272..f5a76e4 100644 (file)
 #include "config.h"
 #include "vi.h"
 
 #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"
 #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 */
         || 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;
        }
                close(infd);
                return;
        }
@@ -138,6 +149,16 @@ void preserve(tname, when)
                return;
        }
 
                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 */
        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);
                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);
                        {
                                /* messed up header */
                                fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c);
@@ -172,9 +194,12 @@ void preserve(tname, when)
                if (!index)
                {
                        perror(PRSVINDEX);
                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];
                /* 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);
        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);
                {
                        /* 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;
 {
        int     argc;
        char    **argv;
 {
@@ -251,10 +277,11 @@ main(argc, argv)
 
 #if MSDOS || TOS
        /* expand any wildcards in the command line */
 
 #if MSDOS || TOS
        /* expand any wildcards in the command line */
+       _ct_init("");
        argv = wildexpand(&argc, argv);
 #endif
 
        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"))
        {
        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 (file)
index 0000000..be954c2
--- /dev/null
@@ -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 <sys/stat.h>
+#include <pwd.h>
+#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);
+}