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