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