* Copyright (c) 1980,1986 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 Regents of the University of California.\n\
static char sccsid
[] = "@(#)savecore.c 5.13 (Berkeley) %G%";
#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)
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 */
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 (argc
> 0 && argv
[0][0] == '-') {
for (cp
= &argv
[0][1]; *cp
; cp
++) switch (*cp
) {
"usage: savecore [-f] [-v] dirname [ system ]\n");
if (argc
!= 1 && argc
!= 2)
openlog("savecore", LOG_ODELAY
, LOG_AUTH
);
if (access(dirname
, W_OK
) < 0) {
Perror(LOG_ERR
, "%s: %m", dirname
);
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
));
if (Verbose
&& word
!= dumpmag
) {
printf("dumplo = %d (%d bytes)\n", dumplo
/DEV_BSIZE
, dumplo
);
printf("magic number mismatch: %x != %x\n", word
, dumpmag
);
return (word
== dumpmag
);
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
));
strcpy(devname
, "/dev/");
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
));
{ X_DUMPDEV
, X_DUMPLO
, X_VERSION
, X_DUMPMAG
, -1 };
{ X_TIME
, X_DUMPSIZE
, X_VERSION
, X_PANICSTR
, X_DUMPMAG
, -1 };
dump_sys
= system
? system
: "/vmunix";
nlist("/vmunix", 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
, "/vmunix: %s not in namelist\n",
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("/dev/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_DUMPMAG
].n_value
, L_SET
);
Read(kmem
, (char *)&dumpmag
, sizeof (dumpmag
));
ddname
= find_dev(dumpdev
, S_IFBLK
);
log(LOG_ERR
, "Couldn't fdopen kmem\n");
fseek(fp
, (long)current_nl
[X_VERSION
].n_value
, L_SET
);
fgets(vers
, sizeof (vers
), fp
);
Perror(LOG_ERR
, "%s: %m", ddname
);
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: vmunix version mismatch:\n");
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
);
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
);
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 (stat(dirname
, &dsb
) < 0) {
Perror(LOG_ERR
, "%s: %m", dirname
);
ddev
= find_dev(dsb
.st_dev
, S_IFBLK
);
dfd
= Open(ddev
, O_RDONLY
);
Lseek(dfd
, SBOFF
, L_SET
);
Read(dfd
, (char *)&fs
, sizeof (fs
));
spacefree
= freespace(&fs
, fs
.fs_minfree
) * fs
.fs_fsize
/ 1024;
if (spacefree
< read_number("minfree")) {
log(LOG_WARNING
, "Dump omitted, not enough space on device\n");
if (freespace(&fs
, fs
.fs_minfree
) < 0)
"Dump performed, but free space threshold crossed\n");
fp
= fopen(path(fn
), "r");
if (fgets(lin
, 80, fp
) == NULL
) {
#define BUFPAGES (256*1024/NBPG) /* 1/4 Mb */
register int ifd
, ofd
, bounds
;
cp
= malloc(BUFPAGES
*NBPG
);
fprintf(stderr
, "savecore: Can't allocate i/o buffer.\n");
bounds
= read_number("bounds");
ifd
= Open(system
?system
:"/vmunix", O_RDONLY
);
while((n
= Read(ifd
, cp
, BUFSIZ
)) > 0)
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
);
ofd
= Create(path(cp
), 0644);
Lseek(ifd
, (off_t
)dumplo
, L_SET
);
log(LOG_NOTICE
, "Saving %d bytes of image in vmcore.%d\n",
(dumpsize
> BUFPAGES
? BUFPAGES
: dumpsize
) * NBPG
);
log(LOG_WARNING
, "WARNING: vmcore may be incomplete\n");
fp
= fopen(path("bounds"), "w");
fprintf(fp
, "%d\n", bounds
+1);
* Versions of std routines that exit on error.
Perror(LOG_ERR
, "%s: %m", name
);
ret
= read(fd
, buff
, size
);
Perror(LOG_ERR
, "read: %m");
ret
= lseek(fd
, off
, flag
);
Perror(LOG_ERR
, "lseek: %m");
Perror(LOG_ERR
, "%s: %m", file
);
if (write(fd
, buf
, size
) < size
) {
Perror(LOG_ERR
, "write: %m");
fprintf(stderr
, msg
, a1
, a2
);
syslog(level
, msg
, a1
, a2
);