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