10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51471Seschrock * Common Development and Distribution License (the "License").
61471Seschrock * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
2212967Sgavin.maltby@oracle.com * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <stdarg.h>
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #include <fcntl.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <deflt.h>
330Sstevel@tonic-gate #include <time.h>
340Sstevel@tonic-gate #include <syslog.h>
350Sstevel@tonic-gate #include <stropts.h>
3610843SDave.Plauger@Sun.COM #include <pthread.h>
3710843SDave.Plauger@Sun.COM #include <limits.h>
3810843SDave.Plauger@Sun.COM #include <atomic.h>
3912967Sgavin.maltby@oracle.com #include <libnvpair.h>
4012967Sgavin.maltby@oracle.com #include <libintl.h>
410Sstevel@tonic-gate #include <sys/mem.h>
420Sstevel@tonic-gate #include <sys/statvfs.h>
430Sstevel@tonic-gate #include <sys/dumphdr.h>
440Sstevel@tonic-gate #include <sys/dumpadm.h>
450Sstevel@tonic-gate #include <sys/compress.h>
4612967Sgavin.maltby@oracle.com #include <sys/panic.h>
470Sstevel@tonic-gate #include <sys/sysmacros.h>
4810843SDave.Plauger@Sun.COM #include <sys/stat.h>
4910843SDave.Plauger@Sun.COM #include <sys/resource.h>
5010843SDave.Plauger@Sun.COM #include <bzip2/bzlib.h>
5112967Sgavin.maltby@oracle.com #include <sys/fm/util.h>
5212967Sgavin.maltby@oracle.com #include <fm/libfmevent.h>
5312967Sgavin.maltby@oracle.com #include <sys/int_fmtio.h>
5412967Sgavin.maltby@oracle.com
5510843SDave.Plauger@Sun.COM
5610843SDave.Plauger@Sun.COM /* fread/fwrite buffer size */
5710843SDave.Plauger@Sun.COM #define FBUFSIZE (1ULL << 20)
5810843SDave.Plauger@Sun.COM
5910843SDave.Plauger@Sun.COM /* minimum size for output buffering */
6010843SDave.Plauger@Sun.COM #define MINCOREBLKSIZE (1ULL << 17)
6110843SDave.Plauger@Sun.COM
6210843SDave.Plauger@Sun.COM /* create this file if metrics collection is enabled in the kernel */
6310843SDave.Plauger@Sun.COM #define METRICSFILE "METRICS.csv"
640Sstevel@tonic-gate
6512967Sgavin.maltby@oracle.com static char progname[9] = "savecore";
660Sstevel@tonic-gate static char *savedir; /* savecore directory */
670Sstevel@tonic-gate static char *dumpfile; /* source of raw crash dump */
6812967Sgavin.maltby@oracle.com static long bounds = -1; /* numeric suffix */
690Sstevel@tonic-gate static long pagesize; /* dump pagesize */
700Sstevel@tonic-gate static int dumpfd = -1; /* dumpfile descriptor */
710Sstevel@tonic-gate static dumphdr_t corehdr, dumphdr; /* initial and terminal dumphdrs */
7212967Sgavin.maltby@oracle.com static boolean_t dump_incomplete; /* dumphdr indicates incomplete */
7312967Sgavin.maltby@oracle.com static boolean_t fm_panic; /* dump is the result of fm_panic */
740Sstevel@tonic-gate static offset_t endoff; /* offset of end-of-dump header */
750Sstevel@tonic-gate static int verbose; /* chatty mode */
760Sstevel@tonic-gate static int disregard_valid_flag; /* disregard valid flag */
770Sstevel@tonic-gate static int livedump; /* dump the current running system */
7810843SDave.Plauger@Sun.COM static int interactive; /* user invoked; no syslog */
7910843SDave.Plauger@Sun.COM static int csave; /* save dump compressed */
8010843SDave.Plauger@Sun.COM static int filemode; /* processing file, not dump device */
8110843SDave.Plauger@Sun.COM static int percent_done; /* progress indicator */
8210843SDave.Plauger@Sun.COM static hrtime_t startts; /* timestamp at start */
8310843SDave.Plauger@Sun.COM static volatile uint64_t saved; /* count of pages written */
8410843SDave.Plauger@Sun.COM static volatile uint64_t zpages; /* count of zero pages not written */
8510843SDave.Plauger@Sun.COM static dumpdatahdr_t datahdr; /* compression info */
8610843SDave.Plauger@Sun.COM static long coreblksize; /* preferred write size (st_blksize) */
8712967Sgavin.maltby@oracle.com static int cflag; /* run as savecore -c */
8812967Sgavin.maltby@oracle.com static int mflag; /* run as savecore -m */
8912967Sgavin.maltby@oracle.com
9012967Sgavin.maltby@oracle.com /*
9112967Sgavin.maltby@oracle.com * Payload information for the events we raise. These are used
9212967Sgavin.maltby@oracle.com * in raise_event to determine what payload to include.
9312967Sgavin.maltby@oracle.com */
9412967Sgavin.maltby@oracle.com #define SC_PAYLOAD_SAVEDIR 0x0001 /* Include savedir in event */
9512967Sgavin.maltby@oracle.com #define SC_PAYLOAD_INSTANCE 0x0002 /* Include bounds instance number */
9612967Sgavin.maltby@oracle.com #define SC_PAYLOAD_IMAGEUUID 0x0004 /* Include dump OS instance uuid */
9712967Sgavin.maltby@oracle.com #define SC_PAYLOAD_CRASHTIME 0x0008 /* Include epoch crashtime */
9812967Sgavin.maltby@oracle.com #define SC_PAYLOAD_PANICSTR 0x0010 /* Include panic string */
9912967Sgavin.maltby@oracle.com #define SC_PAYLOAD_PANICSTACK 0x0020 /* Include panic string */
10012967Sgavin.maltby@oracle.com #define SC_PAYLOAD_FAILREASON 0x0040 /* Include failure reason */
10112967Sgavin.maltby@oracle.com #define SC_PAYLOAD_DUMPCOMPLETE 0x0080 /* Include completeness indicator */
10212967Sgavin.maltby@oracle.com #define SC_PAYLOAD_ISCOMPRESSED 0x0100 /* Dump is in vmdump.N form */
10312967Sgavin.maltby@oracle.com #define SC_PAYLOAD_DUMPADM_EN 0x0200 /* Is dumpadm enabled or not? */
10412967Sgavin.maltby@oracle.com #define SC_PAYLOAD_FM_PANIC 0x0400 /* Panic initiated by FMA */
10512967Sgavin.maltby@oracle.com #define SC_PAYLOAD_JUSTCHECKING 0x0800 /* Run with -c flag? */
10612967Sgavin.maltby@oracle.com
10712967Sgavin.maltby@oracle.com enum sc_event_type {
10812967Sgavin.maltby@oracle.com SC_EVENT_DUMP_PENDING,
10912967Sgavin.maltby@oracle.com SC_EVENT_SAVECORE_FAILURE,
11012967Sgavin.maltby@oracle.com SC_EVENT_DUMP_AVAILABLE
11112967Sgavin.maltby@oracle.com };
11212967Sgavin.maltby@oracle.com
11312967Sgavin.maltby@oracle.com /*
11412967Sgavin.maltby@oracle.com * Common payload
11512967Sgavin.maltby@oracle.com */
11612967Sgavin.maltby@oracle.com #define _SC_PAYLOAD_CMN \
11712967Sgavin.maltby@oracle.com SC_PAYLOAD_IMAGEUUID | \
11812967Sgavin.maltby@oracle.com SC_PAYLOAD_CRASHTIME | \
11912967Sgavin.maltby@oracle.com SC_PAYLOAD_PANICSTR | \
12012967Sgavin.maltby@oracle.com SC_PAYLOAD_PANICSTACK | \
12112967Sgavin.maltby@oracle.com SC_PAYLOAD_DUMPCOMPLETE | \
12212967Sgavin.maltby@oracle.com SC_PAYLOAD_FM_PANIC | \
12312967Sgavin.maltby@oracle.com SC_PAYLOAD_SAVEDIR
12412967Sgavin.maltby@oracle.com
12512967Sgavin.maltby@oracle.com static const struct {
12612967Sgavin.maltby@oracle.com const char *sce_subclass;
12712967Sgavin.maltby@oracle.com uint32_t sce_payload;
12812967Sgavin.maltby@oracle.com } sc_event[] = {
12912967Sgavin.maltby@oracle.com /*
13012967Sgavin.maltby@oracle.com * SC_EVENT_DUMP_PENDING
13112967Sgavin.maltby@oracle.com */
13212967Sgavin.maltby@oracle.com {
13312967Sgavin.maltby@oracle.com "dump_pending_on_device",
13412967Sgavin.maltby@oracle.com _SC_PAYLOAD_CMN | SC_PAYLOAD_DUMPADM_EN |
13512967Sgavin.maltby@oracle.com SC_PAYLOAD_JUSTCHECKING
13612967Sgavin.maltby@oracle.com },
13712967Sgavin.maltby@oracle.com
13812967Sgavin.maltby@oracle.com /*
13912967Sgavin.maltby@oracle.com * SC_EVENT_SAVECORE_FAILURE
14012967Sgavin.maltby@oracle.com */
14112967Sgavin.maltby@oracle.com {
14212967Sgavin.maltby@oracle.com "savecore_failure",
14312967Sgavin.maltby@oracle.com _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_FAILREASON
14412967Sgavin.maltby@oracle.com },
14512967Sgavin.maltby@oracle.com
14612967Sgavin.maltby@oracle.com /*
14712967Sgavin.maltby@oracle.com * SC_EVENT_DUMP_AVAILABLE
14812967Sgavin.maltby@oracle.com */
14912967Sgavin.maltby@oracle.com {
15012967Sgavin.maltby@oracle.com "dump_available",
15112967Sgavin.maltby@oracle.com _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_ISCOMPRESSED
15212967Sgavin.maltby@oracle.com },
15312967Sgavin.maltby@oracle.com };
15412967Sgavin.maltby@oracle.com
15512967Sgavin.maltby@oracle.com static void raise_event(enum sc_event_type, char *);
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate static void
usage(void)1580Sstevel@tonic-gate usage(void)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate (void) fprintf(stderr,
1610Sstevel@tonic-gate "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
1620Sstevel@tonic-gate exit(1);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
16512967Sgavin.maltby@oracle.com #define SC_SL_NONE 0x0001 /* no syslog */
16612967Sgavin.maltby@oracle.com #define SC_SL_ERR 0x0002 /* syslog if !interactive, LOG_ERR */
16712967Sgavin.maltby@oracle.com #define SC_SL_WARN 0x0004 /* syslog if !interactive, LOG_WARNING */
16812967Sgavin.maltby@oracle.com #define SC_IF_VERBOSE 0x0008 /* message only if -v */
16912967Sgavin.maltby@oracle.com #define SC_IF_ISATTY 0x0010 /* message only if interactive */
17012967Sgavin.maltby@oracle.com #define SC_EXIT_OK 0x0020 /* exit(0) */
17112967Sgavin.maltby@oracle.com #define SC_EXIT_ERR 0x0040 /* exit(1) */
17212967Sgavin.maltby@oracle.com #define SC_EXIT_PEND 0x0080 /* exit(2) */
17312967Sgavin.maltby@oracle.com #define SC_EXIT_FM 0x0100 /* exit(3) */
17412967Sgavin.maltby@oracle.com
17512967Sgavin.maltby@oracle.com #define _SC_ALLEXIT (SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM)
17612967Sgavin.maltby@oracle.com
1770Sstevel@tonic-gate static void
logprint(uint32_t flags,char * message,...)17812967Sgavin.maltby@oracle.com logprint(uint32_t flags, char *message, ...)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate va_list args;
1810Sstevel@tonic-gate char buf[1024];
18212967Sgavin.maltby@oracle.com int do_always = ((flags & (SC_IF_VERBOSE | SC_IF_ISATTY)) == 0);
18312967Sgavin.maltby@oracle.com int do_ifverb = (flags & SC_IF_VERBOSE) && verbose;
18412967Sgavin.maltby@oracle.com int do_ifisatty = (flags & SC_IF_ISATTY) && interactive;
18512967Sgavin.maltby@oracle.com int code;
18612967Sgavin.maltby@oracle.com static int logprint_raised = 0;
1870Sstevel@tonic-gate
18812967Sgavin.maltby@oracle.com if (do_always || do_ifverb || do_ifisatty) {
1890Sstevel@tonic-gate va_start(args, message);
19012967Sgavin.maltby@oracle.com /*LINTED: E_SEC_PRINTF_VAR_FMT*/
19110843SDave.Plauger@Sun.COM (void) vsnprintf(buf, sizeof (buf), message, args);
1920Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", progname, buf);
19312967Sgavin.maltby@oracle.com if (!interactive) {
19412967Sgavin.maltby@oracle.com switch (flags & (SC_SL_NONE | SC_SL_ERR | SC_SL_WARN)) {
19512967Sgavin.maltby@oracle.com case SC_SL_ERR:
19612967Sgavin.maltby@oracle.com /*LINTED: E_SEC_PRINTF_VAR_FMT*/
19712967Sgavin.maltby@oracle.com syslog(LOG_ERR, buf);
19812967Sgavin.maltby@oracle.com break;
19912967Sgavin.maltby@oracle.com
20012967Sgavin.maltby@oracle.com case SC_SL_WARN:
20112967Sgavin.maltby@oracle.com /*LINTED: E_SEC_PRINTF_VAR_FMT*/
20212967Sgavin.maltby@oracle.com syslog(LOG_WARNING, buf);
20312967Sgavin.maltby@oracle.com break;
20412967Sgavin.maltby@oracle.com
20512967Sgavin.maltby@oracle.com default:
20612967Sgavin.maltby@oracle.com break;
20712967Sgavin.maltby@oracle.com }
20812967Sgavin.maltby@oracle.com }
2090Sstevel@tonic-gate va_end(args);
2100Sstevel@tonic-gate }
21112967Sgavin.maltby@oracle.com
21212967Sgavin.maltby@oracle.com switch (flags & _SC_ALLEXIT) {
21312967Sgavin.maltby@oracle.com case 0:
21412967Sgavin.maltby@oracle.com return;
21512967Sgavin.maltby@oracle.com
21612967Sgavin.maltby@oracle.com case SC_EXIT_OK:
21712967Sgavin.maltby@oracle.com code = 0;
21812967Sgavin.maltby@oracle.com break;
21912967Sgavin.maltby@oracle.com
22012967Sgavin.maltby@oracle.com case SC_EXIT_PEND:
22112967Sgavin.maltby@oracle.com code = 2;
22212967Sgavin.maltby@oracle.com break;
22312967Sgavin.maltby@oracle.com
22412967Sgavin.maltby@oracle.com case SC_EXIT_FM:
22512967Sgavin.maltby@oracle.com code = 3;
22612967Sgavin.maltby@oracle.com break;
22712967Sgavin.maltby@oracle.com
22812967Sgavin.maltby@oracle.com case SC_EXIT_ERR:
22912967Sgavin.maltby@oracle.com default:
23012967Sgavin.maltby@oracle.com /*
23112967Sgavin.maltby@oracle.com * Raise an ireport saying why we are exiting. Do not
23212967Sgavin.maltby@oracle.com * raise if run as savecore -m. If something in the
23312967Sgavin.maltby@oracle.com * raise_event codepath calls logprint avoid recursion.
23412967Sgavin.maltby@oracle.com */
23512967Sgavin.maltby@oracle.com if (!mflag && logprint_raised++ == 0)
23612967Sgavin.maltby@oracle.com raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
23712967Sgavin.maltby@oracle.com code = 1;
23812967Sgavin.maltby@oracle.com break;
23912967Sgavin.maltby@oracle.com }
24012967Sgavin.maltby@oracle.com
24112967Sgavin.maltby@oracle.com exit(code);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate * System call / libc wrappers that exit on error.
2460Sstevel@tonic-gate */
2470Sstevel@tonic-gate static int
Open(const char * name,int oflags,mode_t mode)2480Sstevel@tonic-gate Open(const char *name, int oflags, mode_t mode)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate int fd;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate if ((fd = open64(name, oflags, mode)) == -1)
25312967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "open(\"%s\"): %s",
2540Sstevel@tonic-gate name, strerror(errno));
2550Sstevel@tonic-gate return (fd);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate static void
Fread(void * buf,size_t size,FILE * f)25910843SDave.Plauger@Sun.COM Fread(void *buf, size_t size, FILE *f)
2600Sstevel@tonic-gate {
26110843SDave.Plauger@Sun.COM if (fread(buf, size, 1, f) != 1)
26212967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "fread: ferror %d feof %d",
26310843SDave.Plauger@Sun.COM ferror(f), feof(f));
26410843SDave.Plauger@Sun.COM }
26510843SDave.Plauger@Sun.COM
26610843SDave.Plauger@Sun.COM static void
Fwrite(void * buf,size_t size,FILE * f)26710843SDave.Plauger@Sun.COM Fwrite(void *buf, size_t size, FILE *f)
26810843SDave.Plauger@Sun.COM {
26910843SDave.Plauger@Sun.COM if (fwrite(buf, size, 1, f) != 1)
27012967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "fwrite: %s",
27112967Sgavin.maltby@oracle.com strerror(errno));
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate static void
Fseek(offset_t off,FILE * f)27510843SDave.Plauger@Sun.COM Fseek(offset_t off, FILE *f)
27610843SDave.Plauger@Sun.COM {
27710843SDave.Plauger@Sun.COM if (fseeko64(f, off, SEEK_SET) != 0)
27812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "fseeko64: %s",
27912967Sgavin.maltby@oracle.com strerror(errno));
28010843SDave.Plauger@Sun.COM }
28110843SDave.Plauger@Sun.COM
28210843SDave.Plauger@Sun.COM typedef struct stat64 Stat_t;
28310843SDave.Plauger@Sun.COM
28410843SDave.Plauger@Sun.COM static void
Fstat(int fd,Stat_t * sb,const char * fname)28510843SDave.Plauger@Sun.COM Fstat(int fd, Stat_t *sb, const char *fname)
28610843SDave.Plauger@Sun.COM {
28710843SDave.Plauger@Sun.COM if (fstat64(fd, sb) != 0)
28812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "fstat(\"%s\"): %s", fname,
28910843SDave.Plauger@Sun.COM strerror(errno));
29010843SDave.Plauger@Sun.COM }
29110843SDave.Plauger@Sun.COM
29210843SDave.Plauger@Sun.COM static void
Stat(const char * fname,Stat_t * sb)29310843SDave.Plauger@Sun.COM Stat(const char *fname, Stat_t *sb)
29410843SDave.Plauger@Sun.COM {
29510843SDave.Plauger@Sun.COM if (stat64(fname, sb) != 0)
29612967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "stat(\"%s\"): %s", fname,
29710843SDave.Plauger@Sun.COM strerror(errno));
29810843SDave.Plauger@Sun.COM }
29910843SDave.Plauger@Sun.COM
30010843SDave.Plauger@Sun.COM static void
Pread(int fd,void * buf,size_t size,offset_t off)30110843SDave.Plauger@Sun.COM Pread(int fd, void *buf, size_t size, offset_t off)
30210843SDave.Plauger@Sun.COM {
30310843SDave.Plauger@Sun.COM ssize_t sz = pread64(fd, buf, size, off);
30410843SDave.Plauger@Sun.COM
30510843SDave.Plauger@Sun.COM if (sz < 0)
30612967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
30710843SDave.Plauger@Sun.COM "pread: %s", strerror(errno));
30810843SDave.Plauger@Sun.COM else if (sz != size)
30912967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
31010843SDave.Plauger@Sun.COM "pread: size %ld != %ld", sz, size);
31110843SDave.Plauger@Sun.COM }
31210843SDave.Plauger@Sun.COM
31310843SDave.Plauger@Sun.COM static void
Pwrite(int fd,void * buf,size_t size,off64_t off)31410843SDave.Plauger@Sun.COM Pwrite(int fd, void *buf, size_t size, off64_t off)
3150Sstevel@tonic-gate {
3160Sstevel@tonic-gate if (pwrite64(fd, buf, size, off) != size)
31712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "pwrite: %s",
31812967Sgavin.maltby@oracle.com strerror(errno));
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate static void *
Zalloc(size_t size)3220Sstevel@tonic-gate Zalloc(size_t size)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate void *buf;
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate if ((buf = calloc(size, 1)) == NULL)
32712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "calloc: %s",
32812967Sgavin.maltby@oracle.com strerror(errno));
3290Sstevel@tonic-gate return (buf);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate static long
read_number_from_file(const char * filename,long default_value)3330Sstevel@tonic-gate read_number_from_file(const char *filename, long default_value)
3340Sstevel@tonic-gate {
3350Sstevel@tonic-gate long file_value = -1;
3360Sstevel@tonic-gate FILE *fp;
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate if ((fp = fopen(filename, "r")) != NULL) {
3390Sstevel@tonic-gate (void) fscanf(fp, "%ld", &file_value);
3400Sstevel@tonic-gate (void) fclose(fp);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate return (file_value < 0 ? default_value : file_value);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate static void
read_dumphdr(void)3460Sstevel@tonic-gate read_dumphdr(void)
3470Sstevel@tonic-gate {
34810843SDave.Plauger@Sun.COM if (filemode)
34910843SDave.Plauger@Sun.COM dumpfd = Open(dumpfile, O_RDONLY, 0644);
35010843SDave.Plauger@Sun.COM else
35110843SDave.Plauger@Sun.COM dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
3520Sstevel@tonic-gate endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
3530Sstevel@tonic-gate Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
35410843SDave.Plauger@Sun.COM Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate pagesize = dumphdr.dump_pagesize;
3570Sstevel@tonic-gate
35810843SDave.Plauger@Sun.COM if (dumphdr.dump_magic != DUMP_MAGIC)
35912967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_EXIT_OK, "bad magic number %x",
36010843SDave.Plauger@Sun.COM dumphdr.dump_magic);
36110843SDave.Plauger@Sun.COM
3620Sstevel@tonic-gate if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag)
36312967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
36412967Sgavin.maltby@oracle.com "dump already processed");
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate if (dumphdr.dump_version != DUMP_VERSION)
36712967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
3680Sstevel@tonic-gate "dump version (%d) != %s version (%d)",
3690Sstevel@tonic-gate dumphdr.dump_version, progname, DUMP_VERSION);
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate if (dumphdr.dump_wordsize != DUMP_WORDSIZE)
37212967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_EXIT_OK,
3730Sstevel@tonic-gate "dump is from %u-bit kernel - cannot save on %u-bit kernel",
3740Sstevel@tonic-gate dumphdr.dump_wordsize, DUMP_WORDSIZE);
37510843SDave.Plauger@Sun.COM
37610843SDave.Plauger@Sun.COM if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
37710843SDave.Plauger@Sun.COM if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
37812967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
37910843SDave.Plauger@Sun.COM "dump data version (%d) != %s data version (%d)",
38010843SDave.Plauger@Sun.COM datahdr.dump_datahdr_version, progname,
38110843SDave.Plauger@Sun.COM DUMP_DATAHDR_VERSION);
38210843SDave.Plauger@Sun.COM } else {
38312967Sgavin.maltby@oracle.com (void) memset(&datahdr, 0, sizeof (datahdr));
38410843SDave.Plauger@Sun.COM datahdr.dump_maxcsize = pagesize;
38510843SDave.Plauger@Sun.COM }
38610843SDave.Plauger@Sun.COM
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate * Read the initial header, clear the valid bits, and compare headers.
3890Sstevel@tonic-gate * The main header may have been overwritten by swapping if we're
3900Sstevel@tonic-gate * using a swap partition as the dump device, in which case we bail.
3910Sstevel@tonic-gate */
3920Sstevel@tonic-gate Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start);
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate corehdr.dump_flags &= ~DF_VALID;
3950Sstevel@tonic-gate dumphdr.dump_flags &= ~DF_VALID;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate * Clear valid bit so we don't complain on every invocation.
4000Sstevel@tonic-gate */
40110843SDave.Plauger@Sun.COM if (!filemode)
40210843SDave.Plauger@Sun.COM Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
40312967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
40412967Sgavin.maltby@oracle.com "initial dump header corrupt");
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate static void
check_space(int csave)40910843SDave.Plauger@Sun.COM check_space(int csave)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate struct statvfs fsb;
41210843SDave.Plauger@Sun.COM int64_t spacefree, dumpsize, minfree, datasize;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate if (statvfs(".", &fsb) < 0)
41512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "statvfs: %s",
41612967Sgavin.maltby@oracle.com strerror(errno));
4170Sstevel@tonic-gate
41810843SDave.Plauger@Sun.COM dumpsize = dumphdr.dump_data - dumphdr.dump_start;
41910843SDave.Plauger@Sun.COM datasize = dumphdr.dump_npages * pagesize;
42010843SDave.Plauger@Sun.COM if (!csave)
42110843SDave.Plauger@Sun.COM dumpsize += datasize;
42210843SDave.Plauger@Sun.COM else
42310843SDave.Plauger@Sun.COM dumpsize += datahdr.dump_data_csize;
42410843SDave.Plauger@Sun.COM
4250Sstevel@tonic-gate spacefree = (int64_t)fsb.f_bavail * fsb.f_frsize;
4260Sstevel@tonic-gate minfree = 1024LL * read_number_from_file("minfree", 1024);
42712967Sgavin.maltby@oracle.com if (spacefree < minfree + dumpsize) {
42812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
4290Sstevel@tonic-gate "not enough space in %s (%lld MB avail, %lld MB needed)",
4300Sstevel@tonic-gate savedir, spacefree >> 20, (minfree + dumpsize) >> 20);
43112967Sgavin.maltby@oracle.com }
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate static void
build_dump_map(int corefd,const pfn_t * pfn_table)4350Sstevel@tonic-gate build_dump_map(int corefd, const pfn_t *pfn_table)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate long i;
4380Sstevel@tonic-gate static long misses = 0;
4390Sstevel@tonic-gate size_t dump_mapsize = (corehdr.dump_hashmask + 1) * sizeof (dump_map_t);
4400Sstevel@tonic-gate mem_vtop_t vtop;
4410Sstevel@tonic-gate dump_map_t *dmp = Zalloc(dump_mapsize);
44210843SDave.Plauger@Sun.COM char *inbuf = Zalloc(FBUFSIZE);
44310843SDave.Plauger@Sun.COM FILE *in = fdopen(dup(dumpfd), "rb");
44410843SDave.Plauger@Sun.COM
44512967Sgavin.maltby@oracle.com (void) setvbuf(in, inbuf, _IOFBF, FBUFSIZE);
44610843SDave.Plauger@Sun.COM Fseek(dumphdr.dump_map, in);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate corehdr.dump_data = corehdr.dump_map + roundup(dump_mapsize, pagesize);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate for (i = 0; i < corehdr.dump_nvtop; i++) {
4510Sstevel@tonic-gate long first = 0;
4520Sstevel@tonic-gate long last = corehdr.dump_npages - 1;
4530Sstevel@tonic-gate long middle;
4540Sstevel@tonic-gate pfn_t pfn;
4550Sstevel@tonic-gate uintptr_t h;
4560Sstevel@tonic-gate
45710843SDave.Plauger@Sun.COM Fread(&vtop, sizeof (mem_vtop_t), in);
4580Sstevel@tonic-gate while (last >= first) {
4590Sstevel@tonic-gate middle = (first + last) / 2;
4600Sstevel@tonic-gate pfn = pfn_table[middle];
4610Sstevel@tonic-gate if (pfn == vtop.m_pfn)
4620Sstevel@tonic-gate break;
4630Sstevel@tonic-gate if (pfn < vtop.m_pfn)
4640Sstevel@tonic-gate first = middle + 1;
4650Sstevel@tonic-gate else
4660Sstevel@tonic-gate last = middle - 1;
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate if (pfn != vtop.m_pfn) {
4690Sstevel@tonic-gate if (++misses <= 10)
4700Sstevel@tonic-gate (void) fprintf(stderr,
4710Sstevel@tonic-gate "pfn %ld not found for as=%p, va=%p\n",
4720Sstevel@tonic-gate vtop.m_pfn, (void *)vtop.m_as, vtop.m_va);
4730Sstevel@tonic-gate continue;
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate dmp[i].dm_as = vtop.m_as;
4770Sstevel@tonic-gate dmp[i].dm_va = (uintptr_t)vtop.m_va;
4780Sstevel@tonic-gate dmp[i].dm_data = corehdr.dump_data +
4790Sstevel@tonic-gate ((uint64_t)middle << corehdr.dump_pageshift);
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate h = DUMP_HASH(&corehdr, dmp[i].dm_as, dmp[i].dm_va);
4820Sstevel@tonic-gate dmp[i].dm_next = dmp[h].dm_first;
4830Sstevel@tonic-gate dmp[h].dm_first = corehdr.dump_map + i * sizeof (dump_map_t);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate Pwrite(corefd, dmp, dump_mapsize, corehdr.dump_map);
4870Sstevel@tonic-gate free(dmp);
48812967Sgavin.maltby@oracle.com (void) fclose(in);
48910843SDave.Plauger@Sun.COM free(inbuf);
49010843SDave.Plauger@Sun.COM }
49110843SDave.Plauger@Sun.COM
49210843SDave.Plauger@Sun.COM /*
49310843SDave.Plauger@Sun.COM * Copy whole sections of the dump device to the file.
49410843SDave.Plauger@Sun.COM */
49510843SDave.Plauger@Sun.COM static void
Copy(offset_t dumpoff,len_t nb,offset_t * offp,int fd,char * buf,size_t sz)49610843SDave.Plauger@Sun.COM Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
49710843SDave.Plauger@Sun.COM size_t sz)
49810843SDave.Plauger@Sun.COM {
49910843SDave.Plauger@Sun.COM size_t nr;
50010843SDave.Plauger@Sun.COM offset_t off = *offp;
50110843SDave.Plauger@Sun.COM
50210843SDave.Plauger@Sun.COM while (nb > 0) {
50310843SDave.Plauger@Sun.COM nr = sz < nb ? sz : (size_t)nb;
50410843SDave.Plauger@Sun.COM Pread(dumpfd, buf, nr, dumpoff);
50510843SDave.Plauger@Sun.COM Pwrite(fd, buf, nr, off);
50610843SDave.Plauger@Sun.COM off += nr;
50710843SDave.Plauger@Sun.COM dumpoff += nr;
50810843SDave.Plauger@Sun.COM nb -= nr;
50910843SDave.Plauger@Sun.COM }
51010843SDave.Plauger@Sun.COM *offp = off;
51110843SDave.Plauger@Sun.COM }
51210843SDave.Plauger@Sun.COM
51310843SDave.Plauger@Sun.COM /*
51410843SDave.Plauger@Sun.COM * Copy pages when the dump data header is missing.
51510843SDave.Plauger@Sun.COM * This supports older kernels with latest savecore.
51610843SDave.Plauger@Sun.COM */
51710843SDave.Plauger@Sun.COM static void
CopyPages(offset_t * offp,int fd,char * buf,size_t sz)51812967Sgavin.maltby@oracle.com CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
51910843SDave.Plauger@Sun.COM {
52010843SDave.Plauger@Sun.COM uint32_t csize;
52110843SDave.Plauger@Sun.COM FILE *in = fdopen(dup(dumpfd), "rb");
52210843SDave.Plauger@Sun.COM FILE *out = fdopen(dup(fd), "wb");
52310843SDave.Plauger@Sun.COM char *cbuf = Zalloc(pagesize);
52410843SDave.Plauger@Sun.COM char *outbuf = Zalloc(FBUFSIZE);
52510843SDave.Plauger@Sun.COM pgcnt_t np = dumphdr.dump_npages;
52610843SDave.Plauger@Sun.COM
52712967Sgavin.maltby@oracle.com (void) setvbuf(out, outbuf, _IOFBF, FBUFSIZE);
52812967Sgavin.maltby@oracle.com (void) setvbuf(in, buf, _IOFBF, sz);
52910843SDave.Plauger@Sun.COM Fseek(dumphdr.dump_data, in);
53010843SDave.Plauger@Sun.COM
53110843SDave.Plauger@Sun.COM Fseek(*offp, out);
53210843SDave.Plauger@Sun.COM while (np > 0) {
53310843SDave.Plauger@Sun.COM Fread(&csize, sizeof (uint32_t), in);
53410843SDave.Plauger@Sun.COM Fwrite(&csize, sizeof (uint32_t), out);
53510843SDave.Plauger@Sun.COM *offp += sizeof (uint32_t);
53610843SDave.Plauger@Sun.COM if (csize > pagesize || csize == 0) {
53712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR,
53810843SDave.Plauger@Sun.COM "CopyPages: page %lu csize %d (0x%x) pagesize %d",
53910843SDave.Plauger@Sun.COM dumphdr.dump_npages - np, csize, csize,
54010843SDave.Plauger@Sun.COM pagesize);
54110843SDave.Plauger@Sun.COM break;
54210843SDave.Plauger@Sun.COM }
54310843SDave.Plauger@Sun.COM Fread(cbuf, csize, in);
54410843SDave.Plauger@Sun.COM Fwrite(cbuf, csize, out);
54510843SDave.Plauger@Sun.COM *offp += csize;
54610843SDave.Plauger@Sun.COM np--;
54710843SDave.Plauger@Sun.COM }
54812967Sgavin.maltby@oracle.com (void) fclose(in);
54912967Sgavin.maltby@oracle.com (void) fclose(out);
55010843SDave.Plauger@Sun.COM free(outbuf);
55110843SDave.Plauger@Sun.COM free(buf);
55210843SDave.Plauger@Sun.COM }
55310843SDave.Plauger@Sun.COM
55410843SDave.Plauger@Sun.COM /*
55510843SDave.Plauger@Sun.COM * Concatenate dump contents into a new file.
55610843SDave.Plauger@Sun.COM * Update corehdr with new offsets.
55710843SDave.Plauger@Sun.COM */
55810843SDave.Plauger@Sun.COM static void
copy_crashfile(const char * corefile)55910843SDave.Plauger@Sun.COM copy_crashfile(const char *corefile)
56010843SDave.Plauger@Sun.COM {
56110843SDave.Plauger@Sun.COM int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
56210843SDave.Plauger@Sun.COM size_t bufsz = FBUFSIZE;
56310843SDave.Plauger@Sun.COM char *inbuf = Zalloc(bufsz);
56410843SDave.Plauger@Sun.COM offset_t coreoff;
56510843SDave.Plauger@Sun.COM size_t nb;
56610843SDave.Plauger@Sun.COM
56712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_IF_VERBOSE,
56810843SDave.Plauger@Sun.COM "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
56910843SDave.Plauger@Sun.COM
57010843SDave.Plauger@Sun.COM /*
57110843SDave.Plauger@Sun.COM * This dump file is still compressed
57210843SDave.Plauger@Sun.COM */
57310843SDave.Plauger@Sun.COM corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
57410843SDave.Plauger@Sun.COM
57510843SDave.Plauger@Sun.COM /*
57610843SDave.Plauger@Sun.COM * Leave room for corehdr, it is updated and written last
57710843SDave.Plauger@Sun.COM */
57810843SDave.Plauger@Sun.COM corehdr.dump_start = 0;
57910843SDave.Plauger@Sun.COM coreoff = sizeof (corehdr);
58010843SDave.Plauger@Sun.COM
58110843SDave.Plauger@Sun.COM /*
58210843SDave.Plauger@Sun.COM * Read in the compressed symbol table, copy it to corefile.
58310843SDave.Plauger@Sun.COM */
58410843SDave.Plauger@Sun.COM coreoff = roundup(coreoff, pagesize);
58510843SDave.Plauger@Sun.COM corehdr.dump_ksyms = coreoff;
58610843SDave.Plauger@Sun.COM Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
58710843SDave.Plauger@Sun.COM inbuf, bufsz);
58810843SDave.Plauger@Sun.COM
58910843SDave.Plauger@Sun.COM /*
59010843SDave.Plauger@Sun.COM * Save the pfn table.
59110843SDave.Plauger@Sun.COM */
59210843SDave.Plauger@Sun.COM coreoff = roundup(coreoff, pagesize);
59310843SDave.Plauger@Sun.COM corehdr.dump_pfn = coreoff;
59410843SDave.Plauger@Sun.COM Copy(dumphdr.dump_pfn, dumphdr.dump_npages * sizeof (pfn_t), &coreoff,
59510843SDave.Plauger@Sun.COM corefd, inbuf, bufsz);
59610843SDave.Plauger@Sun.COM
59710843SDave.Plauger@Sun.COM /*
59810843SDave.Plauger@Sun.COM * Save the dump map.
59910843SDave.Plauger@Sun.COM */
60010843SDave.Plauger@Sun.COM coreoff = roundup(coreoff, pagesize);
60110843SDave.Plauger@Sun.COM corehdr.dump_map = coreoff;
60210843SDave.Plauger@Sun.COM Copy(dumphdr.dump_map, dumphdr.dump_nvtop * sizeof (mem_vtop_t),
60310843SDave.Plauger@Sun.COM &coreoff, corefd, inbuf, bufsz);
60410843SDave.Plauger@Sun.COM
60510843SDave.Plauger@Sun.COM /*
60610843SDave.Plauger@Sun.COM * Save the data pages.
60710843SDave.Plauger@Sun.COM */
60810843SDave.Plauger@Sun.COM coreoff = roundup(coreoff, pagesize);
60910843SDave.Plauger@Sun.COM corehdr.dump_data = coreoff;
61010843SDave.Plauger@Sun.COM if (datahdr.dump_data_csize != 0)
61110843SDave.Plauger@Sun.COM Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff,
61210843SDave.Plauger@Sun.COM corefd, inbuf, bufsz);
61310843SDave.Plauger@Sun.COM else
61412967Sgavin.maltby@oracle.com CopyPages(&coreoff, corefd, inbuf, bufsz);
61510843SDave.Plauger@Sun.COM
61610843SDave.Plauger@Sun.COM /*
61710843SDave.Plauger@Sun.COM * Now write the modified dump header to front and end of the copy.
61810843SDave.Plauger@Sun.COM * Make it look like a valid dump device.
61910843SDave.Plauger@Sun.COM *
62010843SDave.Plauger@Sun.COM * From dumphdr.h: Two headers are written out: one at the
62110843SDave.Plauger@Sun.COM * beginning of the dump, and the other at the very end of the
62210843SDave.Plauger@Sun.COM * dump device. The terminal header is at a known location
62310843SDave.Plauger@Sun.COM * (end of device) so we can always find it.
62410843SDave.Plauger@Sun.COM *
62510843SDave.Plauger@Sun.COM * Pad with zeros to each DUMP_OFFSET boundary.
62610843SDave.Plauger@Sun.COM */
62712967Sgavin.maltby@oracle.com (void) memset(inbuf, 0, DUMP_OFFSET);
62810843SDave.Plauger@Sun.COM
62910843SDave.Plauger@Sun.COM nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
63010843SDave.Plauger@Sun.COM if (nb > 0) {
63110843SDave.Plauger@Sun.COM Pwrite(corefd, inbuf, nb, coreoff);
63210843SDave.Plauger@Sun.COM coreoff += nb;
63310843SDave.Plauger@Sun.COM }
63410843SDave.Plauger@Sun.COM
63510843SDave.Plauger@Sun.COM Pwrite(corefd, &corehdr, sizeof (corehdr), coreoff);
63610843SDave.Plauger@Sun.COM coreoff += sizeof (corehdr);
63710843SDave.Plauger@Sun.COM
63810843SDave.Plauger@Sun.COM Pwrite(corefd, &datahdr, sizeof (datahdr), coreoff);
63910843SDave.Plauger@Sun.COM coreoff += sizeof (datahdr);
64010843SDave.Plauger@Sun.COM
64110843SDave.Plauger@Sun.COM nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
64210843SDave.Plauger@Sun.COM if (nb > 0) {
64310843SDave.Plauger@Sun.COM Pwrite(corefd, inbuf, nb, coreoff);
64410843SDave.Plauger@Sun.COM }
64510843SDave.Plauger@Sun.COM
64610843SDave.Plauger@Sun.COM free(inbuf);
64710843SDave.Plauger@Sun.COM Pwrite(corefd, &corehdr, sizeof (corehdr), corehdr.dump_start);
64810843SDave.Plauger@Sun.COM
64910843SDave.Plauger@Sun.COM /*
65010843SDave.Plauger@Sun.COM * Write out the modified dump header to the dump device.
65110843SDave.Plauger@Sun.COM * The dump device has been processed, so DF_VALID is clear.
65210843SDave.Plauger@Sun.COM */
65310843SDave.Plauger@Sun.COM if (!filemode)
65410843SDave.Plauger@Sun.COM Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
65510843SDave.Plauger@Sun.COM
65610843SDave.Plauger@Sun.COM (void) close(corefd);
65710843SDave.Plauger@Sun.COM }
65810843SDave.Plauger@Sun.COM
65910843SDave.Plauger@Sun.COM /*
66010843SDave.Plauger@Sun.COM * compressed streams
66110843SDave.Plauger@Sun.COM */
66210843SDave.Plauger@Sun.COM typedef struct blockhdr blockhdr_t;
66310843SDave.Plauger@Sun.COM typedef struct block block_t;
66410843SDave.Plauger@Sun.COM
66510843SDave.Plauger@Sun.COM struct blockhdr {
66610843SDave.Plauger@Sun.COM block_t *head;
66710843SDave.Plauger@Sun.COM block_t *tail;
66810843SDave.Plauger@Sun.COM };
66910843SDave.Plauger@Sun.COM
67010843SDave.Plauger@Sun.COM struct block {
67110843SDave.Plauger@Sun.COM block_t *next;
67210843SDave.Plauger@Sun.COM char *block;
67310843SDave.Plauger@Sun.COM int size;
67410843SDave.Plauger@Sun.COM };
67510843SDave.Plauger@Sun.COM
67610843SDave.Plauger@Sun.COM typedef enum streamstate {
67710843SDave.Plauger@Sun.COM STREAMSTART,
67810843SDave.Plauger@Sun.COM STREAMPAGES
67910843SDave.Plauger@Sun.COM } streamstate_t;
68010843SDave.Plauger@Sun.COM
68110843SDave.Plauger@Sun.COM typedef struct stream {
68210843SDave.Plauger@Sun.COM streamstate_t state;
68310843SDave.Plauger@Sun.COM int init;
68410843SDave.Plauger@Sun.COM int tag;
68510843SDave.Plauger@Sun.COM int bound;
68610843SDave.Plauger@Sun.COM int nout;
68710843SDave.Plauger@Sun.COM char *blkbuf;
68810843SDave.Plauger@Sun.COM blockhdr_t blocks;
68910843SDave.Plauger@Sun.COM pgcnt_t pagenum;
69010843SDave.Plauger@Sun.COM pgcnt_t curpage;
69110843SDave.Plauger@Sun.COM pgcnt_t npages;
69210843SDave.Plauger@Sun.COM pgcnt_t done;
69310843SDave.Plauger@Sun.COM bz_stream strm;
69410843SDave.Plauger@Sun.COM dumpcsize_t sc;
69510843SDave.Plauger@Sun.COM dumpstreamhdr_t sh;
69610843SDave.Plauger@Sun.COM } stream_t;
69710843SDave.Plauger@Sun.COM
69810843SDave.Plauger@Sun.COM static stream_t *streams;
69910843SDave.Plauger@Sun.COM static stream_t *endstreams;
70010843SDave.Plauger@Sun.COM
70110843SDave.Plauger@Sun.COM const int cs = sizeof (dumpcsize_t);
70210843SDave.Plauger@Sun.COM
70310843SDave.Plauger@Sun.COM typedef struct tinfo {
70410843SDave.Plauger@Sun.COM pthread_t tid;
70510843SDave.Plauger@Sun.COM int corefd;
70610843SDave.Plauger@Sun.COM } tinfo_t;
70710843SDave.Plauger@Sun.COM
70810843SDave.Plauger@Sun.COM static int threads_stop;
70910843SDave.Plauger@Sun.COM static int threads_active;
71010843SDave.Plauger@Sun.COM static tinfo_t *tinfo;
71110843SDave.Plauger@Sun.COM static tinfo_t *endtinfo;
71210843SDave.Plauger@Sun.COM
71310843SDave.Plauger@Sun.COM static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
71410843SDave.Plauger@Sun.COM static pthread_cond_t cvfree = PTHREAD_COND_INITIALIZER;
71510843SDave.Plauger@Sun.COM static pthread_cond_t cvwork = PTHREAD_COND_INITIALIZER;
71610843SDave.Plauger@Sun.COM static pthread_cond_t cvbarrier = PTHREAD_COND_INITIALIZER;
71710843SDave.Plauger@Sun.COM
71810843SDave.Plauger@Sun.COM static blockhdr_t freeblocks;
71910843SDave.Plauger@Sun.COM
72010843SDave.Plauger@Sun.COM static void
enqt(blockhdr_t * h,block_t * b)72110843SDave.Plauger@Sun.COM enqt(blockhdr_t *h, block_t *b)
72210843SDave.Plauger@Sun.COM {
72310843SDave.Plauger@Sun.COM b->next = NULL;
72410843SDave.Plauger@Sun.COM if (h->tail == NULL)
72510843SDave.Plauger@Sun.COM h->head = b;
72610843SDave.Plauger@Sun.COM else
72710843SDave.Plauger@Sun.COM h->tail->next = b;
72810843SDave.Plauger@Sun.COM h->tail = b;
72910843SDave.Plauger@Sun.COM }
73010843SDave.Plauger@Sun.COM
73110843SDave.Plauger@Sun.COM static block_t *
deqh(blockhdr_t * h)73210843SDave.Plauger@Sun.COM deqh(blockhdr_t *h)
73310843SDave.Plauger@Sun.COM {
73410843SDave.Plauger@Sun.COM block_t *b = h->head;
73510843SDave.Plauger@Sun.COM
73610843SDave.Plauger@Sun.COM if (b != NULL) {
73710843SDave.Plauger@Sun.COM h->head = b->next;
73810843SDave.Plauger@Sun.COM if (h->head == NULL)
73910843SDave.Plauger@Sun.COM h->tail = NULL;
74010843SDave.Plauger@Sun.COM }
74110843SDave.Plauger@Sun.COM return (b);
74210843SDave.Plauger@Sun.COM }
74310843SDave.Plauger@Sun.COM
74410843SDave.Plauger@Sun.COM static void *runstreams(void *arg);
74510843SDave.Plauger@Sun.COM
74610843SDave.Plauger@Sun.COM static void
initstreams(int corefd,int nstreams,int maxcsize)74710843SDave.Plauger@Sun.COM initstreams(int corefd, int nstreams, int maxcsize)
74810843SDave.Plauger@Sun.COM {
74910843SDave.Plauger@Sun.COM int nthreads;
75010843SDave.Plauger@Sun.COM int nblocks;
75110843SDave.Plauger@Sun.COM int i;
75210843SDave.Plauger@Sun.COM block_t *b;
75310843SDave.Plauger@Sun.COM tinfo_t *t;
75410843SDave.Plauger@Sun.COM
75510843SDave.Plauger@Sun.COM nthreads = sysconf(_SC_NPROCESSORS_ONLN);
75610843SDave.Plauger@Sun.COM if (nstreams < nthreads)
75710843SDave.Plauger@Sun.COM nthreads = nstreams;
75810843SDave.Plauger@Sun.COM if (nthreads < 1)
75910843SDave.Plauger@Sun.COM nthreads = 1;
76010843SDave.Plauger@Sun.COM nblocks = nthreads * 2;
76110843SDave.Plauger@Sun.COM
76210843SDave.Plauger@Sun.COM tinfo = Zalloc(nthreads * sizeof (tinfo_t));
76310843SDave.Plauger@Sun.COM endtinfo = &tinfo[nthreads];
76410843SDave.Plauger@Sun.COM
76510843SDave.Plauger@Sun.COM /* init streams */
76610843SDave.Plauger@Sun.COM streams = Zalloc(nstreams * sizeof (stream_t));
76710843SDave.Plauger@Sun.COM endstreams = &streams[nstreams];
76810843SDave.Plauger@Sun.COM
76910843SDave.Plauger@Sun.COM /* init stream block buffers */
77010843SDave.Plauger@Sun.COM for (i = 0; i < nblocks; i++) {
77110843SDave.Plauger@Sun.COM b = Zalloc(sizeof (block_t));
77210843SDave.Plauger@Sun.COM b->block = Zalloc(maxcsize);
77310843SDave.Plauger@Sun.COM enqt(&freeblocks, b);
77410843SDave.Plauger@Sun.COM }
77510843SDave.Plauger@Sun.COM
77610843SDave.Plauger@Sun.COM /* init worker threads */
77712967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
77810843SDave.Plauger@Sun.COM threads_active = 1;
77910843SDave.Plauger@Sun.COM threads_stop = 0;
78010843SDave.Plauger@Sun.COM for (t = tinfo; t != endtinfo; t++) {
78110843SDave.Plauger@Sun.COM t->corefd = dup(corefd);
78210843SDave.Plauger@Sun.COM if (t->corefd < 0) {
78310843SDave.Plauger@Sun.COM nthreads = t - tinfo;
78410843SDave.Plauger@Sun.COM endtinfo = t;
78510843SDave.Plauger@Sun.COM break;
78610843SDave.Plauger@Sun.COM }
78710843SDave.Plauger@Sun.COM if (pthread_create(&t->tid, NULL, runstreams, t) != 0)
78812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "pthread_create: %s",
78910843SDave.Plauger@Sun.COM strerror(errno));
79010843SDave.Plauger@Sun.COM }
79112967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
79210843SDave.Plauger@Sun.COM }
79310843SDave.Plauger@Sun.COM
79410843SDave.Plauger@Sun.COM static void
sbarrier()79510843SDave.Plauger@Sun.COM sbarrier()
79610843SDave.Plauger@Sun.COM {
79710843SDave.Plauger@Sun.COM stream_t *s;
79810843SDave.Plauger@Sun.COM
79912967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
80010843SDave.Plauger@Sun.COM for (s = streams; s != endstreams; s++) {
80110843SDave.Plauger@Sun.COM while (s->bound || s->blocks.head != NULL)
80212967Sgavin.maltby@oracle.com (void) pthread_cond_wait(&cvbarrier, &lock);
80310843SDave.Plauger@Sun.COM }
80412967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
80510843SDave.Plauger@Sun.COM }
80610843SDave.Plauger@Sun.COM
80710843SDave.Plauger@Sun.COM static void
stopstreams()80810843SDave.Plauger@Sun.COM stopstreams()
80910843SDave.Plauger@Sun.COM {
81010843SDave.Plauger@Sun.COM tinfo_t *t;
81110843SDave.Plauger@Sun.COM
81210843SDave.Plauger@Sun.COM if (threads_active) {
81310843SDave.Plauger@Sun.COM sbarrier();
81412967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
81510843SDave.Plauger@Sun.COM threads_stop = 1;
81612967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvwork);
81712967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
81810843SDave.Plauger@Sun.COM for (t = tinfo; t != endtinfo; t++)
81912967Sgavin.maltby@oracle.com (void) pthread_join(t->tid, NULL);
82010843SDave.Plauger@Sun.COM free(tinfo);
82110843SDave.Plauger@Sun.COM tinfo = NULL;
82210843SDave.Plauger@Sun.COM threads_active = 0;
82310843SDave.Plauger@Sun.COM }
82410843SDave.Plauger@Sun.COM }
82510843SDave.Plauger@Sun.COM
82610843SDave.Plauger@Sun.COM static block_t *
getfreeblock()82710843SDave.Plauger@Sun.COM getfreeblock()
82810843SDave.Plauger@Sun.COM {
82910843SDave.Plauger@Sun.COM block_t *b;
83010843SDave.Plauger@Sun.COM
83112967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
83210843SDave.Plauger@Sun.COM while ((b = deqh(&freeblocks)) == NULL)
83312967Sgavin.maltby@oracle.com (void) pthread_cond_wait(&cvfree, &lock);
83412967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
83510843SDave.Plauger@Sun.COM return (b);
83610843SDave.Plauger@Sun.COM }
83710843SDave.Plauger@Sun.COM
83810843SDave.Plauger@Sun.COM /* data page offset from page number */
83910843SDave.Plauger@Sun.COM #define BTOP(b) ((b) >> dumphdr.dump_pageshift)
84010843SDave.Plauger@Sun.COM #define PTOB(p) ((p) << dumphdr.dump_pageshift)
84110843SDave.Plauger@Sun.COM #define DATAOFF(p) (corehdr.dump_data + PTOB(p))
84210843SDave.Plauger@Sun.COM
84310843SDave.Plauger@Sun.COM /* check for coreblksize boundary */
84410843SDave.Plauger@Sun.COM static int
isblkbnd(pgcnt_t pgnum)84510843SDave.Plauger@Sun.COM isblkbnd(pgcnt_t pgnum)
84610843SDave.Plauger@Sun.COM {
84710843SDave.Plauger@Sun.COM return (P2PHASE(DATAOFF(pgnum), coreblksize) == 0);
84810843SDave.Plauger@Sun.COM }
84910843SDave.Plauger@Sun.COM
85010843SDave.Plauger@Sun.COM static int
iszpage(char * buf)85110843SDave.Plauger@Sun.COM iszpage(char *buf)
85210843SDave.Plauger@Sun.COM {
85310843SDave.Plauger@Sun.COM size_t sz;
85410843SDave.Plauger@Sun.COM uint64_t *pl;
85510843SDave.Plauger@Sun.COM
85612967Sgavin.maltby@oracle.com /*LINTED:E_BAD_PTR_CAST_ALIGN*/
85710843SDave.Plauger@Sun.COM pl = (uint64_t *)(buf);
85810843SDave.Plauger@Sun.COM for (sz = 0; sz < pagesize; sz += sizeof (*pl))
85910843SDave.Plauger@Sun.COM if (*pl++ != 0)
86010843SDave.Plauger@Sun.COM return (0);
86110843SDave.Plauger@Sun.COM return (1);
86210843SDave.Plauger@Sun.COM }
86310843SDave.Plauger@Sun.COM
86410843SDave.Plauger@Sun.COM volatile uint_t *hist;
86510843SDave.Plauger@Sun.COM
86610843SDave.Plauger@Sun.COM /* write pages to the core file */
86710843SDave.Plauger@Sun.COM static void
putpage(int corefd,char * buf,pgcnt_t pgnum,pgcnt_t np)86810843SDave.Plauger@Sun.COM putpage(int corefd, char *buf, pgcnt_t pgnum, pgcnt_t np)
86910843SDave.Plauger@Sun.COM {
87010843SDave.Plauger@Sun.COM atomic_inc_uint(&hist[np]);
87110843SDave.Plauger@Sun.COM if (np > 0)
87210843SDave.Plauger@Sun.COM Pwrite(corefd, buf, PTOB(np), DATAOFF(pgnum));
87310843SDave.Plauger@Sun.COM }
87410843SDave.Plauger@Sun.COM
87510843SDave.Plauger@Sun.COM /*
87610843SDave.Plauger@Sun.COM * Process one lzjb block.
87710843SDave.Plauger@Sun.COM * No object (stream header or page) will be split over a block boundary.
87810843SDave.Plauger@Sun.COM */
87910843SDave.Plauger@Sun.COM static void
lzjbblock(int corefd,stream_t * s,char * block,size_t blocksz)88010843SDave.Plauger@Sun.COM lzjbblock(int corefd, stream_t *s, char *block, size_t blocksz)
88110843SDave.Plauger@Sun.COM {
88210843SDave.Plauger@Sun.COM int in = 0;
88310843SDave.Plauger@Sun.COM int csize;
88410843SDave.Plauger@Sun.COM int doflush;
88510843SDave.Plauger@Sun.COM char *out;
88610843SDave.Plauger@Sun.COM size_t dsize;
88710843SDave.Plauger@Sun.COM dumpcsize_t sc;
88810843SDave.Plauger@Sun.COM dumpstreamhdr_t sh;
88910843SDave.Plauger@Sun.COM
89010843SDave.Plauger@Sun.COM if (!s->init) {
89110843SDave.Plauger@Sun.COM s->init = 1;
89210843SDave.Plauger@Sun.COM if (s->blkbuf == NULL)
89310843SDave.Plauger@Sun.COM s->blkbuf = Zalloc(coreblksize);
89410843SDave.Plauger@Sun.COM s->state = STREAMSTART;
89510843SDave.Plauger@Sun.COM }
89610843SDave.Plauger@Sun.COM while (in < blocksz) {
89710843SDave.Plauger@Sun.COM switch (s->state) {
89810843SDave.Plauger@Sun.COM case STREAMSTART:
89912967Sgavin.maltby@oracle.com (void) memcpy(&sh, block + in, sizeof (sh));
90010843SDave.Plauger@Sun.COM in += sizeof (sh);
90110843SDave.Plauger@Sun.COM if (strcmp(DUMP_STREAM_MAGIC, sh.stream_magic) != 0)
90212967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
90310843SDave.Plauger@Sun.COM "LZJB STREAMSTART: bad stream header");
90410843SDave.Plauger@Sun.COM if (sh.stream_npages > datahdr.dump_maxrange)
90512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
90610843SDave.Plauger@Sun.COM "LZJB STREAMSTART: bad range: %d > %d",
90710843SDave.Plauger@Sun.COM sh.stream_npages, datahdr.dump_maxrange);
90810843SDave.Plauger@Sun.COM s->pagenum = sh.stream_pagenum;
90910843SDave.Plauger@Sun.COM s->npages = sh.stream_npages;
91010843SDave.Plauger@Sun.COM s->curpage = s->pagenum;
91110843SDave.Plauger@Sun.COM s->nout = 0;
91210843SDave.Plauger@Sun.COM s->done = 0;
91310843SDave.Plauger@Sun.COM s->state = STREAMPAGES;
91410843SDave.Plauger@Sun.COM break;
91510843SDave.Plauger@Sun.COM case STREAMPAGES:
91612967Sgavin.maltby@oracle.com (void) memcpy(&sc, block + in, cs);
91710843SDave.Plauger@Sun.COM in += cs;
91810843SDave.Plauger@Sun.COM csize = DUMP_GET_CSIZE(sc);
91910843SDave.Plauger@Sun.COM if (csize > pagesize)
92012967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
92110843SDave.Plauger@Sun.COM "LZJB STREAMPAGES: bad csize=%d", csize);
92210843SDave.Plauger@Sun.COM
92310843SDave.Plauger@Sun.COM out = s->blkbuf + PTOB(s->nout);
92410843SDave.Plauger@Sun.COM dsize = decompress(block + in, out, csize, pagesize);
92510843SDave.Plauger@Sun.COM
92610843SDave.Plauger@Sun.COM if (dsize != pagesize)
92712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
92810843SDave.Plauger@Sun.COM "LZJB STREAMPAGES: dsize %d != pagesize %d",
92910843SDave.Plauger@Sun.COM dsize, pagesize);
93010843SDave.Plauger@Sun.COM
93110843SDave.Plauger@Sun.COM in += csize;
93210843SDave.Plauger@Sun.COM atomic_inc_64(&saved);
93310843SDave.Plauger@Sun.COM
93410843SDave.Plauger@Sun.COM doflush = 0;
93510843SDave.Plauger@Sun.COM if (s->nout == 0 && iszpage(out)) {
93610843SDave.Plauger@Sun.COM doflush = 1;
93710843SDave.Plauger@Sun.COM atomic_inc_64(&zpages);
93810843SDave.Plauger@Sun.COM } else if (++s->nout >= BTOP(coreblksize) ||
93910843SDave.Plauger@Sun.COM isblkbnd(s->curpage + s->nout)) {
94010843SDave.Plauger@Sun.COM doflush = 1;
94110843SDave.Plauger@Sun.COM }
94210843SDave.Plauger@Sun.COM if (++s->done >= s->npages) {
94310843SDave.Plauger@Sun.COM s->state = STREAMSTART;
94410843SDave.Plauger@Sun.COM doflush = 1;
94510843SDave.Plauger@Sun.COM }
94610843SDave.Plauger@Sun.COM if (doflush) {
94710843SDave.Plauger@Sun.COM putpage(corefd, s->blkbuf, s->curpage, s->nout);
94810843SDave.Plauger@Sun.COM s->nout = 0;
94910843SDave.Plauger@Sun.COM s->curpage = s->pagenum + s->done;
95010843SDave.Plauger@Sun.COM }
95110843SDave.Plauger@Sun.COM break;
95210843SDave.Plauger@Sun.COM }
95310843SDave.Plauger@Sun.COM }
95410843SDave.Plauger@Sun.COM }
95510843SDave.Plauger@Sun.COM
95610843SDave.Plauger@Sun.COM /* bzlib library reports errors with this callback */
95710843SDave.Plauger@Sun.COM void
bz_internal_error(int errcode)95810843SDave.Plauger@Sun.COM bz_internal_error(int errcode)
95910843SDave.Plauger@Sun.COM {
96012967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "bz_internal_error: err %s\n",
96110843SDave.Plauger@Sun.COM BZ2_bzErrorString(errcode));
96210843SDave.Plauger@Sun.COM }
96310843SDave.Plauger@Sun.COM
96410843SDave.Plauger@Sun.COM /*
96510843SDave.Plauger@Sun.COM * Return one object in the stream.
96610843SDave.Plauger@Sun.COM *
96710843SDave.Plauger@Sun.COM * An object (stream header or page) will likely span an input block
96810843SDave.Plauger@Sun.COM * of compression data. Return non-zero when an entire object has been
96910843SDave.Plauger@Sun.COM * retrieved from the stream.
97010843SDave.Plauger@Sun.COM */
97110843SDave.Plauger@Sun.COM static int
bz2decompress(stream_t * s,void * buf,size_t size)97210843SDave.Plauger@Sun.COM bz2decompress(stream_t *s, void *buf, size_t size)
97310843SDave.Plauger@Sun.COM {
97410843SDave.Plauger@Sun.COM int rc;
97510843SDave.Plauger@Sun.COM
97610843SDave.Plauger@Sun.COM if (s->strm.avail_out == 0) {
97710843SDave.Plauger@Sun.COM s->strm.next_out = buf;
97810843SDave.Plauger@Sun.COM s->strm.avail_out = size;
97910843SDave.Plauger@Sun.COM }
98010843SDave.Plauger@Sun.COM while (s->strm.avail_in > 0) {
98110843SDave.Plauger@Sun.COM rc = BZ2_bzDecompress(&s->strm);
98210843SDave.Plauger@Sun.COM if (rc == BZ_STREAM_END) {
98310843SDave.Plauger@Sun.COM rc = BZ2_bzDecompressReset(&s->strm);
98410843SDave.Plauger@Sun.COM if (rc != BZ_OK)
98512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
98610843SDave.Plauger@Sun.COM "BZ2_bzDecompressReset: %s",
98710843SDave.Plauger@Sun.COM BZ2_bzErrorString(rc));
98810843SDave.Plauger@Sun.COM continue;
98910843SDave.Plauger@Sun.COM }
99010843SDave.Plauger@Sun.COM
99110843SDave.Plauger@Sun.COM if (s->strm.avail_out == 0)
99210843SDave.Plauger@Sun.COM break;
99310843SDave.Plauger@Sun.COM }
99410843SDave.Plauger@Sun.COM return (s->strm.avail_out == 0);
99510843SDave.Plauger@Sun.COM }
99610843SDave.Plauger@Sun.COM
99710843SDave.Plauger@Sun.COM /*
99810843SDave.Plauger@Sun.COM * Process one bzip2 block.
99910843SDave.Plauger@Sun.COM * The interface is documented here:
100010843SDave.Plauger@Sun.COM * http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
100110843SDave.Plauger@Sun.COM */
100210843SDave.Plauger@Sun.COM static void
bz2block(int corefd,stream_t * s,char * block,size_t blocksz)100310843SDave.Plauger@Sun.COM bz2block(int corefd, stream_t *s, char *block, size_t blocksz)
100410843SDave.Plauger@Sun.COM {
100510843SDave.Plauger@Sun.COM int rc = 0;
100610843SDave.Plauger@Sun.COM int doflush;
100710843SDave.Plauger@Sun.COM char *out;
100810843SDave.Plauger@Sun.COM
100910843SDave.Plauger@Sun.COM if (!s->init) {
101010843SDave.Plauger@Sun.COM s->init = 1;
101110843SDave.Plauger@Sun.COM rc = BZ2_bzDecompressInit(&s->strm, 0, 0);
101210843SDave.Plauger@Sun.COM if (rc != BZ_OK)
101312967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
101410843SDave.Plauger@Sun.COM "BZ2_bzDecompressInit: %s", BZ2_bzErrorString(rc));
101510843SDave.Plauger@Sun.COM if (s->blkbuf == NULL)
101610843SDave.Plauger@Sun.COM s->blkbuf = Zalloc(coreblksize);
101710843SDave.Plauger@Sun.COM s->strm.avail_out = 0;
101810843SDave.Plauger@Sun.COM s->state = STREAMSTART;
101910843SDave.Plauger@Sun.COM }
102010843SDave.Plauger@Sun.COM s->strm.next_in = block;
102110843SDave.Plauger@Sun.COM s->strm.avail_in = blocksz;
102210843SDave.Plauger@Sun.COM
102310843SDave.Plauger@Sun.COM while (s->strm.avail_in > 0) {
102410843SDave.Plauger@Sun.COM switch (s->state) {
102510843SDave.Plauger@Sun.COM case STREAMSTART:
102610843SDave.Plauger@Sun.COM if (!bz2decompress(s, &s->sh, sizeof (s->sh)))
102710843SDave.Plauger@Sun.COM return;
102810843SDave.Plauger@Sun.COM if (strcmp(DUMP_STREAM_MAGIC, s->sh.stream_magic) != 0)
102912967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
103010843SDave.Plauger@Sun.COM "BZ2 STREAMSTART: bad stream header");
103110843SDave.Plauger@Sun.COM if (s->sh.stream_npages > datahdr.dump_maxrange)
103212967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
103310843SDave.Plauger@Sun.COM "BZ2 STREAMSTART: bad range: %d > %d",
103410843SDave.Plauger@Sun.COM s->sh.stream_npages, datahdr.dump_maxrange);
103510843SDave.Plauger@Sun.COM s->pagenum = s->sh.stream_pagenum;
103610843SDave.Plauger@Sun.COM s->npages = s->sh.stream_npages;
103710843SDave.Plauger@Sun.COM s->curpage = s->pagenum;
103810843SDave.Plauger@Sun.COM s->nout = 0;
103910843SDave.Plauger@Sun.COM s->done = 0;
104010843SDave.Plauger@Sun.COM s->state = STREAMPAGES;
104110843SDave.Plauger@Sun.COM break;
104210843SDave.Plauger@Sun.COM case STREAMPAGES:
104310843SDave.Plauger@Sun.COM out = s->blkbuf + PTOB(s->nout);
104410843SDave.Plauger@Sun.COM if (!bz2decompress(s, out, pagesize))
104510843SDave.Plauger@Sun.COM return;
104610843SDave.Plauger@Sun.COM
104710843SDave.Plauger@Sun.COM atomic_inc_64(&saved);
104810843SDave.Plauger@Sun.COM
104910843SDave.Plauger@Sun.COM doflush = 0;
105010843SDave.Plauger@Sun.COM if (s->nout == 0 && iszpage(out)) {
105110843SDave.Plauger@Sun.COM doflush = 1;
105210843SDave.Plauger@Sun.COM atomic_inc_64(&zpages);
105310843SDave.Plauger@Sun.COM } else if (++s->nout >= BTOP(coreblksize) ||
105410843SDave.Plauger@Sun.COM isblkbnd(s->curpage + s->nout)) {
105510843SDave.Plauger@Sun.COM doflush = 1;
105610843SDave.Plauger@Sun.COM }
105710843SDave.Plauger@Sun.COM if (++s->done >= s->npages) {
105810843SDave.Plauger@Sun.COM s->state = STREAMSTART;
105910843SDave.Plauger@Sun.COM doflush = 1;
106010843SDave.Plauger@Sun.COM }
106110843SDave.Plauger@Sun.COM if (doflush) {
106210843SDave.Plauger@Sun.COM putpage(corefd, s->blkbuf, s->curpage, s->nout);
106310843SDave.Plauger@Sun.COM s->nout = 0;
106410843SDave.Plauger@Sun.COM s->curpage = s->pagenum + s->done;
106510843SDave.Plauger@Sun.COM }
106610843SDave.Plauger@Sun.COM break;
106710843SDave.Plauger@Sun.COM }
106810843SDave.Plauger@Sun.COM }
106910843SDave.Plauger@Sun.COM }
107010843SDave.Plauger@Sun.COM
107110843SDave.Plauger@Sun.COM /* report progress */
107210843SDave.Plauger@Sun.COM static void
report_progress()107310843SDave.Plauger@Sun.COM report_progress()
107410843SDave.Plauger@Sun.COM {
107510843SDave.Plauger@Sun.COM int sec, percent;
107610843SDave.Plauger@Sun.COM
107710843SDave.Plauger@Sun.COM if (!interactive)
107810843SDave.Plauger@Sun.COM return;
107910843SDave.Plauger@Sun.COM
108010843SDave.Plauger@Sun.COM percent = saved * 100LL / corehdr.dump_npages;
108110843SDave.Plauger@Sun.COM if (percent > percent_done) {
108210843SDave.Plauger@Sun.COM sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
108310843SDave.Plauger@Sun.COM (void) printf("\r%2d:%02d %3d%% done", sec / 60, sec % 60,
108410843SDave.Plauger@Sun.COM percent);
108510843SDave.Plauger@Sun.COM (void) fflush(stdout);
108610843SDave.Plauger@Sun.COM percent_done = percent;
108710843SDave.Plauger@Sun.COM }
108810843SDave.Plauger@Sun.COM }
108910843SDave.Plauger@Sun.COM
109010843SDave.Plauger@Sun.COM /* thread body */
109110843SDave.Plauger@Sun.COM static void *
runstreams(void * arg)109210843SDave.Plauger@Sun.COM runstreams(void *arg)
109310843SDave.Plauger@Sun.COM {
109410843SDave.Plauger@Sun.COM tinfo_t *t = arg;
109510843SDave.Plauger@Sun.COM stream_t *s;
109610843SDave.Plauger@Sun.COM block_t *b;
109710843SDave.Plauger@Sun.COM int bound;
109810843SDave.Plauger@Sun.COM
109912967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
110010843SDave.Plauger@Sun.COM while (!threads_stop) {
110110843SDave.Plauger@Sun.COM bound = 0;
110210843SDave.Plauger@Sun.COM for (s = streams; s != endstreams; s++) {
110310843SDave.Plauger@Sun.COM if (s->bound || s->blocks.head == NULL)
110410843SDave.Plauger@Sun.COM continue;
110510843SDave.Plauger@Sun.COM s->bound = 1;
110610843SDave.Plauger@Sun.COM bound = 1;
110712967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvwork);
110810843SDave.Plauger@Sun.COM while (s->blocks.head != NULL) {
110910843SDave.Plauger@Sun.COM b = deqh(&s->blocks);
111012967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
111110843SDave.Plauger@Sun.COM
111210843SDave.Plauger@Sun.COM if (datahdr.dump_clevel < DUMP_CLEVEL_BZIP2)
111310843SDave.Plauger@Sun.COM lzjbblock(t->corefd, s, b->block,
111410843SDave.Plauger@Sun.COM b->size);
111510843SDave.Plauger@Sun.COM else
111610843SDave.Plauger@Sun.COM bz2block(t->corefd, s, b->block,
111710843SDave.Plauger@Sun.COM b->size);
111810843SDave.Plauger@Sun.COM
111912967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
112010843SDave.Plauger@Sun.COM enqt(&freeblocks, b);
112112967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvfree);
112210843SDave.Plauger@Sun.COM
112310843SDave.Plauger@Sun.COM report_progress();
112410843SDave.Plauger@Sun.COM }
112510843SDave.Plauger@Sun.COM s->bound = 0;
112612967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvbarrier);
112710843SDave.Plauger@Sun.COM }
112810843SDave.Plauger@Sun.COM if (!bound && !threads_stop)
112912967Sgavin.maltby@oracle.com (void) pthread_cond_wait(&cvwork, &lock);
113010843SDave.Plauger@Sun.COM }
113112967Sgavin.maltby@oracle.com (void) close(t->corefd);
113212967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvwork);
113312967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
113410843SDave.Plauger@Sun.COM return (arg);
113510843SDave.Plauger@Sun.COM }
113610843SDave.Plauger@Sun.COM
113710843SDave.Plauger@Sun.COM /*
113810843SDave.Plauger@Sun.COM * Process compressed pages.
113910843SDave.Plauger@Sun.COM *
114010843SDave.Plauger@Sun.COM * The old format, now called single-threaded lzjb, is a 32-bit size
114110843SDave.Plauger@Sun.COM * word followed by 'size' bytes of lzjb compression data for one
114210843SDave.Plauger@Sun.COM * page. The new format extends this by storing a 12-bit "tag" in the
114310843SDave.Plauger@Sun.COM * upper bits of the size word. When the size word is pagesize or
114410843SDave.Plauger@Sun.COM * less, it is assumed to be one lzjb page. When the size word is
114510843SDave.Plauger@Sun.COM * greater than pagesize, it is assumed to be a "stream block",
114610843SDave.Plauger@Sun.COM * belonging to up to 4095 streams. In practice, the number of streams
114710843SDave.Plauger@Sun.COM * is set to one less than the number of CPUs running at crash
114810843SDave.Plauger@Sun.COM * time. One CPU processes the crash dump, the remaining CPUs
114910843SDave.Plauger@Sun.COM * separately process groups of data pages.
115010843SDave.Plauger@Sun.COM *
115110843SDave.Plauger@Sun.COM * savecore creates a thread per stream, but never more threads than
115210843SDave.Plauger@Sun.COM * the number of CPUs running savecore. This is because savecore can
115310843SDave.Plauger@Sun.COM * be processing a crash file from a remote machine, which may have
115410843SDave.Plauger@Sun.COM * more CPUs.
115510843SDave.Plauger@Sun.COM *
115610843SDave.Plauger@Sun.COM * When the kernel uses parallel lzjb or parallel bzip2, we expect a
115710843SDave.Plauger@Sun.COM * series of 128KB blocks of compression data. In this case, each
115810843SDave.Plauger@Sun.COM * block has a "tag", in the range 1-4095. Each block is handed off to
115910843SDave.Plauger@Sun.COM * to the threads running "runstreams". The dump format is either lzjb
116010843SDave.Plauger@Sun.COM * or bzip2, never a mixture. These threads, in turn, process the
116110843SDave.Plauger@Sun.COM * compression data for groups of pages. Groups of pages are delimited
116210843SDave.Plauger@Sun.COM * by a "stream header", which indicates a starting pfn and number of
116310843SDave.Plauger@Sun.COM * pages. When a stream block has been read, the condition variable
116410843SDave.Plauger@Sun.COM * "cvwork" is signalled, which causes one of the avaiable threads to
116510843SDave.Plauger@Sun.COM * wake up and process the stream.
116610843SDave.Plauger@Sun.COM *
116710843SDave.Plauger@Sun.COM * In the parallel case there will be streams blocks encoding all data
116810843SDave.Plauger@Sun.COM * pages. The stream of blocks is terminated by a zero size
116910843SDave.Plauger@Sun.COM * word. There can be a few lzjb pages tacked on the end, depending on
117010843SDave.Plauger@Sun.COM * the architecture. The sbarrier function ensures that all stream
117110843SDave.Plauger@Sun.COM * blocks have been processed so that the page number for the few
117210843SDave.Plauger@Sun.COM * single pages at the end can be known.
117310843SDave.Plauger@Sun.COM */
117410843SDave.Plauger@Sun.COM static void
decompress_pages(int corefd)117510843SDave.Plauger@Sun.COM decompress_pages(int corefd)
117610843SDave.Plauger@Sun.COM {
117710843SDave.Plauger@Sun.COM char *cpage = NULL;
117810843SDave.Plauger@Sun.COM char *dpage = NULL;
117910843SDave.Plauger@Sun.COM char *out;
118010843SDave.Plauger@Sun.COM pgcnt_t curpage;
118110843SDave.Plauger@Sun.COM block_t *b;
118210843SDave.Plauger@Sun.COM FILE *dumpf;
118310843SDave.Plauger@Sun.COM FILE *tracef = NULL;
118410843SDave.Plauger@Sun.COM stream_t *s;
118510843SDave.Plauger@Sun.COM size_t dsize;
118610843SDave.Plauger@Sun.COM size_t insz = FBUFSIZE;
118710843SDave.Plauger@Sun.COM char *inbuf = Zalloc(insz);
118810843SDave.Plauger@Sun.COM uint32_t csize;
118910843SDave.Plauger@Sun.COM dumpcsize_t dcsize;
119010843SDave.Plauger@Sun.COM int nstreams = datahdr.dump_nstreams;
119110843SDave.Plauger@Sun.COM int maxcsize = datahdr.dump_maxcsize;
119210843SDave.Plauger@Sun.COM int nout, tag, doflush;
119310843SDave.Plauger@Sun.COM
119410843SDave.Plauger@Sun.COM dumpf = fdopen(dup(dumpfd), "rb");
119510843SDave.Plauger@Sun.COM if (dumpf == NULL)
119612967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "fdopen: %s",
119712967Sgavin.maltby@oracle.com strerror(errno));
119810843SDave.Plauger@Sun.COM
119912967Sgavin.maltby@oracle.com (void) setvbuf(dumpf, inbuf, _IOFBF, insz);
120010843SDave.Plauger@Sun.COM Fseek(dumphdr.dump_data, dumpf);
120110843SDave.Plauger@Sun.COM
120212967Sgavin.maltby@oracle.com /*LINTED: E_CONSTANT_CONDITION*/
120310843SDave.Plauger@Sun.COM while (1) {
120410843SDave.Plauger@Sun.COM
120510843SDave.Plauger@Sun.COM /*
120610843SDave.Plauger@Sun.COM * The csize word delimits stream blocks.
120710843SDave.Plauger@Sun.COM * See dumphdr.h for a description.
120810843SDave.Plauger@Sun.COM */
120910843SDave.Plauger@Sun.COM Fread(&dcsize, sizeof (dcsize), dumpf);
121010843SDave.Plauger@Sun.COM
121110843SDave.Plauger@Sun.COM tag = DUMP_GET_TAG(dcsize);
121210843SDave.Plauger@Sun.COM csize = DUMP_GET_CSIZE(dcsize);
121310843SDave.Plauger@Sun.COM
121410843SDave.Plauger@Sun.COM if (tag != 0) { /* a stream block */
121510843SDave.Plauger@Sun.COM
121610843SDave.Plauger@Sun.COM if (nstreams == 0)
121712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
121810843SDave.Plauger@Sun.COM "starting data header is missing");
121910843SDave.Plauger@Sun.COM
122010843SDave.Plauger@Sun.COM if (tag > nstreams)
122112967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
122210843SDave.Plauger@Sun.COM "stream tag %d not in range 1..%d",
122310843SDave.Plauger@Sun.COM tag, nstreams);
122410843SDave.Plauger@Sun.COM
122510843SDave.Plauger@Sun.COM if (csize > maxcsize)
122612967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
122710843SDave.Plauger@Sun.COM "block size 0x%x > max csize 0x%x",
122810843SDave.Plauger@Sun.COM csize, maxcsize);
122910843SDave.Plauger@Sun.COM
123010843SDave.Plauger@Sun.COM if (streams == NULL)
123110843SDave.Plauger@Sun.COM initstreams(corefd, nstreams, maxcsize);
123210843SDave.Plauger@Sun.COM s = &streams[tag - 1];
123310843SDave.Plauger@Sun.COM s->tag = tag;
123410843SDave.Plauger@Sun.COM
123510843SDave.Plauger@Sun.COM b = getfreeblock();
123610843SDave.Plauger@Sun.COM b->size = csize;
123710843SDave.Plauger@Sun.COM Fread(b->block, csize, dumpf);
123810843SDave.Plauger@Sun.COM
123912967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&lock);
124010843SDave.Plauger@Sun.COM enqt(&s->blocks, b);
124110843SDave.Plauger@Sun.COM if (!s->bound)
124212967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&cvwork);
124312967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&lock);
124410843SDave.Plauger@Sun.COM
124510843SDave.Plauger@Sun.COM } else if (csize > 0) { /* one lzjb page */
124610843SDave.Plauger@Sun.COM
124710843SDave.Plauger@Sun.COM if (csize > pagesize)
124812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
124910843SDave.Plauger@Sun.COM "csize 0x%x > pagesize 0x%x",
125010843SDave.Plauger@Sun.COM csize, pagesize);
125110843SDave.Plauger@Sun.COM
125210843SDave.Plauger@Sun.COM if (cpage == NULL)
125310843SDave.Plauger@Sun.COM cpage = Zalloc(pagesize);
125410843SDave.Plauger@Sun.COM if (dpage == NULL) {
125510843SDave.Plauger@Sun.COM dpage = Zalloc(coreblksize);
125610843SDave.Plauger@Sun.COM nout = 0;
125710843SDave.Plauger@Sun.COM }
125810843SDave.Plauger@Sun.COM
125910843SDave.Plauger@Sun.COM Fread(cpage, csize, dumpf);
126010843SDave.Plauger@Sun.COM
126110843SDave.Plauger@Sun.COM out = dpage + PTOB(nout);
126210843SDave.Plauger@Sun.COM dsize = decompress(cpage, out, csize, pagesize);
126310843SDave.Plauger@Sun.COM
126410843SDave.Plauger@Sun.COM if (dsize != pagesize)
126512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR,
126610843SDave.Plauger@Sun.COM "dsize 0x%x != pagesize 0x%x",
126710843SDave.Plauger@Sun.COM dsize, pagesize);
126810843SDave.Plauger@Sun.COM
126910843SDave.Plauger@Sun.COM /*
127010843SDave.Plauger@Sun.COM * wait for streams to flush so that 'saved' is correct
127110843SDave.Plauger@Sun.COM */
127210843SDave.Plauger@Sun.COM if (threads_active)
127310843SDave.Plauger@Sun.COM sbarrier();
127410843SDave.Plauger@Sun.COM
127510843SDave.Plauger@Sun.COM doflush = 0;
127610843SDave.Plauger@Sun.COM if (nout == 0)
127710843SDave.Plauger@Sun.COM curpage = saved;
127810843SDave.Plauger@Sun.COM
127910843SDave.Plauger@Sun.COM atomic_inc_64(&saved);
128010843SDave.Plauger@Sun.COM
128110843SDave.Plauger@Sun.COM if (nout == 0 && iszpage(dpage)) {
128210843SDave.Plauger@Sun.COM doflush = 1;
128310843SDave.Plauger@Sun.COM atomic_inc_64(&zpages);
128410843SDave.Plauger@Sun.COM } else if (++nout >= BTOP(coreblksize) ||
128510843SDave.Plauger@Sun.COM isblkbnd(curpage + nout) ||
128610843SDave.Plauger@Sun.COM saved >= dumphdr.dump_npages) {
128710843SDave.Plauger@Sun.COM doflush = 1;
128810843SDave.Plauger@Sun.COM }
128910843SDave.Plauger@Sun.COM
129010843SDave.Plauger@Sun.COM if (doflush) {
129110843SDave.Plauger@Sun.COM putpage(corefd, dpage, curpage, nout);
129210843SDave.Plauger@Sun.COM nout = 0;
129310843SDave.Plauger@Sun.COM }
129410843SDave.Plauger@Sun.COM
129510843SDave.Plauger@Sun.COM report_progress();
129610843SDave.Plauger@Sun.COM
129710843SDave.Plauger@Sun.COM /*
129810843SDave.Plauger@Sun.COM * Non-streams lzjb does not use blocks. Stop
129910843SDave.Plauger@Sun.COM * here if all the pages have been decompressed.
130010843SDave.Plauger@Sun.COM */
130110843SDave.Plauger@Sun.COM if (saved >= dumphdr.dump_npages)
130210843SDave.Plauger@Sun.COM break;
130310843SDave.Plauger@Sun.COM
130410843SDave.Plauger@Sun.COM } else {
130510843SDave.Plauger@Sun.COM break; /* end of data */
130610843SDave.Plauger@Sun.COM }
130710843SDave.Plauger@Sun.COM }
130810843SDave.Plauger@Sun.COM
130910843SDave.Plauger@Sun.COM stopstreams();
131010843SDave.Plauger@Sun.COM if (tracef != NULL)
131112967Sgavin.maltby@oracle.com (void) fclose(tracef);
131212967Sgavin.maltby@oracle.com (void) fclose(dumpf);
131310843SDave.Plauger@Sun.COM if (inbuf)
131410843SDave.Plauger@Sun.COM free(inbuf);
131510843SDave.Plauger@Sun.COM if (cpage)
131610843SDave.Plauger@Sun.COM free(cpage);
131710843SDave.Plauger@Sun.COM if (dpage)
131810843SDave.Plauger@Sun.COM free(dpage);
131910843SDave.Plauger@Sun.COM if (streams)
132010843SDave.Plauger@Sun.COM free(streams);
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate static void
build_corefile(const char * namelist,const char * corefile)13240Sstevel@tonic-gate build_corefile(const char *namelist, const char *corefile)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate size_t pfn_table_size = dumphdr.dump_npages * sizeof (pfn_t);
13270Sstevel@tonic-gate size_t ksyms_size = dumphdr.dump_ksyms_size;
13280Sstevel@tonic-gate size_t ksyms_csize = dumphdr.dump_ksyms_csize;
132910843SDave.Plauger@Sun.COM pfn_t *pfn_table;
13300Sstevel@tonic-gate char *ksyms_base = Zalloc(ksyms_size);
13310Sstevel@tonic-gate char *ksyms_cbase = Zalloc(ksyms_csize);
133210843SDave.Plauger@Sun.COM size_t ksyms_dsize;
133310843SDave.Plauger@Sun.COM Stat_t st;
13340Sstevel@tonic-gate int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
13350Sstevel@tonic-gate int namefd = Open(namelist, O_WRONLY | O_CREAT | O_TRUNC, 0644);
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate (void) printf("Constructing namelist %s/%s\n", savedir, namelist);
13380Sstevel@tonic-gate
13390Sstevel@tonic-gate /*
134010843SDave.Plauger@Sun.COM * Determine the optimum write size for the core file
134110843SDave.Plauger@Sun.COM */
134210843SDave.Plauger@Sun.COM Fstat(corefd, &st, corefile);
134310843SDave.Plauger@Sun.COM
134410843SDave.Plauger@Sun.COM if (verbose > 1)
134512967Sgavin.maltby@oracle.com (void) printf("%s: %ld block size\n", corefile,
134612967Sgavin.maltby@oracle.com (long)st.st_blksize);
134710843SDave.Plauger@Sun.COM coreblksize = st.st_blksize;
134810843SDave.Plauger@Sun.COM if (coreblksize < MINCOREBLKSIZE || !ISP2(coreblksize))
134910843SDave.Plauger@Sun.COM coreblksize = MINCOREBLKSIZE;
135010843SDave.Plauger@Sun.COM
135110843SDave.Plauger@Sun.COM hist = Zalloc((sizeof (uint64_t) * BTOP(coreblksize)) + 1);
135210843SDave.Plauger@Sun.COM
135310843SDave.Plauger@Sun.COM /*
135410843SDave.Plauger@Sun.COM * This dump file is now uncompressed
135510843SDave.Plauger@Sun.COM */
135610843SDave.Plauger@Sun.COM corehdr.dump_flags &= ~DF_COMPRESSED;
135710843SDave.Plauger@Sun.COM
135810843SDave.Plauger@Sun.COM /*
13590Sstevel@tonic-gate * Read in the compressed symbol table, copy it to corefile,
13600Sstevel@tonic-gate * decompress it, and write the result to namelist.
13610Sstevel@tonic-gate */
13620Sstevel@tonic-gate corehdr.dump_ksyms = pagesize;
13630Sstevel@tonic-gate Pread(dumpfd, ksyms_cbase, ksyms_csize, dumphdr.dump_ksyms);
13640Sstevel@tonic-gate Pwrite(corefd, ksyms_cbase, ksyms_csize, corehdr.dump_ksyms);
13650Sstevel@tonic-gate
136610843SDave.Plauger@Sun.COM ksyms_dsize = decompress(ksyms_cbase, ksyms_base, ksyms_csize,
136710843SDave.Plauger@Sun.COM ksyms_size);
136810843SDave.Plauger@Sun.COM if (ksyms_dsize != ksyms_size)
136912967Sgavin.maltby@oracle.com logprint(SC_SL_WARN,
137010843SDave.Plauger@Sun.COM "bad data in symbol table, %lu of %lu bytes saved",
137110843SDave.Plauger@Sun.COM ksyms_dsize, ksyms_size);
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate Pwrite(namefd, ksyms_base, ksyms_size, 0);
13740Sstevel@tonic-gate (void) close(namefd);
13750Sstevel@tonic-gate free(ksyms_cbase);
13760Sstevel@tonic-gate free(ksyms_base);
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate (void) printf("Constructing corefile %s/%s\n", savedir, corefile);
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /*
13810Sstevel@tonic-gate * Read in and write out the pfn table.
13820Sstevel@tonic-gate */
138310843SDave.Plauger@Sun.COM pfn_table = Zalloc(pfn_table_size);
13840Sstevel@tonic-gate corehdr.dump_pfn = corehdr.dump_ksyms + roundup(ksyms_size, pagesize);
13850Sstevel@tonic-gate Pread(dumpfd, pfn_table, pfn_table_size, dumphdr.dump_pfn);
13860Sstevel@tonic-gate Pwrite(corefd, pfn_table, pfn_table_size, corehdr.dump_pfn);
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate /*
13890Sstevel@tonic-gate * Convert the raw translation data into a hashed dump map.
13900Sstevel@tonic-gate */
13910Sstevel@tonic-gate corehdr.dump_map = corehdr.dump_pfn + roundup(pfn_table_size, pagesize);
13920Sstevel@tonic-gate build_dump_map(corefd, pfn_table);
139310843SDave.Plauger@Sun.COM free(pfn_table);
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate /*
139610843SDave.Plauger@Sun.COM * Decompress the pages
13970Sstevel@tonic-gate */
139810843SDave.Plauger@Sun.COM decompress_pages(corefd);
139910843SDave.Plauger@Sun.COM (void) printf(": %ld of %ld pages saved\n", (pgcnt_t)saved,
140010843SDave.Plauger@Sun.COM dumphdr.dump_npages);
14010Sstevel@tonic-gate
140210843SDave.Plauger@Sun.COM if (verbose)
140310843SDave.Plauger@Sun.COM (void) printf("%ld (%ld%%) zero pages were not written\n",
140410843SDave.Plauger@Sun.COM (pgcnt_t)zpages, (pgcnt_t)zpages * 100 /
140510843SDave.Plauger@Sun.COM dumphdr.dump_npages);
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate if (saved != dumphdr.dump_npages)
140812967Sgavin.maltby@oracle.com logprint(SC_SL_WARN, "bad data after page %ld", saved);
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate /*
14110Sstevel@tonic-gate * Write out the modified dump headers.
14120Sstevel@tonic-gate */
14130Sstevel@tonic-gate Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
141410843SDave.Plauger@Sun.COM if (!filemode)
141510843SDave.Plauger@Sun.COM Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate (void) close(corefd);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate * When the system panics, the kernel saves all undelivered messages (messages
14220Sstevel@tonic-gate * that never made it out to syslogd(1M)) in the dump. At a mimimum, the
14230Sstevel@tonic-gate * panic message itself will always fall into this category. Upon reboot,
14240Sstevel@tonic-gate * the syslog startup script runs savecore -m to recover these messages.
14250Sstevel@tonic-gate *
14260Sstevel@tonic-gate * To do this, we read the unsent messages from the dump and send them to
14270Sstevel@tonic-gate * /dev/conslog on priority band 1. This has the effect of prepending them
14280Sstevel@tonic-gate * to any already-accumulated messages in the console backlog, thus preserving
14290Sstevel@tonic-gate * temporal ordering across the reboot.
14300Sstevel@tonic-gate *
14310Sstevel@tonic-gate * Note: since savecore -m is used *only* for this purpose, it does *not*
14320Sstevel@tonic-gate * attempt to save the crash dump. The dump will be saved later, after
14330Sstevel@tonic-gate * syslogd(1M) starts, by the savecore startup script.
14340Sstevel@tonic-gate */
14350Sstevel@tonic-gate static int
message_save(void)14360Sstevel@tonic-gate message_save(void)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE);
14390Sstevel@tonic-gate offset_t ldoff;
14400Sstevel@tonic-gate log_dump_t ld;
14410Sstevel@tonic-gate log_ctl_t lc;
14420Sstevel@tonic-gate struct strbuf ctl, dat;
14430Sstevel@tonic-gate int logfd;
14440Sstevel@tonic-gate
14450Sstevel@tonic-gate logfd = Open("/dev/conslog", O_WRONLY, 0644);
14460Sstevel@tonic-gate dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
14470Sstevel@tonic-gate dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate ctl.buf = (void *)&lc;
14500Sstevel@tonic-gate ctl.len = sizeof (log_ctl_t);
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate dat.buf = Zalloc(DUMP_LOGSIZE);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate for (;;) {
14550Sstevel@tonic-gate ldoff = dumpoff;
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate Pread(dumpfd, &ld, sizeof (log_dump_t), dumpoff);
14580Sstevel@tonic-gate dumpoff += sizeof (log_dump_t);
14590Sstevel@tonic-gate dat.len = ld.ld_msgsize;
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate if (ld.ld_magic == 0)
14620Sstevel@tonic-gate break;
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate if (ld.ld_magic != LOG_MAGIC)
146512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
146612967Sgavin.maltby@oracle.com "bad magic %x", ld.ld_magic);
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate if (dat.len >= DUMP_LOGSIZE)
146912967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
147012967Sgavin.maltby@oracle.com "bad size %d", ld.ld_msgsize);
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate Pread(dumpfd, ctl.buf, ctl.len, dumpoff);
14730Sstevel@tonic-gate dumpoff += ctl.len;
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate if (ld.ld_csum != checksum32(ctl.buf, ctl.len))
147612967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
147712967Sgavin.maltby@oracle.com "bad log_ctl checksum");
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate lc.flags |= SL_LOGONLY;
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate Pread(dumpfd, dat.buf, dat.len, dumpoff);
14820Sstevel@tonic-gate dumpoff += dat.len;
14830Sstevel@tonic-gate
14840Sstevel@tonic-gate if (ld.ld_msum != checksum32(dat.buf, dat.len))
148512967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
148612967Sgavin.maltby@oracle.com "bad message checksum");
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate if (putpmsg(logfd, &ctl, &dat, 1, MSG_BAND) == -1)
148912967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "putpmsg: %s",
149012967Sgavin.maltby@oracle.com strerror(errno));
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate ld.ld_magic = 0; /* clear magic so we never save twice */
14930Sstevel@tonic-gate Pwrite(dumpfd, &ld, sizeof (log_dump_t), ldoff);
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate return (0);
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate
149810843SDave.Plauger@Sun.COM static long
getbounds(const char * f)149910843SDave.Plauger@Sun.COM getbounds(const char *f)
150010843SDave.Plauger@Sun.COM {
150110843SDave.Plauger@Sun.COM long b = -1;
150210843SDave.Plauger@Sun.COM const char *p = strrchr(f, '/');
150310843SDave.Plauger@Sun.COM
150412967Sgavin.maltby@oracle.com (void) sscanf(p ? p + 1 : f, "vmdump.%ld", &b);
150510843SDave.Plauger@Sun.COM return (b);
150610843SDave.Plauger@Sun.COM }
150710843SDave.Plauger@Sun.COM
150812967Sgavin.maltby@oracle.com static void
stack_retrieve(char * stack)150912967Sgavin.maltby@oracle.com stack_retrieve(char *stack)
151012967Sgavin.maltby@oracle.com {
151112967Sgavin.maltby@oracle.com summary_dump_t sd;
151212967Sgavin.maltby@oracle.com offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE +
151312967Sgavin.maltby@oracle.com DUMP_ERPTSIZE);
151412967Sgavin.maltby@oracle.com dumpoff -= DUMP_SUMMARYSIZE;
151512967Sgavin.maltby@oracle.com
151612967Sgavin.maltby@oracle.com dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
151712967Sgavin.maltby@oracle.com dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
151812967Sgavin.maltby@oracle.com
151912967Sgavin.maltby@oracle.com Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
152012967Sgavin.maltby@oracle.com dumpoff += sizeof (summary_dump_t);
152112967Sgavin.maltby@oracle.com
152212967Sgavin.maltby@oracle.com if (sd.sd_magic == 0) {
152312967Sgavin.maltby@oracle.com *stack = '\0';
152412967Sgavin.maltby@oracle.com return;
152512967Sgavin.maltby@oracle.com }
152612967Sgavin.maltby@oracle.com
152712967Sgavin.maltby@oracle.com if (sd.sd_magic != SUMMARY_MAGIC) {
152812967Sgavin.maltby@oracle.com *stack = '\0';
152912967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_VERBOSE,
153012967Sgavin.maltby@oracle.com "bad summary magic %x", sd.sd_magic);
153112967Sgavin.maltby@oracle.com return;
153212967Sgavin.maltby@oracle.com }
153312967Sgavin.maltby@oracle.com Pread(dumpfd, stack, STACK_BUF_SIZE, dumpoff);
153412967Sgavin.maltby@oracle.com if (sd.sd_ssum != checksum32(stack, STACK_BUF_SIZE))
153512967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_VERBOSE, "bad stack checksum");
153612967Sgavin.maltby@oracle.com }
153712967Sgavin.maltby@oracle.com
153812967Sgavin.maltby@oracle.com static void
raise_event(enum sc_event_type evidx,char * warn_string)153912967Sgavin.maltby@oracle.com raise_event(enum sc_event_type evidx, char *warn_string)
154012967Sgavin.maltby@oracle.com {
154112967Sgavin.maltby@oracle.com uint32_t pl = sc_event[evidx].sce_payload;
154212967Sgavin.maltby@oracle.com char panic_stack[STACK_BUF_SIZE];
154312967Sgavin.maltby@oracle.com nvlist_t *attr = NULL;
154412967Sgavin.maltby@oracle.com char uuidbuf[36 + 1];
154512967Sgavin.maltby@oracle.com int err = 0;
154612967Sgavin.maltby@oracle.com
154712967Sgavin.maltby@oracle.com if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0)
154812967Sgavin.maltby@oracle.com goto publish; /* try to send payload-free event */
154912967Sgavin.maltby@oracle.com
155012967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_SAVEDIR && savedir != NULL)
155112967Sgavin.maltby@oracle.com err |= nvlist_add_string(attr, "dumpdir", savedir);
155212967Sgavin.maltby@oracle.com
155312967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_INSTANCE && bounds != -1)
155412967Sgavin.maltby@oracle.com err |= nvlist_add_int64(attr, "instance", bounds);
155512967Sgavin.maltby@oracle.com
155612967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_ISCOMPRESSED) {
155712967Sgavin.maltby@oracle.com err |= nvlist_add_boolean_value(attr, "compressed",
155812967Sgavin.maltby@oracle.com csave ? B_TRUE : B_FALSE);
155912967Sgavin.maltby@oracle.com }
156012967Sgavin.maltby@oracle.com
156112967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_DUMPADM_EN) {
156212967Sgavin.maltby@oracle.com char *disabled = defread("DUMPADM_ENABLE=no");
156312967Sgavin.maltby@oracle.com
156412967Sgavin.maltby@oracle.com err |= nvlist_add_boolean_value(attr, "savecore-enabled",
156512967Sgavin.maltby@oracle.com disabled ? B_FALSE : B_TRUE);
156612967Sgavin.maltby@oracle.com }
156712967Sgavin.maltby@oracle.com
156812967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_IMAGEUUID) {
156912967Sgavin.maltby@oracle.com (void) strncpy(uuidbuf, corehdr.dump_uuid, 36);
157012967Sgavin.maltby@oracle.com uuidbuf[36] = '\0';
157112967Sgavin.maltby@oracle.com err |= nvlist_add_string(attr, "os-instance-uuid", uuidbuf);
157212967Sgavin.maltby@oracle.com }
157312967Sgavin.maltby@oracle.com
157412967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_CRASHTIME) {
157512967Sgavin.maltby@oracle.com err |= nvlist_add_int64(attr, "crashtime",
157612967Sgavin.maltby@oracle.com (int64_t)corehdr.dump_crashtime);
157712967Sgavin.maltby@oracle.com }
157812967Sgavin.maltby@oracle.com
157912967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_PANICSTR && corehdr.dump_panicstring[0] != '\0') {
158012967Sgavin.maltby@oracle.com err |= nvlist_add_string(attr, "panicstr",
158112967Sgavin.maltby@oracle.com corehdr.dump_panicstring);
158212967Sgavin.maltby@oracle.com }
158312967Sgavin.maltby@oracle.com
158412967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_PANICSTACK) {
158512967Sgavin.maltby@oracle.com stack_retrieve(panic_stack);
158612967Sgavin.maltby@oracle.com
158712967Sgavin.maltby@oracle.com if (panic_stack[0] != '\0') {
158812967Sgavin.maltby@oracle.com /*
158912967Sgavin.maltby@oracle.com * The summary page may not be present if the dump
159012967Sgavin.maltby@oracle.com * was previously recorded compressed.
159112967Sgavin.maltby@oracle.com */
159212967Sgavin.maltby@oracle.com (void) nvlist_add_string(attr, "panicstack",
159312967Sgavin.maltby@oracle.com panic_stack);
159412967Sgavin.maltby@oracle.com }
159512967Sgavin.maltby@oracle.com }
159612967Sgavin.maltby@oracle.com
159712967Sgavin.maltby@oracle.com /* add warning string if this is an ireport for dump failure */
159812967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_FAILREASON && warn_string != NULL)
159912967Sgavin.maltby@oracle.com (void) nvlist_add_string(attr, "failure-reason", warn_string);
160012967Sgavin.maltby@oracle.com
160112967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_DUMPCOMPLETE)
160212967Sgavin.maltby@oracle.com err |= nvlist_add_boolean_value(attr, "dump-incomplete",
160312967Sgavin.maltby@oracle.com dump_incomplete ? B_TRUE : B_FALSE);
160412967Sgavin.maltby@oracle.com
160512967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_FM_PANIC) {
160612967Sgavin.maltby@oracle.com err |= nvlist_add_boolean_value(attr, "fm-panic",
160712967Sgavin.maltby@oracle.com fm_panic ? B_TRUE : B_FALSE);
160812967Sgavin.maltby@oracle.com }
160912967Sgavin.maltby@oracle.com
161012967Sgavin.maltby@oracle.com if (pl & SC_PAYLOAD_JUSTCHECKING) {
161112967Sgavin.maltby@oracle.com err |= nvlist_add_boolean_value(attr, "will-attempt-savecore",
161212967Sgavin.maltby@oracle.com cflag ? B_FALSE : B_TRUE);
161312967Sgavin.maltby@oracle.com }
161412967Sgavin.maltby@oracle.com
161512967Sgavin.maltby@oracle.com if (err)
161612967Sgavin.maltby@oracle.com logprint(SC_SL_WARN, "Errors while constructing '%s' "
161712967Sgavin.maltby@oracle.com "event payload; will try to publish anyway.");
161812967Sgavin.maltby@oracle.com publish:
161912967Sgavin.maltby@oracle.com if (fmev_rspublish_nvl(FMEV_RULESET_ON_SUNOS,
162012967Sgavin.maltby@oracle.com "panic", sc_event[evidx].sce_subclass, FMEV_HIPRI,
162112967Sgavin.maltby@oracle.com attr) != FMEV_SUCCESS) {
162212967Sgavin.maltby@oracle.com logprint(SC_SL_ERR, "failed to publish '%s' event: %s",
162312967Sgavin.maltby@oracle.com sc_event[evidx].sce_subclass, fmev_strerror(fmev_errno));
162412967Sgavin.maltby@oracle.com nvlist_free(attr);
162512967Sgavin.maltby@oracle.com }
162612967Sgavin.maltby@oracle.com
162712967Sgavin.maltby@oracle.com }
162812967Sgavin.maltby@oracle.com
162912967Sgavin.maltby@oracle.com
16300Sstevel@tonic-gate int
main(int argc,char * argv[])16310Sstevel@tonic-gate main(int argc, char *argv[])
16320Sstevel@tonic-gate {
163312967Sgavin.maltby@oracle.com int i, c, bfd;
163410843SDave.Plauger@Sun.COM Stat_t st;
163510843SDave.Plauger@Sun.COM struct rlimit rl;
163610843SDave.Plauger@Sun.COM long filebounds = -1;
163710909SDave.Plauger@Sun.COM char namelist[30], corefile[30], boundstr[30];
163810843SDave.Plauger@Sun.COM
163910843SDave.Plauger@Sun.COM startts = gethrtime();
164010843SDave.Plauger@Sun.COM
164112967Sgavin.maltby@oracle.com (void) getrlimit(RLIMIT_NOFILE, &rl);
164210843SDave.Plauger@Sun.COM rl.rlim_cur = rl.rlim_max;
164312967Sgavin.maltby@oracle.com (void) setrlimit(RLIMIT_NOFILE, &rl);
16440Sstevel@tonic-gate
16450Sstevel@tonic-gate openlog(progname, LOG_ODELAY, LOG_AUTH);
164610843SDave.Plauger@Sun.COM
16470Sstevel@tonic-gate (void) defopen("/etc/dumpadm.conf");
164810909SDave.Plauger@Sun.COM savedir = defread("DUMPADM_SAVDIR=");
164910909SDave.Plauger@Sun.COM if (savedir != NULL)
165010909SDave.Plauger@Sun.COM savedir = strdup(savedir);
16510Sstevel@tonic-gate
165212967Sgavin.maltby@oracle.com while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) {
16530Sstevel@tonic-gate switch (c) {
16540Sstevel@tonic-gate case 'L':
16550Sstevel@tonic-gate livedump++;
16560Sstevel@tonic-gate break;
16570Sstevel@tonic-gate case 'v':
16580Sstevel@tonic-gate verbose++;
16590Sstevel@tonic-gate break;
166012967Sgavin.maltby@oracle.com case 'c':
166112967Sgavin.maltby@oracle.com cflag++;
166212967Sgavin.maltby@oracle.com break;
16630Sstevel@tonic-gate case 'd':
16640Sstevel@tonic-gate disregard_valid_flag++;
16650Sstevel@tonic-gate break;
16660Sstevel@tonic-gate case 'm':
16670Sstevel@tonic-gate mflag++;
16680Sstevel@tonic-gate break;
16690Sstevel@tonic-gate case 'f':
16700Sstevel@tonic-gate dumpfile = optarg;
167110843SDave.Plauger@Sun.COM filebounds = getbounds(dumpfile);
16720Sstevel@tonic-gate break;
16730Sstevel@tonic-gate case '?':
16740Sstevel@tonic-gate usage();
16750Sstevel@tonic-gate }
16760Sstevel@tonic-gate }
16770Sstevel@tonic-gate
1678*13110SChris.Beal@Oracle.COM if (geteuid() != 0 && filebounds < 0) {
1679*13110SChris.Beal@Oracle.COM (void) fprintf(stderr, "%s: %s %s\n", progname,
1680*13110SChris.Beal@Oracle.COM gettext("you must be root to use"), progname);
1681*13110SChris.Beal@Oracle.COM exit(1);
1682*13110SChris.Beal@Oracle.COM }
1683*13110SChris.Beal@Oracle.COM
168410843SDave.Plauger@Sun.COM interactive = isatty(STDOUT_FILENO);
168510843SDave.Plauger@Sun.COM
168612967Sgavin.maltby@oracle.com if (cflag && livedump)
168712967Sgavin.maltby@oracle.com usage();
168812967Sgavin.maltby@oracle.com
16890Sstevel@tonic-gate if (dumpfile == NULL || livedump)
16900Sstevel@tonic-gate dumpfd = Open("/dev/dump", O_RDONLY, 0444);
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate if (dumpfile == NULL) {
16930Sstevel@tonic-gate dumpfile = Zalloc(MAXPATHLEN);
169410843SDave.Plauger@Sun.COM if (ioctl(dumpfd, DIOCGETDEV, dumpfile) == -1)
169512967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_IF_ISATTY | SC_EXIT_ERR,
169610843SDave.Plauger@Sun.COM "no dump device configured");
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate if (mflag)
17000Sstevel@tonic-gate return (message_save());
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate if (optind == argc - 1)
17030Sstevel@tonic-gate savedir = argv[optind];
170410843SDave.Plauger@Sun.COM
17050Sstevel@tonic-gate if (savedir == NULL || optind < argc - 1)
17060Sstevel@tonic-gate usage();
17070Sstevel@tonic-gate
17080Sstevel@tonic-gate if (livedump && ioctl(dumpfd, DIOCDUMP, NULL) == -1)
170912967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_EXIT_ERR,
171012967Sgavin.maltby@oracle.com "dedicated dump device required");
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate (void) close(dumpfd);
171310843SDave.Plauger@Sun.COM dumpfd = -1;
171410843SDave.Plauger@Sun.COM
171510843SDave.Plauger@Sun.COM Stat(dumpfile, &st);
171610843SDave.Plauger@Sun.COM
171710843SDave.Plauger@Sun.COM filemode = S_ISREG(st.st_mode);
171810843SDave.Plauger@Sun.COM
171910843SDave.Plauger@Sun.COM if (!filemode && defread("DUMPADM_CSAVE=off") == NULL)
172010843SDave.Plauger@Sun.COM csave = 1;
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate read_dumphdr();
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate /*
17250Sstevel@tonic-gate * We want this message to go to the log file, but not the console.
17260Sstevel@tonic-gate * There's no good way to do that with the existing syslog facility.
17270Sstevel@tonic-gate * We could extend it to handle this, but there doesn't seem to be
17280Sstevel@tonic-gate * a general need for it, so we isolate the complexity here instead.
17290Sstevel@tonic-gate */
17300Sstevel@tonic-gate if (dumphdr.dump_panicstring[0] != '\0') {
17310Sstevel@tonic-gate int logfd = Open("/dev/conslog", O_WRONLY, 0644);
17320Sstevel@tonic-gate log_ctl_t lc;
17330Sstevel@tonic-gate struct strbuf ctl, dat;
17340Sstevel@tonic-gate char msg[DUMP_PANICSIZE + 100];
17350Sstevel@tonic-gate char fmt[] = "reboot after panic: %s";
17360Sstevel@tonic-gate uint32_t msgid;
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate STRLOG_MAKE_MSGID(fmt, msgid);
17390Sstevel@tonic-gate
174012967Sgavin.maltby@oracle.com /* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */
17410Sstevel@tonic-gate (void) sprintf(msg, "%s: [ID %u FACILITY_AND_PRIORITY] ",
17420Sstevel@tonic-gate progname, msgid);
174312967Sgavin.maltby@oracle.com /* LINTED: E_SEC_PRINTF_VAR_FMT */
17440Sstevel@tonic-gate (void) sprintf(msg + strlen(msg), fmt,
17450Sstevel@tonic-gate dumphdr.dump_panicstring);
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate lc.pri = LOG_AUTH | LOG_ERR;
17480Sstevel@tonic-gate lc.flags = SL_CONSOLE | SL_LOGONLY;
17490Sstevel@tonic-gate lc.level = 0;
17500Sstevel@tonic-gate
17510Sstevel@tonic-gate ctl.buf = (void *)&lc;
17520Sstevel@tonic-gate ctl.len = sizeof (log_ctl_t);
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate dat.buf = (void *)msg;
17550Sstevel@tonic-gate dat.len = strlen(msg) + 1;
17560Sstevel@tonic-gate
17570Sstevel@tonic-gate (void) putmsg(logfd, &ctl, &dat, 0);
17580Sstevel@tonic-gate (void) close(logfd);
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate
176112967Sgavin.maltby@oracle.com if ((dumphdr.dump_flags & DF_COMPLETE) == 0) {
176212967Sgavin.maltby@oracle.com logprint(SC_SL_WARN, "incomplete dump on dump device");
176312967Sgavin.maltby@oracle.com dump_incomplete = B_TRUE;
176412967Sgavin.maltby@oracle.com }
176512967Sgavin.maltby@oracle.com
176612967Sgavin.maltby@oracle.com if (dumphdr.dump_fm_panic)
176712967Sgavin.maltby@oracle.com fm_panic = B_TRUE;
176812967Sgavin.maltby@oracle.com
176912967Sgavin.maltby@oracle.com /*
177012967Sgavin.maltby@oracle.com * We have a valid dump on a dump device and know as much about
177112967Sgavin.maltby@oracle.com * it as we're going to at this stage. Raise an event for
177212967Sgavin.maltby@oracle.com * logging and so that FMA can open a case for this panic.
177312967Sgavin.maltby@oracle.com * Avoid this step for FMA-initiated panics - FMA will replay
177412967Sgavin.maltby@oracle.com * ereports off the dump device independently of savecore and
177512967Sgavin.maltby@oracle.com * will make a diagnosis, so we don't want to open two cases
177612967Sgavin.maltby@oracle.com * for the same event. Also avoid raising an event for a
177712967Sgavin.maltby@oracle.com * livedump, or when we inflating a compressed dump.
177812967Sgavin.maltby@oracle.com */
177912967Sgavin.maltby@oracle.com if (!fm_panic && !livedump && !filemode)
178012967Sgavin.maltby@oracle.com raise_event(SC_EVENT_DUMP_PENDING, NULL);
178112967Sgavin.maltby@oracle.com
178212967Sgavin.maltby@oracle.com logprint(SC_SL_WARN, "System dump time: %s",
178312967Sgavin.maltby@oracle.com ctime(&dumphdr.dump_crashtime));
17840Sstevel@tonic-gate
178512967Sgavin.maltby@oracle.com /*
178612967Sgavin.maltby@oracle.com * Option -c is designed for use from svc-dumpadm where we know
178712967Sgavin.maltby@oracle.com * that dumpadm -n is in effect but run savecore -c just to
178812967Sgavin.maltby@oracle.com * get the above dump_pending_on_device event raised. If it is run
178912967Sgavin.maltby@oracle.com * interactively then just print further panic details.
179012967Sgavin.maltby@oracle.com */
179112967Sgavin.maltby@oracle.com if (cflag) {
179212967Sgavin.maltby@oracle.com char *disabled = defread("DUMPADM_ENABLE=no");
179312967Sgavin.maltby@oracle.com int lvl = interactive ? SC_SL_WARN : SC_SL_ERR;
179412967Sgavin.maltby@oracle.com int ec = fm_panic ? SC_EXIT_FM : SC_EXIT_PEND;
17950Sstevel@tonic-gate
179612967Sgavin.maltby@oracle.com logprint(lvl | ec,
179712967Sgavin.maltby@oracle.com "Panic crashdump pending on dump device%s "
179812967Sgavin.maltby@oracle.com "run savecore(1M) manually to extract. "
179912967Sgavin.maltby@oracle.com "Image UUID %s%s.",
180012967Sgavin.maltby@oracle.com disabled ? " but dumpadm -n in effect;" : ";",
180112967Sgavin.maltby@oracle.com corehdr.dump_uuid,
180212967Sgavin.maltby@oracle.com fm_panic ? "(fault-management initiated)" : "");
180312967Sgavin.maltby@oracle.com /*NOTREACHED*/
180412967Sgavin.maltby@oracle.com }
180512967Sgavin.maltby@oracle.com
180612967Sgavin.maltby@oracle.com if (chdir(savedir) == -1)
180712967Sgavin.maltby@oracle.com logprint(SC_SL_ERR | SC_EXIT_ERR, "chdir(\"%s\"): %s",
180812967Sgavin.maltby@oracle.com savedir, strerror(errno));
180910843SDave.Plauger@Sun.COM
181010843SDave.Plauger@Sun.COM check_space(csave);
181110843SDave.Plauger@Sun.COM
181210843SDave.Plauger@Sun.COM if (filebounds < 0)
181310843SDave.Plauger@Sun.COM bounds = read_number_from_file("bounds", 0);
181410843SDave.Plauger@Sun.COM else
181510843SDave.Plauger@Sun.COM bounds = filebounds;
181610843SDave.Plauger@Sun.COM
181710843SDave.Plauger@Sun.COM if (csave) {
181810843SDave.Plauger@Sun.COM size_t metrics_size = datahdr.dump_metrics;
181910843SDave.Plauger@Sun.COM
182010843SDave.Plauger@Sun.COM (void) sprintf(corefile, "vmdump.%ld", bounds);
18210Sstevel@tonic-gate
182210843SDave.Plauger@Sun.COM datahdr.dump_metrics = 0;
182310843SDave.Plauger@Sun.COM
182412967Sgavin.maltby@oracle.com logprint(SC_SL_ERR,
182510843SDave.Plauger@Sun.COM "Saving compressed system crash dump in %s/%s",
182610843SDave.Plauger@Sun.COM savedir, corefile);
182710843SDave.Plauger@Sun.COM
182810843SDave.Plauger@Sun.COM copy_crashfile(corefile);
182910843SDave.Plauger@Sun.COM
183012967Sgavin.maltby@oracle.com /*
183112967Sgavin.maltby@oracle.com * Raise a fault management event that indicates the system
183212967Sgavin.maltby@oracle.com * has panicked. We know a reasonable amount about the
183312967Sgavin.maltby@oracle.com * condition at this time, but the dump is still compressed.
183412967Sgavin.maltby@oracle.com */
183512967Sgavin.maltby@oracle.com if (!livedump && !fm_panic)
183612967Sgavin.maltby@oracle.com raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
183712967Sgavin.maltby@oracle.com
183810843SDave.Plauger@Sun.COM if (metrics_size > 0) {
183910843SDave.Plauger@Sun.COM int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
184010909SDave.Plauger@Sun.COM FILE *mfile = fopen(METRICSFILE, "a");
184110843SDave.Plauger@Sun.COM char *metrics = Zalloc(metrics_size + 1);
184210843SDave.Plauger@Sun.COM
184310843SDave.Plauger@Sun.COM Pread(dumpfd, metrics, metrics_size, endoff +
184410843SDave.Plauger@Sun.COM sizeof (dumphdr) + sizeof (datahdr));
18450Sstevel@tonic-gate
184610937SDave.Plauger@Sun.COM if (sec < 1)
184710937SDave.Plauger@Sun.COM sec = 1;
184810937SDave.Plauger@Sun.COM
184910843SDave.Plauger@Sun.COM if (mfile == NULL) {
185012967Sgavin.maltby@oracle.com logprint(SC_SL_WARN,
185110843SDave.Plauger@Sun.COM "Can't create %s:\n%s",
185210909SDave.Plauger@Sun.COM METRICSFILE, metrics);
185310843SDave.Plauger@Sun.COM } else {
185412967Sgavin.maltby@oracle.com (void) fprintf(mfile, "[[[[,,,");
185510843SDave.Plauger@Sun.COM for (i = 0; i < argc; i++)
185612967Sgavin.maltby@oracle.com (void) fprintf(mfile, "%s ", argv[i]);
185712967Sgavin.maltby@oracle.com (void) fprintf(mfile, "\n");
185812967Sgavin.maltby@oracle.com (void) fprintf(mfile, ",,,%s %s %s %s %s\n",
185910843SDave.Plauger@Sun.COM dumphdr.dump_utsname.sysname,
186010843SDave.Plauger@Sun.COM dumphdr.dump_utsname.nodename,
186110843SDave.Plauger@Sun.COM dumphdr.dump_utsname.release,
186210843SDave.Plauger@Sun.COM dumphdr.dump_utsname.version,
186310843SDave.Plauger@Sun.COM dumphdr.dump_utsname.machine);
186412967Sgavin.maltby@oracle.com (void) fprintf(mfile, ",,,%s dump time %s\n",
186510843SDave.Plauger@Sun.COM dumphdr.dump_flags & DF_LIVE ? "Live" :
186610843SDave.Plauger@Sun.COM "Crash", ctime(&dumphdr.dump_crashtime));
186712967Sgavin.maltby@oracle.com (void) fprintf(mfile, ",,,%s/%s\n", savedir,
186812967Sgavin.maltby@oracle.com corefile);
186912967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Metrics:\n%s\n",
187012967Sgavin.maltby@oracle.com metrics);
187112967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Copy pages,%ld\n",
187212967Sgavin.maltby@oracle.com dumphdr. dump_npages);
187312967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Copy time,%d\n", sec);
187412967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Copy pages/sec,%ld\n",
187510843SDave.Plauger@Sun.COM dumphdr.dump_npages / sec);
187612967Sgavin.maltby@oracle.com (void) fprintf(mfile, "]]]]\n");
187712967Sgavin.maltby@oracle.com (void) fclose(mfile);
187810843SDave.Plauger@Sun.COM }
187910843SDave.Plauger@Sun.COM free(metrics);
188010843SDave.Plauger@Sun.COM }
18810Sstevel@tonic-gate
188212967Sgavin.maltby@oracle.com logprint(SC_SL_ERR,
188310843SDave.Plauger@Sun.COM "Decompress the crash dump with "
188410843SDave.Plauger@Sun.COM "\n'savecore -vf %s/%s'",
188510843SDave.Plauger@Sun.COM savedir, corefile);
18860Sstevel@tonic-gate
188710843SDave.Plauger@Sun.COM } else {
188810843SDave.Plauger@Sun.COM (void) sprintf(namelist, "unix.%ld", bounds);
188910843SDave.Plauger@Sun.COM (void) sprintf(corefile, "vmcore.%ld", bounds);
18900Sstevel@tonic-gate
189110843SDave.Plauger@Sun.COM if (interactive && filebounds >= 0 && access(corefile, F_OK)
189210843SDave.Plauger@Sun.COM == 0)
189312967Sgavin.maltby@oracle.com logprint(SC_SL_NONE | SC_EXIT_ERR,
189410843SDave.Plauger@Sun.COM "%s already exists: remove with "
189510843SDave.Plauger@Sun.COM "'rm -f %s/{unix,vmcore}.%ld'",
189610843SDave.Plauger@Sun.COM corefile, savedir, bounds);
189710843SDave.Plauger@Sun.COM
189812967Sgavin.maltby@oracle.com logprint(SC_SL_ERR,
189910843SDave.Plauger@Sun.COM "saving system crash dump in %s/{unix,vmcore}.%ld",
190010843SDave.Plauger@Sun.COM savedir, bounds);
190110843SDave.Plauger@Sun.COM
190210843SDave.Plauger@Sun.COM build_corefile(namelist, corefile);
190310843SDave.Plauger@Sun.COM
190412967Sgavin.maltby@oracle.com if (!livedump && !filemode && !fm_panic)
190512967Sgavin.maltby@oracle.com raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
190612967Sgavin.maltby@oracle.com
190710909SDave.Plauger@Sun.COM if (access(METRICSFILE, F_OK) == 0) {
190810843SDave.Plauger@Sun.COM int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
190910909SDave.Plauger@Sun.COM FILE *mfile = fopen(METRICSFILE, "a");
19100Sstevel@tonic-gate
191110937SDave.Plauger@Sun.COM if (sec < 1)
191210937SDave.Plauger@Sun.COM sec = 1;
191310937SDave.Plauger@Sun.COM
191412967Sgavin.maltby@oracle.com (void) fprintf(mfile, "[[[[,,,");
191510843SDave.Plauger@Sun.COM for (i = 0; i < argc; i++)
191612967Sgavin.maltby@oracle.com (void) fprintf(mfile, "%s ", argv[i]);
191712967Sgavin.maltby@oracle.com (void) fprintf(mfile, "\n");
191812967Sgavin.maltby@oracle.com (void) fprintf(mfile, ",,,%s/%s\n", savedir, corefile);
191912967Sgavin.maltby@oracle.com (void) fprintf(mfile, ",,,%s %s %s %s %s\n",
192010843SDave.Plauger@Sun.COM dumphdr.dump_utsname.sysname,
192110843SDave.Plauger@Sun.COM dumphdr.dump_utsname.nodename,
192210843SDave.Plauger@Sun.COM dumphdr.dump_utsname.release,
192310843SDave.Plauger@Sun.COM dumphdr.dump_utsname.version,
192410843SDave.Plauger@Sun.COM dumphdr.dump_utsname.machine);
192512967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Uncompress pages,%"PRIu64"\n",
192612967Sgavin.maltby@oracle.com saved);
192712967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Uncompress time,%d\n", sec);
192812967Sgavin.maltby@oracle.com (void) fprintf(mfile, "Uncompress pages/sec,%"
192912967Sgavin.maltby@oracle.com PRIu64"\n", saved / sec);
193012967Sgavin.maltby@oracle.com (void) fprintf(mfile, "]]]]\n");
193112967Sgavin.maltby@oracle.com (void) fclose(mfile);
193210843SDave.Plauger@Sun.COM }
193310843SDave.Plauger@Sun.COM }
193410843SDave.Plauger@Sun.COM
193510843SDave.Plauger@Sun.COM if (filebounds < 0) {
193610843SDave.Plauger@Sun.COM (void) sprintf(boundstr, "%ld\n", bounds + 1);
193710843SDave.Plauger@Sun.COM bfd = Open("bounds", O_WRONLY | O_CREAT | O_TRUNC, 0644);
193810843SDave.Plauger@Sun.COM Pwrite(bfd, boundstr, strlen(boundstr), 0);
193910843SDave.Plauger@Sun.COM (void) close(bfd);
194010843SDave.Plauger@Sun.COM }
194110843SDave.Plauger@Sun.COM
194210843SDave.Plauger@Sun.COM if (verbose) {
194310843SDave.Plauger@Sun.COM int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
194410843SDave.Plauger@Sun.COM
194512967Sgavin.maltby@oracle.com (void) printf("%d:%02d dump %s is done\n",
194610843SDave.Plauger@Sun.COM sec / 60, sec % 60,
194710843SDave.Plauger@Sun.COM csave ? "copy" : "decompress");
194810843SDave.Plauger@Sun.COM }
194910843SDave.Plauger@Sun.COM
195010843SDave.Plauger@Sun.COM if (verbose > 1 && hist != NULL) {
195110843SDave.Plauger@Sun.COM int i, nw;
195210843SDave.Plauger@Sun.COM
195310843SDave.Plauger@Sun.COM for (i = 1, nw = 0; i <= BTOP(coreblksize); ++i)
195410843SDave.Plauger@Sun.COM nw += hist[i] * i;
195512967Sgavin.maltby@oracle.com (void) printf("pages count %%\n");
195610843SDave.Plauger@Sun.COM for (i = 0; i <= BTOP(coreblksize); ++i) {
195710843SDave.Plauger@Sun.COM if (hist[i] == 0)
195810843SDave.Plauger@Sun.COM continue;
195912967Sgavin.maltby@oracle.com (void) printf("%3d %5u %6.2f\n",
196010843SDave.Plauger@Sun.COM i, hist[i], 100.0 * hist[i] * i / nw);
196110843SDave.Plauger@Sun.COM }
196210843SDave.Plauger@Sun.COM }
196310843SDave.Plauger@Sun.COM
196410843SDave.Plauger@Sun.COM (void) close(dumpfd);
196510843SDave.Plauger@Sun.COM dumpfd = -1;
19660Sstevel@tonic-gate
19670Sstevel@tonic-gate return (0);
19680Sstevel@tonic-gate }
1969