Annotation of 43BSDReno/usr.bin/ex/ex3.7preserve/ex3.7preserve.c, revision 1.1.1.1

1.1       root        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.15 (Berkeley) 11/14/89";
                     15: #endif not lint
                     16: 
                     17: #include <sys/param.h>
                     18: #include <sys/stat.h>
                     19: #include <sys/dir.h>
                     20: #include <pwd.h>
                     21: #include <stdio.h>
                     22: #include <ctype.h>
                     23: #include "pathnames.h"
                     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 _PATH_PRESERVE.
                     35:  * Bill Joy UCB November 13, 1977
                     36:  *
                     37:  * This routine is very naive - it doesn't remove anything from
                     38:  * _PATH_PRESERVE... this may mean that we leave
                     39:  * stuff there... the danger in doing anything with _PATH_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(_PATH_VARTMP) < 0) {
                    112:                perror(_PATH_VARTMP);
                    113:                exit(1);
                    114:        }
                    115: 
                    116:        tf = opendir(".");
                    117:        if (tf == NULL) {
                    118:                perror(_PATH_VARTMP);
                    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[MAXPATHLEN];
                    139: 
                    140: /*
                    141:  * Copy file name into pattern[].
                    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:        (void)sprintf(pattern, "%s/Exaa`XXXXX", _PATH_PRESERVE);
                    156:        /*
                    157:         * The first time we put in the digits of our
                    158:         * process number at the end of the pattern.
                    159:         */
                    160:        if (reenter == 0) {
                    161:                mkdigits(pattern);
                    162:                reenter++;
                    163:        }
                    164: 
                    165:        /*
                    166:         * If a file name was given, make it the standard
                    167:         * input if possible.
                    168:         */
                    169:        if (name != 0) {
                    170:                ignore(close(0));
                    171:                /*
                    172:                 * Need read/write access for arcane reasons
                    173:                 * (see below).
                    174:                 */
                    175:                if (open(name, 2) < 0)
                    176:                        return (-1);
                    177:        }
                    178: 
                    179:        /*
                    180:         * Get the header block.
                    181:         */
                    182:        ignorl(lseek(0, 0l, 0));
                    183:        if (read(0, (char *) &H, sizeof H) != sizeof H) {
                    184: format:
                    185:                if (name == 0)
                    186:                        fprintf(stderr, "Buffer format error\t");
                    187:                return (-1);
                    188:        }
                    189: 
                    190:        /*
                    191:         * Consistency checsks so we don't copy out garbage.
                    192:         */
                    193:        if (H.Flines < 0) {
                    194: #ifdef DEBUG
                    195:                fprintf(stderr, "Negative number of lines\n");
                    196: #endif
                    197:                goto format;
                    198:        }
                    199:        if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
                    200: #ifdef DEBUG
                    201:                fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
                    202: #endif
                    203:                goto format;
                    204:        }
                    205:        if (name == 0 && H.Uid != getuid()) {
                    206: #ifdef DEBUG
                    207:                fprintf(stderr, "Wrong user-id\n");
                    208: #endif
                    209:                goto format;
                    210:        }
                    211:        if (lseek(0, 0l, 0)) {
                    212: #ifdef DEBUG
                    213:                fprintf(stderr, "Negative number of lines\n");
                    214: #endif
                    215:                goto format;
                    216:        }
                    217: 
                    218:        /*
                    219:         * If no name was assigned to the file, then give it the name
                    220:         * LOST, by putting this in the header.
                    221:         */
                    222:        if (H.Savedfile[0] == 0) {
                    223:                strcpy(H.Savedfile, "LOST");
                    224:                ignore(write(0, (char *) &H, sizeof H));
                    225:                H.Savedfile[0] = 0;
                    226:                lseek(0, 0l, 0);
                    227:        }
                    228: 
                    229:        /*
                    230:         * File is good.  Get a name and create a file for the copy.
                    231:         */
                    232:        mknext(pattern);
                    233:        ignore(close(1));
                    234:        if (creat(pattern, 0600) < 0) {
                    235:                if (name == 0)
                    236:                        perror(pattern);
                    237:                return (1);
                    238:        }
                    239: 
                    240:        /*
                    241:         * Make the target be owned by the owner of the file.
                    242:         */
                    243:        ignore(chown(pattern, H.Uid, 0));
                    244: 
                    245:        /*
                    246:         * Copy the file.
                    247:         */
                    248:        for (;;) {
                    249:                i = read(0, buf, BUFSIZ);
                    250:                if (i < 0) {
                    251:                        if (name)
                    252:                                perror("Buffer read error");
                    253:                        ignore(unlink(pattern));
                    254:                        return (-1);
                    255:                }
                    256:                if (i == 0) {
                    257:                        if (name)
                    258:                                ignore(unlink(name));
                    259:                        notify(H.Uid, H.Savedfile, (int) name, H.Time);
                    260:                        return (0);
                    261:                }
                    262:                if (write(1, buf, i) != i) {
                    263:                        if (name == 0)
                    264:                                perror(pattern);
                    265:                        unlink(pattern);
                    266:                        return (-1);
                    267:                }
                    268:        }
                    269: }
                    270: 
                    271: /*
                    272:  * Blast the last 5 characters of cp to be the process number.
                    273:  */
                    274: mkdigits(cp)
                    275:        char *cp;
                    276: {
                    277:        register int i, j;
                    278: 
                    279:        for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
                    280:                *--cp = i % 10 | '0';
                    281: }
                    282: 
                    283: /*
                    284:  * Make the name in cp be unique by clobbering up to
                    285:  * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
                    286:  * Mktemp gets weird names too quickly to be useful here.
                    287:  */
                    288: mknext(cp)
                    289:        char *cp;
                    290: {
                    291:        char *dcp;
                    292:        struct stat stb;
                    293: 
                    294:        dcp = cp + strlen(cp) - 1;
                    295:        while (isdigit(*dcp))
                    296:                dcp--;
                    297: whoops:
                    298:        if (dcp[0] == 'z') {
                    299:                dcp[0] = 'a';
                    300:                if (dcp[-1] == 'z') {
                    301:                        dcp[-1] = 'a';
                    302:                        if (dcp[-2] == 'z')
                    303:                                fprintf(stderr, "Can't find a name\t");
                    304:                        dcp[-2]++;
                    305:                } else
                    306:                        dcp[-1]++;
                    307:        } else
                    308:                dcp[0]++;
                    309:        if (stat(cp, &stb) == 0)
                    310:                goto whoops;
                    311: }
                    312: 
                    313: /*
                    314:  * Notify user uid that his file fname has been saved.
                    315:  */
                    316: notify(uid, fname, flag, time)
                    317:        int uid;
                    318:        char *fname;
                    319:        time_t  time;
                    320: {
                    321:        struct passwd *pp = getpwuid(uid);
                    322:        register FILE *mf;
                    323:        char    cmd[BUFSIZ];
                    324:        char    hostname[128];
                    325:        char    croak[128];
                    326:        char    *timestamp, *ctime();
                    327: 
                    328:        if (pp == NULL)
                    329:                return;
                    330:        gethostname(hostname, sizeof(hostname));
                    331:        timestamp = ctime(&time);
                    332:        timestamp[16] = 0;      /* blast from seconds on */
                    333:        sprintf(cmd, "%s %s", _PATH_BINMAIL, pp->pw_name);
                    334:        setuid(getuid());
                    335:        mf = popen(cmd, "w");
                    336:        if (mf == NULL)
                    337:                return;
                    338:        setbuf(mf, cmd);
                    339:        /*
                    340:         *      flag says how the editor croaked:
                    341:         * "the editor was killed" is perhaps still not an ideal
                    342:         * error message.  Usually, either it was forcably terminated
                    343:         * or the phone was hung up, but we don't know which.
                    344:         */
                    345:        sprintf(croak, flag
                    346:                ? "the system went down"
                    347:                : "the editor was killed");
                    348:        if (fname[0] == 0) {
                    349:                fname = "LOST";
                    350:                fprintf(mf,
                    351: "Subject: editor saved ``LOST''\n");
                    352:                fprintf(mf,
                    353: "You were editing a file without a name\n");
                    354:                fprintf(mf,
                    355: "at <%s> on the machine ``%s'' when %s.\n", timestamp, hostname, croak);
                    356:                fprintf(mf,
                    357: "Since the file had no name, it has been named \"LOST\".\n");
                    358:        } else {
                    359:                fprintf(mf,
                    360: "Subject: editor saved ``%s''\n", fname);
                    361:                fprintf(mf,
                    362: "You were editing the file \"%s\"\n", fname);
                    363:                fprintf(mf,
                    364: "at <%s> on the machine ``%s''\n", timestamp, hostname);
                    365:                fprintf(mf,
                    366: "when %s.\n", croak);
                    367:        }
                    368:        fprintf(mf,
                    369: "\nYou can retrieve most of your changes to this file\n");
                    370:        fprintf(mf,
                    371: "using the \"recover\" command of the editor.\n");
                    372:        fprintf(mf,
                    373: "An easy way to do this is to give the command \"vi -r %s\".\n", fname);
                    374:        fprintf(mf,
                    375: "This method also works using \"ex\" and \"edit\".\n");
                    376:        pclose(mf);
                    377: }
                    378: 
                    379: /*
                    380:  *     people making love
                    381:  *     never exactly the same
                    382:  *     just like a snowflake 
                    383:  */
                    384: 
                    385: #ifdef lint
                    386: Ignore(a)
                    387:        int a;
                    388: {
                    389: 
                    390:        a = a;
                    391: }
                    392: 
                    393: Ignorl(a)
                    394:        long a;
                    395: {
                    396: 
                    397:        a = a;
                    398: }
                    399: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.