date and time created 87/10/22 10:11:57 by bostic
[unix-history] / usr / src / sbin / savecore / savecore.c
CommitLineData
5ff67f98 1/*
a8bf8cf3 2 * Copyright (c) 1980,1986 Regents of the University of California.
5ff67f98
DF
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
261f5d78 7#ifndef lint
5ff67f98 8char copyright[] =
a8bf8cf3 9"@(#) Copyright (c) 1980,1986 Regents of the University of California.\n\
5ff67f98
DF
10 All rights reserved.\n";
11#endif not lint
12
13#ifndef lint
99b8650e 14static char sccsid[] = "@(#)savecore.c 5.12 (Berkeley) %G%";
5ff67f98 15#endif not lint
261f5d78 16
d112e9ff 17/*
97d6da0b 18 * savecore
d112e9ff 19 */
a3e4f1d7 20
d112e9ff
BJ
21#include <stdio.h>
22#include <nlist.h>
23#include <sys/param.h>
24#include <sys/dir.h>
25#include <sys/stat.h>
ce4fd43b 26#include <sys/time.h>
865f9d47 27#include <sys/file.h>
a8bf8cf3 28#include <sys/syslog.h>
d112e9ff 29
97d6da0b
BJ
30#define DAY (60L*60L*24L)
31#define LEEWAY (3*DAY)
32
33#define eq(a,b) (!strcmp(a,b))
261f5d78 34#ifdef vax
97d6da0b 35#define ok(number) ((number)&0x7fffffff)
261f5d78 36#else
ce104dfd
SL
37#ifdef tahoe
38#define ok(number) ((number)&~0xc0000000)
39#else
261f5d78
SL
40#define ok(number) (number)
41#endif
ce104dfd 42#endif
97d6da0b 43
a3e4f1d7 44struct nlist current_nl[] = { /* namelist for currently running system */
d112e9ff
BJ
45#define X_DUMPDEV 0
46 { "_dumpdev" },
47#define X_DUMPLO 1
48 { "_dumplo" },
49#define X_TIME 2
50 { "_time" },
261f5d78
SL
51#define X_DUMPSIZE 3
52 { "_dumpsize" },
d112e9ff
BJ
53#define X_VERSION 4
54 { "_version" },
55#define X_PANICSTR 5
56 { "_panicstr" },
261f5d78
SL
57#define X_DUMPMAG 6
58 { "_dumpmag" },
59 { "" },
d112e9ff
BJ
60};
61
a3e4f1d7
RC
62struct nlist dump_nl[] = { /* name list for dumped system */
63 { "_dumpdev" }, /* entries MUST be the same as */
64 { "_dumplo" }, /* those in current_nl[] */
65 { "_time" },
66 { "_dumpsize" },
67 { "_version" },
68 { "_panicstr" },
69 { "_dumpmag" },
70 { "" },
71};
72
f6cc4b0d 73char *system;
97d6da0b
BJ
74char *dirname; /* directory to save dumps in */
75char *ddname; /* name of dump device */
76char *find_dev();
77dev_t dumpdev; /* dump device */
78time_t dumptime; /* time the dump was taken */
79int dumplo; /* where dump starts on dumpdev */
261f5d78
SL
80int dumpsize; /* amount of memory dumped */
81int dumpmag; /* magic number in dump */
97d6da0b
BJ
82time_t now; /* current date */
83char *path();
4d1d39b2 84char *malloc();
97d6da0b
BJ
85char *ctime();
86char vers[80];
87char core_vers[80];
88char panic_mesg[80];
89int panicstr;
97d6da0b
BJ
90off_t lseek();
91off_t Lseek();
a3e4f1d7 92int Verbose;
c6e3f9fb 93int force;
99b8650e 94int clear;
a8bf8cf3 95extern int errno;
d112e9ff
BJ
96
97main(argc, argv)
97d6da0b
BJ
98 char **argv;
99 int argc;
d112e9ff 100{
865f9d47
SL
101 char *cp;
102
103 argc--, argv++;
104 while (argc > 0 && argv[0][0] == '-') {
105 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
97d6da0b 106
c6e3f9fb
MK
107 case 'f':
108 force++;
109 break;
110
a3e4f1d7 111 case 'v':
865f9d47 112 Verbose++;
a3e4f1d7 113 break;
865f9d47 114
99b8650e
MK
115 case 'c':
116 clear++;
117 break;
118
a3e4f1d7 119 default:
865f9d47 120 usage:
a3e4f1d7 121 fprintf(stderr,
c6e3f9fb 122 "usage: savecore [-f] [-v] dirname [ system ]\n");
a3e4f1d7
RC
123 exit(1);
124 }
865f9d47 125 argc--, argv++;
d112e9ff 126 }
865f9d47
SL
127 if (argc != 1 && argc != 2)
128 goto usage;
129 dirname = argv[0];
130 if (argc == 2)
131 system = argv[1];
a96b688d 132 openlog("savecore", LOG_ODELAY, LOG_AUTH);
865f9d47 133 if (access(dirname, W_OK) < 0) {
ce104dfd 134 Perror(LOG_ERR, "%s: %m", dirname);
97d6da0b 135 exit(1);
d112e9ff 136 }
d112e9ff 137 read_kmem();
d112e9ff
BJ
138}
139
739955be
KM
140dump_exists()
141{
142 register int dumpfd;
143 int word;
144
865f9d47
SL
145 dumpfd = Open(ddname, O_RDONLY);
146 Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
147 Read(dumpfd, (char *)&word, sizeof (word));
739955be 148 close(dumpfd);
865f9d47 149 if (Verbose && word != dumpmag) {
f53aabcb 150 printf("dumplo = %d (%d bytes)\n", dumplo/DEV_BSIZE, dumplo);
a3e4f1d7
RC
151 printf("magic number mismatch: %x != %x\n", word, dumpmag);
152 }
261f5d78 153 return (word == dumpmag);
739955be
KM
154}
155
156clear_dump()
157{
158 register int dumpfd;
159 int zero = 0;
160
865f9d47
SL
161 dumpfd = Open(ddname, O_WRONLY);
162 Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
163 Write(dumpfd, (char *)&zero, sizeof (zero));
739955be
KM
164 close(dumpfd);
165}
166
97d6da0b
BJ
167char *
168find_dev(dev, type)
169 register dev_t dev;
170 register int type;
d112e9ff 171{
d112e9ff 172 struct stat statb;
f0326588 173 char *dp;
d112e9ff
BJ
174
175 strcpy(devname, "/dev/");
97d6da0b 176 if (stat(devname, &statb)) {
d112e9ff 177 perror(devname);
97d6da0b
BJ
178 continue;
179 }
180 if ((statb.st_mode&S_IFMT) != type)
181 continue;
182 if (dev == statb.st_rdev) {
4d1d39b2 183 dp = malloc(strlen(devname)+1);
97d6da0b 184 strcpy(dp, devname);
865f9d47 185 return (dp);
d112e9ff
BJ
186 }
187 }
ce104dfd 188 log(LOG_ERR, "Can't find device %d/%d\n", major(dev), minor(dev));
97d6da0b
BJ
189 exit(1);
190 /*NOTREACHED*/
d112e9ff
BJ
191}
192
865f9d47
SL
193int cursyms[] =
194 { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
195int dumpsyms[] =
196 { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
d112e9ff
BJ
197read_kmem()
198{
d112e9ff 199 register char *cp;
865f9d47 200 FILE *fp;
a3e4f1d7 201 char *dump_sys;
865f9d47 202 int kmem, i;
a3e4f1d7
RC
203
204 dump_sys = system ? system : "/vmunix";
a3e4f1d7
RC
205 nlist("/vmunix", current_nl);
206 nlist(dump_sys, dump_nl);
a3e4f1d7
RC
207 /*
208 * Some names we need for the currently running system,
209 * others for the system that was running when the dump was made.
210 * The values obtained from the current system are used
211 * to look for things in /dev/kmem that cannot be found
212 * in the dump_sys namelist, but are presumed to be the same
213 * (since the disk partitions are probably the same!)
214 */
865f9d47
SL
215 for (i = 0; cursyms[i] != -1; i++)
216 if (current_nl[cursyms[i]].n_value == 0) {
99b8650e 217 log(LOG_ERR, "/vmunix: %s not in namelist\n",
865f9d47
SL
218 current_nl[cursyms[i]].n_name);
219 exit(1);
220 }
221 for (i = 0; dumpsyms[i] != -1; i++)
222 if (dump_nl[dumpsyms[i]].n_value == 0) {
99b8650e 223 log(LOG_ERR, "%s: %s not in namelist\n", dump_sys,
865f9d47
SL
224 dump_nl[dumpsyms[i]].n_name);
225 exit(1);
226 }
227 kmem = Open("/dev/kmem", O_RDONLY);
228 Lseek(kmem, (long)current_nl[X_DUMPDEV].n_value, L_SET);
261f5d78 229 Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
865f9d47 230 Lseek(kmem, (long)current_nl[X_DUMPLO].n_value, L_SET);
261f5d78 231 Read(kmem, (char *)&dumplo, sizeof (dumplo));
865f9d47 232 Lseek(kmem, (long)current_nl[X_DUMPMAG].n_value, L_SET);
261f5d78 233 Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
f53aabcb 234 dumplo *= DEV_BSIZE;
d112e9ff 235 ddname = find_dev(dumpdev, S_IFBLK);
865f9d47
SL
236 fp = fdopen(kmem, "r");
237 if (fp == NULL) {
99b8650e 238 log(LOG_ERR, "Couldn't fdopen kmem\n");
97d6da0b 239 exit(1);
d112e9ff 240 }
f6cc4b0d
BJ
241 if (system)
242 return;
865f9d47
SL
243 fseek(fp, (long)current_nl[X_VERSION].n_value, L_SET);
244 fgets(vers, sizeof (vers), fp);
d112e9ff 245 fclose(fp);
798fe693
SL
246}
247
5638c7c2
SL
248check_kmem()
249{
798fe693
SL
250 FILE *fp;
251 register char *cp;
252
865f9d47
SL
253 fp = fopen(ddname, "r");
254 if (fp == NULL) {
ce104dfd 255 Perror(LOG_ERR, "%s: %m", ddname);
97d6da0b 256 exit(1);
d112e9ff 257 }
865f9d47
SL
258 fseek(fp, (off_t)(dumplo+ok(dump_nl[X_VERSION].n_value)), L_SET);
259 fgets(core_vers, sizeof (core_vers), fp);
d112e9ff 260 fclose(fp);
99b8650e
MK
261 if (!eq(vers, core_vers) && system == 0) {
262 log(LOG_WARNING, "Warning: vmunix version mismatch:\n");
263 log(LOG_WARNING, "\t%s\n", vers);
264 log(LOG_WARNING, "and\t%s\n", core_vers);
265 }
97d6da0b 266 fp = fopen(ddname, "r");
865f9d47
SL
267 fseek(fp, (off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
268 fread((char *)&panicstr, sizeof (panicstr), 1, fp);
97d6da0b 269 if (panicstr) {
865f9d47 270 fseek(fp, dumplo + ok(panicstr), L_SET);
d112e9ff
BJ
271 cp = panic_mesg;
272 do
273 *cp = getc(fp);
274 while (*cp++);
d112e9ff 275 }
97d6da0b 276 fclose(fp);
f6cc4b0d 277}
d112e9ff 278
97d6da0b
BJ
279get_crashtime()
280{
d112e9ff 281 int dumpfd;
20f89b8d 282 time_t clobber = (time_t)0;
d112e9ff 283
865f9d47
SL
284 dumpfd = Open(ddname, O_RDONLY);
285 Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
97d6da0b 286 Read(dumpfd, (char *)&dumptime, sizeof dumptime);
d112e9ff 287 close(dumpfd);
a3e4f1d7
RC
288 if (dumptime == 0) {
289 if (Verbose)
c6e3f9fb 290 printf("Dump time is zero.\n");
261f5d78 291 return (0);
a3e4f1d7 292 }
d112e9ff
BJ
293 printf("System went down at %s", ctime(&dumptime));
294 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
865f9d47 295 printf("dump time is unreasonable\n");
261f5d78 296 return (0);
d112e9ff 297 }
261f5d78 298 return (1);
d112e9ff
BJ
299}
300
97d6da0b
BJ
301char *
302path(file)
303 char *file;
d112e9ff 304{
4d1d39b2 305 register char *cp = malloc(strlen(file) + strlen(dirname) + 2);
d112e9ff 306
97d6da0b
BJ
307 (void) strcpy(cp, dirname);
308 (void) strcat(cp, "/");
309 (void) strcat(cp, file);
261f5d78 310 return (cp);
d112e9ff
BJ
311}
312
d112e9ff
BJ
313check_space()
314{
315 struct stat dsb;
316 register char *ddev;
e84afc49 317 int dfd, spacefree;
798fe693 318 struct fs fs;
d112e9ff 319
97d6da0b 320 if (stat(dirname, &dsb) < 0) {
ce104dfd 321 Perror(LOG_ERR, "%s: %m", dirname);
97d6da0b
BJ
322 exit(1);
323 }
d112e9ff 324 ddev = find_dev(dsb.st_dev, S_IFBLK);
865f9d47 325 dfd = Open(ddev, O_RDONLY);
a66ab591 326 Lseek(dfd, SBOFF, L_SET);
865f9d47 327 Read(dfd, (char *)&fs, sizeof (fs));
d112e9ff 328 close(dfd);
865f9d47
SL
329 spacefree = freespace(&fs, fs.fs_minfree) * fs.fs_fsize / 1024;
330 if (spacefree < read_number("minfree")) {
99b8650e 331 log(LOG_WARNING, "Dump omitted, not enough space on device\n");
97d6da0b 332 return (0);
d112e9ff 333 }
ce104dfd
SL
334 if (freespace(&fs, fs.fs_minfree) < 0)
335 log(LOG_WARNING,
99b8650e 336 "Dump performed, but free space threshold crossed\n");
97d6da0b 337 return (1);
d112e9ff
BJ
338}
339
d112e9ff 340read_number(fn)
97d6da0b 341 char *fn;
d112e9ff
BJ
342{
343 char lin[80];
344 register FILE *fp;
345
865f9d47
SL
346 fp = fopen(path(fn), "r");
347 if (fp == NULL)
261f5d78 348 return (0);
97d6da0b
BJ
349 if (fgets(lin, 80, fp) == NULL) {
350 fclose(fp);
261f5d78 351 return (0);
d112e9ff 352 }
97d6da0b 353 fclose(fp);
261f5d78 354 return (atoi(lin));
d112e9ff
BJ
355}
356
4d1d39b2
MK
357#define BUFPAGES (256*1024/NBPG) /* 1/4 Mb */
358
d112e9ff
BJ
359save_core()
360{
361 register int n;
4d1d39b2 362 register char *cp;
d112e9ff
BJ
363 register int ifd, ofd, bounds;
364 register FILE *fp;
365
4d1d39b2 366 cp = malloc(BUFPAGES*NBPG);
865f9d47
SL
367 if (cp == 0) {
368 fprintf(stderr, "savecore: Can't allocate i/o buffer.\n");
4d1d39b2
MK
369 return;
370 }
d112e9ff 371 bounds = read_number("bounds");
865f9d47 372 ifd = Open(system?system:"/vmunix", O_RDONLY);
d112e9ff
BJ
373 while((n = Read(ifd, cp, BUFSIZ)) > 0)
374 Write(ofd, cp, n);
375 close(ifd);
376 close(ofd);
865f9d47
SL
377 ifd = Open(ddname, O_RDONLY);
378 Lseek(ifd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
5638c7c2 379 Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
798fe693
SL
380 sprintf(cp, "vmcore.%d", bounds);
381 ofd = Create(path(cp), 0644);
865f9d47 382 Lseek(ifd, (off_t)dumplo, L_SET);
ce104dfd
SL
383 log(LOG_NOTICE, "Saving %d bytes of image in vmcore.%d\n",
384 NBPG*dumpsize, bounds);
261f5d78 385 while (dumpsize > 0) {
4d1d39b2 386 n = Read(ifd, cp,
865f9d47 387 (dumpsize > BUFPAGES ? BUFPAGES : dumpsize) * NBPG);
f53aabcb 388 if (n == 0) {
99b8650e 389 log(LOG_WARNING, "WARNING: vmcore may be incomplete\n");
f53aabcb
JB
390 break;
391 }
d112e9ff 392 Write(ofd, cp, n);
261f5d78 393 dumpsize -= n/NBPG;
d112e9ff
BJ
394 }
395 close(ifd);
396 close(ofd);
397 fp = fopen(path("bounds"), "w");
398 fprintf(fp, "%d\n", bounds+1);
399 fclose(fp);
4d1d39b2 400 free(cp);
d112e9ff
BJ
401}
402
97d6da0b
BJ
403/*
404 * Versions of std routines that exit on error.
405 */
97d6da0b
BJ
406Open(name, rw)
407 char *name;
408 int rw;
409{
410 int fd;
411
865f9d47
SL
412 fd = open(name, rw);
413 if (fd < 0) {
ce104dfd 414 Perror(LOG_ERR, "%s: %m", name);
97d6da0b
BJ
415 exit(1);
416 }
865f9d47 417 return (fd);
97d6da0b
BJ
418}
419
420Read(fd, buff, size)
421 int fd, size;
422 char *buff;
423{
424 int ret;
425
865f9d47
SL
426 ret = read(fd, buff, size);
427 if (ret < 0) {
ce104dfd 428 Perror(LOG_ERR, "read: %m");
97d6da0b
BJ
429 exit(1);
430 }
865f9d47 431 return (ret);
97d6da0b
BJ
432}
433
434off_t
435Lseek(fd, off, flag)
436 int fd, flag;
437 long off;
438{
439 long ret;
440
865f9d47
SL
441 ret = lseek(fd, off, flag);
442 if (ret == -1) {
ce104dfd 443 Perror(LOG_ERR, "lseek: %m");
97d6da0b
BJ
444 exit(1);
445 }
865f9d47 446 return (ret);
97d6da0b
BJ
447}
448
449Create(file, mode)
450 char *file;
451 int mode;
452{
453 register int fd;
454
865f9d47
SL
455 fd = creat(file, mode);
456 if (fd < 0) {
ce104dfd 457 Perror(LOG_ERR, "%s: %m", file);
97d6da0b
BJ
458 exit(1);
459 }
865f9d47 460 return (fd);
97d6da0b
BJ
461}
462
463Write(fd, buf, size)
464 int fd, size;
465 char *buf;
97d6da0b
BJ
466{
467
468 if (write(fd, buf, size) < size) {
ce104dfd 469 Perror(LOG_ERR, "write: %m");
97d6da0b
BJ
470 exit(1);
471 }
472}
ce104dfd
SL
473
474log(level, msg, a1, a2)
475 int level;
476 char *msg;
477{
478
479 fprintf(stderr, msg, a1, a2);
480 syslog(level, msg, a1, a2);
481}
482
483Perror(level, msg, s)
484 int level;
485 char *msg;
486{
487 int oerrno = errno;
488
489 perror(s);
490 errno = oerrno;
491 syslog(level, msg, s);
492}