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