Annotation of 43BSDReno/sbin/savecore/savecore.c, revision 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.