xref: /illumos-gate/usr/src/cmd/savecore/savecore.c (revision 5ada8a07)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 /*
25  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <deflt.h>
36 #include <time.h>
37 #include <syslog.h>
38 #include <stropts.h>
39 #include <pthread.h>
40 #include <limits.h>
41 #include <atomic.h>
42 #include <libnvpair.h>
43 #include <libintl.h>
44 #include <sys/mem.h>
45 #include <sys/statvfs.h>
46 #include <sys/dumphdr.h>
47 #include <sys/dumpadm.h>
48 #include <sys/compress.h>
49 #include <sys/panic.h>
50 #include <sys/sysmacros.h>
51 #include <sys/stat.h>
52 #include <sys/resource.h>
53 #include <bzip2/bzlib.h>
54 #include <sys/fm/util.h>
55 #include <fm/libfmevent.h>
56 #include <sys/int_fmtio.h>
57 
58 
59 /* fread/fwrite buffer size */
60 #define	FBUFSIZE		(1ULL << 20)
61 
62 /* minimum size for output buffering */
63 #define	MINCOREBLKSIZE		(1ULL << 17)
64 
65 /* create this file if metrics collection is enabled in the kernel */
66 #define	METRICSFILE "METRICS.csv"
67 
68 static char	progname[9] = "savecore";
69 static char	*savedir;		/* savecore directory */
70 static char	*dumpfile;		/* source of raw crash dump */
71 static long	bounds = -1;		/* numeric suffix */
72 static long	pagesize;		/* dump pagesize */
73 static int	dumpfd = -1;		/* dumpfile descriptor */
74 static dumphdr_t corehdr, dumphdr;	/* initial and terminal dumphdrs */
75 static boolean_t dump_incomplete;	/* dumphdr indicates incomplete */
76 static boolean_t fm_panic;		/* dump is the result of fm_panic */
77 static offset_t	endoff;			/* offset of end-of-dump header */
78 static int	verbose;		/* chatty mode */
79 static int	disregard_valid_flag;	/* disregard valid flag */
80 static int	livedump;		/* dump the current running system */
81 static int	interactive;		/* user invoked; no syslog */
82 static int	csave;			/* save dump compressed */
83 static int	filemode;		/* processing file, not dump device */
84 static int	percent_done;		/* progress indicator */
85 static hrtime_t	startts;		/* timestamp at start */
86 static volatile uint64_t saved;		/* count of pages written */
87 static volatile uint64_t zpages;	/* count of zero pages not written */
88 static dumpdatahdr_t datahdr;		/* compression info */
89 static long	coreblksize;		/* preferred write size (st_blksize) */
90 static int	cflag;			/* run as savecore -c */
91 static int	mflag;			/* run as savecore -m */
92 
93 /*
94  * Payload information for the events we raise.  These are used
95  * in raise_event to determine what payload to include.
96  */
97 #define	SC_PAYLOAD_SAVEDIR	0x0001	/* Include savedir in event */
98 #define	SC_PAYLOAD_INSTANCE	0x0002	/* Include bounds instance number */
99 #define	SC_PAYLOAD_IMAGEUUID	0x0004	/* Include dump OS instance uuid */
100 #define	SC_PAYLOAD_CRASHTIME	0x0008	/* Include epoch crashtime */
101 #define	SC_PAYLOAD_PANICSTR	0x0010	/* Include panic string */
102 #define	SC_PAYLOAD_PANICSTACK	0x0020	/* Include panic string */
103 #define	SC_PAYLOAD_FAILREASON	0x0040	/* Include failure reason */
104 #define	SC_PAYLOAD_DUMPCOMPLETE	0x0080	/* Include completeness indicator */
105 #define	SC_PAYLOAD_ISCOMPRESSED	0x0100	/* Dump is in vmdump.N form */
106 #define	SC_PAYLOAD_DUMPADM_EN	0x0200	/* Is dumpadm enabled or not? */
107 #define	SC_PAYLOAD_FM_PANIC	0x0400	/* Panic initiated by FMA */
108 #define	SC_PAYLOAD_JUSTCHECKING	0x0800	/* Run with -c flag? */
109 
110 enum sc_event_type {
111 	SC_EVENT_DUMP_PENDING,
112 	SC_EVENT_SAVECORE_FAILURE,
113 	SC_EVENT_DUMP_AVAILABLE
114 };
115 
116 /*
117  * Common payload
118  */
119 #define	_SC_PAYLOAD_CMN \
120     SC_PAYLOAD_IMAGEUUID | \
121     SC_PAYLOAD_CRASHTIME | \
122     SC_PAYLOAD_PANICSTR | \
123     SC_PAYLOAD_PANICSTACK | \
124     SC_PAYLOAD_DUMPCOMPLETE | \
125     SC_PAYLOAD_FM_PANIC | \
126     SC_PAYLOAD_SAVEDIR
127 
128 static const struct {
129 	const char *sce_subclass;
130 	uint32_t sce_payload;
131 } sc_event[] = {
132 	/*
133 	 * SC_EVENT_DUMP_PENDING
134 	 */
135 	{
136 		"dump_pending_on_device",
137 		_SC_PAYLOAD_CMN | SC_PAYLOAD_DUMPADM_EN |
138 		    SC_PAYLOAD_JUSTCHECKING
139 	},
140 
141 	/*
142 	 * SC_EVENT_SAVECORE_FAILURE
143 	 */
144 	{
145 		"savecore_failure",
146 		_SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_FAILREASON
147 	},
148 
149 	/*
150 	 * SC_EVENT_DUMP_AVAILABLE
151 	 */
152 	{
153 		"dump_available",
154 		_SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_ISCOMPRESSED
155 	},
156 };
157 
158 static void raise_event(enum sc_event_type, char *);
159 
160 static void
161 usage(void)
162 {
163 	(void) fprintf(stderr,
164 	    "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
165 	exit(1);
166 }
167 
168 #define	SC_SL_NONE	0x0001	/* no syslog */
169 #define	SC_SL_ERR	0x0002	/* syslog if !interactive, LOG_ERR */
170 #define	SC_SL_WARN	0x0004	/* syslog if !interactive, LOG_WARNING */
171 #define	SC_IF_VERBOSE	0x0008	/* message only if -v */
172 #define	SC_IF_ISATTY	0x0010	/* message only if interactive */
173 #define	SC_EXIT_OK	0x0020	/* exit(0) */
174 #define	SC_EXIT_ERR	0x0040	/* exit(1) */
175 #define	SC_EXIT_PEND	0x0080	/* exit(2) */
176 #define	SC_EXIT_FM	0x0100	/* exit(3) */
177 
178 #define	_SC_ALLEXIT	(SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM)
179 
180 static void
181 logprint(uint32_t flags, char *message, ...)
182 {
183 	va_list args;
184 	char buf[1024];
185 	int do_always = ((flags & (SC_IF_VERBOSE | SC_IF_ISATTY)) == 0);
186 	int do_ifverb = (flags & SC_IF_VERBOSE) && verbose;
187 	int do_ifisatty = (flags & SC_IF_ISATTY) && interactive;
188 	int code;
189 	static int logprint_raised = 0;
190 
191 	if (do_always || do_ifverb || do_ifisatty) {
192 		va_start(args, message);
193 		/*LINTED: E_SEC_PRINTF_VAR_FMT*/
194 		(void) vsnprintf(buf, sizeof (buf), message, args);
195 		(void) fprintf(stderr, "%s: %s\n", progname, buf);
196 		if (!interactive) {
197 			switch (flags & (SC_SL_NONE | SC_SL_ERR | SC_SL_WARN)) {
198 			case SC_SL_ERR:
199 				/*LINTED: E_SEC_PRINTF_VAR_FMT*/
200 				syslog(LOG_ERR, buf);
201 				break;
202 
203 			case SC_SL_WARN:
204 				/*LINTED: E_SEC_PRINTF_VAR_FMT*/
205 				syslog(LOG_WARNING, buf);
206 				break;
207 
208 			default:
209 				break;
210 			}
211 		}
212 		va_end(args);
213 	}
214 
215 	switch (flags & _SC_ALLEXIT) {
216 	case 0:
217 		return;
218 
219 	case SC_EXIT_OK:
220 		code = 0;
221 		break;
222 
223 	case SC_EXIT_PEND:
224 		/*
225 		 * Raise an ireport saying why we are exiting.  Do not
226 		 * raise if run as savecore -m.  If something in the
227 		 * raise_event codepath calls logprint avoid recursion.
228 		 */
229 		if (!mflag && logprint_raised++ == 0)
230 			raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
231 		code = 2;
232 		break;
233 
234 	case SC_EXIT_FM:
235 		code = 3;
236 		break;
237 
238 	case SC_EXIT_ERR:
239 	default:
240 		if (!mflag && logprint_raised++ == 0)
241 			raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
242 		code = 1;
243 		break;
244 	}
245 
246 	exit(code);
247 }
248 
249 /*
250  * System call / libc wrappers that exit on error.
251  */
252 static int
253 Open(const char *name, int oflags, mode_t mode)
254 {
255 	int fd;
256 
257 	if ((fd = open64(name, oflags, mode)) == -1)
258 		logprint(SC_SL_ERR | SC_EXIT_ERR, "open(\"%s\"): %s",
259 		    name, strerror(errno));
260 	return (fd);
261 }
262 
263 static void
264 Fread(void *buf, size_t size, FILE *f)
265 {
266 	if (fread(buf, size, 1, f) != 1)
267 		logprint(SC_SL_ERR | SC_EXIT_ERR, "fread: ferror %d feof %d",
268 		    ferror(f), feof(f));
269 }
270 
271 static void
272 Fwrite(void *buf, size_t size, FILE *f)
273 {
274 	if (fwrite(buf, size, 1, f) != 1)
275 		logprint(SC_SL_ERR | SC_EXIT_ERR, "fwrite: %s",
276 		    strerror(errno));
277 }
278 
279 static void
280 Fseek(offset_t off, FILE *f)
281 {
282 	if (fseeko64(f, off, SEEK_SET) != 0)
283 		logprint(SC_SL_ERR | SC_EXIT_ERR, "fseeko64: %s",
284 		    strerror(errno));
285 }
286 
287 typedef struct stat64 Stat_t;
288 
289 static void
290 Fstat(int fd, Stat_t *sb, const char *fname)
291 {
292 	if (fstat64(fd, sb) != 0)
293 		logprint(SC_SL_ERR | SC_EXIT_ERR, "fstat(\"%s\"): %s", fname,
294 		    strerror(errno));
295 }
296 
297 static void
298 Stat(const char *fname, Stat_t *sb)
299 {
300 	if (stat64(fname, sb) != 0)
301 		logprint(SC_SL_ERR | SC_EXIT_ERR, "stat(\"%s\"): %s", fname,
302 		    strerror(errno));
303 }
304 
305 static void
306 Pread(int fd, void *buf, size_t size, offset_t off)
307 {
308 	ssize_t sz = pread64(fd, buf, size, off);
309 
310 	if (sz < 0)
311 		logprint(SC_SL_ERR | SC_EXIT_ERR,
312 		    "pread: %s", strerror(errno));
313 	else if (sz != size)
314 		logprint(SC_SL_ERR | SC_EXIT_ERR,
315 		    "pread: size %ld != %ld", sz, size);
316 }
317 
318 static void
319 Pwrite(int fd, void *buf, size_t size, off64_t off)
320 {
321 	if (pwrite64(fd, buf, size, off) != size)
322 		logprint(SC_SL_ERR | SC_EXIT_ERR, "pwrite: %s",
323 		    strerror(errno));
324 }
325 
326 static void *
327 Zalloc(size_t size)
328 {
329 	void *buf;
330 
331 	if ((buf = calloc(size, 1)) == NULL)
332 		logprint(SC_SL_ERR | SC_EXIT_ERR, "calloc: %s",
333 		    strerror(errno));
334 	return (buf);
335 }
336 
337 static long
338 read_number_from_file(const char *filename, long default_value)
339 {
340 	long file_value = -1;
341 	FILE *fp;
342 
343 	if ((fp = fopen(filename, "r")) != NULL) {
344 		(void) fscanf(fp, "%ld", &file_value);
345 		(void) fclose(fp);
346 	}
347 	return (file_value < 0 ? default_value : file_value);
348 }
349 
350 static void
351 read_dumphdr(void)
352 {
353 	if (filemode)
354 		dumpfd = Open(dumpfile, O_RDONLY, 0644);
355 	else
356 		dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
357 	endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
358 	Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
359 	Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));
360 
361 	pagesize = dumphdr.dump_pagesize;
362 
363 	if (dumphdr.dump_magic != DUMP_MAGIC)
364 		logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
365 		    dumphdr.dump_magic);
366 
367 	if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag)
368 		logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
369 		    "dump already processed");
370 
371 	if (dumphdr.dump_version != DUMP_VERSION)
372 		logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
373 		    "dump version (%d) != %s version (%d)",
374 		    dumphdr.dump_version, progname, DUMP_VERSION);
375 
376 	if (dumphdr.dump_wordsize != DUMP_WORDSIZE)
377 		logprint(SC_SL_NONE | SC_EXIT_PEND,
378 		    "dump is from %u-bit kernel - cannot save on %u-bit kernel",
379 		    dumphdr.dump_wordsize, DUMP_WORDSIZE);
380 
381 	if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
382 		if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
383 			logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
384 			    "dump data version (%d) != %s data version (%d)",
385 			    datahdr.dump_datahdr_version, progname,
386 			    DUMP_DATAHDR_VERSION);
387 	} else {
388 		(void) memset(&datahdr, 0, sizeof (datahdr));
389 		datahdr.dump_maxcsize = pagesize;
390 	}
391 
392 	/*
393 	 * Read the initial header, clear the valid bits, and compare headers.
394 	 * The main header may have been overwritten by swapping if we're
395 	 * using a swap partition as the dump device, in which case we bail.
396 	 */
397 	Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start);
398 
399 	corehdr.dump_flags &= ~DF_VALID;
400 	dumphdr.dump_flags &= ~DF_VALID;
401 
402 	if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
403 		/*
404 		 * Clear valid bit so we don't complain on every invocation.
405 		 */
406 		if (!filemode)
407 			Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
408 		logprint(SC_SL_ERR | SC_EXIT_ERR,
409 		    "initial dump header corrupt");
410 	}
411 }
412 
413 static void
414 check_space(int csave)
415 {
416 	struct statvfs fsb;
417 	int64_t spacefree, dumpsize, minfree, datasize;
418 
419 	if (statvfs(".", &fsb) < 0)
420 		logprint(SC_SL_ERR | SC_EXIT_ERR, "statvfs: %s",
421 		    strerror(errno));
422 
423 	dumpsize = dumphdr.dump_data - dumphdr.dump_start;
424 	datasize = dumphdr.dump_npages * pagesize;
425 	if (!csave)
426 		dumpsize += datasize;
427 	else
428 		dumpsize += datahdr.dump_data_csize;
429 
430 	spacefree = (int64_t)fsb.f_bavail * fsb.f_frsize;
431 	minfree = 1024LL * read_number_from_file("minfree", 1024);
432 	if (spacefree < minfree + dumpsize) {
433 		logprint(SC_SL_ERR | SC_EXIT_ERR,
434 		    "not enough space in %s (%lld MB avail, %lld MB needed)",
435 		    savedir, spacefree >> 20, (minfree + dumpsize) >> 20);
436 	}
437 }
438 
439 static void
440 build_dump_map(int corefd, const pfn_t *pfn_table)
441 {
442 	long i;
443 	static long misses = 0;
444 	size_t dump_mapsize = (corehdr.dump_hashmask + 1) * sizeof (dump_map_t);
445 	mem_vtop_t vtop;
446 	dump_map_t *dmp = Zalloc(dump_mapsize);
447 	char *inbuf = Zalloc(FBUFSIZE);
448 	FILE *in = fdopen(dup(dumpfd), "rb");
449 
450 	(void) setvbuf(in, inbuf, _IOFBF, FBUFSIZE);
451 	Fseek(dumphdr.dump_map, in);
452 
453 	corehdr.dump_data = corehdr.dump_map + roundup(dump_mapsize, pagesize);
454 
455 	for (i = 0; i < corehdr.dump_nvtop; i++) {
456 		long first = 0;
457 		long last = corehdr.dump_npages - 1;
458 		long middle;
459 		pfn_t pfn;
460 		uintptr_t h;
461 
462 		Fread(&vtop, sizeof (mem_vtop_t), in);
463 		while (last >= first) {
464 			middle = (first + last) / 2;
465 			pfn = pfn_table[middle];
466 			if (pfn == vtop.m_pfn)
467 				break;
468 			if (pfn < vtop.m_pfn)
469 				first = middle + 1;
470 			else
471 				last = middle - 1;
472 		}
473 		if (pfn != vtop.m_pfn) {
474 			if (++misses <= 10)
475 				(void) fprintf(stderr,
476 				    "pfn %ld not found for as=%p, va=%p\n",
477 				    vtop.m_pfn, (void *)vtop.m_as, vtop.m_va);
478 			continue;
479 		}
480 
481 		dmp[i].dm_as = vtop.m_as;
482 		dmp[i].dm_va = (uintptr_t)vtop.m_va;
483 		dmp[i].dm_data = corehdr.dump_data +
484 		    ((uint64_t)middle << corehdr.dump_pageshift);
485 
486 		h = DUMP_HASH(&corehdr, dmp[i].dm_as, dmp[i].dm_va);
487 		dmp[i].dm_next = dmp[h].dm_first;
488 		dmp[h].dm_first = corehdr.dump_map + i * sizeof (dump_map_t);
489 	}
490 
491 	Pwrite(corefd, dmp, dump_mapsize, corehdr.dump_map);
492 	free(dmp);
493 	(void) fclose(in);
494 	free(inbuf);
495 }
496 
497 /*
498  * Copy whole sections of the dump device to the file.
499  */
500 static void
501 Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
502     size_t sz)
503 {
504 	size_t nr;
505 	offset_t off = *offp;
506 
507 	while (nb > 0) {
508 		nr = sz < nb ? sz : (size_t)nb;
509 		Pread(dumpfd, buf, nr, dumpoff);
510 		Pwrite(fd, buf, nr, off);
511 		off += nr;
512 		dumpoff += nr;
513 		nb -= nr;
514 	}
515 	*offp = off;
516 }
517 
518 /*
519  * Copy pages when the dump data header is missing.
520  * This supports older kernels with latest savecore.
521  */
522 static void
523 CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
524 {
525 	uint32_t csize;
526 	FILE *in = fdopen(dup(dumpfd), "rb");
527 	FILE *out = fdopen(dup(fd), "wb");
528 	char *cbuf = Zalloc(pagesize);
529 	char *outbuf = Zalloc(FBUFSIZE);
530 	pgcnt_t np = dumphdr.dump_npages;
531 
532 	(void) setvbuf(out, outbuf, _IOFBF, FBUFSIZE);
533 	(void) setvbuf(in, buf, _IOFBF, sz);
534 	Fseek(dumphdr.dump_data, in);
535 
536 	Fseek(*offp, out);
537 	while (np > 0) {
538 		Fread(&csize, sizeof (uint32_t), in);
539 		Fwrite(&csize, sizeof (uint32_t), out);
540 		*offp += sizeof (uint32_t);
541 		if (csize > pagesize || csize == 0) {
542 			logprint(SC_SL_ERR,
543 			    "CopyPages: page %lu csize %d (0x%x) pagesize %d",
544 			    dumphdr.dump_npages - np, csize, csize,
545 			    pagesize);
546 			break;
547 		}
548 		Fread(cbuf, csize, in);
549 		Fwrite(cbuf, csize, out);
550 		*offp += csize;
551 		np--;
552 	}
553 	(void) fclose(in);
554 	(void) fclose(out);
555 	free(outbuf);
556 	free(buf);
557 }
558 
559 /*
560  * Concatenate dump contents into a new file.
561  * Update corehdr with new offsets.
562  */
563 static void
564 copy_crashfile(const char *corefile)
565 {
566 	int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
567 	size_t bufsz = FBUFSIZE;
568 	char *inbuf = Zalloc(bufsz);
569 	offset_t coreoff;
570 	size_t nb;
571 
572 	logprint(SC_SL_ERR | SC_IF_VERBOSE,
573 	    "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
574 
575 	/*
576 	 * This dump file is still compressed
577 	 */
578 	corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
579 
580 	/*
581 	 * Leave room for corehdr, it is updated and written last
582 	 */
583 	corehdr.dump_start = 0;
584 	coreoff = sizeof (corehdr);
585 
586 	/*
587 	 * Read in the compressed symbol table, copy it to corefile.
588 	 */
589 	coreoff = roundup(coreoff, pagesize);
590 	corehdr.dump_ksyms = coreoff;
591 	Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
592 	    inbuf, bufsz);
593 
594 	/*
595 	 * Save the pfn table.
596 	 */
597 	coreoff = roundup(coreoff, pagesize);
598 	corehdr.dump_pfn = coreoff;
599 	Copy(dumphdr.dump_pfn, dumphdr.dump_npages * sizeof (pfn_t), &coreoff,
600 	    corefd, inbuf, bufsz);
601 
602 	/*
603 	 * Save the dump map.
604 	 */
605 	coreoff = roundup(coreoff, pagesize);
606 	corehdr.dump_map = coreoff;
607 	Copy(dumphdr.dump_map, dumphdr.dump_nvtop * sizeof (mem_vtop_t),
608 	    &coreoff, corefd, inbuf, bufsz);
609 
610 	/*
611 	 * Save the data pages.
612 	 */
613 	coreoff = roundup(coreoff, pagesize);
614 	corehdr.dump_data = coreoff;
615 	if (datahdr.dump_data_csize != 0)
616 		Copy(dumphdr.dump_data, datahdr.dump_data_csize, &coreoff,
617 		    corefd, inbuf, bufsz);
618 	else
619 		CopyPages(&coreoff, corefd, inbuf, bufsz);
620 
621 	/*
622 	 * Now write the modified dump header to front and end of the copy.
623 	 * Make it look like a valid dump device.
624 	 *
625 	 * From dumphdr.h: Two headers are written out: one at the
626 	 * beginning of the dump, and the other at the very end of the
627 	 * dump device. The terminal header is at a known location
628 	 * (end of device) so we can always find it.
629 	 *
630 	 * Pad with zeros to each DUMP_OFFSET boundary.
631 	 */
632 	(void) memset(inbuf, 0, DUMP_OFFSET);
633 
634 	nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
635 	if (nb > 0) {
636 		Pwrite(corefd, inbuf, nb, coreoff);
637 		coreoff += nb;
638 	}
639 
640 	Pwrite(corefd, &corehdr, sizeof (corehdr), coreoff);
641 	coreoff += sizeof (corehdr);
642 
643 	Pwrite(corefd, &datahdr, sizeof (datahdr), coreoff);
644 	coreoff += sizeof (datahdr);
645 
646 	nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
647 	if (nb > 0) {
648 		Pwrite(corefd, inbuf, nb, coreoff);
649 	}
650 
651 	free(inbuf);
652 	Pwrite(corefd, &corehdr, sizeof (corehdr), corehdr.dump_start);
653 
654 	/*
655 	 * Write out the modified dump header to the dump device.
656 	 * The dump device has been processed, so DF_VALID is clear.
657 	 */
658 	if (!filemode)
659 		Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
660 
661 	(void) close(corefd);
662 }
663 
664 /*
665  * compressed streams
666  */
667 typedef struct blockhdr blockhdr_t;
668 typedef struct block block_t;
669 
670 struct blockhdr {
671 	block_t *head;
672 	block_t *tail;
673 };
674 
675 struct block {
676 	block_t *next;
677 	char *block;
678 	int size;
679 };
680 
681 typedef enum streamstate {
682 	STREAMSTART,
683 	STREAMPAGES
684 } streamstate_t;
685 
686 typedef struct stream {
687 	streamstate_t state;
688 	int init;
689 	int tag;
690 	int bound;
691 	int nout;
692 	char *blkbuf;
693 	blockhdr_t blocks;
694 	pgcnt_t pagenum;
695 	pgcnt_t curpage;
696 	pgcnt_t npages;
697 	pgcnt_t done;
698 	bz_stream strm;
699 	dumpcsize_t sc;
700 	dumpstreamhdr_t sh;
701 } stream_t;
702 
703 static stream_t *streams;
704 static stream_t *endstreams;
705 
706 const int cs = sizeof (dumpcsize_t);
707 
708 typedef struct tinfo {
709 	pthread_t tid;
710 	int corefd;
711 } tinfo_t;
712 
713 static int threads_stop;
714 static int threads_active;
715 static tinfo_t *tinfo;
716 static tinfo_t *endtinfo;
717 
718 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
719 static pthread_cond_t cvfree = PTHREAD_COND_INITIALIZER;
720 static pthread_cond_t cvwork = PTHREAD_COND_INITIALIZER;
721 static pthread_cond_t cvbarrier = PTHREAD_COND_INITIALIZER;
722 
723 static blockhdr_t freeblocks;
724 
725 static void
726 enqt(blockhdr_t *h, block_t *b)
727 {
728 	b->next = NULL;
729 	if (h->tail == NULL)
730 		h->head = b;
731 	else
732 		h->tail->next = b;
733 	h->tail = b;
734 }
735 
736 static block_t *
737 deqh(blockhdr_t *h)
738 {
739 	block_t *b = h->head;
740 
741 	if (b != NULL) {
742 		h->head = b->next;
743 		if (h->head == NULL)
744 			h->tail = NULL;
745 	}
746 	return (b);
747 }
748 
749 static void *runstreams(void *arg);
750 
751 static void
752 initstreams(int corefd, int nstreams, int maxcsize)
753 {
754 	int nthreads;
755 	int nblocks;
756 	int i;
757 	block_t *b;
758 	tinfo_t *t;
759 
760 	nthreads = sysconf(_SC_NPROCESSORS_ONLN);
761 	if (nstreams < nthreads)
762 		nthreads = nstreams;
763 	if (nthreads < 1)
764 		nthreads = 1;
765 	nblocks = nthreads * 2;
766 
767 	tinfo = Zalloc(nthreads * sizeof (tinfo_t));
768 	endtinfo = &tinfo[nthreads];
769 
770 	/* init streams */
771 	streams = Zalloc(nstreams * sizeof (stream_t));
772 	endstreams = &streams[nstreams];
773 
774 	/* init stream block buffers */
775 	for (i = 0; i < nblocks; i++) {
776 		b = Zalloc(sizeof (block_t));
777 		b->block = Zalloc(maxcsize);
778 		enqt(&freeblocks, b);
779 	}
780 
781 	/* init worker threads */
782 	(void) pthread_mutex_lock(&lock);
783 	threads_active = 1;
784 	threads_stop = 0;
785 	for (t = tinfo; t != endtinfo; t++) {
786 		t->corefd = dup(corefd);
787 		if (t->corefd < 0) {
788 			nthreads = t - tinfo;
789 			endtinfo = t;
790 			break;
791 		}
792 		if (pthread_create(&t->tid, NULL, runstreams, t) != 0)
793 			logprint(SC_SL_ERR | SC_EXIT_ERR, "pthread_create: %s",
794 			    strerror(errno));
795 	}
796 	(void) pthread_mutex_unlock(&lock);
797 }
798 
799 static void
800 sbarrier()
801 {
802 	stream_t *s;
803 
804 	(void) pthread_mutex_lock(&lock);
805 	for (s = streams; s != endstreams; s++) {
806 		while (s->bound || s->blocks.head != NULL)
807 			(void) pthread_cond_wait(&cvbarrier, &lock);
808 	}
809 	(void) pthread_mutex_unlock(&lock);
810 }
811 
812 static void
813 stopstreams()
814 {
815 	tinfo_t *t;
816 
817 	if (threads_active) {
818 		sbarrier();
819 		(void) pthread_mutex_lock(&lock);
820 		threads_stop = 1;
821 		(void) pthread_cond_signal(&cvwork);
822 		(void) pthread_mutex_unlock(&lock);
823 		for (t = tinfo; t != endtinfo; t++)
824 			(void) pthread_join(t->tid, NULL);
825 		free(tinfo);
826 		tinfo = NULL;
827 		threads_active = 0;
828 	}
829 }
830 
831 static block_t *
832 getfreeblock()
833 {
834 	block_t *b;
835 
836 	(void) pthread_mutex_lock(&lock);
837 	while ((b = deqh(&freeblocks)) == NULL)
838 		(void) pthread_cond_wait(&cvfree, &lock);
839 	(void) pthread_mutex_unlock(&lock);
840 	return (b);
841 }
842 
843 /* data page offset from page number */
844 #define	BTOP(b)		((b) >> dumphdr.dump_pageshift)
845 #define	PTOB(p)		((p) << dumphdr.dump_pageshift)
846 #define	DATAOFF(p)	(corehdr.dump_data + PTOB(p))
847 
848 /* check for coreblksize boundary */
849 static int
850 isblkbnd(pgcnt_t pgnum)
851 {
852 	return (P2PHASE(DATAOFF(pgnum), coreblksize) == 0);
853 }
854 
855 static int
856 iszpage(char *buf)
857 {
858 	size_t sz;
859 	uint64_t *pl;
860 
861 	/*LINTED:E_BAD_PTR_CAST_ALIGN*/
862 	pl = (uint64_t *)(buf);
863 	for (sz = 0; sz < pagesize; sz += sizeof (*pl))
864 		if (*pl++ != 0)
865 			return (0);
866 	return (1);
867 }
868 
869 volatile uint_t *hist;
870 
871 /* write pages to the core file */
872 static void
873 putpage(int corefd, char *buf, pgcnt_t pgnum, pgcnt_t np)
874 {
875 	atomic_inc_uint(&hist[np]);
876 	if (np > 0)
877 		Pwrite(corefd, buf, PTOB(np), DATAOFF(pgnum));
878 }
879 
880 /*
881  * Process one lzjb block.
882  * No object (stream header or page) will be split over a block boundary.
883  */
884 static void
885 lzjbblock(int corefd, stream_t *s, char *block, size_t blocksz)
886 {
887 	int in = 0;
888 	int csize;
889 	int doflush;
890 	char *out;
891 	size_t dsize;
892 	dumpcsize_t sc;
893 	dumpstreamhdr_t sh;
894 
895 	if (!s->init) {
896 		s->init = 1;
897 		if (s->blkbuf == NULL)
898 			s->blkbuf = Zalloc(coreblksize);
899 		s->state = STREAMSTART;
900 	}
901 	while (in < blocksz) {
902 		switch (s->state) {
903 		case STREAMSTART:
904 			(void) memcpy(&sh, block + in, sizeof (sh));
905 			in += sizeof (sh);
906 			if (strcmp(DUMP_STREAM_MAGIC, sh.stream_magic) != 0)
907 				logprint(SC_SL_ERR | SC_EXIT_ERR,
908 				    "LZJB STREAMSTART: bad stream header");
909 			if (sh.stream_npages > datahdr.dump_maxrange)
910 				logprint(SC_SL_ERR | SC_EXIT_ERR,
911 				    "LZJB STREAMSTART: bad range: %d > %d",
912 				    sh.stream_npages, datahdr.dump_maxrange);
913 			s->pagenum = sh.stream_pagenum;
914 			s->npages = sh.stream_npages;
915 			s->curpage = s->pagenum;
916 			s->nout = 0;
917 			s->done = 0;
918 			s->state = STREAMPAGES;
919 			break;
920 		case STREAMPAGES:
921 			(void) memcpy(&sc, block + in, cs);
922 			in += cs;
923 			csize = DUMP_GET_CSIZE(sc);
924 			if (csize > pagesize)
925 				logprint(SC_SL_ERR | SC_EXIT_ERR,
926 				    "LZJB STREAMPAGES: bad csize=%d", csize);
927 
928 			out =  s->blkbuf + PTOB(s->nout);
929 			dsize = decompress(block + in, out, csize, pagesize);
930 
931 			if (dsize != pagesize)
932 				logprint(SC_SL_ERR | SC_EXIT_ERR,
933 				    "LZJB STREAMPAGES: dsize %d != pagesize %d",
934 				    dsize, pagesize);
935 
936 			in += csize;
937 			atomic_inc_64(&saved);
938 
939 			doflush = 0;
940 			if (s->nout == 0 && iszpage(out)) {
941 				doflush = 1;
942 				atomic_inc_64(&zpages);
943 			} else if (++s->nout >= BTOP(coreblksize) ||
944 			    isblkbnd(s->curpage + s->nout)) {
945 				doflush = 1;
946 			}
947 			if (++s->done >= s->npages) {
948 				s->state = STREAMSTART;
949 				doflush = 1;
950 			}
951 			if (doflush) {
952 				putpage(corefd, s->blkbuf, s->curpage, s->nout);
953 				s->nout = 0;
954 				s->curpage = s->pagenum + s->done;
955 			}
956 			break;
957 		}
958 	}
959 }
960 
961 /* bzlib library reports errors with this callback */
962 void
963 bz_internal_error(int errcode)
964 {
965 	logprint(SC_SL_ERR | SC_EXIT_ERR, "bz_internal_error: err %s\n",
966 	    BZ2_bzErrorString(errcode));
967 }
968 
969 /*
970  * Return one object in the stream.
971  *
972  * An object (stream header or page) will likely span an input block
973  * of compression data. Return non-zero when an entire object has been
974  * retrieved from the stream.
975  */
976 static int
977 bz2decompress(stream_t *s, void *buf, size_t size)
978 {
979 	int rc;
980 
981 	if (s->strm.avail_out == 0) {
982 		s->strm.next_out = buf;
983 		s->strm.avail_out = size;
984 	}
985 	while (s->strm.avail_in > 0) {
986 		rc = BZ2_bzDecompress(&s->strm);
987 		if (rc == BZ_STREAM_END) {
988 			rc = BZ2_bzDecompressReset(&s->strm);
989 			if (rc != BZ_OK)
990 				logprint(SC_SL_ERR | SC_EXIT_ERR,
991 				    "BZ2_bzDecompressReset: %s",
992 				    BZ2_bzErrorString(rc));
993 			continue;
994 		}
995 
996 		if (s->strm.avail_out == 0)
997 			break;
998 	}
999 	return (s->strm.avail_out == 0);
1000 }
1001 
1002 /*
1003  * Process one bzip2 block.
1004  * The interface is documented here:
1005  * http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
1006  */
1007 static void
1008 bz2block(int corefd, stream_t *s, char *block, size_t blocksz)
1009 {
1010 	int rc = 0;
1011 	int doflush;
1012 	char *out;
1013 
1014 	if (!s->init) {
1015 		s->init = 1;
1016 		rc = BZ2_bzDecompressInit(&s->strm, 0, 0);
1017 		if (rc != BZ_OK)
1018 			logprint(SC_SL_ERR | SC_EXIT_ERR,
1019 			    "BZ2_bzDecompressInit: %s", BZ2_bzErrorString(rc));
1020 		if (s->blkbuf == NULL)
1021 			s->blkbuf = Zalloc(coreblksize);
1022 		s->strm.avail_out = 0;
1023 		s->state = STREAMSTART;
1024 	}
1025 	s->strm.next_in = block;
1026 	s->strm.avail_in = blocksz;
1027 
1028 	while (s->strm.avail_in > 0) {
1029 		switch (s->state) {
1030 		case STREAMSTART:
1031 			if (!bz2decompress(s, &s->sh, sizeof (s->sh)))
1032 				return;
1033 			if (strcmp(DUMP_STREAM_MAGIC, s->sh.stream_magic) != 0)
1034 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1035 				    "BZ2 STREAMSTART: bad stream header");
1036 			if (s->sh.stream_npages > datahdr.dump_maxrange)
1037 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1038 				    "BZ2 STREAMSTART: bad range: %d > %d",
1039 				    s->sh.stream_npages, datahdr.dump_maxrange);
1040 			s->pagenum = s->sh.stream_pagenum;
1041 			s->npages = s->sh.stream_npages;
1042 			s->curpage = s->pagenum;
1043 			s->nout = 0;
1044 			s->done = 0;
1045 			s->state = STREAMPAGES;
1046 			break;
1047 		case STREAMPAGES:
1048 			out = s->blkbuf + PTOB(s->nout);
1049 			if (!bz2decompress(s, out, pagesize))
1050 				return;
1051 
1052 			atomic_inc_64(&saved);
1053 
1054 			doflush = 0;
1055 			if (s->nout == 0 && iszpage(out)) {
1056 				doflush = 1;
1057 				atomic_inc_64(&zpages);
1058 			} else if (++s->nout >= BTOP(coreblksize) ||
1059 			    isblkbnd(s->curpage + s->nout)) {
1060 				doflush = 1;
1061 			}
1062 			if (++s->done >= s->npages) {
1063 				s->state = STREAMSTART;
1064 				doflush = 1;
1065 			}
1066 			if (doflush) {
1067 				putpage(corefd, s->blkbuf, s->curpage, s->nout);
1068 				s->nout = 0;
1069 				s->curpage = s->pagenum + s->done;
1070 			}
1071 			break;
1072 		}
1073 	}
1074 }
1075 
1076 /* report progress */
1077 static void
1078 report_progress()
1079 {
1080 	int sec, percent;
1081 
1082 	if (!interactive)
1083 		return;
1084 
1085 	percent = saved * 100LL / corehdr.dump_npages;
1086 	if (percent > percent_done) {
1087 		sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1088 		(void) printf("\r%2d:%02d %3d%% done", sec / 60, sec % 60,
1089 		    percent);
1090 		(void) fflush(stdout);
1091 		percent_done = percent;
1092 	}
1093 }
1094 
1095 /* thread body */
1096 static void *
1097 runstreams(void *arg)
1098 {
1099 	tinfo_t *t = arg;
1100 	stream_t *s;
1101 	block_t *b;
1102 	int bound;
1103 
1104 	(void) pthread_mutex_lock(&lock);
1105 	while (!threads_stop) {
1106 		bound = 0;
1107 		for (s = streams; s != endstreams; s++) {
1108 			if (s->bound || s->blocks.head == NULL)
1109 				continue;
1110 			s->bound = 1;
1111 			bound = 1;
1112 			(void) pthread_cond_signal(&cvwork);
1113 			while (s->blocks.head != NULL) {
1114 				b = deqh(&s->blocks);
1115 				(void) pthread_mutex_unlock(&lock);
1116 
1117 				if (datahdr.dump_clevel < DUMP_CLEVEL_BZIP2)
1118 					lzjbblock(t->corefd, s, b->block,
1119 					    b->size);
1120 				else
1121 					bz2block(t->corefd, s, b->block,
1122 					    b->size);
1123 
1124 				(void) pthread_mutex_lock(&lock);
1125 				enqt(&freeblocks, b);
1126 				(void) pthread_cond_signal(&cvfree);
1127 
1128 				report_progress();
1129 			}
1130 			s->bound = 0;
1131 			(void) pthread_cond_signal(&cvbarrier);
1132 		}
1133 		if (!bound && !threads_stop)
1134 			(void) pthread_cond_wait(&cvwork, &lock);
1135 	}
1136 	(void) close(t->corefd);
1137 	(void) pthread_cond_signal(&cvwork);
1138 	(void) pthread_mutex_unlock(&lock);
1139 	return (arg);
1140 }
1141 
1142 /*
1143  * Process compressed pages.
1144  *
1145  * The old format, now called single-threaded lzjb, is a 32-bit size
1146  * word followed by 'size' bytes of lzjb compression data for one
1147  * page. The new format extends this by storing a 12-bit "tag" in the
1148  * upper bits of the size word. When the size word is pagesize or
1149  * less, it is assumed to be one lzjb page. When the size word is
1150  * greater than pagesize, it is assumed to be a "stream block",
1151  * belonging to up to 4095 streams. In practice, the number of streams
1152  * is set to one less than the number of CPUs running at crash
1153  * time. One CPU processes the crash dump, the remaining CPUs
1154  * separately process groups of data pages.
1155  *
1156  * savecore creates a thread per stream, but never more threads than
1157  * the number of CPUs running savecore. This is because savecore can
1158  * be processing a crash file from a remote machine, which may have
1159  * more CPUs.
1160  *
1161  * When the kernel uses parallel lzjb or parallel bzip2, we expect a
1162  * series of 128KB blocks of compression data. In this case, each
1163  * block has a "tag", in the range 1-4095. Each block is handed off to
1164  * to the threads running "runstreams". The dump format is either lzjb
1165  * or bzip2, never a mixture. These threads, in turn, process the
1166  * compression data for groups of pages. Groups of pages are delimited
1167  * by a "stream header", which indicates a starting pfn and number of
1168  * pages. When a stream block has been read, the condition variable
1169  * "cvwork" is signalled, which causes one of the avaiable threads to
1170  * wake up and process the stream.
1171  *
1172  * In the parallel case there will be streams blocks encoding all data
1173  * pages. The stream of blocks is terminated by a zero size
1174  * word. There can be a few lzjb pages tacked on the end, depending on
1175  * the architecture. The sbarrier function ensures that all stream
1176  * blocks have been processed so that the page number for the few
1177  * single pages at the end can be known.
1178  */
1179 static void
1180 decompress_pages(int corefd)
1181 {
1182 	char *cpage = NULL;
1183 	char *dpage = NULL;
1184 	char *out;
1185 	pgcnt_t curpage;
1186 	block_t *b;
1187 	FILE *dumpf;
1188 	FILE *tracef = NULL;
1189 	stream_t *s;
1190 	size_t dsize;
1191 	size_t insz = FBUFSIZE;
1192 	char *inbuf = Zalloc(insz);
1193 	uint32_t csize;
1194 	dumpcsize_t dcsize;
1195 	int nstreams = datahdr.dump_nstreams;
1196 	int maxcsize = datahdr.dump_maxcsize;
1197 	int nout, tag, doflush;
1198 
1199 	dumpf = fdopen(dup(dumpfd), "rb");
1200 	if (dumpf == NULL)
1201 		logprint(SC_SL_ERR | SC_EXIT_ERR, "fdopen: %s",
1202 		    strerror(errno));
1203 
1204 	(void) setvbuf(dumpf, inbuf, _IOFBF, insz);
1205 	Fseek(dumphdr.dump_data, dumpf);
1206 
1207 	/*LINTED: E_CONSTANT_CONDITION*/
1208 	while (1) {
1209 
1210 		/*
1211 		 * The csize word delimits stream blocks.
1212 		 * See dumphdr.h for a description.
1213 		 */
1214 		Fread(&dcsize, sizeof (dcsize), dumpf);
1215 
1216 		tag = DUMP_GET_TAG(dcsize);
1217 		csize = DUMP_GET_CSIZE(dcsize);
1218 
1219 		if (tag != 0) {		/* a stream block */
1220 
1221 			if (nstreams == 0)
1222 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1223 				    "starting data header is missing");
1224 
1225 			if (tag > nstreams)
1226 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1227 				    "stream tag %d not in range 1..%d",
1228 				    tag, nstreams);
1229 
1230 			if (csize > maxcsize)
1231 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1232 				    "block size 0x%x > max csize 0x%x",
1233 				    csize, maxcsize);
1234 
1235 			if (streams == NULL)
1236 				initstreams(corefd, nstreams, maxcsize);
1237 			s = &streams[tag - 1];
1238 			s->tag = tag;
1239 
1240 			b = getfreeblock();
1241 			b->size = csize;
1242 			Fread(b->block, csize, dumpf);
1243 
1244 			(void) pthread_mutex_lock(&lock);
1245 			enqt(&s->blocks, b);
1246 			if (!s->bound)
1247 				(void) pthread_cond_signal(&cvwork);
1248 			(void) pthread_mutex_unlock(&lock);
1249 
1250 		} else if (csize > 0) {		/* one lzjb page */
1251 
1252 			if (csize > pagesize)
1253 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1254 				    "csize 0x%x > pagesize 0x%x",
1255 				    csize, pagesize);
1256 
1257 			if (cpage == NULL)
1258 				cpage = Zalloc(pagesize);
1259 			if (dpage == NULL) {
1260 				dpage = Zalloc(coreblksize);
1261 				nout = 0;
1262 			}
1263 
1264 			Fread(cpage, csize, dumpf);
1265 
1266 			out = dpage + PTOB(nout);
1267 			dsize = decompress(cpage, out, csize, pagesize);
1268 
1269 			if (dsize != pagesize)
1270 				logprint(SC_SL_ERR | SC_EXIT_ERR,
1271 				    "dsize 0x%x != pagesize 0x%x",
1272 				    dsize, pagesize);
1273 
1274 			/*
1275 			 * wait for streams to flush so that 'saved' is correct
1276 			 */
1277 			if (threads_active)
1278 				sbarrier();
1279 
1280 			doflush = 0;
1281 			if (nout == 0)
1282 				curpage = saved;
1283 
1284 			atomic_inc_64(&saved);
1285 
1286 			if (nout == 0 && iszpage(dpage)) {
1287 				doflush = 1;
1288 				atomic_inc_64(&zpages);
1289 			} else if (++nout >= BTOP(coreblksize) ||
1290 			    isblkbnd(curpage + nout) ||
1291 			    saved >= dumphdr.dump_npages) {
1292 				doflush = 1;
1293 			}
1294 
1295 			if (doflush) {
1296 				putpage(corefd, dpage, curpage, nout);
1297 				nout = 0;
1298 			}
1299 
1300 			report_progress();
1301 
1302 			/*
1303 			 * Non-streams lzjb does not use blocks.  Stop
1304 			 * here if all the pages have been decompressed.
1305 			 */
1306 			if (saved >= dumphdr.dump_npages)
1307 				break;
1308 
1309 		} else {
1310 			break;			/* end of data */
1311 		}
1312 	}
1313 
1314 	stopstreams();
1315 	if (tracef != NULL)
1316 		(void) fclose(tracef);
1317 	(void) fclose(dumpf);
1318 	if (inbuf)
1319 		free(inbuf);
1320 	if (cpage)
1321 		free(cpage);
1322 	if (dpage)
1323 		free(dpage);
1324 	if (streams)
1325 		free(streams);
1326 }
1327 
1328 static void
1329 build_corefile(const char *namelist, const char *corefile)
1330 {
1331 	size_t pfn_table_size = dumphdr.dump_npages * sizeof (pfn_t);
1332 	size_t ksyms_size = dumphdr.dump_ksyms_size;
1333 	size_t ksyms_csize = dumphdr.dump_ksyms_csize;
1334 	pfn_t *pfn_table;
1335 	char *ksyms_base = Zalloc(ksyms_size);
1336 	char *ksyms_cbase = Zalloc(ksyms_csize);
1337 	size_t ksyms_dsize;
1338 	Stat_t st;
1339 	int corefd = Open(corefile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1340 	int namefd = Open(namelist, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1341 
1342 	(void) printf("Constructing namelist %s/%s\n", savedir, namelist);
1343 
1344 	/*
1345 	 * Determine the optimum write size for the core file
1346 	 */
1347 	Fstat(corefd, &st, corefile);
1348 
1349 	if (verbose > 1)
1350 		(void) printf("%s: %ld block size\n", corefile,
1351 		    (long)st.st_blksize);
1352 	coreblksize = st.st_blksize;
1353 	if (coreblksize < MINCOREBLKSIZE || !ISP2(coreblksize))
1354 		coreblksize = MINCOREBLKSIZE;
1355 
1356 	hist = Zalloc((sizeof (uint64_t) * BTOP(coreblksize)) + 1);
1357 
1358 	/*
1359 	 * This dump file is now uncompressed
1360 	 */
1361 	corehdr.dump_flags &= ~DF_COMPRESSED;
1362 
1363 	/*
1364 	 * Read in the compressed symbol table, copy it to corefile,
1365 	 * decompress it, and write the result to namelist.
1366 	 */
1367 	corehdr.dump_ksyms = pagesize;
1368 	Pread(dumpfd, ksyms_cbase, ksyms_csize, dumphdr.dump_ksyms);
1369 	Pwrite(corefd, ksyms_cbase, ksyms_csize, corehdr.dump_ksyms);
1370 
1371 	ksyms_dsize = decompress(ksyms_cbase, ksyms_base, ksyms_csize,
1372 	    ksyms_size);
1373 	if (ksyms_dsize != ksyms_size)
1374 		logprint(SC_SL_WARN,
1375 		    "bad data in symbol table, %lu of %lu bytes saved",
1376 		    ksyms_dsize, ksyms_size);
1377 
1378 	Pwrite(namefd, ksyms_base, ksyms_size, 0);
1379 	(void) close(namefd);
1380 	free(ksyms_cbase);
1381 	free(ksyms_base);
1382 
1383 	(void) printf("Constructing corefile %s/%s\n", savedir, corefile);
1384 
1385 	/*
1386 	 * Read in and write out the pfn table.
1387 	 */
1388 	pfn_table = Zalloc(pfn_table_size);
1389 	corehdr.dump_pfn = corehdr.dump_ksyms + roundup(ksyms_size, pagesize);
1390 	Pread(dumpfd, pfn_table, pfn_table_size, dumphdr.dump_pfn);
1391 	Pwrite(corefd, pfn_table, pfn_table_size, corehdr.dump_pfn);
1392 
1393 	/*
1394 	 * Convert the raw translation data into a hashed dump map.
1395 	 */
1396 	corehdr.dump_map = corehdr.dump_pfn + roundup(pfn_table_size, pagesize);
1397 	build_dump_map(corefd, pfn_table);
1398 	free(pfn_table);
1399 
1400 	/*
1401 	 * Decompress the pages
1402 	 */
1403 	decompress_pages(corefd);
1404 	(void) printf(": %ld of %ld pages saved\n", (pgcnt_t)saved,
1405 	    dumphdr.dump_npages);
1406 
1407 	if (verbose)
1408 		(void) printf("%ld (%ld%%) zero pages were not written\n",
1409 		    (pgcnt_t)zpages, (pgcnt_t)zpages * 100 /
1410 		    dumphdr.dump_npages);
1411 
1412 	if (saved != dumphdr.dump_npages)
1413 		logprint(SC_SL_WARN, "bad data after page %ld", saved);
1414 
1415 	/*
1416 	 * Write out the modified dump headers.
1417 	 */
1418 	Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
1419 	if (!filemode)
1420 		Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
1421 
1422 	(void) close(corefd);
1423 }
1424 
1425 /*
1426  * When the system panics, the kernel saves all undelivered messages (messages
1427  * that never made it out to syslogd(1M)) in the dump.  At a mimimum, the
1428  * panic message itself will always fall into this category.  Upon reboot,
1429  * the syslog startup script runs savecore -m to recover these messages.
1430  *
1431  * To do this, we read the unsent messages from the dump and send them to
1432  * /dev/conslog on priority band 1.  This has the effect of prepending them
1433  * to any already-accumulated messages in the console backlog, thus preserving
1434  * temporal ordering across the reboot.
1435  *
1436  * Note: since savecore -m is used *only* for this purpose, it does *not*
1437  * attempt to save the crash dump.  The dump will be saved later, after
1438  * syslogd(1M) starts, by the savecore startup script.
1439  */
1440 static int
1441 message_save(void)
1442 {
1443 	offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE);
1444 	offset_t ldoff;
1445 	log_dump_t ld;
1446 	log_ctl_t lc;
1447 	struct strbuf ctl, dat;
1448 	int logfd;
1449 
1450 	logfd = Open("/dev/conslog", O_WRONLY, 0644);
1451 	dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
1452 	dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
1453 
1454 	ctl.buf = (void *)&lc;
1455 	ctl.len = sizeof (log_ctl_t);
1456 
1457 	dat.buf = Zalloc(DUMP_LOGSIZE);
1458 
1459 	for (;;) {
1460 		ldoff = dumpoff;
1461 
1462 		Pread(dumpfd, &ld, sizeof (log_dump_t), dumpoff);
1463 		dumpoff += sizeof (log_dump_t);
1464 		dat.len = ld.ld_msgsize;
1465 
1466 		if (ld.ld_magic == 0)
1467 			break;
1468 
1469 		if (ld.ld_magic != LOG_MAGIC)
1470 			logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
1471 			    "bad magic %x", ld.ld_magic);
1472 
1473 		if (dat.len >= DUMP_LOGSIZE)
1474 			logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
1475 			    "bad size %d", ld.ld_msgsize);
1476 
1477 		Pread(dumpfd, ctl.buf, ctl.len, dumpoff);
1478 		dumpoff += ctl.len;
1479 
1480 		if (ld.ld_csum != checksum32(ctl.buf, ctl.len))
1481 			logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
1482 			    "bad log_ctl checksum");
1483 
1484 		lc.flags |= SL_LOGONLY;
1485 
1486 		Pread(dumpfd, dat.buf, dat.len, dumpoff);
1487 		dumpoff += dat.len;
1488 
1489 		if (ld.ld_msum != checksum32(dat.buf, dat.len))
1490 			logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_OK,
1491 			    "bad message checksum");
1492 
1493 		if (putpmsg(logfd, &ctl, &dat, 1, MSG_BAND) == -1)
1494 			logprint(SC_SL_ERR | SC_EXIT_ERR, "putpmsg: %s",
1495 			    strerror(errno));
1496 
1497 		ld.ld_magic = 0;	/* clear magic so we never save twice */
1498 		Pwrite(dumpfd, &ld, sizeof (log_dump_t), ldoff);
1499 	}
1500 	return (0);
1501 }
1502 
1503 static long
1504 getbounds(const char *f)
1505 {
1506 	long b = -1;
1507 	const char *p = strrchr(f, '/');
1508 
1509 	(void) sscanf(p ? p + 1 : f, "vmdump.%ld", &b);
1510 	return (b);
1511 }
1512 
1513 static void
1514 stack_retrieve(char *stack)
1515 {
1516 	summary_dump_t sd;
1517 	offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE +
1518 	    DUMP_ERPTSIZE);
1519 	dumpoff -= DUMP_SUMMARYSIZE;
1520 
1521 	dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
1522 	dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
1523 
1524 	Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
1525 	dumpoff += sizeof (summary_dump_t);
1526 
1527 	if (sd.sd_magic == 0) {
1528 		*stack = '\0';
1529 		return;
1530 	}
1531 
1532 	if (sd.sd_magic != SUMMARY_MAGIC) {
1533 		*stack = '\0';
1534 		logprint(SC_SL_NONE | SC_IF_VERBOSE,
1535 		    "bad summary magic %x", sd.sd_magic);
1536 		return;
1537 	}
1538 	Pread(dumpfd, stack, STACK_BUF_SIZE, dumpoff);
1539 	if (sd.sd_ssum != checksum32(stack, STACK_BUF_SIZE))
1540 		logprint(SC_SL_NONE | SC_IF_VERBOSE, "bad stack checksum");
1541 }
1542 
1543 static void
1544 raise_event(enum sc_event_type evidx, char *warn_string)
1545 {
1546 	uint32_t pl = sc_event[evidx].sce_payload;
1547 	char panic_stack[STACK_BUF_SIZE];
1548 	nvlist_t *attr = NULL;
1549 	char uuidbuf[36 + 1];
1550 	int err = 0;
1551 
1552 	if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0)
1553 		goto publish;	/* try to send payload-free event */
1554 
1555 	if (pl & SC_PAYLOAD_SAVEDIR && savedir != NULL)
1556 		err |= nvlist_add_string(attr, "dumpdir", savedir);
1557 
1558 	if (pl & SC_PAYLOAD_INSTANCE && bounds != -1)
1559 		err |= nvlist_add_int64(attr, "instance", bounds);
1560 
1561 	if (pl & SC_PAYLOAD_ISCOMPRESSED) {
1562 		err |= nvlist_add_boolean_value(attr, "compressed",
1563 		    csave ? B_TRUE : B_FALSE);
1564 	}
1565 
1566 	if (pl & SC_PAYLOAD_DUMPADM_EN) {
1567 		char *disabled = defread("DUMPADM_ENABLE=no");
1568 
1569 		err |= nvlist_add_boolean_value(attr, "savecore-enabled",
1570 		    disabled ? B_FALSE : B_TRUE);
1571 	}
1572 
1573 	if (pl & SC_PAYLOAD_IMAGEUUID) {
1574 		(void) strncpy(uuidbuf, corehdr.dump_uuid, 36);
1575 		uuidbuf[36] = '\0';
1576 		err |= nvlist_add_string(attr, "os-instance-uuid", uuidbuf);
1577 	}
1578 
1579 	if (pl & SC_PAYLOAD_CRASHTIME) {
1580 		err |= nvlist_add_int64(attr, "crashtime",
1581 		    (int64_t)corehdr.dump_crashtime);
1582 	}
1583 
1584 	if (pl & SC_PAYLOAD_PANICSTR && corehdr.dump_panicstring[0] != '\0') {
1585 		err |= nvlist_add_string(attr, "panicstr",
1586 		    corehdr.dump_panicstring);
1587 	}
1588 
1589 	if (pl & SC_PAYLOAD_PANICSTACK) {
1590 		stack_retrieve(panic_stack);
1591 
1592 		if (panic_stack[0] != '\0') {
1593 			/*
1594 			 * The summary page may not be present if the dump
1595 			 * was previously recorded compressed.
1596 			 */
1597 			(void) nvlist_add_string(attr, "panicstack",
1598 			    panic_stack);
1599 		}
1600 	}
1601 
1602 	/* add warning string if this is an ireport for dump failure */
1603 	if (pl & SC_PAYLOAD_FAILREASON && warn_string != NULL)
1604 		(void) nvlist_add_string(attr, "failure-reason", warn_string);
1605 
1606 	if (pl & SC_PAYLOAD_DUMPCOMPLETE)
1607 		err |= nvlist_add_boolean_value(attr, "dump-incomplete",
1608 		    dump_incomplete ? B_TRUE : B_FALSE);
1609 
1610 	if (pl & SC_PAYLOAD_FM_PANIC) {
1611 		err |= nvlist_add_boolean_value(attr, "fm-panic",
1612 		    fm_panic ? B_TRUE : B_FALSE);
1613 	}
1614 
1615 	if (pl & SC_PAYLOAD_JUSTCHECKING) {
1616 		err |= nvlist_add_boolean_value(attr, "will-attempt-savecore",
1617 		    cflag ? B_FALSE : B_TRUE);
1618 	}
1619 
1620 	if (err)
1621 		logprint(SC_SL_WARN, "Errors while constructing '%s' "
1622 		    "event payload; will try to publish anyway.");
1623 publish:
1624 	if (fmev_rspublish_nvl(FMEV_RULESET_ON_SUNOS,
1625 	    "panic", sc_event[evidx].sce_subclass, FMEV_HIPRI,
1626 	    attr) != FMEV_SUCCESS) {
1627 		logprint(SC_SL_ERR, "failed to publish '%s' event: %s",
1628 		    sc_event[evidx].sce_subclass, fmev_strerror(fmev_errno));
1629 		nvlist_free(attr);
1630 	}
1631 
1632 }
1633 
1634 
1635 int
1636 main(int argc, char *argv[])
1637 {
1638 	int i, c, bfd;
1639 	Stat_t st;
1640 	struct rlimit rl;
1641 	long filebounds = -1;
1642 	char namelist[30], corefile[30], boundstr[30];
1643 
1644 	startts = gethrtime();
1645 
1646 	(void) getrlimit(RLIMIT_NOFILE, &rl);
1647 	rl.rlim_cur = rl.rlim_max;
1648 	(void) setrlimit(RLIMIT_NOFILE, &rl);
1649 
1650 	openlog(progname, LOG_ODELAY, LOG_AUTH);
1651 
1652 	(void) defopen("/etc/dumpadm.conf");
1653 	savedir = defread("DUMPADM_SAVDIR=");
1654 	if (savedir != NULL)
1655 		savedir = strdup(savedir);
1656 
1657 	while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) {
1658 		switch (c) {
1659 		case 'L':
1660 			livedump++;
1661 			break;
1662 		case 'v':
1663 			verbose++;
1664 			break;
1665 		case 'c':
1666 			cflag++;
1667 			break;
1668 		case 'd':
1669 			disregard_valid_flag++;
1670 			break;
1671 		case 'm':
1672 			mflag++;
1673 			break;
1674 		case 'f':
1675 			dumpfile = optarg;
1676 			filebounds = getbounds(dumpfile);
1677 			break;
1678 		case '?':
1679 			usage();
1680 		}
1681 	}
1682 
1683 	if (geteuid() != 0 && filebounds < 0) {
1684 		(void) fprintf(stderr, "%s: %s %s\n", progname,
1685 		    gettext("you must be root to use"), progname);
1686 		exit(1);
1687 	}
1688 
1689 	interactive = isatty(STDOUT_FILENO);
1690 
1691 	if (cflag && livedump)
1692 		usage();
1693 
1694 	if (dumpfile == NULL || livedump)
1695 		dumpfd = Open("/dev/dump", O_RDONLY, 0444);
1696 
1697 	if (dumpfile == NULL) {
1698 		dumpfile = Zalloc(MAXPATHLEN);
1699 		if (ioctl(dumpfd, DIOCGETDEV, dumpfile) == -1)
1700 			logprint(SC_SL_NONE | SC_IF_ISATTY | SC_EXIT_ERR,
1701 			    "no dump device configured");
1702 	}
1703 
1704 	if (mflag)
1705 		return (message_save());
1706 
1707 	if (optind == argc - 1)
1708 		savedir = argv[optind];
1709 
1710 	if (savedir == NULL || optind < argc - 1)
1711 		usage();
1712 
1713 	if (livedump && ioctl(dumpfd, DIOCDUMP, NULL) == -1)
1714 		logprint(SC_SL_NONE | SC_EXIT_ERR,
1715 		    "dedicated dump device required");
1716 
1717 	(void) close(dumpfd);
1718 	dumpfd = -1;
1719 
1720 	Stat(dumpfile, &st);
1721 
1722 	filemode = S_ISREG(st.st_mode);
1723 
1724 	if (!filemode && defread("DUMPADM_CSAVE=off") == NULL)
1725 		csave = 1;
1726 
1727 	read_dumphdr();
1728 
1729 	/*
1730 	 * We want this message to go to the log file, but not the console.
1731 	 * There's no good way to do that with the existing syslog facility.
1732 	 * We could extend it to handle this, but there doesn't seem to be
1733 	 * a general need for it, so we isolate the complexity here instead.
1734 	 */
1735 	if (dumphdr.dump_panicstring[0] != '\0') {
1736 		int logfd = Open("/dev/conslog", O_WRONLY, 0644);
1737 		log_ctl_t lc;
1738 		struct strbuf ctl, dat;
1739 		char msg[DUMP_PANICSIZE + 100];
1740 		char fmt[] = "reboot after panic: %s";
1741 		uint32_t msgid;
1742 
1743 		STRLOG_MAKE_MSGID(fmt, msgid);
1744 
1745 		/* LINTED: E_SEC_SPRINTF_UNBOUNDED_COPY */
1746 		(void) sprintf(msg, "%s: [ID %u FACILITY_AND_PRIORITY] ",
1747 		    progname, msgid);
1748 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
1749 		(void) sprintf(msg + strlen(msg), fmt,
1750 		    dumphdr.dump_panicstring);
1751 
1752 		lc.pri = LOG_AUTH | LOG_ERR;
1753 		lc.flags = SL_CONSOLE | SL_LOGONLY;
1754 		lc.level = 0;
1755 
1756 		ctl.buf = (void *)&lc;
1757 		ctl.len = sizeof (log_ctl_t);
1758 
1759 		dat.buf = (void *)msg;
1760 		dat.len = strlen(msg) + 1;
1761 
1762 		(void) putmsg(logfd, &ctl, &dat, 0);
1763 		(void) close(logfd);
1764 	}
1765 
1766 	if ((dumphdr.dump_flags & DF_COMPLETE) == 0) {
1767 		logprint(SC_SL_WARN, "incomplete dump on dump device");
1768 		dump_incomplete = B_TRUE;
1769 	}
1770 
1771 	if (dumphdr.dump_fm_panic)
1772 		fm_panic = B_TRUE;
1773 
1774 	/*
1775 	 * We have a valid dump on a dump device and know as much about
1776 	 * it as we're going to at this stage.  Raise an event for
1777 	 * logging and so that FMA can open a case for this panic.
1778 	 * Avoid this step for FMA-initiated panics - FMA will replay
1779 	 * ereports off the dump device independently of savecore and
1780 	 * will make a diagnosis, so we don't want to open two cases
1781 	 * for the same event.  Also avoid raising an event for a
1782 	 * livedump, or when we inflating a compressed dump.
1783 	 */
1784 	if (!fm_panic && !livedump && !filemode)
1785 		raise_event(SC_EVENT_DUMP_PENDING, NULL);
1786 
1787 	logprint(SC_SL_WARN, "System dump time: %s",
1788 	    ctime(&dumphdr.dump_crashtime));
1789 
1790 	/*
1791 	 * Option -c is designed for use from svc-dumpadm where we know
1792 	 * that dumpadm -n is in effect but run savecore -c just to
1793 	 * get the above dump_pending_on_device event raised.  If it is run
1794 	 * interactively then just print further panic details.
1795 	 */
1796 	if (cflag) {
1797 		char *disabled = defread("DUMPADM_ENABLE=no");
1798 		int lvl = interactive ? SC_SL_WARN : SC_SL_ERR;
1799 		int ec = fm_panic ? SC_EXIT_FM : SC_EXIT_PEND;
1800 
1801 		logprint(lvl | ec,
1802 		    "Panic crashdump pending on dump device%s "
1803 		    "run savecore(1M) manually to extract. "
1804 		    "Image UUID %s%s.",
1805 		    disabled ? " but dumpadm -n in effect;" : ";",
1806 		    corehdr.dump_uuid,
1807 		    fm_panic ?  "(fault-management initiated)" : "");
1808 		/*NOTREACHED*/
1809 	}
1810 
1811 	if (chdir(savedir) == -1)
1812 		logprint(SC_SL_ERR | SC_EXIT_ERR, "chdir(\"%s\"): %s",
1813 		    savedir, strerror(errno));
1814 
1815 	check_space(csave);
1816 
1817 	if (filebounds < 0)
1818 		bounds = read_number_from_file("bounds", 0);
1819 	else
1820 		bounds = filebounds;
1821 
1822 	if (csave) {
1823 		size_t metrics_size = datahdr.dump_metrics;
1824 
1825 		(void) sprintf(corefile, "vmdump.%ld", bounds);
1826 
1827 		datahdr.dump_metrics = 0;
1828 
1829 		logprint(SC_SL_ERR,
1830 		    "Saving compressed system crash dump in %s/%s",
1831 		    savedir, corefile);
1832 
1833 		copy_crashfile(corefile);
1834 
1835 		/*
1836 		 * Raise a fault management event that indicates the system
1837 		 * has panicked. We know a reasonable amount about the
1838 		 * condition at this time, but the dump is still compressed.
1839 		 */
1840 		if (!livedump && !fm_panic)
1841 			raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
1842 
1843 		if (metrics_size > 0) {
1844 			int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1845 			FILE *mfile = fopen(METRICSFILE, "a");
1846 			char *metrics = Zalloc(metrics_size + 1);
1847 
1848 			Pread(dumpfd, metrics, metrics_size, endoff +
1849 			    sizeof (dumphdr) + sizeof (datahdr));
1850 
1851 			if (sec < 1)
1852 				sec = 1;
1853 
1854 			if (mfile == NULL) {
1855 				logprint(SC_SL_WARN,
1856 				    "Can't create %s:\n%s",
1857 				    METRICSFILE, metrics);
1858 			} else {
1859 				(void) fprintf(mfile, "[[[[,,,");
1860 				for (i = 0; i < argc; i++)
1861 					(void) fprintf(mfile, "%s ", argv[i]);
1862 				(void) fprintf(mfile, "\n");
1863 				(void) fprintf(mfile, ",,,%s %s %s %s %s\n",
1864 				    dumphdr.dump_utsname.sysname,
1865 				    dumphdr.dump_utsname.nodename,
1866 				    dumphdr.dump_utsname.release,
1867 				    dumphdr.dump_utsname.version,
1868 				    dumphdr.dump_utsname.machine);
1869 				(void) fprintf(mfile, ",,,%s dump time %s\n",
1870 				    dumphdr.dump_flags & DF_LIVE ? "Live" :
1871 				    "Crash", ctime(&dumphdr.dump_crashtime));
1872 				(void) fprintf(mfile, ",,,%s/%s\n", savedir,
1873 				    corefile);
1874 				(void) fprintf(mfile, "Metrics:\n%s\n",
1875 				    metrics);
1876 				(void) fprintf(mfile, "Copy pages,%ld\n",
1877 				    dumphdr.  dump_npages);
1878 				(void) fprintf(mfile, "Copy time,%d\n", sec);
1879 				(void) fprintf(mfile, "Copy pages/sec,%ld\n",
1880 				    dumphdr.dump_npages / sec);
1881 				(void) fprintf(mfile, "]]]]\n");
1882 				(void) fclose(mfile);
1883 			}
1884 			free(metrics);
1885 		}
1886 
1887 		logprint(SC_SL_ERR,
1888 		    "Decompress the crash dump with "
1889 		    "\n'savecore -vf %s/%s'",
1890 		    savedir, corefile);
1891 
1892 	} else {
1893 		(void) sprintf(namelist, "unix.%ld", bounds);
1894 		(void) sprintf(corefile, "vmcore.%ld", bounds);
1895 
1896 		if (interactive && filebounds >= 0 && access(corefile, F_OK)
1897 		    == 0)
1898 			logprint(SC_SL_NONE | SC_EXIT_ERR,
1899 			    "%s already exists: remove with "
1900 			    "'rm -f %s/{unix,vmcore}.%ld'",
1901 			    corefile, savedir, bounds);
1902 
1903 		logprint(SC_SL_ERR,
1904 		    "saving system crash dump in %s/{unix,vmcore}.%ld",
1905 		    savedir, bounds);
1906 
1907 		build_corefile(namelist, corefile);
1908 
1909 		if (!livedump && !filemode && !fm_panic)
1910 			raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
1911 
1912 		if (access(METRICSFILE, F_OK) == 0) {
1913 			int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1914 			FILE *mfile = fopen(METRICSFILE, "a");
1915 
1916 			if (sec < 1)
1917 				sec = 1;
1918 
1919 			(void) fprintf(mfile, "[[[[,,,");
1920 			for (i = 0; i < argc; i++)
1921 				(void) fprintf(mfile, "%s ", argv[i]);
1922 			(void) fprintf(mfile, "\n");
1923 			(void) fprintf(mfile, ",,,%s/%s\n", savedir, corefile);
1924 			(void) fprintf(mfile, ",,,%s %s %s %s %s\n",
1925 			    dumphdr.dump_utsname.sysname,
1926 			    dumphdr.dump_utsname.nodename,
1927 			    dumphdr.dump_utsname.release,
1928 			    dumphdr.dump_utsname.version,
1929 			    dumphdr.dump_utsname.machine);
1930 			(void) fprintf(mfile, "Uncompress pages,%"PRIu64"\n",
1931 			    saved);
1932 			(void) fprintf(mfile, "Uncompress time,%d\n", sec);
1933 			(void) fprintf(mfile, "Uncompress pages/sec,%"
1934 			    PRIu64"\n", saved / sec);
1935 			(void) fprintf(mfile, "]]]]\n");
1936 			(void) fclose(mfile);
1937 		}
1938 	}
1939 
1940 	if (filebounds < 0) {
1941 		(void) sprintf(boundstr, "%ld\n", bounds + 1);
1942 		bfd = Open("bounds", O_WRONLY | O_CREAT | O_TRUNC, 0644);
1943 		Pwrite(bfd, boundstr, strlen(boundstr), 0);
1944 		(void) close(bfd);
1945 	}
1946 
1947 	if (verbose) {
1948 		int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1949 
1950 		(void) printf("%d:%02d dump %s is done\n",
1951 		    sec / 60, sec % 60,
1952 		    csave ? "copy" : "decompress");
1953 	}
1954 
1955 	if (verbose > 1 && hist != NULL) {
1956 		int i, nw;
1957 
1958 		for (i = 1, nw = 0; i <= BTOP(coreblksize); ++i)
1959 			nw += hist[i] * i;
1960 		(void) printf("pages count     %%\n");
1961 		for (i = 0; i <= BTOP(coreblksize); ++i) {
1962 			if (hist[i] == 0)
1963 				continue;
1964 			(void) printf("%3d   %5u  %6.2f\n",
1965 			    i, hist[i], 100.0 * hist[i] * i / nw);
1966 		}
1967 	}
1968 
1969 	(void) close(dumpfd);
1970 	dumpfd = -1;
1971 
1972 	return (0);
1973 }
1974