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