386BSD 0.1 development
[unix-history] / usr / src / sbin / savecore / savecore.c
index a4dd681..31ff825 100644 (file)
@@ -1,31 +1,56 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+"@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)savecore.c 5.5 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)savecore.c 5.26 (Berkeley) 4/8/91";
+#endif /* not lint */
 
 
-/*
- * savecore
- */
-
-#include <stdio.h>
-#include <nlist.h>
 #include <sys/param.h>
 #include <sys/param.h>
-#include <sys/dir.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/file.h>
-#include <syslog.h>
+#include <sys/syslog.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <nlist.h>
+#include <paths.h>
 
 #define        DAY     (60L*60L*24L)
 #define        LEEWAY  (3*DAY)
 
 #define        DAY     (60L*60L*24L)
 #define        LEEWAY  (3*DAY)
@@ -34,10 +59,16 @@ static char sccsid[] = "@(#)savecore.c      5.5 (Berkeley) %G%";
 #ifdef vax
 #define ok(number) ((number)&0x7fffffff)
 #else
 #ifdef vax
 #define ok(number) ((number)&0x7fffffff)
 #else
+#ifdef tahoe
+#define ok(number) ((number)&~0xc0000000)
+#else
+#ifdef i386
+#define ok(number) ((number)&~0xfe000000)
+#else
 #define ok(number) (number)
 #endif
 #define ok(number) (number)
 #endif
-
-#define SHUTDOWNLOG "/usr/adm/shutdownlog"
+#endif
+#endif
 
 struct nlist current_nl[] = {  /* namelist for currently running system */
 #define X_DUMPDEV      0
 
 struct nlist current_nl[] = {  /* namelist for currently running system */
 #define X_DUMPDEV      0
@@ -71,6 +102,7 @@ struct nlist dump_nl[] = {   /* name list for dumped system */
 char   *system;
 char   *dirname;                       /* directory to save dumps in */
 char   *ddname;                        /* name of dump device */
 char   *system;
 char   *dirname;                       /* directory to save dumps in */
 char   *ddname;                        /* name of dump device */
+int    dumpfd;                         /* read/write descriptor on block dev */
 char   *find_dev();
 dev_t  dumpdev;                        /* dump device */
 time_t dumptime;                       /* time the dump was taken */
 char   *find_dev();
 dev_t  dumpdev;                        /* dump device */
 time_t dumptime;                       /* time the dump was taken */
@@ -87,68 +119,95 @@ char       panic_mesg[80];
 int    panicstr;
 off_t  lseek();
 off_t  Lseek();
 int    panicstr;
 off_t  lseek();
 off_t  Lseek();
-int    Verbose;
+int    verbose;
+int    force;
+int    clear;
+extern int errno;
 
 main(argc, argv)
        char **argv;
        int argc;
 {
 
 main(argc, argv)
        char **argv;
        int argc;
 {
+       extern char *optarg;
+       extern int optind;
+       int ch;
        char *cp;
 
        char *cp;
 
-       argc--, argv++;
-       while (argc > 0 && argv[0][0] == '-') {
-               for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
-
+       while ((ch = getopt(argc, argv, "cdfv")) != EOF)
+               switch(ch) {
+               case 'c':
+                       clear = 1;
+                       break;
+               case 'd':               /* not documented */
                case 'v':
                case 'v':
-                       Verbose++;
+                       verbose = 1;
                        break;
                        break;
-
+               case 'f':
+                       force = 1;
+                       break;
+               case '?':
                default:
                default:
-               usage:
-                       fprintf(stderr,
-                           "usage: savecore [-v] dirname [ system ]\n");
-                       exit(1);
+                       usage();
                }
                }
-               argc--, argv++;
+       argc -= optind;
+       argv += optind;
+
+       /* This is wrong, but I want "savecore -c" to work. */
+       if (!clear) {
+               if (argc != 1 && argc != 2)
+                       usage();
+               dirname = argv[0];
        }
        }
-       if (argc != 1 && argc != 2)
-               goto usage;
-       dirname = argv[0];
        if (argc == 2)
                system = argv[1];
        if (argc == 2)
                system = argv[1];
-       openlog("savecore", LOG_ODELAY, LOG_USER);
+
+       openlog("savecore", LOG_ODELAY, LOG_AUTH);
+
+       read_kmem();
+       if (!dump_exists()) {
+/*             (void)fprintf(stderr, "savecore: no core dump\n");*/
+               if (!force)
+                       exit(0);
+       }
+       if (clear) {
+               clear_dump();
+               exit(0);
+       }
+       (void) time(&now);
+       check_kmem();
+       if (panicstr)
+               log(LOG_CRIT, "reboot after panic: %s\n", panic_mesg);
+       else
+               syslog(LOG_CRIT, "reboot\n");
+
        if (access(dirname, W_OK) < 0) {
        if (access(dirname, W_OK) < 0) {
-               syslog(LOG_ERR, "%s: %m", dirname);
+               Perror(LOG_ERR, "%s: %m\n", dirname);
                exit(1);
        }
                exit(1);
        }
-       read_kmem();
+       if ((!get_crashtime() || !check_space()) && !force)
+               exit(1);
+       save_core();
+       clear_dump();
+       exit(0);
 }
 
 dump_exists()
 {
 }
 
 dump_exists()
 {
-       register int dumpfd;
        int word;
 
        int word;
 
-       dumpfd = Open(ddname, O_RDONLY);
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
        Read(dumpfd, (char *)&word, sizeof (word));
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
        Read(dumpfd, (char *)&word, sizeof (word));
-       close(dumpfd);
-       if (Verbose && word != dumpmag) {
-               printf("dumplo = %d (%d bytes)\n", dumplo/DEV_BSIZE, dumplo);
+       if (verbose && word != dumpmag)
                printf("magic number mismatch: %x != %x\n", word, dumpmag);
                printf("magic number mismatch: %x != %x\n", word, dumpmag);
-       }
        return (word == dumpmag);
 }
 
 clear_dump()
 {
        return (word == dumpmag);
 }
 
 clear_dump()
 {
-       register int dumpfd;
        int zero = 0;
 
        int zero = 0;
 
-       dumpfd = Open(ddname, O_WRONLY);
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
        Write(dumpfd, (char *)&zero, sizeof (zero));
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
        Write(dumpfd, (char *)&zero, sizeof (zero));
-       close(dumpfd);
 }
 
 char *
 }
 
 char *
@@ -156,10 +215,15 @@ find_dev(dev, type)
        register dev_t dev;
        register int type;
 {
        register dev_t dev;
        register int type;
 {
+       register DIR *dfd = opendir(_PATH_DEV);
+       struct dirent *dir;
        struct stat statb;
        struct stat statb;
+       static char devname[MAXPATHLEN + 1];
        char *dp;
 
        char *dp;
 
-       strcpy(devname, "/dev/");
+       strcpy(devname, _PATH_DEV);
+       while ((dir = readdir(dfd))) {
+               strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name);
                if (stat(devname, &statb)) {
                        perror(devname);
                        continue;
                if (stat(devname, &statb)) {
                        perror(devname);
                        continue;
@@ -167,16 +231,33 @@ find_dev(dev, type)
                if ((statb.st_mode&S_IFMT) != type)
                        continue;
                if (dev == statb.st_rdev) {
                if ((statb.st_mode&S_IFMT) != type)
                        continue;
                if (dev == statb.st_rdev) {
+                       closedir(dfd);
                        dp = malloc(strlen(devname)+1);
                        strcpy(dp, devname);
                        return (dp);
                }
        }
                        dp = malloc(strlen(devname)+1);
                        strcpy(dp, devname);
                        return (dp);
                }
        }
-       syslog(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
+       closedir(dfd);
+       log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
        exit(1);
        /*NOTREACHED*/
 }
 
        exit(1);
        /*NOTREACHED*/
 }
 
+char *
+rawname(s)
+       char *s;
+{
+       static char name[MAXPATHLEN];
+       char *sl, *rindex();
+
+       if ((sl = rindex(s, '/')) == NULL || sl[1] == '0') {
+               log(LOG_ERR, "can't make raw dump device name from %s?\n", s);
+               return (s);
+       }
+       sprintf(name, "%.*s/r%s", sl - s, s, sl + 1);
+       return (name);
+}
+
 int    cursyms[] =
     { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
 int    dumpsyms[] =
 int    cursyms[] =
     { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
 int    dumpsyms[] =
@@ -188,8 +269,8 @@ read_kmem()
        char *dump_sys;
        int kmem, i;
        
        char *dump_sys;
        int kmem, i;
        
-       dump_sys = system ? system : "/vmunix";
-       nlist("/vmunix", current_nl);
+       dump_sys = system ? system : _PATH_UNIX;
+       nlist(_PATH_UNIX, current_nl);
        nlist(dump_sys, dump_nl);
        /*
         * Some names we need for the currently running system,
        nlist(dump_sys, dump_nl);
        /*
         * Some names we need for the currently running system,
@@ -201,28 +282,32 @@ read_kmem()
         */
        for (i = 0; cursyms[i] != -1; i++)
                if (current_nl[cursyms[i]].n_value == 0) {
         */
        for (i = 0; cursyms[i] != -1; i++)
                if (current_nl[cursyms[i]].n_value == 0) {
-                       syslog(LOG_ERR, "/vmunix: %s not in namelist",
+                       log(LOG_ERR, "%s: %s not in namelist\n", _PATH_UNIX,
                            current_nl[cursyms[i]].n_name);
                        exit(1);
                }
        for (i = 0; dumpsyms[i] != -1; i++)
                if (dump_nl[dumpsyms[i]].n_value == 0) {
                            current_nl[cursyms[i]].n_name);
                        exit(1);
                }
        for (i = 0; dumpsyms[i] != -1; i++)
                if (dump_nl[dumpsyms[i]].n_value == 0) {
-                       syslog(LOG_ERR, "%s: %s not in namelist", dump_sys,
+                       log(LOG_ERR, "%s: %s not in namelist\n", dump_sys,
                            dump_nl[dumpsyms[i]].n_name);
                        exit(1);
                }
                            dump_nl[dumpsyms[i]].n_name);
                        exit(1);
                }
-       kmem = Open("/dev/kmem", O_RDONLY);
+       kmem = Open(_PATH_KMEM, O_RDONLY);
        Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET);
        Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
        Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
        Read(kmem, (char *)&dumplo, sizeof (dumplo));
        Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET);
        Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
        Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
        Read(kmem, (char *)&dumplo, sizeof (dumplo));
+       if (verbose)
+               printf("dumplo = %d (%d * %d)\n", dumplo, dumplo/DEV_BSIZE,
+                   DEV_BSIZE);
        Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
        Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
        dumplo *= DEV_BSIZE;
        ddname = find_dev(dumpdev, S_IFBLK);
        Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
        Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
        dumplo *= DEV_BSIZE;
        ddname = find_dev(dumpdev, S_IFBLK);
+       dumpfd = Open(ddname, O_RDWR);
        fp = fdopen(kmem, "r");
        if (fp == NULL) {
        fp = fdopen(kmem, "r");
        if (fp == NULL) {
-               syslog(LOG_ERR, "Couldn't fdopen kmem");
+               log(LOG_ERR, "Couldn't fdopen kmem\n");
                exit(1);
        }
        if (system)
                exit(1);
        }
        if (system)
@@ -237,19 +322,20 @@ check_kmem()
        FILE *fp;
        register char *cp;
 
        FILE *fp;
        register char *cp;
 
-       fp = fopen(ddname, "r");
+       fp = fdopen(dumpfd, "r");
        if (fp == NULL) {
        if (fp == NULL) {
-               syslog(LOG_ERR, "%s: %m", ddname);
+               log(LOG_ERR, "Can't fdopen dumpfd\n");
                exit(1);
        }
                exit(1);
        }
+
        fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
        fgets(core_vers, sizeof (core_vers), fp);
        fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
        fgets(core_vers, sizeof (core_vers), fp);
-       fclose(fp);
-       if (!eq(vers, core_vers) && system == 0)
-               fprintf(stderr,
-                  "Warning: vmunix version mismatch:\n\t%sand\n\t%s",
-                  vers, core_vers);
-       fp = fopen(ddname, "r");
+       if (!eq(vers, core_vers) && system == 0) {
+               log(LOG_WARNING, "Warning: %s version mismatch:\n", _PATH_UNIX);
+               log(LOG_WARNING, "\t%s\n", vers);
+               log(LOG_WARNING, "and\t%s\n", core_vers);
+       }
+
        fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
        fread((char *)&panicstr, sizeof (panicstr), 1, fp);
        if (panicstr) {
        fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
        fread((char *)&panicstr, sizeof (panicstr), 1, fp);
        if (panicstr) {
@@ -257,23 +343,20 @@ check_kmem()
                cp = panic_mesg;
                do
                        *cp = getc(fp);
                cp = panic_mesg;
                do
                        *cp = getc(fp);
-               while (*cp++);
+               while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]);
        }
        }
-       fclose(fp);
+       /* don't fclose(fp); we want the file descriptor */
 }
 
 get_crashtime()
 {
 }
 
 get_crashtime()
 {
-       int dumpfd;
        time_t clobber = (time_t)0;
 
        time_t clobber = (time_t)0;
 
-       dumpfd = Open(ddname, O_RDONLY);
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
        Read(dumpfd, (char *)&dumptime, sizeof dumptime);
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
        Read(dumpfd, (char *)&dumptime, sizeof dumptime);
-       close(dumpfd);
        if (dumptime == 0) {
        if (dumptime == 0) {
-               if (Verbose)
-                       printf("Dump time not found.\n");
+               if (verbose)
+                       printf("Dump time is zero.\n");
                return (0);
        }
        printf("System went down at %s", ctime(&dumptime));
                return (0);
        }
        printf("System went down at %s", ctime(&dumptime));
@@ -298,28 +381,22 @@ path(file)
 
 check_space()
 {
 
 check_space()
 {
-       struct stat dsb;
-       register char *ddev;
-       int dfd, spacefree;
-       struct fs fs;
+       long minfree, spacefree;
+       struct statfs fsbuf;
 
 
-       if (stat(dirname, &dsb) < 0) {
-               syslog(LOG_ERR, "%s: %m", dirname);
+       if (statfs(dirname, &fsbuf) < 0) {
+               Perror(LOG_ERR, "%s: %m\n", dirname);
                exit(1);
        }
                exit(1);
        }
-       ddev = find_dev(dsb.st_dev, S_IFBLK);
-       dfd = Open(ddev, O_RDONLY);
-       Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), L_SET);
-       Read(dfd, (char *)&fs, sizeof (fs));
-       close(dfd);
-       spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024;
-       if (spacefree < read_number("minfree")) {
-               syslog(LOG_WARNING, "Dump omitted, not enough space on device");
+       spacefree = fsbuf.f_bavail * fsbuf.f_fsize / 1024;
+       minfree = read_number("minfree");
+       if (minfree > 0 && spacefree - dumpsize < minfree) {
+               log(LOG_WARNING, "Dump omitted, not enough space on device\n");
                return (0);
        }
                return (0);
        }
-       if (freespace(&fs, fs.fs_minfree) < 0)
-               syslog(LOG_WARNING,
-                   "Dump performed, but free space threshold crossed");
+       if (spacefree - dumpsize < minfree)
+               log(LOG_WARNING,
+                   "Dump performed, but free space threshold crossed\n");
        return (1);
 }
 
        return (1);
 }
 
@@ -340,78 +417,80 @@ read_number(fn)
        return (atoi(lin));
 }
 
        return (atoi(lin));
 }
 
-#define        BUFPAGES        (256*1024/NBPG)         /* 1/4 Mb */
+/*#define      BUFSIZE         (256*1024)              /* 1/4 Mb */
+#define        BUFSIZE         (8*1024)
 
 save_core()
 {
        register int n;
        register char *cp;
        register int ifd, ofd, bounds;
 
 save_core()
 {
        register int n;
        register char *cp;
        register int ifd, ofd, bounds;
+       int ret;
+       char *bfile;
        register FILE *fp;
 
        register FILE *fp;
 
-       cp = malloc(BUFPAGES*NBPG);
+       cp = malloc(BUFSIZE);
        if (cp == 0) {
        if (cp == 0) {
-               fprintf(stderr, "savecore: Can't allocate i/o buffer.\n");
+               log(LOG_ERR, "savecore: Can't allocate i/o buffer.\n");
                return;
        }
        bounds = read_number("bounds");
                return;
        }
        bounds = read_number("bounds");
-       ifd = Open(system?system:"/vmunix", O_RDONLY);
-       while((n = Read(ifd, cp, BUFSIZ)) > 0)
+       ifd = Open(system ? system : _PATH_UNIX, O_RDONLY);
+       (void)sprintf(cp, "system.%d", bounds);
+       ofd = Create(path(cp), 0644);
+       while((n = Read(ifd, cp, BUFSIZE)) > 0)
                Write(ofd, cp, n);
        close(ifd);
        close(ofd);
                Write(ofd, cp, n);
        close(ifd);
        close(ofd);
-       ifd = Open(ddname, O_RDONLY);
-       Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
-       Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
-       sprintf(cp, "vmcore.%d", bounds);
+       if ((ifd = open(rawname(ddname), O_RDONLY)) == -1) {
+               log(LOG_WARNING, "Can't open %s (%m); using block device",
+                       rawname(ddname));
+               ifd = dumpfd;
+       }
+       Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
+       Read(dumpfd, (char *)&dumpsize, sizeof (dumpsize));
+       (void)sprintf(cp, "ram.%d", bounds);
        ofd = Create(path(cp), 0644);
        Lseek(ifd, (off_t)dumplo, L_SET);
        ofd = Create(path(cp), 0644);
        Lseek(ifd, (off_t)dumplo, L_SET);
-       printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize,
-               bounds);
+       dumpsize *= NBPG;
+       log(LOG_NOTICE, "Saving %d bytes of image in ram.%d\n",
+           dumpsize, bounds);
        while (dumpsize > 0) {
        while (dumpsize > 0) {
-               n = Read(ifd, cp,
-                   (dumpsize > BUFPAGES ? BUFPAGES : dumpsize) * NBPG);
-               if (n == 0) {
-                       printf("WARNING: core may be incomplete\n");
+               n = read(ifd, cp,
+                   dumpsize > BUFSIZE ? BUFSIZE : dumpsize);
+               if (n <= 0) {
+                       if (n == 0)
+                               log(LOG_WARNING,
+                                   "WARNING: EOF on dump device; %s\n",
+                                   "ram file may be incomplete");
+                       else
+                               Perror(LOG_ERR, "read from dumpdev: %m",
+                                   "read");
                        break;
                }
                        break;
                }
-               Write(ofd, cp, n);
-               dumpsize -= n/NBPG;
+               if ((ret = write(ofd, cp, n)) < n) {
+                       if (ret < 0)
+                               Perror(LOG_ERR, "write: %m", "write");
+                       else
+                               log(LOG_ERR, "short write: wrote %d of %d\n",
+                                   ret, n);
+                       log(LOG_WARNING, "WARNING: ram file may be incomplete\n");
+                       break;
+               }
+               dumpsize -= n;
        }
        close(ifd);
        close(ofd);
        }
        close(ifd);
        close(ofd);
-       fp = fopen(path("bounds"), "w");
-       fprintf(fp, "%d\n", bounds+1);
-       fclose(fp);
+       bfile = path("bounds");
+       fp = fopen(bfile, "w");
+       if (fp) {
+               fprintf(fp, "%d\n", bounds+1);
+               fclose(fp);
+       } else
+               Perror(LOG_ERR, "Can't create bounds file %s: %m", bfile);
        free(cp);
 }
 
        free(cp);
 }
 
-char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
-char *months[] = {
-       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
-       "Oct", "Nov", "Dec"
-};
-
-log_entry()
-{
-       FILE *fp;
-       struct tm *tm, *localtime();
-
-       fp = fopen("/usr/adm/shutdownlog", "a");
-       if (fp == 0)
-               return;
-       tm = localtime(&now);
-       fseek(fp, 0L, L_XTND);
-       fprintf(fp, "%02d:%02d  %s %s %2d, %4d.  Reboot", tm->tm_hour,
-               tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
-               tm->tm_mday, tm->tm_year + 1900);
-       if (panicstr)
-               fprintf(fp, " after panic: %s\n", panic_mesg);
-       else
-               putc('\n', fp);
-       fclose(fp);
-}
-
 /*
  * Versions of std routines that exit on error.
  */
 /*
  * Versions of std routines that exit on error.
  */
@@ -423,7 +502,7 @@ Open(name, rw)
 
        fd = open(name, rw);
        if (fd < 0) {
 
        fd = open(name, rw);
        if (fd < 0) {
-               syslog(LOG_ERR, "%s: %m", name);
+               Perror(LOG_ERR, "%s: %m", name);
                exit(1);
        }
        return (fd);
                exit(1);
        }
        return (fd);
@@ -437,7 +516,7 @@ Read(fd, buff, size)
 
        ret = read(fd, buff, size);
        if (ret < 0) {
 
        ret = read(fd, buff, size);
        if (ret < 0) {
-               syslog(LOG_ERR, "read: %m");
+               Perror(LOG_ERR, "read: %m", "read");
                exit(1);
        }
        return (ret);
                exit(1);
        }
        return (ret);
@@ -452,7 +531,7 @@ Lseek(fd, off, flag)
 
        ret = lseek(fd, off, flag);
        if (ret == -1) {
 
        ret = lseek(fd, off, flag);
        if (ret == -1) {
-               syslog(LOG_ERR, "lseek: %m");
+               Perror(LOG_ERR, "lseek: %m", "lseek");
                exit(1);
        }
        return (ret);
                exit(1);
        }
        return (ret);
@@ -466,7 +545,7 @@ Create(file, mode)
 
        fd = creat(file, mode);
        if (fd < 0) {
 
        fd = creat(file, mode);
        if (fd < 0) {
-               syslog(LOG_ERR, "%s: %m", file);
+               Perror(LOG_ERR, "%s: %m", file);
                exit(1);
        }
        return (fd);
                exit(1);
        }
        return (fd);
@@ -476,9 +555,40 @@ Write(fd, buf, size)
        int fd, size;
        char *buf;
 {
        int fd, size;
        char *buf;
 {
+       int n;
 
 
-       if (write(fd, buf, size) < size) {
-               syslog(LOG_ERR, "write: %m");
+       if ((n = write(fd, buf, size)) < size) {
+               if (n < 0)
+                       Perror(LOG_ERR, "write: %m", "write");
+               else
+                       log(LOG_ERR, "short write: wrote %d of %d\n", n, size);
                exit(1);
        }
 }
                exit(1);
        }
 }
+
+/* VARARGS2 */
+log(level, msg, a1, a2)
+       int level;
+       char *msg;
+{
+
+       fprintf(stderr, msg, a1, a2);
+       syslog(level, msg, a1, a2);
+}
+
+Perror(level, msg, s)
+       int level;
+       char *msg, *s;
+{
+       int oerrno = errno;
+       
+       perror(s);
+       errno = oerrno;
+       syslog(level, msg, s);
+}
+
+usage()
+{
+       (void)fprintf(stderr, "usage: savecore [-cfv] dirname [system]\n");
+       exit(1);
+}