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

Defined functions

Ignore defined in line 385; used 2 times
Ignorl defined in line 392; used 1 times
  • in line 71
copyout defined in line 148; used 2 times
main defined in line 83; never used
mkdigits defined in line 273; used 1 times
mknext defined in line 287; used 1 times
notify defined in line 315; used 1 times

Defined variables

H defined in line 67; used 18 times
copyright defined in line 8; never used
pattern defined in line 138; used 8 times
sccsid defined in line 12; never used
xstr defined in line 31; never used

Defined struct's

header defined in line 57; never used

Defined macros

FNSIZE defined in line 55; used 1 times
  • in line 65
HBLKS defined in line 28; used 2 times
  • in line 198(2)
LBLKS defined in line 53; used 1 times
  • in line 66
TMP defined in line 23; used 3 times
eq defined in line 81; never used
ignore defined in line 73; used 7 times
ignorl defined in line 74; used 1 times
Last modified: 1996-10-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4405
Valid CSS Valid XHTML 1.0 Strict