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