5334 cleanup gcc warning for cmd/savecore
[illumos-gate.git] / usr / src / cmd / savecore / savecore.c
blob746c528347745c334daf73a029813ce3534f2319
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
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>
60 /* fread/fwrite buffer size */
61 #define FBUFSIZE (1ULL << 20)
63 /* minimum size for output buffering */
64 #define MINCOREBLKSIZE (1ULL << 17)
66 /* create this file if metrics collection is enabled in the kernel */
67 #define METRICSFILE "METRICS.csv"
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 */
95 * Payload information for the events we raise. These are used
96 * in raise_event to determine what payload to include.
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? */
111 enum sc_event_type {
112 SC_EVENT_DUMP_PENDING,
113 SC_EVENT_SAVECORE_FAILURE,
114 SC_EVENT_DUMP_AVAILABLE
118 * Common payload
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
129 static const struct {
130 const char *sce_subclass;
131 uint32_t sce_payload;
132 } sc_event[] = {
134 * SC_EVENT_DUMP_PENDING
137 "dump_pending_on_device",
138 _SC_PAYLOAD_CMN | SC_PAYLOAD_DUMPADM_EN |
139 SC_PAYLOAD_JUSTCHECKING
143 * SC_EVENT_SAVECORE_FAILURE
146 "savecore_failure",
147 _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_FAILREASON
151 * SC_EVENT_DUMP_AVAILABLE
154 "dump_available",
155 _SC_PAYLOAD_CMN | SC_PAYLOAD_INSTANCE | SC_PAYLOAD_ISCOMPRESSED
159 static void raise_event(enum sc_event_type, char *);
161 static void
162 usage(void)
164 (void) fprintf(stderr,
165 "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
166 exit(1);
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) */
179 #define _SC_ALLEXIT (SC_EXIT_OK | SC_EXIT_ERR | SC_EXIT_PEND | SC_EXIT_FM)
181 static void
182 logprint(uint32_t flags, char *message, ...)
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;
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;
204 case SC_SL_WARN:
205 /*LINTED: E_SEC_PRINTF_VAR_FMT*/
206 syslog(LOG_WARNING, buf);
207 break;
209 default:
210 break;
213 va_end(args);
216 switch (flags & _SC_ALLEXIT) {
217 case 0:
218 return;
220 case SC_EXIT_OK:
221 code = 0;
222 break;
224 case SC_EXIT_PEND:
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.
230 if (!mflag && logprint_raised++ == 0)
231 raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
232 code = 2;
233 break;
235 case SC_EXIT_FM:
236 code = 3;
237 break;
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;
247 exit(code);
251 * System call / libc wrappers that exit on error.
253 static int
254 Open(const char *name, int oflags, mode_t mode)
256 int fd;
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);
264 static void
265 Fread(void *buf, size_t size, FILE *f)
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));
272 static void
273 Fwrite(void *buf, size_t size, FILE *f)
275 if (fwrite(buf, size, 1, f) != 1)
276 logprint(SC_SL_ERR | SC_EXIT_ERR, "fwrite: %s",
277 strerror(errno));
280 static void
281 Fseek(offset_t off, FILE *f)
283 if (fseeko64(f, off, SEEK_SET) != 0)
284 logprint(SC_SL_ERR | SC_EXIT_ERR, "fseeko64: %s",
285 strerror(errno));
288 typedef struct stat64 Stat_t;
290 static void
291 Fstat(int fd, Stat_t *sb, const char *fname)
293 if (fstat64(fd, sb) != 0)
294 logprint(SC_SL_ERR | SC_EXIT_ERR, "fstat(\"%s\"): %s", fname,
295 strerror(errno));
298 static void
299 Stat(const char *fname, Stat_t *sb)
301 if (stat64(fname, sb) != 0)
302 logprint(SC_SL_ERR | SC_EXIT_ERR, "stat(\"%s\"): %s", fname,
303 strerror(errno));
306 static void
307 Pread(int fd, void *buf, size_t size, offset_t off)
309 ssize_t sz = pread64(fd, buf, size, off);
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);
319 static void
320 Pwrite(int fd, void *buf, size_t size, off64_t off)
322 if (pwrite64(fd, buf, size, off) != size)
323 logprint(SC_SL_ERR | SC_EXIT_ERR, "pwrite: %s",
324 strerror(errno));
327 static void *
328 Zalloc(size_t size)
330 void *buf;
332 if ((buf = calloc(size, 1)) == NULL)
333 logprint(SC_SL_ERR | SC_EXIT_ERR, "calloc: %s",
334 strerror(errno));
335 return (buf);
338 static long
339 read_number_from_file(const char *filename, long default_value)
341 long file_value = -1;
342 FILE *fp;
344 if ((fp = fopen(filename, "r")) != NULL) {
345 (void) fscanf(fp, "%ld", &file_value);
346 (void) fclose(fp);
348 return (file_value < 0 ? default_value : file_value);
351 static void
352 read_dumphdr(void)
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));
362 pagesize = dumphdr.dump_pagesize;
364 if (dumphdr.dump_magic != DUMP_MAGIC)
365 logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
366 dumphdr.dump_magic);
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");
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);
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);
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;
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.
398 Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start);
400 corehdr.dump_flags &= ~DF_VALID;
401 dumphdr.dump_flags &= ~DF_VALID;
403 if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
405 * Clear valid bit so we don't complain on every invocation.
407 if (!filemode)
408 Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
409 logprint(SC_SL_ERR | SC_EXIT_ERR,
410 "initial dump header corrupt");
414 static void
415 check_space(int csave)
417 struct statvfs fsb;
418 int64_t spacefree, dumpsize, minfree, datasize;
420 if (statvfs(".", &fsb) < 0)
421 logprint(SC_SL_ERR | SC_EXIT_ERR, "statvfs: %s",
422 strerror(errno));
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;
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);
440 static void
441 build_dump_map(int corefd, const pfn_t *pfn_table)
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");
451 (void) setvbuf(in, inbuf, _IOFBF, FBUFSIZE);
452 Fseek(dumphdr.dump_map, in);
454 corehdr.dump_data = corehdr.dump_map + roundup(dump_mapsize, pagesize);
456 for (i = 0; i < corehdr.dump_nvtop; i++) {
457 long first = 0;
458 long last = corehdr.dump_npages - 1;
459 long middle = 0;
460 pfn_t pfn = 0;
461 uintptr_t h;
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;
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;
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);
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);
492 Pwrite(corefd, dmp, dump_mapsize, corehdr.dump_map);
493 free(dmp);
494 (void) fclose(in);
495 free(inbuf);
499 * Copy whole sections of the dump device to the file.
501 static void
502 Copy(offset_t dumpoff, len_t nb, offset_t *offp, int fd, char *buf,
503 size_t sz)
505 size_t nr;
506 offset_t off = *offp;
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;
516 *offp = off;
520 * Copy pages when the dump data header is missing.
521 * This supports older kernels with latest savecore.
523 static void
524 CopyPages(offset_t *offp, int fd, char *buf, size_t sz)
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;
533 (void) setvbuf(out, outbuf, _IOFBF, FBUFSIZE);
534 (void) setvbuf(in, buf, _IOFBF, sz);
535 Fseek(dumphdr.dump_data, in);
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;
549 Fread(cbuf, csize, in);
550 Fwrite(cbuf, csize, out);
551 *offp += csize;
552 np--;
554 (void) fclose(in);
555 (void) fclose(out);
556 free(outbuf);
557 free(buf);
561 * Concatenate dump contents into a new file.
562 * Update corehdr with new offsets.
564 static void
565 copy_crashfile(const char *corefile)
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;
573 logprint(SC_SL_ERR | SC_IF_VERBOSE,
574 "Copying %s to %s/%s\n", dumpfile, savedir, corefile);
577 * This dump file is still compressed
579 corehdr.dump_flags |= DF_COMPRESSED | DF_VALID;
582 * Leave room for corehdr, it is updated and written last
584 corehdr.dump_start = 0;
585 coreoff = sizeof (corehdr);
588 * Read in the compressed symbol table, copy it to corefile.
590 coreoff = roundup(coreoff, pagesize);
591 corehdr.dump_ksyms = coreoff;
592 Copy(dumphdr.dump_ksyms, dumphdr.dump_ksyms_csize, &coreoff, corefd,
593 inbuf, bufsz);
596 * Save the pfn table.
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);
604 * Save the dump map.
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);
612 * Save the data pages.
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);
623 * Now write the modified dump header to front and end of the copy.
624 * Make it look like a valid dump device.
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.
631 * Pad with zeros to each DUMP_OFFSET boundary.
633 (void) memset(inbuf, 0, DUMP_OFFSET);
635 nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
636 if (nb > 0) {
637 Pwrite(corefd, inbuf, nb, coreoff);
638 coreoff += nb;
641 Pwrite(corefd, &corehdr, sizeof (corehdr), coreoff);
642 coreoff += sizeof (corehdr);
644 Pwrite(corefd, &datahdr, sizeof (datahdr), coreoff);
645 coreoff += sizeof (datahdr);
647 nb = DUMP_OFFSET - (coreoff & (DUMP_OFFSET - 1));
648 if (nb > 0) {
649 Pwrite(corefd, inbuf, nb, coreoff);
652 free(inbuf);
653 Pwrite(corefd, &corehdr, sizeof (corehdr), corehdr.dump_start);
656 * Write out the modified dump header to the dump device.
657 * The dump device has been processed, so DF_VALID is clear.
659 if (!filemode)
660 Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
662 (void) close(corefd);
666 * compressed streams
668 typedef struct blockhdr blockhdr_t;
669 typedef struct block block_t;
671 struct blockhdr {
672 block_t *head;
673 block_t *tail;
676 struct block {
677 block_t *next;
678 char *block;
679 int size;
682 typedef enum streamstate {
683 STREAMSTART,
684 STREAMPAGES
685 } streamstate_t;
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;
704 static stream_t *streams;
705 static stream_t *endstreams;
707 const int cs = sizeof (dumpcsize_t);
709 typedef struct tinfo {
710 pthread_t tid;
711 int corefd;
712 } tinfo_t;
714 static int threads_stop;
715 static int threads_active;
716 static tinfo_t *tinfo;
717 static tinfo_t *endtinfo;
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;
724 static blockhdr_t freeblocks;
726 static void
727 enqt(blockhdr_t *h, block_t *b)
729 b->next = NULL;
730 if (h->tail == NULL)
731 h->head = b;
732 else
733 h->tail->next = b;
734 h->tail = b;
737 static block_t *
738 deqh(blockhdr_t *h)
740 block_t *b = h->head;
742 if (b != NULL) {
743 h->head = b->next;
744 if (h->head == NULL)
745 h->tail = NULL;
747 return (b);
750 static void *runstreams(void *arg);
752 static void
753 initstreams(int corefd, int nstreams, int maxcsize)
755 int nthreads;
756 int nblocks;
757 int i;
758 block_t *b;
759 tinfo_t *t;
761 nthreads = sysconf(_SC_NPROCESSORS_ONLN);
762 if (nstreams < nthreads)
763 nthreads = nstreams;
764 if (nthreads < 1)
765 nthreads = 1;
766 nblocks = nthreads * 2;
768 tinfo = Zalloc(nthreads * sizeof (tinfo_t));
769 endtinfo = &tinfo[nthreads];
771 /* init streams */
772 streams = Zalloc(nstreams * sizeof (stream_t));
773 endstreams = &streams[nstreams];
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);
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;
793 if (pthread_create(&t->tid, NULL, runstreams, t) != 0)
794 logprint(SC_SL_ERR | SC_EXIT_ERR, "pthread_create: %s",
795 strerror(errno));
797 (void) pthread_mutex_unlock(&lock);
800 static void
801 sbarrier()
803 stream_t *s;
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);
810 (void) pthread_mutex_unlock(&lock);
813 static void
814 stopstreams()
816 tinfo_t *t;
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;
832 static block_t *
833 getfreeblock()
835 block_t *b;
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);
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))
849 /* check for coreblksize boundary */
850 static int
851 isblkbnd(pgcnt_t pgnum)
853 return (P2PHASE(DATAOFF(pgnum), coreblksize) == 0);
856 static int
857 iszpage(char *buf)
859 size_t sz;
860 uint64_t *pl;
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);
870 volatile uint_t *hist;
872 /* write pages to the core file */
873 static void
874 putpage(int corefd, char *buf, pgcnt_t pgnum, pgcnt_t np)
876 atomic_inc_uint(&hist[np]);
877 if (np > 0)
878 Pwrite(corefd, buf, PTOB(np), DATAOFF(pgnum));
882 * Process one lzjb block.
883 * No object (stream header or page) will be split over a block boundary.
885 static void
886 lzjbblock(int corefd, stream_t *s, char *block, size_t blocksz)
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;
896 if (!s->init) {
897 s->init = 1;
898 if (s->blkbuf == NULL)
899 s->blkbuf = Zalloc(coreblksize);
900 s->state = STREAMSTART;
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);
929 out = s->blkbuf + PTOB(s->nout);
930 dsize = decompress(block + in, out, csize, pagesize);
932 if (dsize != pagesize)
933 logprint(SC_SL_ERR | SC_EXIT_ERR,
934 "LZJB STREAMPAGES: dsize %d != pagesize %d",
935 dsize, pagesize);
937 in += csize;
938 atomic_inc_64(&saved);
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;
948 if (++s->done >= s->npages) {
949 s->state = STREAMSTART;
950 doflush = 1;
952 if (doflush) {
953 putpage(corefd, s->blkbuf, s->curpage, s->nout);
954 s->nout = 0;
955 s->curpage = s->pagenum + s->done;
957 break;
962 /* bzlib library reports errors with this callback */
963 void
964 bz_internal_error(int errcode)
966 logprint(SC_SL_ERR | SC_EXIT_ERR, "bz_internal_error: err %s\n",
967 BZ2_bzErrorString(errcode));
971 * Return one object in the stream.
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.
977 static int
978 bz2decompress(stream_t *s, void *buf, size_t size)
980 int rc;
982 if (s->strm.avail_out == 0) {
983 s->strm.next_out = buf;
984 s->strm.avail_out = size;
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;
997 if (s->strm.avail_out == 0)
998 break;
1000 return (s->strm.avail_out == 0);
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
1008 static void
1009 bz2block(int corefd, stream_t *s, char *block, size_t blocksz)
1011 int rc = 0;
1012 int doflush;
1013 char *out;
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;
1026 s->strm.next_in = block;
1027 s->strm.avail_in = blocksz;
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;
1053 atomic_inc_64(&saved);
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;
1063 if (++s->done >= s->npages) {
1064 s->state = STREAMSTART;
1065 doflush = 1;
1067 if (doflush) {
1068 putpage(corefd, s->blkbuf, s->curpage, s->nout);
1069 s->nout = 0;
1070 s->curpage = s->pagenum + s->done;
1072 break;
1077 /* report progress */
1078 static void
1079 report_progress()
1081 int sec, percent;
1083 if (!interactive)
1084 return;
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;
1096 /* thread body */
1097 static void *
1098 runstreams(void *arg)
1100 tinfo_t *t = arg;
1101 stream_t *s;
1102 block_t *b;
1103 int bound;
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);
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);
1125 (void) pthread_mutex_lock(&lock);
1126 enqt(&freeblocks, b);
1127 (void) pthread_cond_signal(&cvfree);
1129 report_progress();
1131 s->bound = 0;
1132 (void) pthread_cond_signal(&cvbarrier);
1134 if (!bound && !threads_stop)
1135 (void) pthread_cond_wait(&cvwork, &lock);
1137 (void) close(t->corefd);
1138 (void) pthread_cond_signal(&cvwork);
1139 (void) pthread_mutex_unlock(&lock);
1140 return (arg);
1144 * Process compressed pages.
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.
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.
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.
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.
1180 static void
1181 decompress_pages(int corefd)
1183 char *cpage = NULL;
1184 char *dpage = NULL;
1185 char *out;
1186 pgcnt_t curpage = 0;
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 = 0, tag, doflush;
1200 dumpf = fdopen(dup(dumpfd), "rb");
1201 if (dumpf == NULL)
1202 logprint(SC_SL_ERR | SC_EXIT_ERR, "fdopen: %s",
1203 strerror(errno));
1205 (void) setvbuf(dumpf, inbuf, _IOFBF, insz);
1206 Fseek(dumphdr.dump_data, dumpf);
1208 /*LINTED: E_CONSTANT_CONDITION*/
1209 while (1) {
1212 * The csize word delimits stream blocks.
1213 * See dumphdr.h for a description.
1215 Fread(&dcsize, sizeof (dcsize), dumpf);
1217 tag = DUMP_GET_TAG(dcsize);
1218 csize = DUMP_GET_CSIZE(dcsize);
1220 if (tag != 0) { /* a stream block */
1222 if (nstreams == 0)
1223 logprint(SC_SL_ERR | SC_EXIT_ERR,
1224 "starting data header is missing");
1226 if (tag > nstreams)
1227 logprint(SC_SL_ERR | SC_EXIT_ERR,
1228 "stream tag %d not in range 1..%d",
1229 tag, nstreams);
1231 if (csize > maxcsize)
1232 logprint(SC_SL_ERR | SC_EXIT_ERR,
1233 "block size 0x%x > max csize 0x%x",
1234 csize, maxcsize);
1236 if (streams == NULL)
1237 initstreams(corefd, nstreams, maxcsize);
1238 s = &streams[tag - 1];
1239 s->tag = tag;
1241 b = getfreeblock();
1242 b->size = csize;
1243 Fread(b->block, csize, dumpf);
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);
1251 } else if (csize > 0) { /* one lzjb page */
1253 if (csize > pagesize)
1254 logprint(SC_SL_ERR | SC_EXIT_ERR,
1255 "csize 0x%x > pagesize 0x%x",
1256 csize, pagesize);
1258 if (cpage == NULL)
1259 cpage = Zalloc(pagesize);
1260 if (dpage == NULL) {
1261 dpage = Zalloc(coreblksize);
1262 nout = 0;
1265 Fread(cpage, csize, dumpf);
1267 out = dpage + PTOB(nout);
1268 dsize = decompress(cpage, out, csize, pagesize);
1270 if (dsize != pagesize)
1271 logprint(SC_SL_ERR | SC_EXIT_ERR,
1272 "dsize 0x%x != pagesize 0x%x",
1273 dsize, pagesize);
1276 * wait for streams to flush so that 'saved' is correct
1278 if (threads_active)
1279 sbarrier();
1281 doflush = 0;
1282 if (nout == 0)
1283 curpage = saved;
1285 atomic_inc_64(&saved);
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;
1296 if (doflush) {
1297 putpage(corefd, dpage, curpage, nout);
1298 nout = 0;
1301 report_progress();
1304 * Non-streams lzjb does not use blocks. Stop
1305 * here if all the pages have been decompressed.
1307 if (saved >= dumphdr.dump_npages)
1308 break;
1310 } else {
1311 break; /* end of data */
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);
1329 static void
1330 build_corefile(const char *namelist, const char *corefile)
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);
1343 (void) printf("Constructing namelist %s/%s\n", savedir, namelist);
1346 * Determine the optimum write size for the core file
1348 Fstat(corefd, &st, corefile);
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;
1357 hist = Zalloc((sizeof (uint64_t) * BTOP(coreblksize)) + 1);
1360 * This dump file is now uncompressed
1362 corehdr.dump_flags &= ~DF_COMPRESSED;
1365 * Read in the compressed symbol table, copy it to corefile,
1366 * decompress it, and write the result to namelist.
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);
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);
1379 Pwrite(namefd, ksyms_base, ksyms_size, 0);
1380 (void) close(namefd);
1381 free(ksyms_cbase);
1382 free(ksyms_base);
1384 (void) printf("Constructing corefile %s/%s\n", savedir, corefile);
1387 * Read in and write out the pfn table.
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);
1395 * Convert the raw translation data into a hashed dump map.
1397 corehdr.dump_map = corehdr.dump_pfn + roundup(pfn_table_size, pagesize);
1398 build_dump_map(corefd, pfn_table);
1399 free(pfn_table);
1402 * Decompress the pages
1404 decompress_pages(corefd);
1405 (void) printf(": %ld of %ld pages saved\n", (pgcnt_t)saved,
1406 dumphdr.dump_npages);
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);
1413 if (saved != dumphdr.dump_npages)
1414 logprint(SC_SL_WARN, "bad data after page %ld", saved);
1417 * Write out the modified dump headers.
1419 Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
1420 if (!filemode)
1421 Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
1423 (void) close(corefd);
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.
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.
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.
1441 static int
1442 message_save(void)
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;
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;
1455 ctl.buf = (void *)&lc;
1456 ctl.len = sizeof (log_ctl_t);
1458 dat.buf = Zalloc(DUMP_LOGSIZE);
1460 for (;;) {
1461 ldoff = dumpoff;
1463 Pread(dumpfd, &ld, sizeof (log_dump_t), dumpoff);
1464 dumpoff += sizeof (log_dump_t);
1465 dat.len = ld.ld_msgsize;
1467 if (ld.ld_magic == 0)
1468 break;
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);
1474 if (dat.len >= DUMP_LOGSIZE)
1475 logprint(SC_SL_ERR | SC_IF_VERBOSE | SC_EXIT_ERR,
1476 "bad size %d", ld.ld_msgsize);
1478 Pread(dumpfd, ctl.buf, ctl.len, dumpoff);
1479 dumpoff += ctl.len;
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");
1485 lc.flags |= SL_LOGONLY;
1487 Pread(dumpfd, dat.buf, dat.len, dumpoff);
1488 dumpoff += dat.len;
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");
1494 if (putpmsg(logfd, &ctl, &dat, 1, MSG_BAND) == -1)
1495 logprint(SC_SL_ERR | SC_EXIT_ERR, "putpmsg: %s",
1496 strerror(errno));
1498 ld.ld_magic = 0; /* clear magic so we never save twice */
1499 Pwrite(dumpfd, &ld, sizeof (log_dump_t), ldoff);
1501 return (0);
1504 static long
1505 getbounds(const char *f)
1507 long b = -1;
1508 const char *p = strrchr(f, '/');
1510 if (p == NULL || strncmp(p, "vmdump", 6) != 0)
1511 p = strstr(f, "vmdump");
1513 if (p != NULL && *p == '/')
1514 p++;
1516 (void) sscanf(p ? p : f, "vmdump.%ld", &b);
1518 return (b);
1521 static void
1522 stack_retrieve(char *stack)
1524 summary_dump_t sd;
1525 offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE +
1526 DUMP_ERPTSIZE);
1527 dumpoff -= DUMP_SUMMARYSIZE;
1529 dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
1530 dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
1532 Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
1533 dumpoff += sizeof (summary_dump_t);
1535 if (sd.sd_magic == 0) {
1536 *stack = '\0';
1537 return;
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;
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");
1551 static void
1552 raise_event(enum sc_event_type evidx, char *warn_string)
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;
1560 if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0)
1561 goto publish; /* try to send payload-free event */
1563 if (pl & SC_PAYLOAD_SAVEDIR && savedir != NULL)
1564 err |= nvlist_add_string(attr, "dumpdir", savedir);
1566 if (pl & SC_PAYLOAD_INSTANCE && bounds != -1)
1567 err |= nvlist_add_int64(attr, "instance", bounds);
1569 if (pl & SC_PAYLOAD_ISCOMPRESSED) {
1570 err |= nvlist_add_boolean_value(attr, "compressed",
1571 csave ? B_TRUE : B_FALSE);
1574 if (pl & SC_PAYLOAD_DUMPADM_EN) {
1575 char *disabled = defread("DUMPADM_ENABLE=no");
1577 err |= nvlist_add_boolean_value(attr, "savecore-enabled",
1578 disabled ? B_FALSE : B_TRUE);
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);
1587 if (pl & SC_PAYLOAD_CRASHTIME) {
1588 err |= nvlist_add_int64(attr, "crashtime",
1589 (int64_t)corehdr.dump_crashtime);
1592 if (pl & SC_PAYLOAD_PANICSTR && corehdr.dump_panicstring[0] != '\0') {
1593 err |= nvlist_add_string(attr, "panicstr",
1594 corehdr.dump_panicstring);
1597 if (pl & SC_PAYLOAD_PANICSTACK) {
1598 stack_retrieve(panic_stack);
1600 if (panic_stack[0] != '\0') {
1602 * The summary page may not be present if the dump
1603 * was previously recorded compressed.
1605 (void) nvlist_add_string(attr, "panicstack",
1606 panic_stack);
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);
1614 if (pl & SC_PAYLOAD_DUMPCOMPLETE)
1615 err |= nvlist_add_boolean_value(attr, "dump-incomplete",
1616 dump_incomplete ? B_TRUE : B_FALSE);
1618 if (pl & SC_PAYLOAD_FM_PANIC) {
1619 err |= nvlist_add_boolean_value(attr, "fm-panic",
1620 fm_panic ? B_TRUE : B_FALSE);
1623 if (pl & SC_PAYLOAD_JUSTCHECKING) {
1624 err |= nvlist_add_boolean_value(attr, "will-attempt-savecore",
1625 cflag ? B_FALSE : B_TRUE);
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);
1644 main(int argc, char *argv[])
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;
1653 startts = gethrtime();
1655 (void) getrlimit(RLIMIT_NOFILE, &rl);
1656 rl.rlim_cur = rl.rlim_max;
1657 (void) setrlimit(RLIMIT_NOFILE, &rl);
1659 openlog(progname, LOG_ODELAY, LOG_AUTH);
1661 (void) defopen("/etc/dumpadm.conf");
1662 savedir = defread("DUMPADM_SAVDIR=");
1663 if (savedir != NULL)
1664 savedir = strdup(savedir);
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();
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.
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);
1702 interactive = isatty(STDOUT_FILENO);
1704 if (cflag && livedump)
1705 usage();
1707 if (dumpfile == NULL || livedump)
1708 dumpfd = Open("/dev/dump", O_RDONLY, 0444);
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");
1717 if (mflag)
1718 return (message_save());
1720 if (optind == argc - 1)
1721 savedir = argv[optind];
1723 if (savedir == NULL || optind < argc - 1)
1724 usage();
1726 if (livedump && ioctl(dumpfd, DIOCDUMP, NULL) == -1)
1727 logprint(SC_SL_NONE | SC_EXIT_ERR,
1728 "dedicated dump device required");
1730 (void) close(dumpfd);
1731 dumpfd = -1;
1733 Stat(dumpfile, &st);
1735 filemode = S_ISREG(st.st_mode);
1737 if (!filemode && defread("DUMPADM_CSAVE=off") == NULL)
1738 csave = 1;
1740 read_dumphdr();
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.
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;
1756 STRLOG_MAKE_MSGID(fmt, msgid);
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);
1765 lc.pri = LOG_AUTH | LOG_ERR;
1766 lc.flags = SL_CONSOLE | SL_LOGONLY;
1767 lc.level = 0;
1769 ctl.buf = (void *)&lc;
1770 ctl.len = sizeof (log_ctl_t);
1772 dat.buf = (void *)msg;
1773 dat.len = strlen(msg) + 1;
1775 (void) putmsg(logfd, &ctl, &dat, 0);
1776 (void) close(logfd);
1779 if ((dumphdr.dump_flags & DF_COMPLETE) == 0) {
1780 logprint(SC_SL_WARN, "incomplete dump on dump device");
1781 dump_incomplete = B_TRUE;
1784 if (dumphdr.dump_fm_panic)
1785 fm_panic = B_TRUE;
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.
1797 if (!fm_panic && !livedump && !filemode)
1798 raise_event(SC_EVENT_DUMP_PENDING, NULL);
1800 logprint(SC_SL_WARN, "System dump time: %s",
1801 ctime(&dumphdr.dump_crashtime));
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.
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;
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*/
1824 if (chdir(savedir) == -1)
1825 logprint(SC_SL_ERR | SC_EXIT_ERR, "chdir(\"%s\"): %s",
1826 savedir, strerror(errno));
1828 check_space(csave);
1830 if (filebounds < 0)
1831 bounds = read_number_from_file("bounds", 0);
1832 else
1833 bounds = filebounds;
1835 if (csave) {
1836 size_t metrics_size = datahdr.dump_metrics;
1838 (void) sprintf(corefile, "vmdump.%ld", bounds);
1840 datahdr.dump_metrics = 0;
1842 logprint(SC_SL_ERR,
1843 "Saving compressed system crash dump in %s/%s",
1844 savedir, corefile);
1846 copy_crashfile(corefile);
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.
1853 if (!livedump && !fm_panic)
1854 raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
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);
1861 Pread(dumpfd, metrics, metrics_size, endoff +
1862 sizeof (dumphdr) + sizeof (datahdr));
1864 if (sec < 1)
1865 sec = 1;
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);
1897 free(metrics);
1900 logprint(SC_SL_ERR,
1901 "Decompress the crash dump with "
1902 "\n'savecore -vf %s/%s'",
1903 savedir, corefile);
1905 } else {
1906 (void) sprintf(namelist, "unix.%ld", bounds);
1907 (void) sprintf(corefile, "vmcore.%ld", bounds);
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);
1916 logprint(SC_SL_ERR,
1917 "saving system crash dump in %s/{unix,vmcore}.%ld",
1918 savedir, bounds);
1920 build_corefile(namelist, corefile);
1922 if (!livedump && !filemode && !fm_panic)
1923 raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
1925 if (access(METRICSFILE, F_OK) == 0) {
1926 int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1927 FILE *mfile = fopen(METRICSFILE, "a");
1929 if (sec < 1)
1930 sec = 1;
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);
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);
1960 if (verbose) {
1961 int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
1963 (void) printf("%d:%02d dump %s is done\n",
1964 sec / 60, sec % 60,
1965 csave ? "copy" : "decompress");
1968 if (verbose > 1 && hist != NULL) {
1969 int i, nw;
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);
1982 (void) close(dumpfd);
1983 dumpfd = -1;
1985 return (0);