Print this page
10654 savecore(1M) should be able to work on read-only dump devices
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: John Levon <john.levon@joyent.com>
Reviewed by: Andy Stormont <astormont@racktopsystems.com>
Reviewed by: Gergő Doma <domag02@gmail.com>
Reviewed by: Toomas Soome <tsoome@me.com>

@@ -18,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 /*
  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  */
 

@@ -90,10 +90,11 @@
 static volatile uint64_t zpages;        /* count of zero pages not written */
 static dumpdatahdr_t datahdr;           /* compression info */
 static long     coreblksize;            /* preferred write size (st_blksize) */
 static int      cflag;                  /* run as savecore -c */
 static int      mflag;                  /* run as savecore -m */
+static int      rflag;                  /* run as savecore -r */
 
 /*
  * Payload information for the events we raise.  These are used
  * in raise_event to determine what payload to include.
  */

@@ -162,11 +163,11 @@
 
 static void
 usage(void)
 {
         (void) fprintf(stderr,
-            "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
+            "usage: %s [-L | -r] [-vd] [-f dumpfile] [dirname]\n", progname);
         exit(1);
 }
 
 #define SC_SL_NONE      0x0001  /* no syslog */
 #define SC_SL_ERR       0x0002  /* syslog if !interactive, LOG_ERR */

@@ -227,11 +228,11 @@
                 /*
                  * Raise an ireport saying why we are exiting.  Do not
                  * raise if run as savecore -m.  If something in the
                  * raise_event codepath calls logprint avoid recursion.
                  */
-                if (!mflag && logprint_raised++ == 0)
+                if (!mflag && !rflag && logprint_raised++ == 0)
                         raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
                 code = 2;
                 break;
 
         case SC_EXIT_FM:

@@ -238,11 +239,11 @@
                 code = 3;
                 break;
 
         case SC_EXIT_ERR:
         default:
-                if (!mflag && logprint_raised++ == 0 && have_dumpfile)
+                if (!mflag && !rflag && logprint_raised++ == 0 && have_dumpfile)
                         raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
                 code = 1;
                 break;
         }
 

@@ -353,11 +354,11 @@
 }
 
 static void
 read_dumphdr(void)
 {
-        if (filemode)
+        if (filemode || rflag)
                 dumpfd = Open(dumpfile, O_RDONLY, 0644);
         else
                 dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
         endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
         Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);

@@ -406,11 +407,11 @@
 
         if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
                 /*
                  * Clear valid bit so we don't complain on every invocation.
                  */
-                if (!filemode)
+                if (!filemode && !rflag)
                         Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
                 logprint(SC_SL_ERR | SC_EXIT_ERR,
                     "initial dump header corrupt");
         }
 }

@@ -658,11 +659,11 @@
 
         /*
          * Write out the modified dump header to the dump device.
          * The dump device has been processed, so DF_VALID is clear.
          */
-        if (!filemode)
+        if (!filemode && !rflag)
                 Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
 
         (void) close(corefd);
 }
 

@@ -1420,11 +1421,11 @@
 
         /*
          * Write out the modified dump headers.
          */
         Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
-        if (!filemode)
+        if (!filemode && !rflag)
                 Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
 
         (void) close(corefd);
 }
 

@@ -1529,10 +1530,13 @@
         summary_dump_t sd;
         offset_t dumpoff = -(DUMP_OFFSET + DUMP_LOGSIZE +
             DUMP_ERPTSIZE);
         dumpoff -= DUMP_SUMMARYSIZE;
 
+        if (rflag)
+                dumpfd = Open(dumpfile, O_RDONLY, 0644);
+        else
         dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
         dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
 
         Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
         dumpoff += sizeof (summary_dump_t);

@@ -1666,11 +1670,11 @@
         (void) defopen("/etc/dumpadm.conf");
         savedir = defread("DUMPADM_SAVDIR=");
         if (savedir != NULL)
                 savedir = strdup(savedir);
 
-        while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) {
+        while ((c = getopt(argc, argv, "Lvcdmf:r")) != EOF) {
                 switch (c) {
                 case 'L':
                         livedump++;
                         break;
                 case 'v':

@@ -1683,10 +1687,13 @@
                         disregard_valid_flag++;
                         break;
                 case 'm':
                         mflag++;
                         break;
+                case 'r':
+                        rflag++;
+                        break;
                 case 'f':
                         dumpfile = optarg;
                         filebounds = getbounds(dumpfile);
                         break;
                 case '?':

@@ -1707,10 +1714,13 @@
         interactive = isatty(STDOUT_FILENO);
 
         if (cflag && livedump)
                 usage();
 
+        if (rflag && (cflag || mflag || livedump))
+                usage();
+
         if (dumpfile == NULL || livedump)
                 dumpfd = Open("/dev/dump", O_RDONLY, 0444);
 
         if (dumpfile == NULL) {
                 dumpfile = Zalloc(MAXPATHLEN);

@@ -1750,11 +1760,11 @@
          * We want this message to go to the log file, but not the console.
          * There's no good way to do that with the existing syslog facility.
          * We could extend it to handle this, but there doesn't seem to be
          * a general need for it, so we isolate the complexity here instead.
          */
-        if (dumphdr.dump_panicstring[0] != '\0') {
+        if (dumphdr.dump_panicstring[0] != '\0' && !rflag) {
                 int logfd = Open("/dev/conslog", O_WRONLY, 0644);
                 log_ctl_t lc;
                 struct strbuf ctl, dat;
                 char msg[DUMP_PANICSIZE + 100];
                 char fmt[] = "reboot after panic: %s";

@@ -1799,11 +1809,11 @@
          * ereports off the dump device independently of savecore and
          * will make a diagnosis, so we don't want to open two cases
          * for the same event.  Also avoid raising an event for a
          * livedump, or when we inflating a compressed dump.
          */
-        if (!fm_panic && !livedump && !filemode)
+        if (!fm_panic && !livedump && !filemode && !rflag)
                 raise_event(SC_EVENT_DUMP_PENDING, NULL);
 
         logprint(SC_SL_WARN, "System dump time: %s",
             ctime(&dumphdr.dump_crashtime));
 

@@ -1855,11 +1865,11 @@
                 /*
                  * Raise a fault management event that indicates the system
                  * has panicked. We know a reasonable amount about the
                  * condition at this time, but the dump is still compressed.
                  */
-                if (!livedump && !fm_panic)
+                if (!livedump && !fm_panic && !rflag)
                         raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
 
                 if (metrics_size > 0) {
                         int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
                         FILE *mfile = fopen(METRICSFILE, "a");

@@ -1924,11 +1934,11 @@
                     "saving system crash dump in %s/{unix,vmcore}.%ld",
                     savedir, bounds);
 
                 build_corefile(namelist, corefile);
 
-                if (!livedump && !filemode && !fm_panic)
+                if (!livedump && !filemode && !fm_panic && !rflag)
                         raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
 
                 if (access(METRICSFILE, F_OK) == 0) {
                         int sec = (gethrtime() - startts) / 1000 / 1000 / 1000;
                         FILE *mfile = fopen(METRICSFILE, "a");