# 2.11BSD#431 - /usr/src/ucb/ex/expreserve.c

##### Functions

    Ignore            X
    Ignorl            X
    copyout           X
    main              X
    mkdigits          X
    mknext            X
    notify            X

##### Variables

    H                 X
    copyright         X
    pattern           X
    xstr              X

##### Macros

    FNSIZE            X
    HBLKS             X
    LBLKS             X
    TMP               X
    eq                X
    ignore            X
    ignorl            X

##### struct's

    header            X

       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

- in line 70
- in /usr/src/ucb/ex/ex.h line 391

Ignorl defined in line 392; used 1 times

- in line 71

copyout defined in line 148; used 2 times

- in line 94, 132

main defined in line 83; never used
mkdigits defined in line 273; used 1 times

- in line 160

mknext defined in line 287; used 1 times

- in line 231

notify defined in line 315; used 1 times

- in line 258

#### Defined variables

H defined in line 67; used 18 times

- in line 182(3), 192, 198-204(5), 221-224(5), 242, 258(3)

copyright defined in line 8; never used
pattern defined in line 138; used 8 times

- in line 160, 231-235(3), 242, 252, 263-264(2)

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

- in line 111-112(2), 118

eq defined in line 81; never used
ignore defined in line 73; used 7 times

- in line 132, 169, 223, 232, 242, 252-257(2)

ignorl defined in line 74; used 1 times

- in line 181

Last modified: 1996-10-27 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2062 |