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