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