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