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