* Copyright (c) 1980, 1986, 1989 The Regents of the University of California.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1980, 1986, 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)savecore.c 5.28 (Berkeley) %G%";
#define DAY (60L*60L*24L)
#define eq(a,b) (!strcmp(a,b))
#define ok(number) ((number) - KERNBASE)
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
);
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
));
strcpy(devname
, _PATH_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
));
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_bsize
/ 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
);
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
, "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
> BUFSIZE
? BUFSIZE
: dumpsize
);
"WARNING: EOF on dump device; %s\n",
"vmcore 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: vmcore may be incomplete\n");
(void)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
);
(void)fprintf(stderr
, msg
, a1
, a2
);
syslog(level
, msg
, a1
, a2
);
(void)fprintf(stderr
, "usage: savecore [-cfv] dirname [system]\n");