|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)savecore.c 4.13 (Berkeley) 83/07/02";
3: #endif
4:
5: /*
6: * savecore
7: */
8: #include <stdio.h>
9: #include <nlist.h>
10: #include <sys/param.h>
11: #include <sys/dir.h>
12: #include <sys/stat.h>
13: #include <sys/fs.h>
14: #include <sys/time.h>
15:
16: #define DAY (60L*60L*24L)
17: #define LEEWAY (3*DAY)
18:
19: #define eq(a,b) (!strcmp(a,b))
20: #ifdef vax
21: #define ok(number) ((number)&0x7fffffff)
22: #else
23: #define ok(number) (number)
24: #endif
25:
26: #define SHUTDOWNLOG "/usr/adm/shutdownlog"
27:
28: struct nlist nl[] = {
29: #define X_DUMPDEV 0
30: { "_dumpdev" },
31: #define X_DUMPLO 1
32: { "_dumplo" },
33: #define X_TIME 2
34: { "_time" },
35: #define X_DUMPSIZE 3
36: { "_dumpsize" },
37: #define X_VERSION 4
38: { "_version" },
39: #define X_PANICSTR 5
40: { "_panicstr" },
41: #define X_DUMPMAG 6
42: { "_dumpmag" },
43: { "" },
44: };
45:
46: char *system;
47: char *dirname; /* directory to save dumps in */
48: char *ddname; /* name of dump device */
49: char *find_dev();
50: dev_t dumpdev; /* dump device */
51: time_t dumptime; /* time the dump was taken */
52: int dumplo; /* where dump starts on dumpdev */
53: int dumpsize; /* amount of memory dumped */
54: int dumpmag; /* magic number in dump */
55: time_t now; /* current date */
56: char *path();
57: unsigned malloc();
58: char *ctime();
59: char vers[80];
60: char core_vers[80];
61: char panic_mesg[80];
62: int panicstr;
63: off_t lseek();
64: off_t Lseek();
65:
66: main(argc, argv)
67: char **argv;
68: int argc;
69: {
70:
71: if (argc != 2 && argc != 3) {
72: fprintf(stderr, "usage: savecore dirname [ system ]\n");
73: exit(1);
74: }
75: dirname = argv[1];
76: if (argc == 3)
77: system = argv[2];
78: if (access(dirname, 2) < 0) {
79: perror(dirname);
80: exit(1);
81: }
82: read_kmem();
83: if (dump_exists()) {
84: (void) time(&now);
85: check_kmem();
86: log_entry();
87: if (get_crashtime() && check_space()) {
88: save_core();
89: clear_dump();
90: } else
91: exit(1);
92: }
93: return 0;
94: }
95:
96: int
97: dump_exists()
98: {
99: register int dumpfd;
100: int word;
101:
102: dumpfd = Open(ddname, 0);
103: Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_DUMPMAG].n_value)), 0);
104: Read(dumpfd, (char *)&word, sizeof word);
105: close(dumpfd);
106: return (word == dumpmag);
107: }
108:
109: clear_dump()
110: {
111: register int dumpfd;
112: int zero = 0;
113:
114: dumpfd = Open(ddname, 1);
115: Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_DUMPMAG].n_value)), 0);
116: Write(dumpfd, (char *)&zero, sizeof zero);
117: close(dumpfd);
118: }
119:
120: char *
121: find_dev(dev, type)
122: register dev_t dev;
123: register int type;
124: {
125: register DIR *dfd = opendir("/dev");
126: struct direct *dir;
127: struct stat statb;
128: static char devname[MAXPATHLEN + 1];
129: char *dp;
130:
131: strcpy(devname, "/dev/");
132: while ((dir = readdir(dfd))) {
133: strcpy(devname + 5, dir->d_name);
134: if (stat(devname, &statb)) {
135: perror(devname);
136: continue;
137: }
138: if ((statb.st_mode&S_IFMT) != type)
139: continue;
140: if (dev == statb.st_rdev) {
141: closedir(dfd);
142: dp = (char *)malloc(strlen(devname)+1);
143: strcpy(dp, devname);
144: return dp;
145: }
146: }
147: closedir(dfd);
148: fprintf(stderr, "savecore: Can't find device %d,%d\n",
149: major(dev), minor(dev));
150: exit(1);
151: /*NOTREACHED*/
152: }
153:
154: read_kmem()
155: {
156: int kmem;
157: FILE *fp;
158: register char *cp;
159:
160: nlist("/vmunix", nl);
161: if (nl[X_DUMPDEV].n_value == 0) {
162: fprintf(stderr, "savecore: /vmunix: dumpdev not in namelist\n");
163: exit(1);
164: }
165: if (nl[X_DUMPLO].n_value == 0) {
166: fprintf(stderr, "savecore: /vmunix: dumplo not in namelist\n");
167: exit(1);
168: }
169: if (nl[X_TIME].n_value == 0) {
170: fprintf(stderr, "savecore: /vmunix: time not in namelist\n");
171: exit(1);
172: }
173: if (nl[X_DUMPSIZE].n_value == 0) {
174: fprintf(stderr, "savecore: /vmunix: dumpsize not in namelist\n");
175: exit(1);
176: }
177: if (nl[X_VERSION].n_value == 0) {
178: fprintf(stderr, "savecore: /vmunix: version not in namelist\n");
179: exit(1);
180: }
181: if (nl[X_PANICSTR].n_value == 0) {
182: fprintf(stderr, "savecore: /vmunix: panicstr not in namelist\n");
183: exit(1);
184: }
185: if (nl[X_DUMPMAG].n_value == 0) {
186: fprintf(stderr, "savecore: /vmunix: dumpmag not in namelist\n");
187: exit(1);
188: }
189: kmem = Open("/dev/kmem", 0);
190: Lseek(kmem, (long)nl[X_DUMPDEV].n_value, 0);
191: Read(kmem, (char *)&dumpdev, sizeof (dumpdev));
192: Lseek(kmem, (long)nl[X_DUMPLO].n_value, 0);
193: Read(kmem, (char *)&dumplo, sizeof (dumplo));
194: Lseek(kmem, (long)nl[X_DUMPMAG].n_value, 0);
195: Read(kmem, (char *)&dumpmag, sizeof (dumpmag));
196: dumplo *= 512L;
197: ddname = find_dev(dumpdev, S_IFBLK);
198: if ((fp = fdopen(kmem, "r")) == NULL) {
199: fprintf(stderr, "savecore: Couldn't fdopen kmem\n");
200: exit(1);
201: }
202: if (system)
203: return;
204: fseek(fp, (long)nl[X_VERSION].n_value, 0);
205: fgets(vers, sizeof vers, fp);
206: fclose(fp);
207: }
208:
209: check_kmem()
210: {
211: FILE *fp;
212: register char *cp;
213:
214: if ((fp = fopen(ddname, "r")) == NULL) {
215: perror(ddname);
216: exit(1);
217: }
218: fseek(fp, (off_t)(dumplo+ok(nl[X_VERSION].n_value)), 0);
219: fgets(core_vers, sizeof core_vers, fp);
220: fclose(fp);
221: if (!eq(vers, core_vers))
222: fprintf(stderr,
223: "savecore: Warning: vmunix version mismatch:\n\t%sand\n\t%s",
224: vers, core_vers);
225: fp = fopen(ddname, "r");
226: fseek(fp, (off_t)(dumplo + ok(nl[X_PANICSTR].n_value)), 0);
227: fread((char *)&panicstr, sizeof panicstr, 1, fp);
228: if (panicstr) {
229: fseek(fp, dumplo + ok(panicstr), 0);
230: cp = panic_mesg;
231: do
232: *cp = getc(fp);
233: while (*cp++);
234: }
235: fclose(fp);
236: }
237:
238: get_crashtime()
239: {
240: int dumpfd;
241: time_t clobber = (time_t)0;
242:
243: if (system)
244: return (1);
245: dumpfd = Open(ddname, 0);
246: Lseek(dumpfd, (off_t)(dumplo + ok(nl[X_TIME].n_value)), 0);
247: Read(dumpfd, (char *)&dumptime, sizeof dumptime);
248: close(dumpfd);
249: if (dumptime == 0)
250: return (0);
251: printf("System went down at %s", ctime(&dumptime));
252: if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
253: printf("Dump time is unreasonable\n");
254: return (0);
255: }
256: return (1);
257: }
258:
259: char *
260: path(file)
261: char *file;
262: {
263: register char *cp = (char *)malloc(strlen(file) + strlen(dirname) + 2);
264:
265: (void) strcpy(cp, dirname);
266: (void) strcat(cp, "/");
267: (void) strcat(cp, file);
268: return (cp);
269: }
270:
271: check_space()
272: {
273: struct stat dsb;
274: register char *ddev;
275: int dfd, spacefree;
276: struct fs fs;
277:
278: if (stat(dirname, &dsb) < 0) {
279: perror(dirname);
280: exit(1);
281: }
282: ddev = find_dev(dsb.st_dev, S_IFBLK);
283: dfd = Open(ddev, 0);
284: Lseek(dfd, (long)(SBLOCK * DEV_BSIZE), 0);
285: Read(dfd, (char *)&fs, sizeof fs);
286: close(dfd);
287: spacefree = fs.fs_cstotal.cs_nbfree * fs.fs_bsize / 1024;
288: if (read_number("minfree") > spacefree) {
289: fprintf(stderr,
290: "savecore: Dump omitted, not enough space on device\n");
291: return (0);
292: }
293: if (fs.fs_cstotal.cs_nbfree * fs.fs_frag + fs.fs_cstotal.cs_nffree <
294: fs.fs_dsize * fs.fs_minfree / 100)
295: fprintf(stderr,
296: "Dump performed, but free space threshold crossed\n");
297: return (1);
298: }
299:
300: read_number(fn)
301: char *fn;
302: {
303: char lin[80];
304: register FILE *fp;
305:
306: if ((fp = fopen(path(fn), "r")) == NULL)
307: return (0);
308: if (fgets(lin, 80, fp) == NULL) {
309: fclose(fp);
310: return (0);
311: }
312: fclose(fp);
313: return (atoi(lin));
314: }
315:
316: save_core()
317: {
318: register int n;
319: char buffer[32*NBPG];
320: register char *cp = buffer;
321: register int ifd, ofd, bounds;
322: register FILE *fp;
323:
324: bounds = read_number("bounds");
325: ifd = Open(system?system:"/vmunix", 0);
326: sprintf(cp, "vmunix.%d", bounds);
327: ofd = Create(path(cp), 0644);
328: while((n = Read(ifd, cp, BUFSIZ)) > 0)
329: Write(ofd, cp, n);
330: close(ifd);
331: close(ofd);
332: ifd = Open(ddname, 0);
333: Lseek(ifd, (off_t)(dumplo + ok(nl[X_DUMPSIZE].n_value)), 0);
334: Read(ifd, (char *)&dumpsize, sizeof (dumpsize));
335: sprintf(cp, "vmcore.%d", bounds);
336: ofd = Create(path(cp), 0644);
337: Lseek(ifd, (off_t)dumplo, 0);
338: printf("Saving %d bytes of image in vmcore.%d\n", NBPG*dumpsize,
339: bounds);
340: while (dumpsize > 0) {
341: n = Read(ifd, cp, (dumpsize > 32 ? 32 : dumpsize) * NBPG);
342: Write(ofd, cp, n);
343: dumpsize -= n/NBPG;
344: }
345: close(ifd);
346: close(ofd);
347: fp = fopen(path("bounds"), "w");
348: fprintf(fp, "%d\n", bounds+1);
349: fclose(fp);
350: }
351:
352: char *days[] = {
353: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
354: };
355:
356: char *months[] = {
357: "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
358: "Oct", "Nov", "Dec"
359: };
360:
361: log_entry()
362: {
363: FILE *fp;
364: struct tm *tm, *localtime();
365:
366: tm = localtime(&now);
367: fp = fopen("/usr/adm/shutdownlog", "a");
368: if (fp == 0)
369: return;
370: fseek(fp, 0L, 2);
371: fprintf(fp, "%02d:%02d %s %s %2d, %4d. Reboot", tm->tm_hour,
372: tm->tm_min, days[tm->tm_wday], months[tm->tm_mon],
373: tm->tm_mday, tm->tm_year + 1900);
374: if (panicstr)
375: fprintf(fp, " after panic: %s\n", panic_mesg);
376: else
377: putc('\n', fp);
378: fclose(fp);
379: }
380:
381: /*
382: * Versions of std routines that exit on error.
383: */
384:
385: Open(name, rw)
386: char *name;
387: int rw;
388: {
389: int fd;
390:
391: if ((fd = open(name, rw)) < 0) {
392: perror(name);
393: exit(1);
394: }
395: return fd;
396: }
397:
398: Read(fd, buff, size)
399: int fd, size;
400: char *buff;
401: {
402: int ret;
403:
404: if ((ret = read(fd, buff, size)) < 0) {
405: perror("read");
406: exit(1);
407: }
408: return ret;
409: }
410:
411: off_t
412: Lseek(fd, off, flag)
413: int fd, flag;
414: long off;
415: {
416: long ret;
417:
418: if ((ret = lseek(fd, off, flag)) == -1L) {
419: perror("lseek");
420: exit(1);
421: }
422: return ret;
423: }
424:
425: Create(file, mode)
426: char *file;
427: int mode;
428: {
429: register int fd;
430:
431: if ((fd = creat(file, mode)) < 0) {
432: perror(file);
433: exit(1);
434: }
435: return fd;
436: }
437:
438: Write(fd, buf, size)
439: int fd, size;
440: char *buf;
441: {
442:
443: if (write(fd, buf, size) < size) {
444: perror("write");
445: exit(1);
446: }
447: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.