home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / ex / expreserve.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  7KB  |  344 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <sys/dir.h>
  7. #include <pwd.h>
  8.  
  9. /*
  10.  * Expreserve - preserve a file in /usr/preserve
  11.  * Bill Joy UCB November 13, 1977
  12.  *
  13.  * This routine is very naive - it doesn't remove anything from
  14.  * /usr/preserve... this may mean that we will be unable to preserve
  15.  * stuff there... the danger in doing anything with /usr/preserve
  16.  * is that the clock may be screwed up and we may get confused.
  17.  *
  18.  * We are called in two ways - first from the editor with no argumentss
  19.  * and the standard input open on the temp file. Second with an argument
  20.  * to preserve the entire contents of /tmp (root only).
  21.  *
  22.  * BUG: should do something about preserving Rx... (register contents)
  23.  *      temporaries.
  24.  */
  25.  
  26. #define    LBLKS    125
  27. #define    FNSIZE    128
  28.  
  29. struct     header {
  30.     time_t    Time;            /* Time temp file last updated */
  31.     short    Uid;            /* This users identity */
  32.     short    Flines;            /* Number of lines in file */
  33.     char    Savedfile[FNSIZE];    /* The current file name */
  34.     short    Blocks[LBLKS];        /* Blocks where line pointers stashed */
  35. } H;
  36.  
  37. #ifdef    lint
  38. #define    ignore(a)    Ignore(a)
  39. #define    ignorl(a)    Ignorl(a)
  40. #else
  41. #define    ignore(a)    a
  42. #define    ignorl(a)    a
  43. #endif
  44.  
  45. struct    passwd *getpwuid();
  46. off_t    lseek();
  47. FILE    *popen();
  48.  
  49. #define eq(a, b) strcmp(a, b) == 0
  50.  
  51. main(argc)
  52.     int argc;
  53. {
  54.     register FILE *tf;
  55.     struct direct dirent;
  56.     struct stat stbuf;
  57.  
  58.     /*
  59.      * If only one argument, then preserve the standard input.
  60.      */
  61.     if (argc == 1) {
  62.         if (copyout((char *) 0))
  63.             exit(1);
  64.         exit(0);
  65.     }
  66.  
  67.     /*
  68.      * If not super user, then can only preserve standard input.
  69.      */
  70.     if (getuid()) {
  71.         fprintf(stderr, "NOT super user\n");
  72.         exit(1);
  73.     }
  74.  
  75.     /*
  76.      * ... else preserve all the stuff in /tmp, removing
  77.      * it as we go.
  78.      */
  79.     if (chdir("/tmp") < 0) {
  80.         perror("/tmp");
  81.         exit(1);
  82.     }
  83.  
  84.     tf = fopen(".", "r");
  85.     if (tf == NULL) {
  86.         perror("/tmp");
  87.         exit(1);
  88.     }
  89.     while (fread((char *) &dirent, sizeof dirent, 1, tf) == 1) {
  90.         if (dirent.d_ino == 0)
  91.             continue;
  92.         /*
  93.          * Ex temporaries must begin with Ex;
  94.          * we check that the 10th character of the name is null
  95.          * so we won't have to worry about non-null terminated names
  96.          * later on.
  97.          */
  98.         if (dirent.d_name[0] != 'E' || dirent.d_name[1] != 'x' || dirent.d_name[10])
  99.             continue;
  100.         if (stat(dirent.d_name, &stbuf))
  101.             continue;
  102.         if ((stbuf.st_mode & S_IFMT) != S_IFREG)
  103.             continue;
  104.         /*
  105.          * Save the bastard.
  106.          */
  107.         ignore(copyout(dirent.d_name));
  108.     }
  109.     exit(0);
  110. }
  111.  
  112. char    pattern[] =    "/usr/preserve/Exaa`XXXXX";
  113.  
  114. /*
  115.  * Copy file name into /usr/preserve/...
  116.  * If name is (char *) 0, then do the standard input.
  117.  * We make some checks on the input to make sure it is
  118.  * really an editor temporary, generate a name for the
  119.  * file (this is the slowest thing since we must stat
  120.  * to find a unique name), and finally copy the file.
  121.  */
  122. copyout(name)
  123.     char *name;
  124. {
  125.     int i;
  126.     static int reenter;
  127.     char buf[BUFSIZ];
  128.  
  129.     /*
  130.      * The first time we put in the digits of our
  131.      * process number at the end of the pattern.
  132.      */
  133.     if (reenter == 0) {
  134.         mkdigits(pattern);
  135.         reenter++;
  136.     }
  137.  
  138.     /*
  139.      * If a file name was given, make it the standard
  140.      * input if possible.
  141.      */
  142.     if (name != 0) {
  143.         ignore(close(0));
  144.         /*
  145.          * Need read/write access for arcane reasons
  146.          * (see below).
  147.          */
  148.         if (open(name, 2) < 0)
  149.             return (-1);
  150.     }
  151.  
  152.     /*
  153.      * Get the header block.
  154.      */
  155.     ignorl(lseek(0, 0l, 0));
  156.     if (read(0, (char *) &H, sizeof H) != sizeof H) {
  157. format:
  158.         if (name == 0)
  159.             fprintf(stderr, "Buffer format error\n");
  160.         return (-1);
  161.     }
  162.  
  163.     /*
  164.      * Consistency checsks so we don't copy out garbage.
  165.      */
  166.     if (H.Flines < 0) {
  167. #ifdef DEBUG
  168.         fprintf(stderr, "Negative number of lines\n");
  169. #endif
  170.         goto format;
  171.     }
  172.     if (H.Blocks[0] != 1 || H.Blocks[1] != 2) {
  173. #ifdef DEBUG
  174.         fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
  175. #endif
  176.         goto format;
  177.     }
  178.     if (name == 0 && H.Uid != getuid()) {
  179. #ifdef DEBUG
  180.         fprintf(stderr, "Wrong user-id\n");
  181. #endif
  182.         goto format;
  183.     }
  184.     if (lseek(0, 0l, 0)) {
  185. #ifdef DEBUG
  186.         fprintf(stderr, "Negative number of lines\n");
  187. #endif
  188.         goto format;
  189.     }
  190.  
  191.     /*
  192.      * If no name was assigned to the file, then give it the name
  193.      * LOST, by putting this in the header.
  194.      */
  195.     if (H.Savedfile[0] == 0) {
  196.         strcpy(H.Savedfile, "LOST");
  197.         ignore(write(0, (char *) &H, sizeof H));
  198.         H.Savedfile[0] = 0;
  199.         lseek(0, 0l, 0);
  200.     }
  201.  
  202.     /*
  203.      * File is good.  Get a name and create a file for the copy.
  204.      */
  205.     mknext(pattern);
  206.     ignore(close(1));
  207.     if (creat(pattern, 0600) < 0) {
  208.         if (name == 0)
  209.             perror(pattern);
  210.         return (1);
  211.     }
  212.  
  213.     /*
  214.      * Make the target be owned by the owner of the file.
  215.      */
  216.     ignore(chown(pattern, H.Uid, 0));
  217.  
  218.     /*
  219.      * Copy the file.
  220.      */
  221.     for (;;) {
  222.         i = read(0, buf, BUFSIZ);
  223.         if (i < 0) {
  224.             if (name)
  225.                 perror("Buffer read error");
  226.             ignore(unlink(pattern));
  227.             return (-1);
  228.         }
  229.         if (i == 0) {
  230.             if (name) {
  231.                 ignore(unlink(name));
  232.                 notify(H.Uid, H.Savedfile);
  233.             }
  234.             return (0);
  235.         }
  236.         if (write(1, buf, i) != i) {
  237.             if (name == 0)
  238.                 perror(pattern);
  239.             unlink(pattern);
  240.             return (-1);
  241.         }
  242.     }
  243. }
  244.  
  245. /*
  246.  * Blast the last 5 characters of cp to be the process number.
  247.  */
  248. mkdigits(cp)
  249.     char *cp;
  250. {
  251.     register int i, j;
  252.  
  253.     for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
  254.         *--cp = i % 10 | '0';
  255. }
  256.  
  257. /*
  258.  * Make the name in cp be unique by clobbering up to
  259.  * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
  260.  * Mktemp gets weird names too quickly to be useful here.
  261.  */
  262. mknext(cp)
  263.     char *cp;
  264. {
  265.     char *dcp;
  266.     struct stat stb;
  267.  
  268.     dcp = cp + strlen(cp) - 1;
  269.     while (isdigit(*dcp))
  270.         dcp--;
  271. whoops:
  272.     if (dcp[0] == 'z') {
  273.         dcp[0] = 'a';
  274.         if (dcp[-1] == 'z') {
  275.             dcp[-1] = 'a';
  276.             if (dcp[-2] == 'z')
  277.                 fprintf(stderr, "Can't find a name\n");
  278.             dcp[-2]++;
  279.         } else
  280.             dcp[-1]++;
  281.     } else
  282.         dcp[0]++;
  283.     if (stat(cp, &stb) == 0)
  284.         goto whoops;
  285. }
  286.  
  287. /*
  288.  * Notify user uid that his file fname has been saved.
  289.  */
  290. notify(uid, fname)
  291.     int uid;
  292.     char *fname;
  293. {
  294.     struct passwd *pp = getpwuid(uid);
  295.     register FILE *mf;
  296.     char cmd[BUFSIZ];
  297.  
  298.     if (pp == NULL)
  299.         return;
  300.     sprintf(cmd, "mail %s", pp->pw_name);
  301.     mf = popen(cmd, "w");
  302.     if (mf == NULL)
  303.         return;
  304.     setbuf(mf, cmd);
  305.     if (fname[0] == 0)
  306.         fprintf(mf,
  307. "A copy of an editor buffer of yours was saved when the system went down.\n\
  308. No name was associated with this buffer so it has been named \"LOST\".\n"
  309.         );
  310.     else
  311.         fprintf(mf,
  312. "A copy of an editor buffer of your file \"%s\"\n\
  313. was saved when the system went down.\n",
  314.         fname);
  315.     fprintf(mf,
  316. "This buffer can be retrieved using the \"recover\" command of the editor.\n\
  317. An easy way to do this is to give the command ``ex -r'' followed by the\n\
  318. name of file you were editing.  This works for ``edit'' and ``vi'' also.\n"
  319.         );
  320.     pclose(mf);
  321. }
  322.  
  323. /*
  324.  *    people making love
  325.  *    never exactly the same
  326.  *    just like a snowflake 
  327.  */
  328.  
  329. #ifdef lint
  330. Ignore(a)
  331.     int a;
  332. {
  333.  
  334.     a = a;
  335. }
  336.  
  337. Ignorl(a)
  338.     long a;
  339. {
  340.  
  341.     a = a;
  342. }
  343. #endif
  344.