1: /* Copyright (c) 1979 Regents of the University of California */
   2: #ifdef V6
   3: #include <retrofit.h>
   4: #endif
   5: #include <stdio.h>
   6: #include <ctype.h>
   7: #include <sys/types.h>
   8: #include <sys/stat.h>
   9: #include <sys/dir.h>
  10: #include <pwd.h>
  11: #include "local/uparm.h"
  12: 
  13: /*
  14:  * Expreserve - preserve a file in usrpath(preserve)
  15:  * Bill Joy UCB November 13, 1977
  16:  *
  17:  * This routine is very naive - it doesn't remove anything from
  18:  * usrpath(preserve)... this may mean that we will be unable to preserve
  19:  * stuff there... the danger in doing anything with usrpath(preserve)
  20:  * is that the clock may be screwed up and we may get confused.
  21:  *
  22:  * We are called in two ways - first from the editor with no argumentss
  23:  * and the standard input open on the temp file. Second with an argument
  24:  * to preserve the entire contents of /tmp (root only).
  25:  *
  26:  * BUG: should do something about preserving Rx... (register contents)
  27:  *      temporaries.
  28:  */
  29: 
  30: #define LBLKS   125
  31: #define FNSIZE  128
  32: 
  33: struct  header {
  34:     time_t  Time;           /* Time temp file last updated */
  35:     short   Uid;            /* This users identity */
  36:     short   Flines;         /* Number of lines in file */
  37:     char    Savedfile[FNSIZE];  /* The current file name */
  38:     short   Blocks[LBLKS];      /* Blocks where line pointers stashed */
  39: } H;
  40: 
  41: #ifdef  lint
  42: #define ignore(a)   Ignore(a)
  43: #define ignorl(a)   Ignorl(a)
  44: #else
  45: #define ignore(a)   a
  46: #define ignorl(a)   a
  47: #endif
  48: 
  49: struct  passwd *getpwuid();
  50: #ifndef V6
  51: off_t   lseek();
  52: #endif
  53: FILE    *popen();
  54: 
  55: #define eq(a, b) strcmp(a, b) == 0
  56: 
  57: main(argc)
  58:     int argc;
  59: {
  60:     register FILE *tf;
  61:     struct direct dirent;
  62:     struct stat stbuf;
  63: 
  64:     /*
  65: 	 * If only one argument, then preserve the standard input.
  66: 	 */
  67:     if (argc == 1) {
  68:         if (copyout((char *) 0))
  69:             exit(1);
  70:         exit(0);
  71:     }
  72: 
  73:     /*
  74: 	 * If not super user, then can only preserve standard input.
  75: 	 */
  76:     if (getuid()) {
  77:         fprintf(stderr, "NOT super user\n");
  78:         exit(1);
  79:     }
  80: 
  81:     /*
  82: 	 * ... else preserve all the stuff in /tmp, removing
  83: 	 * it as we go.
  84: 	 */
  85:     if (chdir("/tmp") < 0) {
  86:         perror("/tmp");
  87:         exit(1);
  88:     }
  89: 
  90:     tf = fopen(".", "r");
  91:     if (tf == NULL) {
  92:         perror("/tmp");
  93:         exit(1);
  94:     }
  95:     while (fread((char *) &dirent, sizeof dirent, 1, tf) == 1) {
  96:         if (dirent.d_ino == 0)
  97:             continue;
  98:         /*
  99: 		 * Ex temporaries must begin with Ex;
 100: 		 * we check that the 10th character of the name is null
 101: 		 * so we won't have to worry about non-null terminated names
 102: 		 * later on.
 103: 		 */
 104:         if (dirent.d_name[0] != 'E' || dirent.d_name[1] != 'x' || dirent.d_name[10])
 105:             continue;
 106:         if (stat(dirent.d_name, &stbuf))
 107:         {
 108: #ifdef DEBUG
 109:             fprintf(stderr, "stat(%s) fails\n", dirent.d_name);
 110: #endif
 111:             continue;
 112:         }
 113:         if ((stbuf.st_mode & S_IFMT) != S_IFREG)
 114:         {
 115: #ifdef DEBUG
 116:             fprintf(stderr, "mode(%s) = %o\n", dirent.d_name, stbuf.st_mode);
 117: #endif
 118:             continue;
 119:         }
 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:         {
 166: #ifdef DEBUG
 167:             fprintf(stderr, "can't open %s\n", name);
 168: #endif
 169:             return (-1);
 170:         }
 171:     }
 172: 
 173:     /*
 174: 	 * Get the header block.
 175: 	 */
 176:     ignorl(lseek(0, (long) 0, 0));
 177:     if (read(0, (char *) &H, sizeof H) != sizeof H) {
 178: format:
 179:         if (name == 0)
 180:             fprintf(stderr, "Buffer format error\n");
 181:         return (-1);
 182:     }
 183: 
 184:     /*
 185: 	 * Consistency checsks so we don't copy out garbage.
 186: 	 */
 187:     if (H.Flines < 0) {
 188: #ifdef DEBUG
 189:         fprintf(stderr, "Negative number of lines (%d)\n", H.Flines);
 190: #endif
 191:         goto format;
 192:     }
 193:     if (H.Blocks[0] != 1 || H.Blocks[1] != 2) {
 194: #ifdef DEBUG
 195:         fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
 196: #endif
 197:         goto format;
 198:     }
 199:     if (name == 0 && H.Uid != getuid()) {
 200: #ifdef DEBUG
 201:         fprintf(stderr, "Wrong user-id\n");
 202: #endif
 203:         goto format;
 204:     }
 205:     if (lseek(0, (long) 0, 0)) {
 206: #ifdef DEBUG
 207:         fprintf(stderr, "Negative number of lines\n");
 208: #endif
 209:         goto format;
 210:     }
 211: 
 212:     /*
 213: 	 * If no name was assigned to the file, then give it the name
 214: 	 * LOST, by putting this in the header.
 215: 	 */
 216:     if (H.Savedfile[0] == 0) {
 217:         strcpy(H.Savedfile, "LOST");
 218:         ignore(write(0, (char *) &H, sizeof H));
 219:         H.Savedfile[0] = 0;
 220:         lseek(0, 0l, 0);
 221:     }
 222: 
 223:     /*
 224: 	 * File is good.  Get a name and create a file for the copy.
 225: 	 */
 226:     mknext(pattern);
 227:     ignore(close(1));
 228:     if (creat(pattern, 0600) < 0) {
 229:         if (name == 0)
 230:             perror(pattern);
 231:         return (1);
 232:     }
 233: 
 234:     /*
 235: 	 * Make the target be owned by the owner of the file.
 236: 	 */
 237:     ignore(chown(pattern, H.Uid, 0));
 238: 
 239:     /*
 240: 	 * Copy the file.
 241: 	 */
 242:     for (;;) {
 243:         i = read(0, buf, BUFSIZ);
 244:         if (i < 0) {
 245:             if (name)
 246:                 perror("Buffer read error");
 247:             ignore(unlink(pattern));
 248:             return (-1);
 249:         }
 250:         if (i == 0) {
 251:             if (name)
 252:                 ignore(unlink(name));
 253:             notify(H.Uid, H.Savedfile, (int) name);
 254:             return (0);
 255:         }
 256:         if (write(1, buf, i) != i) {
 257:             if (name == 0)
 258:                 perror(pattern);
 259:             unlink(pattern);
 260:             return (-1);
 261:         }
 262:     }
 263: }
 264: 
 265: /*
 266:  * Blast the last 5 characters of cp to be the process number.
 267:  */
 268: mkdigits(cp)
 269:     char *cp;
 270: {
 271:     register int i, j;
 272: 
 273:     for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
 274:         *--cp = i % 10 | '0';
 275: }
 276: 
 277: /*
 278:  * Make the name in cp be unique by clobbering up to
 279:  * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
 280:  * Mktemp gets weird names too quickly to be useful here.
 281:  */
 282: mknext(cp)
 283:     char *cp;
 284: {
 285:     char *dcp;
 286:     struct stat stb;
 287: 
 288:     dcp = cp + strlen(cp) - 1;
 289:     while (isdigit(*dcp))
 290:         dcp--;
 291: whoops:
 292:     if (dcp[0] == 'z') {
 293:         dcp[0] = 'a';
 294:         if (dcp[-1] == 'z') {
 295:             dcp[-1] = 'a';
 296:             if (dcp[-2] == 'z')
 297:                 fprintf(stderr, "Can't find a name\n");
 298:             dcp[-2]++;
 299:         } else
 300:             dcp[-1]++;
 301:     } else
 302:         dcp[0]++;
 303:     if (stat(cp, &stb) == 0)
 304:         goto whoops;
 305: }
 306: 
 307: /*
 308:  * Notify user uid that his file fname has been saved.
 309:  */
 310: notify(uid, fname, flag)
 311:     int uid;
 312:     char *fname;
 313: {
 314:     struct passwd *pp = getpwuid(uid);
 315:     register FILE *mf;
 316:     char cmd[BUFSIZ];
 317: 
 318:     if (pp == NULL)
 319:         return;
 320:     sprintf(cmd, "/bin/mail %s", pp->pw_name);
 321:     mf = popen(cmd, "w");
 322:     if (mf == NULL)
 323:         return;
 324:     setbuf(mf, cmd);
 325:     if (fname[0] == 0) {
 326:         fprintf(mf,
 327: "A copy of an editor buffer of yours was saved when %s.\n",
 328:         flag ? "the system went down" : "your phone was hung up");
 329:         fprintf(mf,
 330: "No name was associated with this buffer so it has been named \"LOST\".\n");
 331:     } else
 332:         fprintf(mf,
 333: "A copy of an editor buffer of your file \"%s\"\nwas saved when %s.\n", fname,
 334:         flag ? "the system went down" : "your phone was hung up");
 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

Defined functions

Ignore defined in line 351; used 2 times
Ignorl defined in line 358; used 1 times
  • in line 43
copyout defined in line 138; used 2 times
main defined in line 57; never used
mkdigits defined in line 268; used 1 times
mknext defined in line 282; used 1 times
notify defined in line 310; used 1 times

Defined variables

H defined in line 39; used 18 times
pattern defined in line 128; used 8 times

Defined struct's

header defined in line 33; never used

Defined macros

FNSIZE defined in line 31; used 1 times
  • in line 37
LBLKS defined in line 30; used 1 times
  • in line 38
eq defined in line 55; never used
ignore defined in line 45; used 7 times
ignorl defined in line 46; used 1 times
Last modified: 1983-12-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1024
Valid CSS Valid XHTML 1.0 Strict