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