Annotation of 43BSDReno/sbin/savecore/savecore.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that: (1) source distributions retain this entire copyright
                      7:  * notice and comment, and (2) distributions including binaries display
                      8:  * the following acknowledgement:  ``This product includes software
                      9:  * developed by the University of California, Berkeley and its contributors''
                     10:  * in the documentation or other materials provided with the distribution
                     11:  * and in all advertising materials mentioning features or use of this
                     12:  * software. Neither the name of the University nor the names of its
                     13:  * contributors may be used to endorse or promote products derived
                     14:  * from this software without specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     16:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: char copyright[] =
                     22: "@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\
                     23:  All rights reserved.\n";
                     24: #endif /* not lint */
                     25: 
                     26: #ifndef lint
                     27: static char sccsid[] = "@(#)savecore.c 5.22 (Berkeley) 6/1/90";
                     28: #endif /* not lint */
                     29: 
                     30: /*
                     31:  * savecore
                     32:  */
                     33: 
                     34: #include <sys/param.h>
                     35: #include <sys/mount.h>
                     36: #include <sys/stat.h>
                     37: #include <sys/time.h>
                     38: #include <sys/file.h>
                     39: #include <sys/syslog.h>
                     40: #include <dirent.h>
                     41: #include <stdio.h>
                     42: #include <nlist.h>
                     43: #include <paths.h>
                     44: 
                     45: #define        DAY     (60L*60L*24L)
                     46: #define        LEEWAY  (3*DAY)
                     47: 
                     48: #define eq(a,b) (!strcmp(a,b))
                     49: #ifdef vax
                     50: #define ok(number) ((number)&0x7fffffff)
                     51: #else
                     52: #ifdef tahoe
                     53: #define ok(number) ((number)&~0xc0000000)
                     54: #else
                     55: #define ok(number) (number)
                     56: #endif
                     57: #endif
                     58: 
                     59: struct nlist current_nl[] = {  /* namelist for currently running system */
                     60: #define X_DUMPDEV      0
                     61:        { "_dumpdev" },
                     62: #define X_DUMPLO       1
                     63:        { "_dumplo" },
                     64: #define X_TIME         2
                     65:        { "_time" },
                     66: #define        X_DUMPSIZE      3
                     67:        { "_dumpsize" },
                     68: #define X_VERSION      4
                     69:        { "_version" },
                     70: #define X_PANICSTR     5
                     71:        { "_panicstr" },
                     72: #define        X_DUMPMAG       6
                     73:        { "_dumpmag" },
                     74:        { "" },
                     75: };
                     76: 
                     77: struct nlist dump_nl[] = {     /* name list for dumped system */
                     78:        { "_dumpdev" },         /* entries MUST be the same as */
                     79:        { "_dumplo" },          /*      those in current_nl[]  */
                     80:        { "_time" },
                     81:        { "_dumpsize" },
                     82:        { "_version" },
                     83:        { "_panicstr" },
                     84:        { "_dumpmag" },
                     85:        { "" },
                     86: };
                     87: 
                     88: char   *system;
                     89: char   *dirname;                       /* directory to save dumps in */
                     90: char   *ddname;                        /* name of dump device */
                     91: int    dumpfd;                         /* read/write descriptor on block dev */
                     92: char   *find_dev();
                     93: dev_t  dumpdev;                        /* dump device */
                     94: time_t dumptime;                       /* time the dump was taken */
                     95: int    dumplo;                         /* where dump starts on dumpdev */
                     96: int    dumpsize;                       /* amount of memory dumped */
                     97: int    dumpmag;                        /* magic number in dump */
                     98: time_t now;                            /* current date */
                     99: char   *path();
                    100: char   *malloc();
                    101: char   *ctime();
                    102: char   vers[80];
                    103: char   core_vers[80];
                    104: char   panic_mesg[80];
                    105: int    panicstr;
                    106: off_t  lseek();
                    107: off_t  Lseek();
                    108: int    Verbose;
                    109: int    force;
                    110: int    clear;
                    111: extern int errno;
                    112: 
                    113: main(argc, argv)
                    114:        char **argv;
                    115:        int argc;
                    116: {
                    117:        char *cp;
                    118: 
                    119:        argc--, argv++;
                    120:        while (argc > 0 && argv[0][0] == '-') {
                    121:                for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
                    122: 
                    123:                case 'f':
                    124:                        force++;
                    125:                        break;
                    126: 
                    127:                case 'v':
                    128:                case 'd':
                    129:                        Verbose++;
                    130:                        break;
                    131: 
                    132:                case 'c':
                    133:                        clear++;
                    134:                        break;
                    135: 
                    136:                default:
                    137:                usage:
                    138:                        fprintf(stderr,
                    139:                            "usage: savecore [-f] [-v] [-c] dirname [ system ]\n");
                    140:                        exit(1);
                    141:                }
                    142:                argc--, argv++;
                    143:        }
                    144:        if (argc != 1 && argc != 2)
                    145:                goto usage;
                    146:        dirname = argv[0];
                    147:        if (argc == 2)
                    148:                system = argv[1];
                    149:        openlog("savecore", LOG_ODELAY, LOG_AUTH);
                    150:        if (access(dirname, W_OK) < 0) {
                    151:                Perror(LOG_ERR, "%s: %m\n", dirname);
                    152:                exit(1);
                    153:        }
                    154:        read_kmem();
                    155:        if (!dump_exists()) {
                    156:                if (Verbose)
                    157:                        fprintf(stderr, "savecore: No dump exists.\n");
                    158:                if (!force)
                    159:                        exit(0);
                    160:        }
                    161:        if (clear) {
                    162:                clear_dump();
                    163:                exit(0);
                    164:        }
                    165:        (void) time(&now);
                    166:        check_kmem();
                    167:        if (panicstr)
                    168:                log(LOG_CRIT, "reboot after panic: %s\n", panic_mesg);
                    169:        else
                    170:                syslog(LOG_CRIT, "reboot\n");
                    171:        if ((!get_crashtime() || !check_space()) && !force)
                    172:                exit(1);
                    173:        save_core();
                    174:        clear_dump();
                    175:        exit(0);
                    176: }
                    177: 
                    178: dump_exists()
                    179: {
                    180:        int word;
                    181: 
                    182:        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
                    183:        Read(dumpfd, (char *)&word, sizeof (word));
                    184:        if (Verbose && word != dumpmag)
                    185:                printf("magic number mismatch: %x != %x\n", word, dumpmag);
                    186:        return (word == dumpmag);
                    187: }
                    188: 
                    189: clear_dump()
                    190: {
                    191:        int zero = 0;
                    192: 
                    193:        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
                    194:        Write(dumpfd, (char *)&zero, sizeof (zero));
                    195: }
                    196: 
                    197: char *
                    198: find_dev(dev, type)
                    199:        register dev_t dev;
                    200:        register int type;
                    201: {
                    202:        register DIR *dfd = opendir(_PATH_DEV);
                    203:        struct dirent *dir;
                    204:        struct stat statb;
                    205:        static char devname[MAXPATHLEN + 1];
                    206:        char *dp;
                    207: 
                    208:        strcpy(devname, _PATH_DEV);
                    209:        while ((dir = readdir(dfd))) {
                    210:                strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name);
                    211:                if (stat(devname, &statb)) {
                    212:                        perror(devname);
                    213:                        continue;
                    214:                }
                    215:                if ((statb.st_mode&S_IFMT) != type)
                    216:                        continue;
                    217:                if (dev == statb.st_rdev) {
                    218:                        closedir(dfd);
                    219:                        dp = malloc(strlen(devname)+1);
                    220:                        strcpy(dp, devname);
                    221:                        return (dp);
                    222:                }
                    223:        }
                    224:        closedir(dfd);
                    225:        log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
                    226:        exit(1);
                    227:        /*NOTREACHED*/
                    228: }
                    229: 
                    230: char *
                    231: rawname(s)
                    232:        char *s;
                    233: {
                    234:        static char name[MAXPATHLEN];
                    235:        char *sl, *rindex();
                    236: 
                    237:        if ((sl = rindex(s, '/')) == NULL || sl[1] == '0') {
                    238:                log(LOG_ERR, "can't make raw dump device name from %s?\n", s);
                    239:                return (s);
                    240:        }
                    241:        sprintf(name, "%.*s/r%s", sl - s, s, sl + 1);
                    242:        return (name);
                    243: }
                    244: 
                    245: int    cursyms[] =
                    246:     { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
                    247: int    dumpsyms[] =
                    248:     { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
                    249: read_kmem()
                    250: {
                    251:        register char *cp;
                    252:        FILE *fp;
                    253:        char *dump_sys;
                    254:        int kmem, i;
                    255:        
                    256:        dump_sys = system ? system : _PATH_UNIX;
                    257:        nlist(_PATH_UNIX, current_nl);
                    258:        nlist(dump_sys, dump_nl);
                    259:        /*
                    260:         * Some names we need for the currently running system,
                    261:         * others for the system that was running when the dump was made.
                    262:         * The values obtained from the current system are used
                    263:         * to look for things in /dev/kmem that cannot be found
                    264:         * in the dump_sys namelist, but are presumed to be the same
                    265:         * (since the disk partitions are probably the same!)
                    266:         */
                    267:        for (i = 0; cursyms[i] != -1; i++)
                    268:                if (current_nl[cursyms[i]].n_value == 0) {
                    269:                        log(LOG_ERR, "%s: %s not in namelist\n", _PATH_UNIX,
                    270:                            current_nl[cursyms[i]].n_name);
                    271:                        exit(1);
                    272:                }
                    273:        for (i = 0; dumpsyms[i] != -1; i++)
                    274:                if (dump_nl[dumpsyms[i]].n_value == 0) {
                    275:                        log(LOG_ERR, "%s: %s not in namelist\n", dump_sys,
                    276:                            dump_nl[dumpsyms[i]].n_name);
                    277:                        exit(1);
                    278:                }
                    279:        kmem = Open(_PATH_KMEM, O_RDONLY);
                    280:        Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET);
                    281:        Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
                    282:        Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
                    283:        Read(kmem, (char *)&dumplo, sizeof (dumplo));
                    284:        if (Verbose)
                    285:                printf("dumplo = %d (%d * %d)\n", dumplo, dumplo/DEV_BSIZE,
                    286:                    DEV_BSIZE);
                    287:        Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
                    288:        Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
                    289:        dumplo *= DEV_BSIZE;
                    290:        ddname = find_dev(dumpdev, S_IFBLK);
                    291:        dumpfd = Open(ddname, O_RDWR);
                    292:        fp = fdopen(kmem, "r");
                    293:        if (fp == NULL) {
                    294:                log(LOG_ERR, "Couldn't fdopen kmem\n");
                    295:                exit(1);
                    296:        }
                    297:        if (system)
                    298:                return;
                    299:        fseek(fp, (long)current_nl[X_VERSION].n_value, L_SET);
                    300:        fgets(vers, sizeof (vers), fp);
                    301:        fclose(fp);
                    302: }
                    303: 
                    304: check_kmem()
                    305: {
                    306:        FILE *fp;
                    307:        register char *cp;
                    308: 
                    309:        fp = fdopen(dumpfd, "r");
                    310:        if (fp == NULL) {
                    311:                log(LOG_ERR, "Can't fdopen dumpfd\n");
                    312:                exit(1);
                    313:        }
                    314:        fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
                    315:        fgets(core_vers, sizeof (core_vers), fp);
                    316:        if (!eq(vers, core_vers) && system == 0) {
                    317:                log(LOG_WARNING, "Warning: %s version mismatch:\n", _PATH_UNIX);
                    318:                log(LOG_WARNING, "\t%s\n", vers);
                    319:                log(LOG_WARNING, "and\t%s\n", core_vers);
                    320:        }
                    321:        fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
                    322:        fread((char *)&panicstr, sizeof (panicstr), 1, fp);
                    323:        if (panicstr) {
                    324:                fseek(fp, dumplo + ok(panicstr), L_SET);
                    325:                cp = panic_mesg;
                    326:                do
                    327:                        *cp = getc(fp);
                    328:                while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]);
                    329:        }
                    330:        /* don't fclose(fp); we want the file descriptor */
                    331: }
                    332: 
                    333: get_crashtime()
                    334: {
                    335:        time_t clobber = (time_t)0;
                    336: 
                    337:        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
                    338:        Read(dumpfd, (char *)&dumptime, sizeof dumptime);
                    339:        if (dumptime == 0) {
                    340:                if (Verbose)
                    341:                        printf("Dump time is zero.\n");
                    342:                return (0);
                    343:        }
                    344:        printf("System went down at %s", ctime(&dumptime));
                    345:        if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
                    346:                printf("dump time is unreasonable\n");
                    347:                return (0);
                    348:        }
                    349:        return (1);
                    350: }
                    351: 
                    352: char *
                    353: path(file)
                    354:        char *file;
                    355: {
                    356:        register char *cp = malloc(strlen(file) + strlen(dirname) + 2);
                    357: 
                    358:        (void) strcpy(cp, dirname);
                    359:        (void) strcat(cp, "/");
                    360:        (void) strcat(cp, file);
                    361:        return (cp);
                    362: }
                    363: 
                    364: check_space()
                    365: {
                    366:        long minfree, spacefree;
                    367:        struct statfs fsbuf;
                    368: 
                    369:        if (statfs(dirname, &fsbuf) < 0) {
                    370:                Perror(LOG_ERR, "%s: %m\n", dirname);
                    371:                exit(1);
                    372:        }
                    373:        spacefree = fsbuf.f_bavail * fsbuf.f_fsize / 1024;
                    374:        minfree = read_number("minfree");
                    375:        if (minfree > 0 && spacefree - dumpsize < minfree) {
                    376:                log(LOG_WARNING, "Dump omitted, not enough space on device\n");
                    377:                return (0);
                    378:        }
                    379:        if (spacefree - dumpsize < minfree)
                    380:                log(LOG_WARNING,
                    381:                    "Dump performed, but free space threshold crossed\n");
                    382:        return (1);
                    383: }
                    384: 
                    385: read_number(fn)
                    386:        char *fn;
                    387: {
                    388:        char lin[80];
                    389:        register FILE *fp;
                    390: 
                    391:        fp = fopen(path(fn), "r");
                    392:        if (fp == NULL)
                    393:                return (0);
                    394:        if (fgets(lin, 80, fp) == NULL) {
                    395:                fclose(fp);
                    396:                return (0);
                    397:        }
                    398:        fclose(fp);
                    399:        return (atoi(lin));
                    400: }
                    401: 
                    402: #define        BUFSIZE         (256*1024)              /* 1/4 Mb */
                    403: 
                    404: save_core()
                    405: {
                    406:        register int n;
                    407:        register char *cp;
                    408:        register int ifd, ofd, bounds;
                    409:        int ret;
                    410:        char *bfile;
                    411:        register FILE *fp;
                    412: 
                    413:        cp = malloc(BUFSIZE);
                    414:        if (cp == 0) {
                    415:                log(LOG_ERR, "savecore: Can't allocate i/o buffer.\n");
                    416:                return;
                    417:        }
                    418:        bounds = read_number("bounds");
                    419:        ifd = Open(system ? system : _PATH_UNIX, O_RDONLY);
                    420:        (void)sprintf(cp, "vmunix.%d", bounds);
                    421:        ofd = Create(path(cp), 0644);
                    422:        while((n = Read(ifd, cp, BUFSIZE)) > 0)
                    423:                Write(ofd, cp, n);
                    424:        close(ifd);
                    425:        close(ofd);
                    426:        if ((ifd = open(rawname(ddname), O_RDONLY)) == -1) {
                    427:                log(LOG_WARNING, "Can't open %s (%m); using block device",
                    428:                        rawname(ddname));
                    429:                ifd = dumpfd;
                    430:        }
                    431:        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
                    432:        Read(dumpfd, (char *)&dumpsize, sizeof (dumpsize));
                    433:        (void)sprintf(cp, "vmcore.%d", bounds);
                    434:        ofd = Create(path(cp), 0644);
                    435:        Lseek(ifd, (off_t)dumplo, L_SET);
                    436:        dumpsize *= NBPG;
                    437:        log(LOG_NOTICE, "Saving %d bytes of image in vmcore.%d\n",
                    438:            dumpsize, bounds);
                    439:        while (dumpsize > 0) {
                    440:                n = read(ifd, cp,
                    441:                    dumpsize > BUFSIZE ? BUFSIZE : dumpsize);
                    442:                if (n <= 0) {
                    443:                        if (n == 0)
                    444:                                log(LOG_WARNING,
                    445:                                    "WARNING: EOF on dump device; %s\n",
                    446:                                    "vmcore may be incomplete");
                    447:                        else
                    448:                                Perror(LOG_ERR, "read from dumpdev: %m",
                    449:                                    "read");
                    450:                        break;
                    451:                }
                    452:                if ((ret = write(ofd, cp, n)) < n) {
                    453:                        if (ret < 0)
                    454:                                Perror(LOG_ERR, "write: %m", "write");
                    455:                        else
                    456:                                log(LOG_ERR, "short write: wrote %d of %d\n",
                    457:                                    ret, n);
                    458:                        log(LOG_WARNING, "WARNING: vmcore may be incomplete\n");
                    459:                        break;
                    460:                }
                    461:                dumpsize -= n;
                    462:        }
                    463:        close(ifd);
                    464:        close(ofd);
                    465:        bfile = path("bounds");
                    466:        fp = fopen(bfile, "w");
                    467:        if (fp) {
                    468:                fprintf(fp, "%d\n", bounds+1);
                    469:                fclose(fp);
                    470:        } else
                    471:                Perror(LOG_ERR, "Can't create bounds file %s: %m", bfile);
                    472:        free(cp);
                    473: }
                    474: 
                    475: /*
                    476:  * Versions of std routines that exit on error.
                    477:  */
                    478: Open(name, rw)
                    479:        char *name;
                    480:        int rw;
                    481: {
                    482:        int fd;
                    483: 
                    484:        fd = open(name, rw);
                    485:        if (fd < 0) {
                    486:                Perror(LOG_ERR, "%s: %m", name);
                    487:                exit(1);
                    488:        }
                    489:        return (fd);
                    490: }
                    491: 
                    492: Read(fd, buff, size)
                    493:        int fd, size;
                    494:        char *buff;
                    495: {
                    496:        int ret;
                    497: 
                    498:        ret = read(fd, buff, size);
                    499:        if (ret < 0) {
                    500:                Perror(LOG_ERR, "read: %m", "read");
                    501:                exit(1);
                    502:        }
                    503:        return (ret);
                    504: }
                    505: 
                    506: off_t
                    507: Lseek(fd, off, flag)
                    508:        int fd, flag;
                    509:        long off;
                    510: {
                    511:        long ret;
                    512: 
                    513:        ret = lseek(fd, off, flag);
                    514:        if (ret == -1) {
                    515:                Perror(LOG_ERR, "lseek: %m", "lseek");
                    516:                exit(1);
                    517:        }
                    518:        return (ret);
                    519: }
                    520: 
                    521: Create(file, mode)
                    522:        char *file;
                    523:        int mode;
                    524: {
                    525:        register int fd;
                    526: 
                    527:        fd = creat(file, mode);
                    528:        if (fd < 0) {
                    529:                Perror(LOG_ERR, "%s: %m", file);
                    530:                exit(1);
                    531:        }
                    532:        return (fd);
                    533: }
                    534: 
                    535: Write(fd, buf, size)
                    536:        int fd, size;
                    537:        char *buf;
                    538: {
                    539:        int n;
                    540: 
                    541:        if ((n = write(fd, buf, size)) < size) {
                    542:                if (n < 0)
                    543:                        Perror(LOG_ERR, "write: %m", "write");
                    544:                else
                    545:                        log(LOG_ERR, "short write: wrote %d of %d\n", n, size);
                    546:                exit(1);
                    547:        }
                    548: }
                    549: 
                    550: /* VARARGS2 */
                    551: log(level, msg, a1, a2)
                    552:        int level;
                    553:        char *msg;
                    554: {
                    555: 
                    556:        fprintf(stderr, msg, a1, a2);
                    557:        syslog(level, msg, a1, a2);
                    558: }
                    559: 
                    560: Perror(level, msg, s)
                    561:        int level;
                    562:        char *msg;
                    563: {
                    564:        int oerrno = errno;
                    565:        
                    566:        perror(s);
                    567:        errno = oerrno;
                    568:        syslog(level, msg, s);
                    569: }

unix.superglobalmegacorp.com

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