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

Defined functions

Ignore defined in line 387; used 2 times
Ignorl defined in line 394; used 1 times
  • in line 73
copyout defined in line 150; used 2 times
main defined in line 85; never used
mkdigits defined in line 275; used 1 times
mknext defined in line 289; used 1 times
notify defined in line 317; used 1 times

Defined variables

H defined in line 69; used 18 times
copyright defined in line 8; never used
pattern defined in line 140; used 8 times
sccsid defined in line 14; never used
xstr defined in line 33; never used

Defined struct's

header defined in line 59; never used

Defined macros

FNSIZE defined in line 57; used 1 times
  • in line 67
HBLKS defined in line 30; used 2 times
  • in line 200(2)
LBLKS defined in line 55; used 1 times
  • in line 68
TMP defined in line 25; used 3 times
eq defined in line 83; never used
ignore defined in line 75; used 7 times
ignorl defined in line 76; used 1 times
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1954
Valid CSS Valid XHTML 1.0 Strict