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