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

Defined functions

Ignore defined in line 354; used 3 times
Ignorl defined in line 361; used 1 times
  • in line 58
copyout defined in line 141; used 2 times
main defined in line 70; never used
mkdigits defined in line 266; used 1 times
mknext defined in line 280; used 1 times
notify defined in line 308; used 1 times

Defined variables

H defined in line 54; used 17 times
pattern defined in line 131; used 8 times
sccsid defined in line 2; never used
xstr defined in line 19; never used

Defined struct's

header defined in line 44; never used

Defined macros

FNSIZE defined in line 42; used 1 times
  • in line 52
HBLKS defined in line 16; used 2 times
  • in line 191(2)
LBLKS defined in line 40; used 1 times
  • in line 53
TMP defined in line 11; used 3 times
eq defined in line 68; never used
ignore defined in line 60; used 7 times
ignorl defined in line 61; used 1 times
Last modified: 1983-12-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1214
Valid CSS Valid XHTML 1.0 Strict