* Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
"@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)savecore.c 5.26 (Berkeley) 4/8/91";
#define DAY (60L*60L*24L)
#define eq(a,b) (!strcmp(a,b))
#define ok(number) ((number)&0x7fffffff)
#define ok(number) ((number)&~0xc0000000)
#define ok(number) ((number)&~0xfe000000)
#define ok(number) (number)
struct nlist current_nl
[] = { /* namelist for currently running system */
struct nlist dump_nl
[] = { /* name list for dumped system */
{ "_dumpdev" }, /* entries MUST be the same as */
{ "_dumplo" }, /* those in current_nl[] */
char *dirname
; /* directory to save dumps in */
char *ddname
; /* name of dump device */
int dumpfd
; /* read/write descriptor on block dev */
dev_t dumpdev
; /* dump device */
time_t dumptime
; /* time the dump was taken */
int dumplo
; /* where dump starts on dumpdev */
int dumpsize
; /* amount of memory dumped */
int dumpmag
; /* magic number in dump */
time_t now
; /* current date */
while ((ch
= getopt(argc
, argv
, "cdfv")) != EOF
)
case 'd': /* not documented */
/* This is wrong, but I want "savecore -c" to work. */
if (argc
!= 1 && argc
!= 2)
openlog("savecore", LOG_ODELAY
, LOG_AUTH
);
/* (void)fprintf(stderr, "savecore: no core dump\n");*/
log(LOG_CRIT
, "reboot after panic: %s\n", panic_mesg
);
syslog(LOG_CRIT
, "reboot\n");
if (access(dirname
, W_OK
) < 0) {
Perror(LOG_ERR
, "%s: %m\n", dirname
);
if ((!get_crashtime() || !check_space()) && !force
)
Lseek(dumpfd
, (off_t
)(dumplo
+ ok(dump_nl
[X_DUMPMAG
].n_value
)), L_SET
);
Read(dumpfd
, (char *)&word
, sizeof (word
));
if (verbose
&& word
!= dumpmag
)
printf("magic number mismatch: %x != %x\n", word
, dumpmag
);
return (word
== dumpmag
);
Lseek(dumpfd
, (off_t
)(dumplo
+ ok(dump_nl
[X_DUMPMAG
].n_value
)), L_SET
);
Write(dumpfd
, (char *)&zero
, sizeof (zero
));
register DIR *dfd
= opendir(_PATH_DEV
);
static char devname
[MAXPATHLEN
+ 1];
strcpy(devname
, _PATH_DEV
);
while ((dir
= readdir(dfd
))) {
strcpy(devname
+ sizeof(_PATH_DEV
) - 1, dir
->d_name
);
if (stat(devname
, &statb
)) {
if ((statb
.st_mode
&S_IFMT
) != type
)
if (dev
== statb
.st_rdev
) {
dp
= malloc(strlen(devname
)+1);
log(LOG_ERR
, "Can't find device %d/%d\n", major(dev
), minor(dev
));
static char name
[MAXPATHLEN
];
if ((sl
= rindex(s
, '/')) == NULL
|| sl
[1] == '0') {
log(LOG_ERR
, "can't make raw dump device name from %s?\n", s
);
sprintf(name
, "%.*s/r%s", sl
- s
, s
, sl
+ 1);
{ X_DUMPDEV
, X_DUMPLO
, X_VERSION
, X_DUMPMAG
, -1 };
{ X_TIME
, X_DUMPSIZE
, X_VERSION
, X_PANICSTR
, X_DUMPMAG
, -1 };
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,
* others for the system that was running when the dump was made.
* The values obtained from the current system are used
* to look for things in /dev/kmem that cannot be found
* in the dump_sys namelist, but are presumed to be the same
* (since the disk partitions are probably the same!)
for (i
= 0; cursyms
[i
] != -1; i
++)
if (current_nl
[cursyms
[i
]].n_value
== 0) {
log(LOG_ERR
, "%s: %s not in namelist\n", _PATH_UNIX
,
current_nl
[cursyms
[i
]].n_name
);
for (i
= 0; dumpsyms
[i
] != -1; i
++)
if (dump_nl
[dumpsyms
[i
]].n_value
== 0) {
log(LOG_ERR
, "%s: %s not in namelist\n", dump_sys
,
dump_nl
[dumpsyms
[i
]].n_name
);
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
));
printf("dumplo = %d (%d * %d)\n", dumplo
, dumplo
/DEV_BSIZE
,
Lseek(kmem
, (long)current_nl
[X_DUMPMAG
].n_value
, L_SET
);
Read(kmem
, (char *)&dumpmag
, sizeof (dumpmag
));
ddname
= find_dev(dumpdev
, S_IFBLK
);
dumpfd
= Open(ddname
, O_RDWR
);
log(LOG_ERR
, "Couldn't fdopen kmem\n");
fseek(fp
, (long)current_nl
[X_VERSION
].n_value
, L_SET
);
fgets(vers
, sizeof (vers
), fp
);
fp
= fdopen(dumpfd
, "r");
log(LOG_ERR
, "Can't fdopen dumpfd\n");
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) {
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
);
fseek(fp
, dumplo
+ ok(panicstr
), L_SET
);
while (*cp
++ && cp
< &panic_mesg
[sizeof(panic_mesg
)]);
/* don't fclose(fp); we want the file descriptor */
time_t clobber
= (time_t)0;
Lseek(dumpfd
, (off_t
)(dumplo
+ ok(dump_nl
[X_TIME
].n_value
)), L_SET
);
Read(dumpfd
, (char *)&dumptime
, sizeof dumptime
);
printf("Dump time is zero.\n");
printf("System went down at %s", ctime(&dumptime
));
if (dumptime
< now
- LEEWAY
|| dumptime
> now
+ LEEWAY
) {
printf("dump time is unreasonable\n");
register char *cp
= malloc(strlen(file
) + strlen(dirname
) + 2);
(void) strcpy(cp
, dirname
);
if (statfs(dirname
, &fsbuf
) < 0) {
Perror(LOG_ERR
, "%s: %m\n", dirname
);
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");
if (spacefree
- dumpsize
< minfree
)
"Dump performed, but free space threshold crossed\n");
fp
= fopen(path(fn
), "r");
if (fgets(lin
, 80, fp
) == NULL
) {
/*#define BUFSIZE (256*1024) /* 1/4 Mb */
register int ifd
, ofd
, bounds
;
log(LOG_ERR
, "savecore: Can't allocate i/o buffer.\n");
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)
if ((ifd
= open(rawname(ddname
), O_RDONLY
)) == -1) {
log(LOG_WARNING
, "Can't open %s (%m); using block device",
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
);
log(LOG_NOTICE
, "Saving %d bytes of image in ram.%d\n",
dumpsize
> BUFSIZE
? BUFSIZE
: dumpsize
);
"WARNING: EOF on dump device; %s\n",
"ram file may be incomplete");
Perror(LOG_ERR
, "read from dumpdev: %m",
if ((ret
= write(ofd
, cp
, n
)) < n
) {
Perror(LOG_ERR
, "write: %m", "write");
log(LOG_ERR
, "short write: wrote %d of %d\n",
log(LOG_WARNING
, "WARNING: ram file may be incomplete\n");
fprintf(fp
, "%d\n", bounds
+1);
Perror(LOG_ERR
, "Can't create bounds file %s: %m", bfile
);
* Versions of std routines that exit on error.
Perror(LOG_ERR
, "%s: %m", name
);
ret
= read(fd
, buff
, size
);
Perror(LOG_ERR
, "read: %m", "read");
ret
= lseek(fd
, off
, flag
);
Perror(LOG_ERR
, "lseek: %m", "lseek");
Perror(LOG_ERR
, "%s: %m", file
);
if ((n
= write(fd
, buf
, size
)) < size
) {
Perror(LOG_ERR
, "write: %m", "write");
log(LOG_ERR
, "short write: wrote %d of %d\n", n
, size
);
fprintf(stderr
, msg
, a1
, a2
);
syslog(level
, msg
, a1
, a2
);
(void)fprintf(stderr
, "usage: savecore [-cfv] dirname [system]\n");