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