diff options
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/savecore/savecore.c | 120 |
1 files changed, 89 insertions, 31 deletions
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c index d5e0a31..188e01c 100644 --- a/sbin/savecore/savecore.c +++ b/sbin/savecore/savecore.c @@ -55,7 +55,7 @@ static const char rcsid[] = #include <vm/vm_param.h> #include <vm/pmap.h> -#include <errno.h> +#include <dirent.h> #include <fcntl.h> #include <nlist.h> #include <paths.h> @@ -106,15 +106,15 @@ off_t dumplo; /* where dump starts on dumpdev */ int dumpmag; /* magic number in dump */ int dumpsize; /* amount of memory dumped */ -char *kernel; +char *kernel; /* user-specified kernel */ char *savedir; /* directory to save dumps in */ -char *ddname; /* name of dump device */ +char ddname[MAXPATHLEN]; /* name of dump device */ dev_t dumpdev; /* dump device */ int dumpfd; /* read/write descriptor on char dev */ time_t now; /* current date */ -char panic_mesg[1024]; -int panicstr; -char vers[1024]; +char panic_mesg[1024]; /* panic message */ +int panicstr; /* flag: dump was caused by panic */ +char vers[1024]; /* version of kernel that crashed */ int clear, compress, force, verbose; /* flags */ @@ -124,7 +124,7 @@ void clear_dump __P((void)); void DumpRead __P((int fd, void *bp, int size, off_t off, int flag)); void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag)); int dump_exists __P((void)); -char *find_dev __P((dev_t)); +void find_dev __P((dev_t)); int get_crashtime __P((void)); void get_dumpsize __P((void)); void kmem_setup __P((void)); @@ -226,8 +226,7 @@ kmem_setup() * the same!) */ if ((nlist(getbootfile(), current_nl)) == -1) - syslog(LOG_ERR, "%s: nlist: %s", getbootfile(), - strerror(errno)); + syslog(LOG_ERR, "%s: nlist: %m", getbootfile()); for (i = 0; cursyms[i] != -1; i++) if (current_nl[cursyms[i]].n_value == 0) { syslog(LOG_ERR, "%s: %s not in namelist", @@ -237,7 +236,7 @@ kmem_setup() dump_sys = kernel ? kernel : getbootfile(); if ((nlist(dump_sys, dump_nl)) == -1) - syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno)); + syslog(LOG_ERR, "%s: nlist: %m", dump_sys); for (i = 0; dumpsyms[i] != -1; i++) if (dump_nl[dumpsyms[i]].n_value == 0) { syslog(LOG_ERR, "%s: %s not in namelist", @@ -266,7 +265,7 @@ kmem_setup() (long long)dumplo, kdumplo, DEV_BSIZE); Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET); (void)Read(kmem, &dumpmag, sizeof(dumpmag)); - ddname = find_dev(dumpdev); + find_dev(dumpdev); dumpfd = Open(ddname, O_RDWR); fp = fdopen(kmem, "r"); if (fp == NULL) { @@ -304,17 +303,24 @@ check_kmem() } } +/* + * Clear the magic number in the dump header. + */ void clear_dump() { - long newdumplo; + int newdumpmag; - newdumplo = 0; - DumpWrite(dumpfd, &newdumplo, sizeof(newdumplo), + newdumpmag = 0; + DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag), (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET); close(dumpfd); } +/* + * Check if a dump exists by looking for a magic number in the dump + * header. + */ int dump_exists() { @@ -334,6 +340,9 @@ dump_exists() char buf[1024 * 1024]; +/* + * Save the core dump. + */ void save_core() { @@ -351,7 +360,7 @@ save_core() goto err1; if (fgets(buf, sizeof(buf), fp) == NULL) { if (ferror(fp)) -err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); +err1: syslog(LOG_WARNING, "%s: %m", path); bounds = 0; } else bounds = atoi(buf); @@ -373,7 +382,7 @@ err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); else fp = fopen(path, "w"); if (fp == NULL) { - syslog(LOG_ERR, "%s: %s", path, strerror(errno)); + syslog(LOG_ERR, "%s: %m", path); exit(1); } (void)umask(oumask); @@ -398,8 +407,7 @@ err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno)); } nw = fwrite(buf, 1, nr, fp); if (nw != nr) { - syslog(LOG_ERR, "%s: %s", - path, strerror(nw == 0 ? EIO : errno)); + syslog(LOG_ERR, "%s: %m", path); err2: syslog(LOG_WARNING, "WARNING: vmcore may be incomplete"); (void)printf("\n"); @@ -418,7 +426,7 @@ err2: syslog(LOG_WARNING, else fp = fopen(path, "w"); if (fp == NULL) { - syslog(LOG_ERR, "%s: %s", path, strerror(errno)); + syslog(LOG_ERR, "%s: %m", path); exit(1); } syslog(LOG_NOTICE, "writing %skernel to %s", @@ -426,16 +434,14 @@ err2: syslog(LOG_WARNING, while ((nr = read(ifd, buf, sizeof(buf))) > 0) { nw = fwrite(buf, 1, nr, fp); if (nw != nr) { - syslog(LOG_ERR, "%s: %s", - path, strerror(nw == 0 ? EIO : errno)); + syslog(LOG_ERR, "%s: %m", path); syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); exit(1); } } if (nr < 0) { - syslog(LOG_ERR, "%s: %s", - kernel ? kernel : getbootfile(), strerror(errno)); + syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile()); syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); exit(1); @@ -444,22 +450,67 @@ err2: syslog(LOG_WARNING, close(ifd); } -char * +/* + * Verify that the specified device node exists and matches the + * specified device. + */ +int +verify_dev(name, dev) + char *name; + register dev_t dev; +{ + struct stat sb; + + if (lstat(name, &sb) == -1) + return (-1); + if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev) + return (-1); + return (0); +} + +/* + * Find the dump device. + * + * 1) try devname(3); see if it returns something sensible + * 2) scan /dev for the desired node + * 3) as a last resort, try to create the node we need + */ +void find_dev(dev) register dev_t dev; { - char *dn; + struct dirent *ent; + char *dn, *dnp; + DIR *d; + strcpy(ddname, _PATH_DEV); + dnp = ddname + sizeof _PATH_DEV - 1; if ((dn = devname(dev, S_IFCHR)) != NULL) { - if (asprintf(&dn, "/dev/%s", dn) != -1) - return dn; - syslog(LOG_ERR, "insufficient memory"); - } else { - syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev)); + strcpy(dnp, dn); + if (verify_dev(ddname, dev) == 0) + return; + } + if ((d = opendir(_PATH_DEV)) != NULL) { + while ((ent = readdir(d))) { + strcpy(dnp, ent->d_name); + if (verify_dev(ddname, dev) == 0) { + closedir(d); + return; + } + } + closedir(d); } + strcpy(dnp, "dump"); + if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0) + return; + syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev)); exit(1); } +/* + * Extract the date and time of the crash from the dump header, and + * make sure it looks sane (within one week of current date and time). + */ int get_crashtime() { @@ -481,6 +532,9 @@ get_crashtime() return (1); } +/* + * Extract the size of the dump from the dump header. + */ void get_dumpsize() { @@ -490,6 +544,10 @@ get_dumpsize() dumpsize *= getpagesize(); } +/* + * Check that sufficient space is available on the disk that holds the + * save directory. + */ int check_space() { @@ -658,7 +716,7 @@ Write(fd, bp, size) int n; if ((n = write(fd, bp, size)) < size) { - syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO)); + syslog(LOG_ERR, "write: %m"); exit(1); } } |