386BSD 0.1 development
[unix-history] / usr / src / sbin / savecore / savecore.c
index 451a514..31ff825 100644 (file)
@@ -1,43 +1,56 @@
 /*
 /*
- * Copyright (c) 1980, 1986 The Regents of the University of California.
+ * Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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, 1986 The Regents of the University of California.\n\
+"@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)savecore.c 5.15 (Berkeley) %G%";
+static char sccsid[] = "@(#)savecore.c 5.26 (Berkeley) 4/8/91";
 #endif /* not lint */
 
 #endif /* not lint */
 
-/*
- * savecore
- */
-
 #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/syslog.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/file.h>
 #include <sys/syslog.h>
+#include <dirent.h>
 #include <stdio.h>
 #include <nlist.h>
 #include <stdio.h>
 #include <nlist.h>
-#include "pathnames.h"
+#include <paths.h>
 
 #define        DAY     (60L*60L*24L)
 #define        LEEWAY  (3*DAY)
 
 #define        DAY     (60L*60L*24L)
 #define        LEEWAY  (3*DAY)
@@ -49,9 +62,13 @@ static char sccsid[] = "@(#)savecore.c       5.15 (Berkeley) %G%";
 #ifdef tahoe
 #define ok(number) ((number)&~0xc0000000)
 #else
 #ifdef tahoe
 #define ok(number) ((number)&~0xc0000000)
 #else
+#ifdef i386
+#define ok(number) ((number)&~0xfe000000)
+#else
 #define ok(number) (number)
 #endif
 #endif
 #define ok(number) (number)
 #endif
 #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
@@ -85,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 */
@@ -101,7 +119,7 @@ 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;
 int    force;
 int    clear;
 extern int errno;
@@ -110,70 +128,86 @@ main(argc, argv)
        char **argv;
        int argc;
 {
        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) {
-
-               case 'f':
-                       force++;
+       while ((ch = getopt(argc, argv, "cdfv")) != EOF)
+               switch(ch) {
+               case 'c':
+                       clear = 1;
                        break;
                        break;
-
+               case 'd':               /* not documented */
                case 'v':
                case 'v':
-                       Verbose++;
+                       verbose = 1;
                        break;
                        break;
-
-               case 'c':
-                       clear++;
+               case 'f':
+                       force = 1;
                        break;
                        break;
-
+               case '?':
                default:
                default:
-               usage:
-                       fprintf(stderr,
-                           "usage: savecore [-f] [-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_AUTH);
        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) {
-               Perror(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 *
@@ -181,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;
@@ -192,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);
                }
        }
+       closedir(dfd);
        log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
        exit(1);
        /*NOTREACHED*/
 }
 
        log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
        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[] =
@@ -241,10 +297,14 @@ read_kmem()
        Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
        Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
        Read(kmem, (char *)&dumplo, sizeof (dumplo));
        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) {
                log(LOG_ERR, "Couldn't fdopen kmem\n");
        fp = fdopen(kmem, "r");
        if (fp == NULL) {
                log(LOG_ERR, "Couldn't fdopen kmem\n");
@@ -262,20 +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) {
-               Perror(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) {
                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);
        }
        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);
        }
-       fp = fopen(ddname, "r");
+
        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) {
@@ -283,22 +343,19 @@ 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)
+               if (verbose)
                        printf("Dump time is zero.\n");
                return (0);
        }
                        printf("Dump time is zero.\n");
                return (0);
        }
@@ -324,26 +381,20 @@ 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) {
-               Perror(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, SBOFF, 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")) {
+       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);
        }
                log(LOG_WARNING, "Dump omitted, not enough space on device\n");
                return (0);
        }
-       if (freespace(&fs, fs.fs_minfree) < 0)
+       if (spacefree - dumpsize < minfree)
                log(LOG_WARNING,
                    "Dump performed, but free space threshold crossed\n");
        return (1);
                log(LOG_WARNING,
                    "Dump performed, but free space threshold crossed\n");
        return (1);
@@ -366,49 +417,77 @@ 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");
        ifd = Open(system ? system : _PATH_UNIX, O_RDONLY);
                return;
        }
        bounds = read_number("bounds");
        ifd = Open(system ? system : _PATH_UNIX, O_RDONLY);
-       while((n = Read(ifd, cp, BUFSIZ)) > 0)
+       (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));
-       (void)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);
-       log(LOG_NOTICE, "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) {
-                       log(LOG_WARNING, "WARNING: vmcore 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);
 }
 
@@ -437,7 +516,7 @@ Read(fd, buff, size)
 
        ret = read(fd, buff, size);
        if (ret < 0) {
 
        ret = read(fd, buff, size);
        if (ret < 0) {
-               Perror(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) {
-               Perror(LOG_ERR, "lseek: %m");
+               Perror(LOG_ERR, "lseek: %m", "lseek");
                exit(1);
        }
        return (ret);
                exit(1);
        }
        return (ret);
@@ -476,13 +555,18 @@ Write(fd, buf, size)
        int fd, size;
        char *buf;
 {
        int fd, size;
        char *buf;
 {
+       int n;
 
 
-       if (write(fd, buf, size) < size) {
-               Perror(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;
 log(level, msg, a1, a2)
        int level;
        char *msg;
@@ -494,7 +578,7 @@ log(level, msg, a1, a2)
 
 Perror(level, msg, s)
        int level;
 
 Perror(level, msg, s)
        int level;
-       char *msg;
+       char *msg, *s;
 {
        int oerrno = errno;
        
 {
        int oerrno = errno;
        
@@ -502,3 +586,9 @@ Perror(level, msg, s)
        errno = oerrno;
        syslog(level, msg, s);
 }
        errno = oerrno;
        syslog(level, msg, s);
 }
+
+usage()
+{
+       (void)fprintf(stderr, "usage: savecore [-cfv] dirname [system]\n");
+       exit(1);
+}