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