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