home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume14 / jove4.9 / part07 / recover.c < prev   
C/C++ Source or Header  |  1988-04-25  |  14KB  |  731 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* Recovers JOVE files after a system/editor crash.
  9.    Usage: recover [-d directory] [-syscrash]
  10.    The -syscrash option is specified in /etc/rc and what it does is
  11.    move all the jove tmp files from TMP_DIR to REC_DIR.
  12.  
  13.    The -d option lets you specify the directory to search for tmp files when
  14.    the default isn't the right one.
  15.  
  16.    Look in Makefile to change the default directories. */
  17.  
  18. #include <stdio.h>    /* Do stdio first so it doesn't override OUR
  19.                definitions. */
  20. #undef EOF
  21. #undef BUFSIZ
  22. #undef putchar
  23. #undef getchar
  24.  
  25. #define STDIO
  26.  
  27. #include "jove.h"
  28. #include "temp.h"
  29. #include "rec.h"
  30. #include <signal.h>
  31. #include <sys/file.h>
  32. #include <sys/stat.h>
  33. #include <sys/dir.h>
  34.  
  35. #ifndef L_SET
  36. #    define L_SET    0
  37. #    define L_INCR    1
  38. #endif
  39.  
  40. char    blk_buf[BUFSIZ];
  41. int    nleft;
  42. FILE    *ptrs_fp;
  43. int    data_fd;
  44. struct rec_head    Header;
  45. char    datafile[40],
  46.     pntrfile[40];
  47. long    Nchars,
  48.     Nlines;
  49. char    tty[] = "/dev/tty";
  50. int    UserID,
  51.     Verbose = 0;
  52. char    *Directory = 0;        /* the directory we're looking in */
  53.  
  54. struct file_pair {
  55.     char    *file_data,
  56.         *file_rec;
  57. #define INSPECTED    01
  58.     int    file_flags;
  59.     struct file_pair    *file_next;
  60. } *First = 0,
  61.   *Last = 0;
  62.  
  63. struct rec_entry    *buflist[100] = {0};
  64.  
  65. #ifndef BSD4_2
  66.  
  67. typedef struct {
  68.     int    d_fd;        /* File descriptor for this directory */
  69. } DIR;
  70.  
  71. DIR *
  72. opendir(dir)
  73. char    *dir;
  74. {
  75.     DIR    *dp = (DIR *) malloc(sizeof *dp);
  76.  
  77.     if ((dp->d_fd = open(dir, 0)) == -1)
  78.         return NULL;
  79.     return dp;
  80. }
  81.  
  82. closedir(dp)
  83. DIR    *dp;
  84. {
  85.     (void) close(dp->d_fd);
  86.     free(dp);
  87. }
  88.  
  89. struct direct *
  90. readdir(dp)
  91. DIR    *dp;
  92. {
  93.     static struct direct    dir;
  94.  
  95.     do
  96.         if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
  97.             return NULL;
  98. #if defined(elxsi) && defined(SYSV)
  99.     /*
  100.      * Elxsi has a BSD4.2 implementation which may or may not use
  101.      * `twisted inodes' ...  Anyone able to check?
  102.      */
  103.     while (*(unsigned short *)&dir.d_ino == 0);
  104. #else
  105.     while (dir.d_ino == 0);
  106. #endif
  107.  
  108.     return &dir;
  109. }
  110.  
  111. #endif /* BSD4_2 */
  112.  
  113. /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
  114.    long. */
  115.  
  116. getline(tl, buf)
  117. disk_line    tl;
  118. char    *buf;
  119. {
  120.     register char    *bp,
  121.             *lp;
  122.     register int    nl;
  123.     char    *getblock();
  124.  
  125.     lp = buf;
  126.     bp = getblock(tl >> 1);
  127.     nl = nleft;
  128.     tl = blk_round(tl);
  129.  
  130.     while (*lp++ = *bp++) {
  131.         if (--nl == 0) {
  132.             tl = forward_block(tl);
  133.             bp = getblock(tl >> 1);
  134.             nl = nleft;
  135.         }
  136.     }
  137. }
  138.  
  139. char *
  140. getblock(atl)
  141. disk_line    atl;
  142. {
  143.     int    bno,
  144.         off;
  145.     static int    curblock = -1;
  146.  
  147.     bno = da_to_bno(atl);
  148.     off = da_to_off(atl);
  149.     nleft = BUFSIZ - off;
  150.  
  151.     if (bno != curblock) {
  152.         lseek(data_fd, (long) bno * BUFSIZ, L_SET);
  153.         read(data_fd, blk_buf, BUFSIZ);
  154.         curblock = bno;
  155.     }
  156.     return blk_buf + off;
  157. }
  158.  
  159. char *
  160. copystr(s)
  161. char    *s;
  162. {
  163.     char    *str;
  164.  
  165.     str = malloc(strlen(s) + 1);
  166.     strcpy(str, s);
  167.  
  168.     return str;
  169. }
  170.  
  171. /* Scandir returns the number of entries or -1 if the directory cannoot
  172.    be opened or malloc fails. */
  173.  
  174. scandir(dir, nmptr, qualify, sorter)
  175. char    *dir;
  176. struct direct    ***nmptr;
  177. int    (*qualify)();
  178. struct direct    *(*sorter)();
  179. {
  180.     DIR    *dirp;
  181.     struct direct    *entry,
  182.             **ourarray;
  183.     int    nalloc = 10,
  184.         nentries = 0;
  185.  
  186.     if ((dirp = opendir(dir)) == NULL)
  187.         return -1;
  188.     ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
  189.     while ((entry = readdir(dirp)) != NULL) {
  190.         if (qualify != 0 && (*qualify)(entry) == 0)
  191.             continue;
  192.         if (nentries == nalloc) {
  193.             ourarray = (struct direct **) realloc(ourarray, (nalloc += 10) * sizeof (struct direct));
  194.             if (ourarray == NULL)
  195.                 return -1;
  196.         }
  197.         ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
  198.         *ourarray[nentries] = *entry;
  199.         nentries += 1;
  200.     }
  201.     closedir(dirp);
  202.     if (nentries != nalloc)
  203.         ourarray = (struct direct **) realloc(ourarray,
  204.                     (nentries * sizeof (struct direct)));
  205.     if (sorter != 0)
  206.         qsort(ourarray, nentries, sizeof (struct direct **), sorter);
  207.     *nmptr = ourarray;
  208.  
  209.     return nentries;
  210. }
  211.  
  212. alphacomp(a, b)
  213. struct direct    **a,
  214.         **b;
  215. {
  216.     return strcmp((*a)->d_name, (*b)->d_name);
  217. }
  218.  
  219. char    *CurDir;
  220.  
  221. /* Scan the DIRNAME directory for jove tmp files, and make a linked list
  222.    out of them. */
  223.  
  224. get_files(dirname)
  225. char    *dirname;
  226. {
  227.     int    add_name();
  228.     struct direct    **nmptr;
  229.  
  230.     CurDir = dirname;
  231.     scandir(dirname, &nmptr, add_name, (int (*)())0);
  232. }
  233.  
  234. add_name(dp)
  235. struct direct    *dp;
  236. {
  237.     char    dfile[128],
  238.         rfile[128];
  239.     struct file_pair    *fp;
  240.     struct rec_head        header;
  241.     int    fd;
  242.  
  243.     if (strncmp(dp->d_name, "jrec", 4) != 0)
  244.         return 0;
  245.     /* If we get here, we found a "recover" tmp file, so now
  246.        we look for the corresponding "data" tmp file.  First,
  247.        though, we check to see whether there is anything in
  248.        the "recover" file.  If it's 0 length, there's no point
  249.        in saving its name. */
  250.     (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
  251.     (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4);
  252.     if ((fd = open(rfile, 0)) != -1) {
  253.         if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
  254.             close(fd);
  255.                 return 0;
  256.         } else
  257.             close(fd);
  258.     }
  259.     if (access(dfile, 0) != 0) {
  260.         fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name);
  261.         fprintf(stderr, "so deleting...\n");
  262.         (void) unlink(rfile);
  263.         (void) unlink(dfile);
  264.         return 0;
  265.     }
  266.     /* If we get here, we've found both files, so we put them
  267.        in the list. */
  268.     fp = (struct file_pair *) malloc (sizeof *fp);
  269.     if ((char *) fp == 0) {
  270.         fprintf(stderr, "recover: cannot malloc for file_pair.\n");
  271.         exit(-1);
  272.     }
  273.     fp->file_data = copystr(dfile);
  274.     fp->file_rec = copystr(rfile);
  275.     fp->file_flags = 0;
  276.     fp->file_next = First;
  277.     First = fp;
  278.  
  279.     return 1;
  280. }
  281.  
  282. options()
  283. {
  284.     printf("Options are:\n");
  285.     printf("    ?        list options.\n");
  286.     printf("    get        get a buffer to a file.\n");
  287.     printf("    list        list known buffers.\n");
  288.     printf("    print        print a buffer to terminal.\n");
  289.     printf("    quit        quit and delete jove tmp files.\n");
  290.     printf("    restore        restore all buffers.\n");
  291. }
  292.  
  293. /* Returns a legitimate buffer # */
  294.  
  295. struct rec_entry **
  296. getsrc()
  297. {
  298.     char    name[128];
  299.     int    number;
  300.  
  301.     for (;;) {
  302.         tellme("Which buffer ('?' for list)? ", name);
  303.         if (name[0] == '?')
  304.             list();
  305.         else if (name[0] == '\0')
  306.             return 0;
  307.         else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
  308.             return &buflist[number];
  309.         else {
  310.             int    i;
  311.  
  312.             for (i = 1; i <= Header.Nbuffers; i++)
  313.                 if (strcmp(buflist[i]->r_bname, name) == 0)
  314.                     return &buflist[i];
  315.             printf("%s: unknown buffer.\n", name);
  316.         }
  317.     }
  318. }
  319.  
  320. /* Get a destination file name. */
  321.  
  322. static char *
  323. getdest()
  324. {
  325.     static char    filebuf[256];
  326.  
  327.     tellme("Output file: ", filebuf);
  328.     if (filebuf[0] == '\0')
  329.         return 0;
  330.     return filebuf;
  331. }
  332.  
  333. #include "ctype.h"
  334.  
  335. char *
  336. readword(buf)
  337. char    *buf;
  338. {
  339.     int    c;
  340.     char    *bp = buf;
  341.  
  342.     while (index(" \t\n", c = getchar()))
  343.         ;
  344.  
  345.     do {
  346.         if (index(" \t\n", c))
  347.             break;
  348.         *bp++ = c;
  349.     } while ((c = getchar()) != EOF);
  350.     *bp = 0;
  351.  
  352.     return buf;
  353. }
  354.  
  355. tellme(quest, answer)
  356. char    *quest,
  357.     *answer;
  358. {
  359.     if (stdin->_cnt <= 0) {
  360.         printf("%s", quest);
  361.         fflush(stdout);
  362.     }
  363.     readword(answer);
  364. }
  365.  
  366. /* Print the specified file to strandard output. */
  367.  
  368. jmp_buf    int_env;
  369.  
  370. catch()
  371. {
  372.     longjmp(int_env, 1);
  373. }
  374.  
  375. restore()
  376. {
  377.     register int    i;
  378.     char    tofile[100],
  379.         answer[30];
  380.     int    nrecovered = 0;
  381.  
  382.     for (i = 1; i <= Header.Nbuffers; i++) {
  383.         (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
  384. tryagain:
  385.         printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
  386.                              tofile);
  387.         tellme(" ", answer);
  388.         switch (answer[0]) {
  389.         case 'y':
  390.             break;
  391.  
  392.         case 'n':
  393.             continue;
  394.  
  395.         default:
  396.             tellme("What file should I use instead? ", tofile);
  397.             goto tryagain;
  398.         }
  399.         get(&buflist[i], tofile);
  400.         nrecovered += 1;
  401.     }
  402.     printf("Recovered %d buffers.\n", nrecovered);
  403. }
  404.  
  405. get(src, dest)
  406. struct rec_entry    **src;
  407. char    *dest;
  408. {
  409.     FILE    *outfile;
  410.  
  411.     if (src == 0 || dest == 0)
  412.         return;
  413.     (void) signal(SIGINT, catch);
  414.     if (setjmp(int_env) == 0) {
  415.         if ((outfile = fopen(dest, "w")) == NULL) {
  416.             printf("recover: cannot create %s.\n", dest);
  417.             return;
  418.         }
  419.         if (dest != tty)
  420.             printf("\"%s\"", dest);
  421.         dump_file(src - buflist, outfile);
  422.     } else
  423.         printf("\nAborted!\n");
  424.     fclose(outfile);
  425.     if (dest != tty)
  426.         printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
  427.     (void) signal(SIGINT, SIG_DFL);
  428. }
  429.  
  430. char **
  431. scanvec(args, str)
  432. register char    **args,
  433.         *str;
  434. {
  435.     while (*args) {
  436.         if (strcmp(*args, str) == 0)
  437.             return args;
  438.         args += 1;
  439.     }
  440.     return 0;
  441. }
  442.  
  443. read_rec(recptr)
  444. struct rec_entry    *recptr;
  445. {
  446.     if (fread((char *) recptr, sizeof *recptr, 1, ptrs_fp) != 1)
  447.         fprintf(stderr, "recover: cannot read record.\n");
  448. }
  449.  
  450. seekto(which)
  451. {
  452.     struct rec_entry    rec;
  453.     long    offset;
  454.     int    i;
  455.  
  456.     offset = sizeof (Header) + (Header.Nbuffers * sizeof (rec));
  457.     for (i = 1; i < which; i++)
  458.         offset += buflist[i]->r_nlines * sizeof (disk_line);
  459.     fseek(ptrs_fp, offset, L_SET);
  460. }
  461.  
  462. makblist()
  463. {
  464.     int    i;
  465.  
  466.     fseek(ptrs_fp, (long) sizeof (Header), L_SET);
  467.     for (i = 1; i <= Header.Nbuffers; i++) {
  468.         if (buflist[i] == 0)
  469.             buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
  470.         read_rec(buflist[i]);
  471.     }
  472.     while (buflist[i]) {
  473.         free((char *) buflist[i]);
  474.         buflist[i] = 0;
  475.         i += 1;
  476.     }
  477. }
  478.  
  479. disk_line
  480. getaddr(fp)
  481. register FILE    *fp;
  482. {
  483.     register int    nchars = sizeof (disk_line);
  484.     disk_line    addr;
  485.     register char    *cp = (char *) &addr;
  486.  
  487.     while (--nchars >= 0)
  488.         *cp++ = getc(fp);
  489.  
  490.     return addr;
  491. }
  492.  
  493. dump_file(which, out)
  494. FILE    *out;
  495. {
  496.     register int    nlines;
  497.     register disk_line    daddr;
  498.     char    buf[BUFSIZ];
  499.  
  500.     seekto(which);
  501.     nlines = buflist[which]->r_nlines;
  502.     Nchars = Nlines = 0L;
  503.     while (--nlines >= 0) {
  504.         daddr = getaddr(ptrs_fp);
  505.         getline(daddr, buf);
  506.         Nlines += 1;
  507.         Nchars += 1 + strlen(buf);
  508.         fputs(buf, out);
  509.         if (nlines > 0)
  510.             fputc('\n', out);
  511.     }
  512.     if (out != stdout)
  513.         fclose(out);
  514. }
  515.  
  516. /* List all the buffers. */
  517.  
  518. list()
  519. {
  520.     int    i;
  521.  
  522.     for (i = 1; i <= Header.Nbuffers; i++)
  523.         printf("%d) buffer %s  \"%s\" (%d lines)\n", i,
  524.             buflist[i]->r_bname,
  525.             buflist[i]->r_fname,
  526.             buflist[i]->r_nlines);
  527. }
  528.  
  529. doit(fp)
  530. struct file_pair    *fp;
  531. {
  532.     char    answer[30];
  533.     char    *datafile = fp->file_data,
  534.         *pntrfile = fp->file_rec;
  535.  
  536.     ptrs_fp = fopen(pntrfile, "r");
  537.     if (ptrs_fp == NULL) {
  538.         if (Verbose)
  539.             fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
  540.         return 0;
  541.     }
  542.     fread((char *) &Header, sizeof Header, 1, ptrs_fp);
  543.     if (Header.Uid != UserID)
  544.         return 0;
  545.  
  546.     /* Don't ask about JOVE's that are still running ... */
  547. #ifdef KILL0
  548.     if (kill(Header.Pid, 0) == 0)
  549.         return 0;
  550. #endif /* KILL0 */
  551.  
  552.     if (Header.Nbuffers == 0) {
  553.         printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
  554.         ask_del(" ", fp);
  555.         return 1;
  556.     }
  557.         
  558.     if (Header.Nbuffers < 0) {
  559.         fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
  560.         ask_del("Should I delete it? ", fp);
  561.         return 1;    /* We'll, we sort of found something. */
  562.     }
  563.     printf("Found %d buffer%s last updated: %s",
  564.         Header.Nbuffers,
  565.         Header.Nbuffers != 1 ? "s" : "",
  566.         ctime(&Header.UpdTime));
  567.     data_fd = open(datafile, 0);
  568.     if (data_fd == -1) {
  569.         fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
  570.         ask_del("Should I delete the tmp files? ", fp);
  571.         return 1;
  572.     }
  573.     makblist();
  574.     list();
  575.  
  576.     for (;;) {
  577.         tellme("(Type '?' for options): ", answer);
  578.         switch (answer[0]) {
  579.         case '\0':
  580.             continue;
  581.  
  582.         case '?':
  583.             options();
  584.             break;
  585.  
  586.         case 'l':
  587.             list();
  588.             break;
  589.  
  590.         case 'p':
  591.             get(getsrc(), tty);
  592.             break;
  593.  
  594.         case 'q':
  595.             ask_del("Shall I delete the tmp files? ", fp);
  596.             return 1;
  597.  
  598.         case 'g':
  599.             {    /* So it asks for src first. */
  600.                 char    *dest;
  601.                 struct rec_entry    **src;
  602.  
  603.                 if ((src = getsrc()) == 0)
  604.                     break;
  605.                 dest = getdest();
  606.             get(src, dest);
  607.             break;
  608.             }
  609.  
  610.         case 'r':
  611.             restore();
  612.             break;
  613.  
  614.         default:
  615.             printf("I don't know how to \"%s\"!\n", answer);
  616.             break;
  617.         }
  618.     }
  619. }
  620.  
  621. ask_del(prompt, fp)
  622. char    *prompt;
  623. struct file_pair    *fp;
  624. {
  625.     char    yorn[20];
  626.  
  627.     tellme(prompt, yorn);
  628.     if (yorn[0] == 'y')
  629.         del_files(fp);
  630. }
  631.  
  632. del_files(fp)
  633. struct file_pair    *fp;
  634. {
  635.     (void) unlink(fp->file_data);
  636.     (void) unlink(fp->file_rec);
  637. }
  638.  
  639. #ifdef notdef
  640. savetmps()
  641. {
  642.     struct file_pair    *fp;
  643.     int    status,
  644.         pid;
  645.  
  646.     if (strcmp(TMP_DIR, REC_DIR) == 0)
  647.         return;        /* Files are moved to the same place. */
  648.     get_files(TMP_DIR);
  649.     for (fp = First; fp != 0; fp = fp->file_next) {
  650.         switch (pid = fork()) {
  651.         case -1:
  652.             fprintf(stderr, "recover: can't fork\n!");
  653.             exit(-1);
  654.  
  655.         case 0:
  656.             execl("/bin/cp", "cp", fp->file_data, fp->file_rec, 
  657.                   REC_DIR, (char *)0);
  658.             fprintf(stderr, "recover: cannot execl /bin/cp.\n");
  659.             exit(-1);
  660.  
  661.         default:
  662.             while (wait(&status) != pid)
  663.                 ;
  664.             if (status != 0)
  665.                 fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
  666.         }
  667.     }
  668. }
  669. #endif
  670.  
  671. lookup(dir)
  672. char    *dir;
  673. {
  674.     struct file_pair    *fp;
  675.     struct rec_head        header;
  676.     char    yorn[20];
  677.     int    nfound = 0,
  678.         this_one;
  679.  
  680.     printf("Checking %s ...\n", dir);
  681.     Directory = dir;
  682.     get_files(dir);
  683.     for (fp = First; fp != 0; fp = fp->file_next) {
  684.         nfound += doit(fp);
  685.         if (ptrs_fp)
  686.             (void) fclose(ptrs_fp);
  687.         if (data_fd > 0)
  688.             (void) close(data_fd);
  689.     }
  690.     return nfound;
  691. }
  692.  
  693. main(argc, argv)
  694. int    argc;
  695. char    *argv[];
  696. {
  697.     int    nfound;
  698.     char    **argvp;
  699.  
  700.     UserID = getuid();
  701.  
  702.     if (scanvec(argv, "-help")) {
  703.         printf("recover: usage: recover [-d directory]\n");
  704.         printf("Use \"recover\" after JOVE has died for some\n");
  705.         printf("unknown reason.\n\n");
  706. /*        printf("Use \"recover -syscrash\" when the system is in the process\n");
  707.         printf("of rebooting.  This is done automatically at reboot time\n");
  708.         printf("and so most of you don't have to worry about that.\n\n");
  709.  */
  710.         printf("Use \"recover -d directory\" when the tmp files are store\n");
  711.         printf("in DIRECTORY instead of the default one (/tmp).\n");
  712.         exit(0);
  713.     }
  714.     if (scanvec(argv, "-v"))
  715.         Verbose = YES;
  716. /*    if (scanvec(argv, "-syscrash")) {
  717.         printf("Recovering jove files ... ");
  718.         savetmps();
  719.         printf("Done.\n");
  720.         exit(0);
  721.     } */
  722.     if (argvp = scanvec(argv, "-uid"))
  723.         UserID = atoi(argvp[1]);
  724.     if (argvp = scanvec(argv, "-d"))
  725.         nfound = lookup(argvp[1]);
  726.     else
  727.         nfound = lookup(TmpFilePath);
  728.     if (nfound == 0)
  729.         printf("There's nothing to recover.\n");
  730. }
  731.