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