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