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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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
 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 *
 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
 856 isblkbnd(pgcnt_t pgnum)
 857 {
 858         return (P2PHASE(DATAOFF(pgnum), coreblksize) == 0);
 859 }
 860 
 861 static int
 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
 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
 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
 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
 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
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
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 *
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
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
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(1M)) 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(1M) starts, by the savecore startup script.
1446  */
1447 static int
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
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
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
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
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(1M) 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 }