Annotation of researchv10no/cmd/ex/expreserve.c, revision 1.1.1.1

1.1       root        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, "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

unix.superglobalmegacorp.com

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