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