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