Annotation of 43BSD/etc/savecore.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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