386BSD 0.1 development
[unix-history] / usr / src / sbin / savecore / savecore.c
index ec8c6bd..31ff825 100644 (file)
@@ -2,17 +2,33 @@
  * Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
  * 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
  */
 
 #ifndef lint
@@ -22,19 +38,16 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)savecore.c 5.20 (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 <paths.h>
 #include <stdio.h>
 #include <nlist.h>
 #include <paths.h>
@@ -49,9 +62,13 @@ static char sccsid[] = "@(#)savecore.c       5.20 (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
@@ -102,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;
@@ -111,44 +128,67 @@ 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':
-               case 'd':
-                       Verbose++;
+                       verbose = 1;
                        break;
                        break;
-
-               case 'c':
-                       clear++;
+               case 'f':
+                       force = 1;
                        break;
                        break;
-
+               case '?':
                default:
                default:
-               usage:
-                       fprintf(stderr,
-                           "usage: savecore [-f] [-v] [-c] 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) {
                Perror(LOG_ERR, "%s: %m\n", dirname);
                exit(1);
        }
        if (access(dirname, W_OK) < 0) {
                Perror(LOG_ERR, "%s: %m\n", dirname);
                exit(1);
        }
-       read_kmem();
+       if ((!get_crashtime() || !check_space()) && !force)
+               exit(1);
+       save_core();
+       clear_dump();
+       exit(0);
 }
 
 dump_exists()
 }
 
 dump_exists()
@@ -157,7 +197,7 @@ dump_exists()
 
        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));
-       if (Verbose && word != dumpmag)
+       if (verbose && word != dumpmag)
                printf("magic number mismatch: %x != %x\n", word, dumpmag);
        return (word == dumpmag);
 }
                printf("magic number mismatch: %x != %x\n", word, dumpmag);
        return (word == dumpmag);
 }
@@ -175,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;
 
        strcpy(devname, _PATH_DEV);
        char *dp;
 
        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;
@@ -186,11 +231,13 @@ 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*/
@@ -250,7 +297,7 @@ 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)
+       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);
                printf("dumplo = %d (%d * %d)\n", dumplo, dumplo/DEV_BSIZE,
                    DEV_BSIZE);
        Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
@@ -280,6 +327,7 @@ check_kmem()
                log(LOG_ERR, "Can't fdopen dumpfd\n");
                exit(1);
        }
                log(LOG_ERR, "Can't fdopen dumpfd\n");
                exit(1);
        }
+
        fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
        fgets(core_vers, sizeof (core_vers), fp);
        if (!eq(vers, core_vers) && system == 0) {
        fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
        fgets(core_vers, sizeof (core_vers), fp);
        if (!eq(vers, core_vers) && system == 0) {
@@ -287,6 +335,7 @@ check_kmem()
                log(LOG_WARNING, "\t%s\n", vers);
                log(LOG_WARNING, "and\t%s\n", core_vers);
        }
                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) {
@@ -306,7 +355,7 @@ get_crashtime()
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
        Read(dumpfd, (char *)&dumptime, sizeof dumptime);
        if (dumptime == 0) {
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
        Read(dumpfd, (char *)&dumptime, sizeof dumptime);
        if (dumptime == 0) {
-               if (Verbose)
+               if (verbose)
                        printf("Dump time is zero.\n");
                return (0);
        }
                        printf("Dump time is zero.\n");
                return (0);
        }
@@ -332,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) {
+       if (statfs(dirname, &fsbuf) < 0) {
                Perror(LOG_ERR, "%s: %m\n", dirname);
                exit(1);
        }
                Perror(LOG_ERR, "%s: %m\n", dirname);
                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);
@@ -374,7 +417,8 @@ read_number(fn)
        return (atoi(lin));
 }
 
        return (atoi(lin));
 }
 
-#define        BUFSIZE         (256*1024)              /* 1/4 Mb */
+/*#define      BUFSIZE         (256*1024)              /* 1/4 Mb */
+#define        BUFSIZE         (8*1024)
 
 save_core()
 {
 
 save_core()
 {
@@ -392,6 +436,8 @@ save_core()
        }
        bounds = read_number("bounds");
        ifd = Open(system ? system : _PATH_UNIX, O_RDONLY);
        }
        bounds = read_number("bounds");
        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);
        while((n = Read(ifd, cp, BUFSIZE)) > 0)
                Write(ofd, cp, n);
        close(ifd);
@@ -403,11 +449,11 @@ save_core()
        }
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
        Read(dumpfd, (char *)&dumpsize, sizeof (dumpsize));
        }
        Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
        Read(dumpfd, (char *)&dumpsize, sizeof (dumpsize));
-       (void)sprintf(cp, "vmcore.%d", bounds);
+       (void)sprintf(cp, "ram.%d", bounds);
        ofd = Create(path(cp), 0644);
        Lseek(ifd, (off_t)dumplo, L_SET);
        dumpsize *= NBPG;
        ofd = Create(path(cp), 0644);
        Lseek(ifd, (off_t)dumplo, L_SET);
        dumpsize *= NBPG;
-       log(LOG_NOTICE, "Saving %d bytes of image in vmcore.%d\n",
+       log(LOG_NOTICE, "Saving %d bytes of image in ram.%d\n",
            dumpsize, bounds);
        while (dumpsize > 0) {
                n = read(ifd, cp,
            dumpsize, bounds);
        while (dumpsize > 0) {
                n = read(ifd, cp,
@@ -416,7 +462,7 @@ save_core()
                        if (n == 0)
                                log(LOG_WARNING,
                                    "WARNING: EOF on dump device; %s\n",
                        if (n == 0)
                                log(LOG_WARNING,
                                    "WARNING: EOF on dump device; %s\n",
-                                   "vmcore may be incomplete");
+                                   "ram file may be incomplete");
                        else
                                Perror(LOG_ERR, "read from dumpdev: %m",
                                    "read");
                        else
                                Perror(LOG_ERR, "read from dumpdev: %m",
                                    "read");
@@ -428,7 +474,7 @@ save_core()
                        else
                                log(LOG_ERR, "short write: wrote %d of %d\n",
                                    ret, n);
                        else
                                log(LOG_ERR, "short write: wrote %d of %d\n",
                                    ret, n);
-                       log(LOG_WARNING, "WARNING: vmcore may be incomplete\n");
+                       log(LOG_WARNING, "WARNING: ram file may be incomplete\n");
                        break;
                }
                dumpsize -= n;
                        break;
                }
                dumpsize -= n;
@@ -532,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;
        
@@ -540,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);
+}