|
|
1.1 ! root 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 it ! 11: move all the jove tmp files from TMP_DIR (/tmp) to REC_DIR (/usr/preserve). ! 12: recover -syscrash must be invoked in /ect/rc BEFORE /tmp gets cleared out. ! 13: (about the same place as expreserve gets invoked to save ed/vi/ex files. ! 14: ! 15: The -d option lets you specify the directory to search for tmp files when ! 16: the default isn't the right one. ! 17: ! 18: Look in Makefile to change the default directories. */ ! 19: ! 20: #include <stdio.h> /* Do stdio first so it doesn't override OUR ! 21: definitions. */ ! 22: #include "jove.h" ! 23: #include "temp.h" ! 24: #include "rec.h" ! 25: #include "rectune.h" ! 26: #include <signal.h> ! 27: #include <sys/file.h> ! 28: #include <sys/stat.h> ! 29: #include <sys/dir.h> ! 30: #include <pwd.h> ! 31: #include <time.h> ! 32: #ifdef SYSV ! 33: # include <sys/utsname.h> ! 34: #endif ! 35: ! 36: #ifndef L_SET ! 37: # define L_SET 0 ! 38: # define L_INCR 1 ! 39: #endif ! 40: ! 41: extern char *ctime proto((const time_t *)); ! 42: ! 43: private char blk_buf[JBUFSIZ]; ! 44: private int nleft; ! 45: private FILE *ptrs_fp; ! 46: private int data_fd; ! 47: private struct rec_head Header; ! 48: private long Nchars, ! 49: Nlines; ! 50: private char tty[] = "/dev/tty"; ! 51: private int UserID, ! 52: Verbose = 0; ! 53: private char *Directory = 0; /* the directory we're looking in */ ! 54: ! 55: private struct file_pair { ! 56: char *file_data, ! 57: *file_rec; ! 58: #define INSPECTED 01 ! 59: int file_flags; ! 60: struct file_pair *file_next; ! 61: } *First = 0; ! 62: ! 63: private struct rec_entry *buflist[100]; /* system initializes to 0 */ ! 64: ! 65: #ifndef BSD_DIR ! 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: private char *getblock proto((daddr atl)); ! 117: ! 118: void ! 119: getline(tl, buf) ! 120: daddr tl; ! 121: char *buf; ! 122: { ! 123: register char *bp, ! 124: *lp; ! 125: register int nl; ! 126: ! 127: lp = buf; ! 128: bp = getblock(tl >> 1); ! 129: nl = nleft; ! 130: tl = blk_round(tl); ! 131: ! 132: while ((*lp++ = *bp++) != '\0') { ! 133: if (--nl == 0) { ! 134: tl = forward_block(tl); ! 135: bp = getblock(tl >> 1); ! 136: nl = nleft; ! 137: } ! 138: } ! 139: } ! 140: ! 141: private char * ! 142: getblock(atl) ! 143: daddr atl; ! 144: { ! 145: int bno, ! 146: off; ! 147: static int curblock = -1; ! 148: ! 149: bno = da_to_bno(atl); ! 150: off = da_to_off(atl); ! 151: nleft = JBUFSIZ - off; ! 152: ! 153: if (bno != curblock) { ! 154: extern long lseek proto((int, long, int)); ! 155: ! 156: lseek(data_fd, (long) bno * JBUFSIZ, L_SET); ! 157: read(data_fd, blk_buf, (size_t)JBUFSIZ); ! 158: curblock = bno; ! 159: } ! 160: return blk_buf + off; ! 161: } ! 162: ! 163: char * ! 164: copystr(s) ! 165: char *s; ! 166: { ! 167: char *str; ! 168: ! 169: str = malloc((size_t) (strlen(s) + 1)); ! 170: strcpy(str, s); ! 171: ! 172: return str; ! 173: } ! 174: ! 175: /* Scandir returns the number of entries or -1 if the directory cannoot ! 176: be opened or malloc fails. */ ! 177: ! 178: private int ! 179: scandir(dir, nmptr, qualify, sorter) ! 180: char *dir; ! 181: struct direct ***nmptr; ! 182: int (*qualify) proto((struct direct *)); ! 183: int (*sorter) proto((UnivConstPtr, UnivConstPtr)); ! 184: { ! 185: DIR *dirp; ! 186: struct direct *entry, ! 187: **ourarray; ! 188: int nalloc = 10, ! 189: nentries = 0; ! 190: ! 191: if ((dirp = opendir(dir)) == NULL) ! 192: return -1; ! 193: ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *)); ! 194: while ((entry = readdir(dirp)) != NULL) { ! 195: if (qualify != NULL && (*qualify)(entry) == 0) ! 196: continue; ! 197: if (nentries == nalloc) { ! 198: ourarray = (struct direct **) realloc((char *)ourarray, ! 199: (nalloc += 10) * sizeof (struct direct)); ! 200: if (ourarray == NULL) ! 201: return -1; ! 202: } ! 203: ourarray[nentries] = (struct direct *) malloc(sizeof *entry); ! 204: *ourarray[nentries] = *entry; ! 205: nentries += 1; ! 206: } ! 207: closedir(dirp); ! 208: if (nentries != nalloc) ! 209: ourarray = (struct direct **) realloc((char *)ourarray, ! 210: (nentries * sizeof (struct direct))); ! 211: if (sorter != NULL) ! 212: qsort((UnivPtr)ourarray, (size_t) nentries, sizeof (struct direct **), sorter); ! 213: *nmptr = ourarray; ! 214: ! 215: return nentries; ! 216: } ! 217: ! 218: private char *CurDir; ! 219: ! 220: /* Scan the DIRNAME directory for jove tmp files, and make a linked list ! 221: out of them. */ ! 222: ! 223: private int add_name proto((struct direct *dp)); ! 224: ! 225: private void ! 226: get_files(dirname) ! 227: char *dirname; ! 228: { ! 229: struct direct **nmptr; ! 230: ! 231: CurDir = dirname; ! 232: First = NULL; ! 233: scandir(dirname, &nmptr, add_name, ! 234: (int (*) proto((UnivConstPtr, UnivConstPtr)))NULL); ! 235: } ! 236: ! 237: private int ! 238: add_name(dp) ! 239: struct direct *dp; ! 240: { ! 241: char dfile[128], ! 242: rfile[128]; ! 243: struct file_pair *fp; ! 244: struct rec_head header; ! 245: int fd; ! 246: ! 247: if (strncmp(dp->d_name, "jrec", (size_t)4) != 0) ! 248: return 0; ! 249: /* If we get here, we found a "recover" tmp file, so now ! 250: we look for the corresponding "data" tmp file. First, ! 251: though, we check to see whether there is anything in ! 252: the "recover" file. If it's 0 length, there's no point ! 253: in saving its name. */ ! 254: (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name); ! 255: (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4); ! 256: if ((fd = open(rfile, 0)) != -1) { ! 257: if ((read(fd, (char *) &header, sizeof header) != sizeof header)) { ! 258: close(fd); ! 259: return 0; ! 260: } else ! 261: close(fd); ! 262: } ! 263: if (access(dfile, 0) != 0) { ! 264: fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name); ! 265: fprintf(stderr, "so deleting...\n"); ! 266: (void) unlink(rfile); ! 267: (void) unlink(dfile); ! 268: return 0; ! 269: } ! 270: /* If we get here, we've found both files, so we put them ! 271: in the list. */ ! 272: fp = (struct file_pair *) malloc (sizeof *fp); ! 273: if ((char *) fp == 0) { ! 274: fprintf(stderr, "recover: cannot malloc for file_pair.\n"); ! 275: exit(-1); ! 276: } ! 277: fp->file_data = copystr(dfile); ! 278: fp->file_rec = copystr(rfile); ! 279: fp->file_flags = 0; ! 280: fp->file_next = First; ! 281: First = fp; ! 282: ! 283: return 1; ! 284: } ! 285: ! 286: private void ! 287: options() ! 288: { ! 289: printf("Options are:\n"); ! 290: printf(" ? list options.\n"); ! 291: printf(" get get a buffer to a file.\n"); ! 292: printf(" list list known buffers.\n"); ! 293: printf(" print print a buffer to terminal.\n"); ! 294: printf(" quit quit and delete jove tmp files.\n"); ! 295: printf(" restore restore all buffers.\n"); ! 296: } ! 297: ! 298: /* Returns a legitimate buffer # */ ! 299: ! 300: private void tellme proto((char *, char *)), ! 301: list proto((void)); ! 302: ! 303: private struct rec_entry ** ! 304: getsrc() ! 305: { ! 306: char name[128]; ! 307: int number; ! 308: ! 309: for (;;) { ! 310: tellme("Which buffer ('?' for list)? ", name); ! 311: if (name[0] == '?') ! 312: list(); ! 313: else if (name[0] == '\0') ! 314: return 0; ! 315: else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers) ! 316: return &buflist[number]; ! 317: else { ! 318: int i; ! 319: ! 320: for (i = 1; i <= Header.Nbuffers; i++) ! 321: if (strcmp(buflist[i]->r_bname, name) == 0) ! 322: return &buflist[i]; ! 323: printf("%s: unknown buffer.\n", name); ! 324: } ! 325: } ! 326: } ! 327: ! 328: /* Get a destination file name. */ ! 329: ! 330: static char * ! 331: getdest() ! 332: { ! 333: static char filebuf[256]; ! 334: ! 335: tellme("Output file: ", filebuf); ! 336: if (filebuf[0] == '\0') ! 337: return 0; ! 338: return filebuf; ! 339: } ! 340: ! 341: #include "ctype.h" ! 342: ! 343: private char * ! 344: readword(buf) ! 345: char *buf; ! 346: { ! 347: int c; ! 348: char *bp = buf; ! 349: ! 350: while (strchr(" \t\n", c = getchar())) ! 351: ; ! 352: ! 353: do { ! 354: if (strchr(" \t\n", c)) ! 355: break; ! 356: *bp++ = c; ! 357: } while ((c = getchar()) != EOF); ! 358: *bp = 0; ! 359: ! 360: return buf; ! 361: } ! 362: ! 363: private void ! 364: tellme(quest, answer) ! 365: char *quest, ! 366: *answer; ! 367: { ! 368: if (stdin->_cnt <= 0) { ! 369: printf("%s", quest); ! 370: fflush(stdout); ! 371: } ! 372: readword(answer); ! 373: } ! 374: ! 375: /* Print the specified file to standard output. */ ! 376: ! 377: private jmp_buf int_env; ! 378: ! 379: private SIGRESULT ! 380: catch(junk) ! 381: int junk; ! 382: { ! 383: longjmp(int_env, 1); ! 384: /*NOTREACHED*/ ! 385: } ! 386: ! 387: private void get proto((struct rec_entry **src, char *dest)); ! 388: ! 389: private void ! 390: restore() ! 391: { ! 392: register int i; ! 393: char tofile[100], ! 394: answer[30]; ! 395: int nrecovered = 0; ! 396: ! 397: for (i = 1; i <= Header.Nbuffers; i++) { ! 398: (void) sprintf(tofile, "#%s", buflist[i]->r_bname); ! 399: tryagain: ! 400: printf("Restoring %s to %s, okay?", buflist[i]->r_bname, ! 401: tofile); ! 402: tellme(" ", answer); ! 403: switch (answer[0]) { ! 404: case 'y': ! 405: break; ! 406: ! 407: case 'n': ! 408: continue; ! 409: ! 410: default: ! 411: tellme("What file should I use instead? ", tofile); ! 412: goto tryagain; ! 413: } ! 414: get(&buflist[i], tofile); ! 415: nrecovered += 1; ! 416: } ! 417: printf("Recovered %d buffers.\n", nrecovered); ! 418: } ! 419: ! 420: private void dump_file proto((int which, FILE *out)); ! 421: ! 422: private void ! 423: get(src, dest) ! 424: struct rec_entry **src; ! 425: char *dest; ! 426: { ! 427: FILE *outfile; ! 428: ! 429: if (src == 0 || dest == 0) ! 430: return; ! 431: (void) signal(SIGINT, catch); ! 432: if (setjmp(int_env) == 0) { ! 433: if (dest == tty) ! 434: outfile = stdout; ! 435: else { ! 436: if ((outfile = fopen(dest, "w")) == NULL) { ! 437: printf("recover: cannot create %s.\n", dest); ! 438: (void) signal(SIGINT, SIG_DFL); ! 439: return; ! 440: } ! 441: printf("\"%s\"", dest); ! 442: } ! 443: dump_file(src - buflist, outfile); ! 444: } else ! 445: printf("\nAborted!\n"); ! 446: (void) signal(SIGINT, SIG_DFL); ! 447: if (dest != tty) { ! 448: fclose(outfile); ! 449: printf(" %ld lines, %ld characters.\n", Nlines, Nchars); ! 450: } ! 451: } ! 452: ! 453: private char ** ! 454: scanvec(args, str) ! 455: register char **args, ! 456: *str; ! 457: { ! 458: while (*args) { ! 459: if (strcmp(*args, str) == 0) ! 460: return args; ! 461: args += 1; ! 462: } ! 463: return 0; ! 464: } ! 465: ! 466: private void ! 467: read_rec(recptr) ! 468: struct rec_entry *recptr; ! 469: { ! 470: if (fread((char *) recptr, sizeof *recptr, (size_t)1, ptrs_fp) != 1) ! 471: fprintf(stderr, "recover: cannot read record.\n"); ! 472: } ! 473: ! 474: private void ! 475: seekto(which) ! 476: int which; ! 477: { ! 478: long offset; ! 479: int i; ! 480: ! 481: offset = sizeof (Header) + (Header.Nbuffers * sizeof (struct rec_entry)); ! 482: for (i = 1; i < which; i++) ! 483: offset += buflist[i]->r_nlines * sizeof (daddr); ! 484: fseek(ptrs_fp, offset, L_SET); ! 485: } ! 486: ! 487: private void ! 488: makblist() ! 489: { ! 490: int i; ! 491: ! 492: fseek(ptrs_fp, (long) sizeof (Header), L_SET); ! 493: for (i = 1; i <= Header.Nbuffers; i++) { ! 494: if (buflist[i] == 0) ! 495: buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry)); ! 496: read_rec(buflist[i]); ! 497: } ! 498: while (buflist[i]) { ! 499: free((char *) buflist[i]); ! 500: buflist[i] = 0; ! 501: i += 1; ! 502: } ! 503: } ! 504: ! 505: private daddr ! 506: getaddr(fp) ! 507: register FILE *fp; ! 508: { ! 509: register int nchars = sizeof (daddr); ! 510: daddr addr; ! 511: register char *cp = (char *) &addr; ! 512: ! 513: while (--nchars >= 0) ! 514: *cp++ = getc(fp); ! 515: ! 516: return addr; ! 517: } ! 518: ! 519: private void ! 520: dump_file(which, out) ! 521: int which; ! 522: FILE *out; ! 523: { ! 524: register int nlines; ! 525: register daddr addr; ! 526: char buf[JBUFSIZ]; ! 527: ! 528: seekto(which); ! 529: nlines = buflist[which]->r_nlines; ! 530: Nchars = Nlines = 0L; ! 531: while (--nlines >= 0) { ! 532: addr = getaddr(ptrs_fp); ! 533: getline(addr, buf); ! 534: Nlines += 1; ! 535: Nchars += 1 + strlen(buf); ! 536: fputs(buf, out); ! 537: if (nlines > 0) ! 538: fputc('\n', out); ! 539: } ! 540: } ! 541: ! 542: /* List all the buffers. */ ! 543: ! 544: private void ! 545: list() ! 546: { ! 547: int i; ! 548: ! 549: for (i = 1; i <= Header.Nbuffers; i++) ! 550: printf("%d) buffer %s \"%s\" (%d lines)\n", i, ! 551: buflist[i]->r_bname, ! 552: buflist[i]->r_fname, ! 553: buflist[i]->r_nlines); ! 554: } ! 555: ! 556: private void ask_del proto((char *prompt, struct file_pair *fp)); ! 557: ! 558: private int ! 559: doit(fp) ! 560: struct file_pair *fp; ! 561: { ! 562: char answer[30]; ! 563: char *datafile = fp->file_data, ! 564: *pntrfile = fp->file_rec; ! 565: ! 566: ptrs_fp = fopen(pntrfile, "r"); ! 567: if (ptrs_fp == NULL) { ! 568: if (Verbose) ! 569: fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile); ! 570: return 0; ! 571: } ! 572: fread((char *) &Header, sizeof Header, (size_t)1, ptrs_fp); ! 573: if (Header.Uid != UserID) ! 574: return 0; ! 575: ! 576: /* Don't ask about JOVE's that are still running ... */ ! 577: #ifdef KILL0 ! 578: if (kill(Header.Pid, 0) == 0) ! 579: return 0; ! 580: #endif /* KILL0 */ ! 581: ! 582: if (Header.Nbuffers == 0) { ! 583: printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile); ! 584: ask_del(" ", fp); ! 585: return 1; ! 586: } ! 587: ! 588: if (Header.Nbuffers < 0) { ! 589: fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile); ! 590: ask_del("Should I delete it? ", fp); ! 591: return 1; /* We'll, we sort of found something. */ ! 592: } ! 593: printf("Found %d buffer%s last updated: %s", ! 594: Header.Nbuffers, ! 595: Header.Nbuffers != 1 ? "s" : "", ! 596: ctime(&Header.UpdTime)); ! 597: data_fd = open(datafile, 0); ! 598: if (data_fd == -1) { ! 599: fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile); ! 600: ask_del("Should I delete the tmp files? ", fp); ! 601: return 1; ! 602: } ! 603: makblist(); ! 604: list(); ! 605: ! 606: for (;;) { ! 607: tellme("(Type '?' for options): ", answer); ! 608: switch (answer[0]) { ! 609: case '\0': ! 610: continue; ! 611: ! 612: case '?': ! 613: options(); ! 614: break; ! 615: ! 616: case 'l': ! 617: list(); ! 618: break; ! 619: ! 620: case 'p': ! 621: get(getsrc(), tty); ! 622: break; ! 623: ! 624: case 'q': ! 625: ask_del("Shall I delete the tmp files? ", fp); ! 626: return 1; ! 627: ! 628: case 'g': ! 629: { /* So it asks for src first. */ ! 630: char *dest; ! 631: struct rec_entry **src; ! 632: ! 633: if ((src = getsrc()) == 0) ! 634: break; ! 635: dest = getdest(); ! 636: get(src, dest); ! 637: break; ! 638: } ! 639: ! 640: case 'r': ! 641: restore(); ! 642: break; ! 643: ! 644: default: ! 645: printf("I don't know how to \"%s\"!\n", answer); ! 646: break; ! 647: } ! 648: } ! 649: } ! 650: ! 651: private void del_files proto((struct file_pair *fp)); ! 652: ! 653: private void ! 654: ask_del(prompt, fp) ! 655: char *prompt; ! 656: struct file_pair *fp; ! 657: { ! 658: char yorn[20]; ! 659: ! 660: tellme(prompt, yorn); ! 661: if (yorn[0] == 'y') ! 662: del_files(fp); ! 663: } ! 664: ! 665: private void ! 666: del_files(fp) ! 667: struct file_pair *fp; ! 668: { ! 669: (void) unlink(fp->file_data); ! 670: (void) unlink(fp->file_rec); ! 671: } ! 672: ! 673: ! 674: ! 675: MailUser(rec) ! 676: struct rec_head *rec; ! 677: { ! 678: #ifdef SYSV ! 679: struct utsname mach; ! 680: #else ! 681: char mach[BUFSIZ]; ! 682: #endif ! 683: char mail_cmd[BUFSIZ]; ! 684: char *last_update; ! 685: char *buf_string; ! 686: FILE *mail_pipe; ! 687: struct passwd *pw; ! 688: extern struct passwd *getpwuid proto((int)); ! 689: ! 690: if ((pw = getpwuid(rec->Uid))== NULL) ! 691: return; ! 692: #ifdef SYSV ! 693: if (uname(&mach) < 0) ! 694: strcpy(mach.sysname, "unknown"); ! 695: #else ! 696: gethostname(mach, sizeof(mach)); ! 697: #endif ! 698: last_update = ctime(&(rec->UpdTime)); ! 699: /* Start up mail */ ! 700: sprintf(mail_cmd, "/bin/mail %s", pw->pw_name); ! 701: setuid(getuid()); ! 702: if ((mail_pipe = popen(mail_cmd, "w")) == NULL) ! 703: return; ! 704: setbuf(mail_pipe, mail_cmd); ! 705: /* Let's be grammatically correct! */ ! 706: if (rec->Nbuffers == 1) ! 707: buf_string = "buffer"; ! 708: else ! 709: buf_string = "buffers"; ! 710: fprintf(mail_pipe, "Subject: System crash\n"); ! 711: fprintf(mail_pipe, " \n"); ! 712: fprintf(mail_pipe, "Jove saved %d %s when the system \"%s\"\n", ! 713: rec->Nbuffers, buf_string, ! 714: #ifdef SYSV ! 715: mach.sysname ! 716: #else ! 717: mach ! 718: #endif ! 719: ); ! 720: fprintf(mail_pipe, "crashed on %s\n\n", last_update); ! 721: fprintf(mail_pipe, "You can retrieve the %s using Jove's -r\n", ! 722: buf_string); ! 723: fprintf(mail_pipe, "(recover option) i.e. give the command.\n"); ! 724: fprintf(mail_pipe, "\tjove -r\n"); ! 725: fprintf(mail_pipe, "See the Jove manual for more details\n"); ! 726: pclose(mail_pipe); ! 727: } ! 728: ! 729: ! 730: savetmps() ! 731: { ! 732: struct file_pair *fp; ! 733: int status, ! 734: pid, ! 735: fd; ! 736: struct rec_head header; ! 737: char buf[BUFSIZ]; ! 738: char *fname; ! 739: struct stat stbuf; ! 740: ! 741: if (strcmp(TMP_DIR, REC_DIR) == 0) ! 742: return; /* Files are moved to the same place. */ ! 743: get_files(TMP_DIR); ! 744: for (fp = First; fp != 0; fp = fp->file_next) { ! 745: stat(fp->file_data, &stbuf); ! 746: switch (pid = fork()) { ! 747: case -1: ! 748: fprintf(stderr, "recover: can't fork\n!"); ! 749: exit(-1); ! 750: ! 751: case 0: ! 752: fprintf(stderr, "Recovering: %s, %s\n", fp->file_data, ! 753: fp->file_rec); ! 754: if ((fd = open(fp->file_rec, 0)) != -1) { ! 755: if ((read(fd, (char *) &header, sizeof header) != sizeof header)) { ! 756: close(fd); ! 757: return 0; ! 758: } else ! 759: close(fd); ! 760: } ! 761: MailUser(&header); ! 762: execl("/bin/mv", "mv", fp->file_data, fp->file_rec, ! 763: REC_DIR, (char *)0); ! 764: fprintf(stderr, "recover: cannot execl /bin/mv.\n"); ! 765: exit(-1); ! 766: ! 767: default: ! 768: while (wait(&status) != pid) ! 769: ; ! 770: if (status != 0) ! 771: fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status); ! 772: fname = fp->file_data + strlen(TMP_DIR); ! 773: strcpy(buf, REC_DIR); ! 774: strcat(buf, fname); ! 775: if(chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0) ! 776: perror("recover: chown failed."); ! 777: fname = fp->file_rec + strlen(TMP_DIR); ! 778: strcpy(buf, REC_DIR); ! 779: strcat(buf, fname); ! 780: if(chown(buf, (int) stbuf.st_uid, (int) stbuf.st_gid) != 0) ! 781: perror("recover: chown failed."); ! 782: } ! 783: } ! 784: } ! 785: ! 786: private int ! 787: lookup(dir) ! 788: char *dir; ! 789: { ! 790: struct file_pair *fp; ! 791: int nfound = 0; ! 792: ! 793: printf("Checking %s ...\n", dir); ! 794: Directory = dir; ! 795: get_files(dir); ! 796: for (fp = First; fp != 0; fp = fp->file_next) { ! 797: nfound += doit(fp); ! 798: if (ptrs_fp) ! 799: (void) fclose(ptrs_fp); ! 800: if (data_fd > 0) ! 801: (void) close(data_fd); ! 802: } ! 803: return nfound; ! 804: } ! 805: ! 806: void ! 807: main(argc, argv) ! 808: int argc; ! 809: char *argv[]; ! 810: { ! 811: int nfound; ! 812: char **argvp; ! 813: char *tmp_dir; ! 814: ! 815: UserID = getuid(); ! 816: ! 817: if (scanvec(argv, "-help")) { ! 818: printf("recover: usage: recover [-d directory] [-syscrash]\n"); ! 819: printf("Use \"jove -r\" after JOVE has died for some\n"); ! 820: printf("unknown reason.\n\n"); ! 821: printf("Use \"%s -syscrash\"\n", Recover); ! 822: printf("when the system is in the process of rebooting."); ! 823: printf("This is done automatically at reboot time\n"); ! 824: printf("and so most of you don't have to worry about that.\n\n"); ! 825: printf("Use \"recover -d directory\" when the tmp files are store\n"); ! 826: printf("in DIRECTORY instead of the default one (/tmp).\n"); ! 827: exit(0); ! 828: } ! 829: if (scanvec(argv, "-v")) ! 830: Verbose = YES; ! 831: if (scanvec(argv, "-syscrash")) { ! 832: printf("Recovering jove files ... "); ! 833: savetmps(); ! 834: printf("Done.\n"); ! 835: exit(0); ! 836: } ! 837: if ((argvp = scanvec(argv, "-uid")) != NULL) ! 838: UserID = atoi(argvp[1]); ! 839: if ((argvp = scanvec(argv, "-d")) != NULL) ! 840: tmp_dir = argvp[1]; ! 841: else ! 842: tmp_dir = TmpFilePath; ! 843: /* Check default directory */ ! 844: nfound = lookup(tmp_dir); ! 845: /* Check whether anything was saved when system died? */ ! 846: if (strcmp(tmp_dir, REC_DIR) != 0) ! 847: nfound += lookup(REC_DIR); ! 848: if (nfound == 0) ! 849: printf("There's nothing to recover.\n"); ! 850: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.