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