xref: /onnv-gate/usr/src/cmd/savecore/savecore.c (revision 13110:ac4251963b1b)
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