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