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