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