1/*- 2 * Copyright (c) 1986, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1986, 1992, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)savecore.c 8.3 (Berkeley) 1/2/94"; 43#endif 44static const char rcsid[] =
| 1/*- 2 * Copyright (c) 1986, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1986, 1992, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)savecore.c 8.3 (Berkeley) 1/2/94"; 43#endif 44static const char rcsid[] =
|
45 "$FreeBSD: head/sbin/savecore/savecore.c 92086 2002-03-11 11:23:48Z des $";
| 45 "$FreeBSD: head/sbin/savecore/savecore.c 92806 2002-03-20 17:55:10Z obrien $";
|
46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/stat.h> 50#include <sys/mount.h> 51#include <sys/syslog.h> 52#include <sys/sysctl.h> 53 54#include <vm/vm.h> 55#include <vm/vm_param.h> 56#include <vm/pmap.h> 57 58#include <dirent.h> 59#include <fcntl.h> 60#include <nlist.h> 61#include <paths.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <unistd.h> 66 67extern FILE *zopen(const char *fname, const char *mode); 68 69#if defined(__i386__) || defined(__sparc64__) 70#define ok(number) ((number) - kernbase) 71#elif defined(__alpha__) 72#define ok(number) ALPHA_K0SEG_TO_PHYS(number) 73#else 74#error savecore has not been ported to this platform yet. 75#endif 76 77struct nlist current_nl[] = { /* Namelist for currently running system. */ 78#define X_DUMPLO 0 79 { "_dumplo" }, 80#define X_TIME 1 81 { "_time_second" }, 82#define X_DUMPSIZE 2 83 { "_dumpsize" }, 84#define X_VERSION 3 85 { "_version" }, 86#define X_PANICSTR 4 87 { "_panicstr" }, 88#define X_DUMPMAG 5 89 { "_dumpmag" }, 90#define X_KERNBASE 6 91 { "_kernbase" }, 92 { "" }, 93}; 94int cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; 95int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; 96 97struct nlist dump_nl[] = { /* Name list for dumped system. */ 98 { "_dumplo" }, /* Entries MUST be the same as */ 99 { "_time_second" }, /* those in current_nl[]. */ 100 { "_dumpsize" }, 101 { "_version" }, 102 { "_panicstr" }, 103 { "_dumpmag" }, 104 { "_kernbase" }, 105 { "" }, 106}; 107 108/* Types match kernel declarations. */ 109u_long dumpmag; /* magic number in dump */ 110 111/* Based on kernel variables, but with more convenient types. */ 112off_t dumplo; /* where dump starts on dumpdev */ 113off_t dumpsize; /* amount of memory dumped */ 114 115char *kernel; /* user-specified kernel */ 116char *savedir; /* directory to save dumps in */ 117char ddname[MAXPATHLEN]; /* name of dump device */ 118dev_t dumpdev; /* dump device */ 119int dumpfd; /* read/write descriptor on char dev */ 120time_t now; /* current date */ 121char panic_mesg[1024]; /* panic message */ 122int panicstr; /* flag: dump was caused by panic */ 123char vers[1024]; /* version of kernel that crashed */ 124 125#if defined(__i386__) || defined(__sparc64__) 126u_long kernbase; /* offset of kvm to core file */ 127#endif 128 129int clear, compress, force, verbose; /* flags */ 130int keep; /* keep dump on device */ 131 132void check_kmem __P((void)); 133int check_space __P((void)); 134void clear_dump __P((void)); 135void DumpRead __P((int fd, void *bp, int size, off_t off, int flag)); 136void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag)); 137int dump_exists __P((void)); 138void find_dev __P((dev_t)); 139int get_crashtime __P((void)); 140void get_dumpsize __P((void)); 141void kmem_setup __P((void)); 142void Lseek __P((int, off_t, int)); 143int Open __P((const char *, int rw)); 144int Read __P((int, void *, int)); 145void save_core __P((void)); 146void usage __P((void)); 147void Write __P((int, void *, int)); 148 149int 150main(argc, argv) 151 int argc; 152 char *argv[]; 153{ 154 int ch; 155 156 openlog("savecore", LOG_PERROR, LOG_DAEMON); 157 158 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 159 switch(ch) { 160 case 'c': 161 clear = 1; 162 break; 163 case 'd': /* Not documented. */ 164 case 'v': 165 verbose = 1; 166 break; 167 case 'f': 168 force = 1; 169 break; 170 case 'k': 171 keep = 1; 172 break; 173 case 'N': 174 kernel = optarg; 175 break; 176 case 'z': 177 compress = 1; 178 break; 179 case '?': 180 default: 181 usage(); 182 } 183 argc -= optind; 184 argv += optind; 185 186 if (!clear) { 187 if (argc != 1 && argc != 2) 188 usage(); 189 savedir = argv[0]; 190 } 191 if (argc == 2) 192 kernel = argv[1]; 193 194 (void)time(&now); 195 kmem_setup(); 196 197 if (clear) { 198 clear_dump(); 199 exit(0); 200 } 201 202 if (!dump_exists() && !force) 203 exit(1); 204 205 check_kmem(); 206 207 if (panicstr) 208 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 209 else 210 syslog(LOG_ALERT, "reboot"); 211 212 get_dumpsize(); 213 214 if ((!get_crashtime() || !check_space()) && !force) 215 exit(1); 216 217 save_core(); 218 219 if (!keep) 220 clear_dump(); 221 222 exit(0); 223} 224 225void 226kmem_setup() 227{ 228 int kmem, i; 229 const char *dump_sys; 230 size_t len; 231 long kdumplo; /* block number where dump starts on dumpdev */ 232 char *p; 233 234 /* 235 * Some names we need for the currently running system, others for 236 * the system that was running when the dump was made. The values 237 * obtained from the current system are used to look for things in 238 * /dev/kmem that cannot be found in the dump_sys namelist, but are 239 * presumed to be the same (since the disk partitions are probably 240 * the same!) 241 */ 242 if ((nlist(getbootfile(), current_nl)) == -1) 243 syslog(LOG_ERR, "%s: nlist: %m", getbootfile()); 244 for (i = 0; cursyms[i] != -1; i++) 245 if (current_nl[cursyms[i]].n_value == 0) { 246 syslog(LOG_ERR, "%s: %s not in namelist", 247 getbootfile(), current_nl[cursyms[i]].n_name); 248 exit(1); 249 } 250 251 dump_sys = kernel ? kernel : getbootfile(); 252 if ((nlist(dump_sys, dump_nl)) == -1) 253 syslog(LOG_ERR, "%s: nlist: %m", dump_sys); 254 for (i = 0; dumpsyms[i] != -1; i++) 255 if (dump_nl[dumpsyms[i]].n_value == 0) { 256 syslog(LOG_ERR, "%s: %s not in namelist", 257 dump_sys, dump_nl[dumpsyms[i]].n_name); 258 exit(1); 259 } 260 261#if defined(__i386__) || defined(__sparc64__) 262 if (dump_nl[X_KERNBASE].n_value != 0) 263 kernbase = dump_nl[X_KERNBASE].n_value; 264 else 265 kernbase = KERNBASE; 266#endif 267 268 len = sizeof dumpdev; 269 if (sysctlbyname("kern.dumpdev", &dumpdev, &len, NULL, 0) == -1) { 270 syslog(LOG_ERR, "sysctl: kern.dumpdev: %m"); 271 exit(1); 272 } 273 if (dumpdev == NODEV) { 274 syslog(LOG_WARNING, "no core dump (no dumpdev)"); 275 exit(1); 276 } 277 278 kmem = Open(_PATH_KMEM, O_RDONLY); 279 Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, SEEK_SET); 280 (void)Read(kmem, &kdumplo, sizeof(kdumplo)); 281 dumplo = (off_t)kdumplo * DEV_BSIZE; 282 if (verbose) 283 (void)printf("dumplo = %lld (%ld * %d)\n", 284 (long long)dumplo, kdumplo, DEV_BSIZE); 285 Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, SEEK_SET); 286 (void)Read(kmem, &dumpmag, sizeof(dumpmag)); 287 find_dev(dumpdev); 288 dumpfd = Open(ddname, O_RDWR); 289 if (kernel) 290 return; 291 292 Lseek(kmem, (off_t)current_nl[X_VERSION].n_value, SEEK_SET); 293 Read(kmem, vers, sizeof(vers)); 294 vers[sizeof(vers) - 1] = '\0'; 295 p = strchr(vers, '\n'); 296 if (p) 297 p[1] = '\0'; 298 299 /* Don't fclose(fp), we use kmem later. */ 300} 301 302void 303check_kmem() 304{ 305 char core_vers[1024], *p; 306 307 DumpRead(dumpfd, core_vers, sizeof(core_vers), 308 dumplo + ok(dump_nl[X_VERSION].n_value), SEEK_SET); 309 core_vers[sizeof(core_vers) - 1] = '\0'; 310 p = strchr(core_vers, '\n'); 311 if (p) 312 p[1] = '\0'; 313 if (strcmp(vers, core_vers) && kernel == 0) 314 syslog(LOG_WARNING, 315 "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n", 316 getbootfile(), vers, core_vers); 317 DumpRead(dumpfd, &panicstr, sizeof(panicstr), 318 dumplo + ok(dump_nl[X_PANICSTR].n_value), SEEK_SET); 319 if (panicstr) { 320 DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg), 321 dumplo + ok(panicstr), SEEK_SET); 322 } 323} 324 325/* 326 * Clear the magic number in the dump header. 327 */ 328void 329clear_dump() 330{ 331 u_long newdumpmag; 332 333 newdumpmag = 0; 334 DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag), 335 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET); 336 close(dumpfd); 337} 338 339/* 340 * Check if a dump exists by looking for a magic number in the dump 341 * header. 342 */ 343int 344dump_exists() 345{ 346 u_long newdumpmag; 347 348 DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag), 349 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET); 350 if (newdumpmag != dumpmag) { 351 if (verbose) 352 syslog(LOG_WARNING, "magic number mismatch (%x != %x)", 353 newdumpmag, dumpmag); 354 syslog(LOG_WARNING, "no core dump"); 355 return (0); 356 } 357 return (1); 358} 359 360char buf[1024 * 1024]; 361#define BLOCKSIZE (1<<12) 362#define BLOCKMASK (~(BLOCKSIZE-1)) 363 364/* 365 * Save the core dump. 366 */ 367void 368save_core() 369{
| 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/stat.h> 50#include <sys/mount.h> 51#include <sys/syslog.h> 52#include <sys/sysctl.h> 53 54#include <vm/vm.h> 55#include <vm/vm_param.h> 56#include <vm/pmap.h> 57 58#include <dirent.h> 59#include <fcntl.h> 60#include <nlist.h> 61#include <paths.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <unistd.h> 66 67extern FILE *zopen(const char *fname, const char *mode); 68 69#if defined(__i386__) || defined(__sparc64__) 70#define ok(number) ((number) - kernbase) 71#elif defined(__alpha__) 72#define ok(number) ALPHA_K0SEG_TO_PHYS(number) 73#else 74#error savecore has not been ported to this platform yet. 75#endif 76 77struct nlist current_nl[] = { /* Namelist for currently running system. */ 78#define X_DUMPLO 0 79 { "_dumplo" }, 80#define X_TIME 1 81 { "_time_second" }, 82#define X_DUMPSIZE 2 83 { "_dumpsize" }, 84#define X_VERSION 3 85 { "_version" }, 86#define X_PANICSTR 4 87 { "_panicstr" }, 88#define X_DUMPMAG 5 89 { "_dumpmag" }, 90#define X_KERNBASE 6 91 { "_kernbase" }, 92 { "" }, 93}; 94int cursyms[] = { X_DUMPLO, X_VERSION, X_DUMPMAG, -1 }; 95int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 }; 96 97struct nlist dump_nl[] = { /* Name list for dumped system. */ 98 { "_dumplo" }, /* Entries MUST be the same as */ 99 { "_time_second" }, /* those in current_nl[]. */ 100 { "_dumpsize" }, 101 { "_version" }, 102 { "_panicstr" }, 103 { "_dumpmag" }, 104 { "_kernbase" }, 105 { "" }, 106}; 107 108/* Types match kernel declarations. */ 109u_long dumpmag; /* magic number in dump */ 110 111/* Based on kernel variables, but with more convenient types. */ 112off_t dumplo; /* where dump starts on dumpdev */ 113off_t dumpsize; /* amount of memory dumped */ 114 115char *kernel; /* user-specified kernel */ 116char *savedir; /* directory to save dumps in */ 117char ddname[MAXPATHLEN]; /* name of dump device */ 118dev_t dumpdev; /* dump device */ 119int dumpfd; /* read/write descriptor on char dev */ 120time_t now; /* current date */ 121char panic_mesg[1024]; /* panic message */ 122int panicstr; /* flag: dump was caused by panic */ 123char vers[1024]; /* version of kernel that crashed */ 124 125#if defined(__i386__) || defined(__sparc64__) 126u_long kernbase; /* offset of kvm to core file */ 127#endif 128 129int clear, compress, force, verbose; /* flags */ 130int keep; /* keep dump on device */ 131 132void check_kmem __P((void)); 133int check_space __P((void)); 134void clear_dump __P((void)); 135void DumpRead __P((int fd, void *bp, int size, off_t off, int flag)); 136void DumpWrite __P((int fd, void *bp, int size, off_t off, int flag)); 137int dump_exists __P((void)); 138void find_dev __P((dev_t)); 139int get_crashtime __P((void)); 140void get_dumpsize __P((void)); 141void kmem_setup __P((void)); 142void Lseek __P((int, off_t, int)); 143int Open __P((const char *, int rw)); 144int Read __P((int, void *, int)); 145void save_core __P((void)); 146void usage __P((void)); 147void Write __P((int, void *, int)); 148 149int 150main(argc, argv) 151 int argc; 152 char *argv[]; 153{ 154 int ch; 155 156 openlog("savecore", LOG_PERROR, LOG_DAEMON); 157 158 while ((ch = getopt(argc, argv, "cdfkN:vz")) != -1) 159 switch(ch) { 160 case 'c': 161 clear = 1; 162 break; 163 case 'd': /* Not documented. */ 164 case 'v': 165 verbose = 1; 166 break; 167 case 'f': 168 force = 1; 169 break; 170 case 'k': 171 keep = 1; 172 break; 173 case 'N': 174 kernel = optarg; 175 break; 176 case 'z': 177 compress = 1; 178 break; 179 case '?': 180 default: 181 usage(); 182 } 183 argc -= optind; 184 argv += optind; 185 186 if (!clear) { 187 if (argc != 1 && argc != 2) 188 usage(); 189 savedir = argv[0]; 190 } 191 if (argc == 2) 192 kernel = argv[1]; 193 194 (void)time(&now); 195 kmem_setup(); 196 197 if (clear) { 198 clear_dump(); 199 exit(0); 200 } 201 202 if (!dump_exists() && !force) 203 exit(1); 204 205 check_kmem(); 206 207 if (panicstr) 208 syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 209 else 210 syslog(LOG_ALERT, "reboot"); 211 212 get_dumpsize(); 213 214 if ((!get_crashtime() || !check_space()) && !force) 215 exit(1); 216 217 save_core(); 218 219 if (!keep) 220 clear_dump(); 221 222 exit(0); 223} 224 225void 226kmem_setup() 227{ 228 int kmem, i; 229 const char *dump_sys; 230 size_t len; 231 long kdumplo; /* block number where dump starts on dumpdev */ 232 char *p; 233 234 /* 235 * Some names we need for the currently running system, others for 236 * the system that was running when the dump was made. The values 237 * obtained from the current system are used to look for things in 238 * /dev/kmem that cannot be found in the dump_sys namelist, but are 239 * presumed to be the same (since the disk partitions are probably 240 * the same!) 241 */ 242 if ((nlist(getbootfile(), current_nl)) == -1) 243 syslog(LOG_ERR, "%s: nlist: %m", getbootfile()); 244 for (i = 0; cursyms[i] != -1; i++) 245 if (current_nl[cursyms[i]].n_value == 0) { 246 syslog(LOG_ERR, "%s: %s not in namelist", 247 getbootfile(), current_nl[cursyms[i]].n_name); 248 exit(1); 249 } 250 251 dump_sys = kernel ? kernel : getbootfile(); 252 if ((nlist(dump_sys, dump_nl)) == -1) 253 syslog(LOG_ERR, "%s: nlist: %m", dump_sys); 254 for (i = 0; dumpsyms[i] != -1; i++) 255 if (dump_nl[dumpsyms[i]].n_value == 0) { 256 syslog(LOG_ERR, "%s: %s not in namelist", 257 dump_sys, dump_nl[dumpsyms[i]].n_name); 258 exit(1); 259 } 260 261#if defined(__i386__) || defined(__sparc64__) 262 if (dump_nl[X_KERNBASE].n_value != 0) 263 kernbase = dump_nl[X_KERNBASE].n_value; 264 else 265 kernbase = KERNBASE; 266#endif 267 268 len = sizeof dumpdev; 269 if (sysctlbyname("kern.dumpdev", &dumpdev, &len, NULL, 0) == -1) { 270 syslog(LOG_ERR, "sysctl: kern.dumpdev: %m"); 271 exit(1); 272 } 273 if (dumpdev == NODEV) { 274 syslog(LOG_WARNING, "no core dump (no dumpdev)"); 275 exit(1); 276 } 277 278 kmem = Open(_PATH_KMEM, O_RDONLY); 279 Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, SEEK_SET); 280 (void)Read(kmem, &kdumplo, sizeof(kdumplo)); 281 dumplo = (off_t)kdumplo * DEV_BSIZE; 282 if (verbose) 283 (void)printf("dumplo = %lld (%ld * %d)\n", 284 (long long)dumplo, kdumplo, DEV_BSIZE); 285 Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, SEEK_SET); 286 (void)Read(kmem, &dumpmag, sizeof(dumpmag)); 287 find_dev(dumpdev); 288 dumpfd = Open(ddname, O_RDWR); 289 if (kernel) 290 return; 291 292 Lseek(kmem, (off_t)current_nl[X_VERSION].n_value, SEEK_SET); 293 Read(kmem, vers, sizeof(vers)); 294 vers[sizeof(vers) - 1] = '\0'; 295 p = strchr(vers, '\n'); 296 if (p) 297 p[1] = '\0'; 298 299 /* Don't fclose(fp), we use kmem later. */ 300} 301 302void 303check_kmem() 304{ 305 char core_vers[1024], *p; 306 307 DumpRead(dumpfd, core_vers, sizeof(core_vers), 308 dumplo + ok(dump_nl[X_VERSION].n_value), SEEK_SET); 309 core_vers[sizeof(core_vers) - 1] = '\0'; 310 p = strchr(core_vers, '\n'); 311 if (p) 312 p[1] = '\0'; 313 if (strcmp(vers, core_vers) && kernel == 0) 314 syslog(LOG_WARNING, 315 "warning: %s version mismatch:\n\t\"%s\"\nand\t\"%s\"\n", 316 getbootfile(), vers, core_vers); 317 DumpRead(dumpfd, &panicstr, sizeof(panicstr), 318 dumplo + ok(dump_nl[X_PANICSTR].n_value), SEEK_SET); 319 if (panicstr) { 320 DumpRead(dumpfd, panic_mesg, sizeof(panic_mesg), 321 dumplo + ok(panicstr), SEEK_SET); 322 } 323} 324 325/* 326 * Clear the magic number in the dump header. 327 */ 328void 329clear_dump() 330{ 331 u_long newdumpmag; 332 333 newdumpmag = 0; 334 DumpWrite(dumpfd, &newdumpmag, sizeof(newdumpmag), 335 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET); 336 close(dumpfd); 337} 338 339/* 340 * Check if a dump exists by looking for a magic number in the dump 341 * header. 342 */ 343int 344dump_exists() 345{ 346 u_long newdumpmag; 347 348 DumpRead(dumpfd, &newdumpmag, sizeof(newdumpmag), 349 dumplo + ok(dump_nl[X_DUMPMAG].n_value), SEEK_SET); 350 if (newdumpmag != dumpmag) { 351 if (verbose) 352 syslog(LOG_WARNING, "magic number mismatch (%x != %x)", 353 newdumpmag, dumpmag); 354 syslog(LOG_WARNING, "no core dump"); 355 return (0); 356 } 357 return (1); 358} 359 360char buf[1024 * 1024]; 361#define BLOCKSIZE (1<<12) 362#define BLOCKMASK (~(BLOCKSIZE-1)) 363 364/* 365 * Save the core dump. 366 */ 367void 368save_core() 369{
|
370 register FILE *fp; 371 register int bounds, ifd, nr, nw;
| 370 FILE *fp; 371 int bounds, ifd, nr, nw;
|
372 int hs, he; /* start and end of hole */ 373 char path[MAXPATHLEN]; 374 mode_t oumask; 375 376 /* 377 * Get the current number and update the bounds file. Do the update 378 * now, because may fail later and don't want to overwrite anything. 379 */ 380 (void)snprintf(path, sizeof(path), "%s/bounds", savedir); 381 if ((fp = fopen(path, "r")) == NULL) 382 goto err1; 383 if (fgets(buf, sizeof(buf), fp) == NULL) { 384 if (ferror(fp)) 385err1: syslog(LOG_WARNING, "%s: %m", path); 386 bounds = 0; 387 } else 388 bounds = atoi(buf); 389 if (fp != NULL) 390 (void)fclose(fp); 391 if ((fp = fopen(path, "w")) == NULL) 392 syslog(LOG_ERR, "%s: %m", path); 393 else { 394 (void)fprintf(fp, "%d\n", bounds + 1); 395 (void)fclose(fp); 396 } 397 398 /* Create the core file. */ 399 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 400 (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s", 401 savedir, bounds, compress ? ".gz" : ""); 402 if (compress) 403 fp = zopen(path, "w"); 404 else 405 fp = fopen(path, "w"); 406 if (fp == NULL) { 407 syslog(LOG_ERR, "%s: %m", path); 408 exit(1); 409 } 410 (void)umask(oumask); 411 412 /* Seek to the start of the core. */ 413 Lseek(dumpfd, dumplo, SEEK_SET); 414 415 /* Copy the core file. */ 416 syslog(LOG_NOTICE, "writing %score to %s", 417 compress ? "compressed " : "", path); 418 for (; dumpsize > 0; dumpsize -= nr) { 419 (void)printf("%6dK\r", dumpsize / 1024); 420 (void)fflush(stdout); 421 nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf))); 422 if (nr <= 0) { 423 if (nr == 0) 424 syslog(LOG_WARNING, 425 "WARNING: EOF on dump device"); 426 else 427 syslog(LOG_ERR, "%s: %m", ddname); 428 goto err2; 429 } 430 431 if (compress) { 432 nw = fwrite(buf, 1, nr, fp); 433 } else { 434 for (nw = 0; nw < nr; nw = he) { 435 /* find a contiguous block of zeroes */ 436 for (hs = nw; hs < nr; hs += BLOCKSIZE) { 437 for (he = hs; he < nr && buf[he] == 0; ++he) 438 /* nothing */ ; 439 /* is the hole long enough to matter? */ 440 if (he >= hs + BLOCKSIZE) 441 break; 442 } 443 444 /* back down to a block boundary */ 445 he &= BLOCKMASK; 446 447 /* 448 * 1) Don't go beyond the end of the buffer. 449 * 2) If the end of the buffer is less than 450 * BLOCKSIZE bytes away, we're at the end 451 * of the file, so just grab what's left. 452 */ 453 if (hs + BLOCKSIZE > nr) 454 hs = he = nr; 455 456 /* 457 * At this point, we have a partial ordering: 458 * nw <= hs <= he <= nr 459 * If hs > nw, buf[nw..hs] contains non-zero data. 460 * If he > hs, buf[hs..he] is all zeroes. 461 */ 462 if (hs > nw) 463 if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 464 break; 465 if (he > hs) 466 if (fseek(fp, he - hs, SEEK_CUR) == -1) 467 break; 468 } 469 } 470 if (nw != nr) { 471 syslog(LOG_ERR, "%s: %m", path); 472err2: syslog(LOG_WARNING, 473 "WARNING: vmcore may be incomplete"); 474 (void)printf("\n"); 475 exit(1); 476 } 477 } 478 479 (void)fclose(fp); 480 481 /* Copy the kernel. */ 482 ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY); 483 (void)snprintf(path, sizeof(path), "%s/kernel.%d%s", 484 savedir, bounds, compress ? ".gz" : ""); 485 if (compress) 486 fp = zopen(path, "w"); 487 else 488 fp = fopen(path, "w"); 489 if (fp == NULL) { 490 syslog(LOG_ERR, "%s: %m", path); 491 exit(1); 492 } 493 syslog(LOG_NOTICE, "writing %skernel to %s", 494 compress ? "compressed " : "", path); 495 while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 496 nw = fwrite(buf, 1, nr, fp); 497 if (nw != nr) { 498 syslog(LOG_ERR, "%s: %m", path); 499 syslog(LOG_WARNING, 500 "WARNING: kernel may be incomplete"); 501 exit(1); 502 } 503 } 504 if (nr < 0) { 505 syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile()); 506 syslog(LOG_WARNING, 507 "WARNING: kernel may be incomplete"); 508 exit(1); 509 } 510 (void)fclose(fp); 511 close(ifd); 512} 513 514/* 515 * Verify that the specified device node exists and matches the 516 * specified device. 517 */ 518int 519verify_dev(name, dev) 520 char *name;
| 372 int hs, he; /* start and end of hole */ 373 char path[MAXPATHLEN]; 374 mode_t oumask; 375 376 /* 377 * Get the current number and update the bounds file. Do the update 378 * now, because may fail later and don't want to overwrite anything. 379 */ 380 (void)snprintf(path, sizeof(path), "%s/bounds", savedir); 381 if ((fp = fopen(path, "r")) == NULL) 382 goto err1; 383 if (fgets(buf, sizeof(buf), fp) == NULL) { 384 if (ferror(fp)) 385err1: syslog(LOG_WARNING, "%s: %m", path); 386 bounds = 0; 387 } else 388 bounds = atoi(buf); 389 if (fp != NULL) 390 (void)fclose(fp); 391 if ((fp = fopen(path, "w")) == NULL) 392 syslog(LOG_ERR, "%s: %m", path); 393 else { 394 (void)fprintf(fp, "%d\n", bounds + 1); 395 (void)fclose(fp); 396 } 397 398 /* Create the core file. */ 399 oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ 400 (void)snprintf(path, sizeof(path), "%s/vmcore.%d%s", 401 savedir, bounds, compress ? ".gz" : ""); 402 if (compress) 403 fp = zopen(path, "w"); 404 else 405 fp = fopen(path, "w"); 406 if (fp == NULL) { 407 syslog(LOG_ERR, "%s: %m", path); 408 exit(1); 409 } 410 (void)umask(oumask); 411 412 /* Seek to the start of the core. */ 413 Lseek(dumpfd, dumplo, SEEK_SET); 414 415 /* Copy the core file. */ 416 syslog(LOG_NOTICE, "writing %score to %s", 417 compress ? "compressed " : "", path); 418 for (; dumpsize > 0; dumpsize -= nr) { 419 (void)printf("%6dK\r", dumpsize / 1024); 420 (void)fflush(stdout); 421 nr = read(dumpfd, buf, MIN(dumpsize, sizeof(buf))); 422 if (nr <= 0) { 423 if (nr == 0) 424 syslog(LOG_WARNING, 425 "WARNING: EOF on dump device"); 426 else 427 syslog(LOG_ERR, "%s: %m", ddname); 428 goto err2; 429 } 430 431 if (compress) { 432 nw = fwrite(buf, 1, nr, fp); 433 } else { 434 for (nw = 0; nw < nr; nw = he) { 435 /* find a contiguous block of zeroes */ 436 for (hs = nw; hs < nr; hs += BLOCKSIZE) { 437 for (he = hs; he < nr && buf[he] == 0; ++he) 438 /* nothing */ ; 439 /* is the hole long enough to matter? */ 440 if (he >= hs + BLOCKSIZE) 441 break; 442 } 443 444 /* back down to a block boundary */ 445 he &= BLOCKMASK; 446 447 /* 448 * 1) Don't go beyond the end of the buffer. 449 * 2) If the end of the buffer is less than 450 * BLOCKSIZE bytes away, we're at the end 451 * of the file, so just grab what's left. 452 */ 453 if (hs + BLOCKSIZE > nr) 454 hs = he = nr; 455 456 /* 457 * At this point, we have a partial ordering: 458 * nw <= hs <= he <= nr 459 * If hs > nw, buf[nw..hs] contains non-zero data. 460 * If he > hs, buf[hs..he] is all zeroes. 461 */ 462 if (hs > nw) 463 if (fwrite(buf + nw, hs - nw, 1, fp) != 1) 464 break; 465 if (he > hs) 466 if (fseek(fp, he - hs, SEEK_CUR) == -1) 467 break; 468 } 469 } 470 if (nw != nr) { 471 syslog(LOG_ERR, "%s: %m", path); 472err2: syslog(LOG_WARNING, 473 "WARNING: vmcore may be incomplete"); 474 (void)printf("\n"); 475 exit(1); 476 } 477 } 478 479 (void)fclose(fp); 480 481 /* Copy the kernel. */ 482 ifd = Open(kernel ? kernel : getbootfile(), O_RDONLY); 483 (void)snprintf(path, sizeof(path), "%s/kernel.%d%s", 484 savedir, bounds, compress ? ".gz" : ""); 485 if (compress) 486 fp = zopen(path, "w"); 487 else 488 fp = fopen(path, "w"); 489 if (fp == NULL) { 490 syslog(LOG_ERR, "%s: %m", path); 491 exit(1); 492 } 493 syslog(LOG_NOTICE, "writing %skernel to %s", 494 compress ? "compressed " : "", path); 495 while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 496 nw = fwrite(buf, 1, nr, fp); 497 if (nw != nr) { 498 syslog(LOG_ERR, "%s: %m", path); 499 syslog(LOG_WARNING, 500 "WARNING: kernel may be incomplete"); 501 exit(1); 502 } 503 } 504 if (nr < 0) { 505 syslog(LOG_ERR, "%s: %m", kernel ? kernel : getbootfile()); 506 syslog(LOG_WARNING, 507 "WARNING: kernel may be incomplete"); 508 exit(1); 509 } 510 (void)fclose(fp); 511 close(ifd); 512} 513 514/* 515 * Verify that the specified device node exists and matches the 516 * specified device. 517 */ 518int 519verify_dev(name, dev) 520 char *name;
|
521 register dev_t dev;
| 521 dev_t dev;
|
522{ 523 struct stat sb; 524 525 if (lstat(name, &sb) == -1) 526 return (-1); 527 if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev) 528 return (-1); 529 return (0); 530} 531 532/* 533 * Find the dump device. 534 * 535 * 1) try devname(3); see if it returns something sensible 536 * 2) scan /dev for the desired node 537 * 3) as a last resort, try to create the node we need 538 */ 539void 540find_dev(dev)
| 522{ 523 struct stat sb; 524 525 if (lstat(name, &sb) == -1) 526 return (-1); 527 if (!S_ISCHR(sb.st_mode) || sb.st_rdev != dev) 528 return (-1); 529 return (0); 530} 531 532/* 533 * Find the dump device. 534 * 535 * 1) try devname(3); see if it returns something sensible 536 * 2) scan /dev for the desired node 537 * 3) as a last resort, try to create the node we need 538 */ 539void 540find_dev(dev)
|
541 register dev_t dev;
| 541 dev_t dev;
|
542{ 543 struct dirent *ent; 544 char *dn, *dnp; 545 DIR *d; 546 547 strcpy(ddname, _PATH_DEV); 548 dnp = ddname + sizeof _PATH_DEV - 1; 549 if ((dn = devname(dev, S_IFCHR)) != NULL) { 550 strcpy(dnp, dn); 551 if (verify_dev(ddname, dev) == 0) 552 return; 553 } 554 if ((d = opendir(_PATH_DEV)) != NULL) { 555 while ((ent = readdir(d))) { 556 strcpy(dnp, ent->d_name); 557 if (verify_dev(ddname, dev) == 0) { 558 closedir(d); 559 return; 560 } 561 } 562 closedir(d); 563 } 564 strcpy(dnp, "dump"); 565 if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0) 566 return; 567 syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev)); 568 exit(1); 569} 570 571/* 572 * Extract the date and time of the crash from the dump header, and 573 * make sure it looks sane (within one week of current date and time). 574 */ 575int 576get_crashtime() 577{ 578 time_t dumptime; /* Time the dump was taken. */ 579 580 DumpRead(dumpfd, &dumptime, sizeof(dumptime), 581 dumplo + ok(dump_nl[X_TIME].n_value), SEEK_SET); 582 if (dumptime == 0) { 583 if (verbose) 584 syslog(LOG_ERR, "dump time is zero"); 585 return (0); 586 } 587 (void)printf("savecore: system went down at %s", ctime(&dumptime)); 588#define LEEWAY (7 * 86400) 589 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 590 (void)printf("dump time is unreasonable\n"); 591 return (0); 592 } 593 return (1); 594} 595 596/* 597 * Extract the size of the dump from the dump header. 598 */ 599void 600get_dumpsize() 601{ 602 int kdumpsize; 603 604 /* Read the dump size. */ 605 DumpRead(dumpfd, &kdumpsize, sizeof(kdumpsize), 606 dumplo + ok(dump_nl[X_DUMPSIZE].n_value), SEEK_SET); 607 dumpsize = (off_t)kdumpsize * getpagesize(); 608} 609 610/* 611 * Check that sufficient space is available on the disk that holds the 612 * save directory. 613 */ 614int 615check_space() 616{
| 542{ 543 struct dirent *ent; 544 char *dn, *dnp; 545 DIR *d; 546 547 strcpy(ddname, _PATH_DEV); 548 dnp = ddname + sizeof _PATH_DEV - 1; 549 if ((dn = devname(dev, S_IFCHR)) != NULL) { 550 strcpy(dnp, dn); 551 if (verify_dev(ddname, dev) == 0) 552 return; 553 } 554 if ((d = opendir(_PATH_DEV)) != NULL) { 555 while ((ent = readdir(d))) { 556 strcpy(dnp, ent->d_name); 557 if (verify_dev(ddname, dev) == 0) { 558 closedir(d); 559 return; 560 } 561 } 562 closedir(d); 563 } 564 strcpy(dnp, "dump"); 565 if (mknod(ddname, S_IFCHR|S_IRUSR|S_IWUSR, dev) == 0) 566 return; 567 syslog(LOG_ERR, "can't find device %d/%#x", major(dev), minor(dev)); 568 exit(1); 569} 570 571/* 572 * Extract the date and time of the crash from the dump header, and 573 * make sure it looks sane (within one week of current date and time). 574 */ 575int 576get_crashtime() 577{ 578 time_t dumptime; /* Time the dump was taken. */ 579 580 DumpRead(dumpfd, &dumptime, sizeof(dumptime), 581 dumplo + ok(dump_nl[X_TIME].n_value), SEEK_SET); 582 if (dumptime == 0) { 583 if (verbose) 584 syslog(LOG_ERR, "dump time is zero"); 585 return (0); 586 } 587 (void)printf("savecore: system went down at %s", ctime(&dumptime)); 588#define LEEWAY (7 * 86400) 589 if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 590 (void)printf("dump time is unreasonable\n"); 591 return (0); 592 } 593 return (1); 594} 595 596/* 597 * Extract the size of the dump from the dump header. 598 */ 599void 600get_dumpsize() 601{ 602 int kdumpsize; 603 604 /* Read the dump size. */ 605 DumpRead(dumpfd, &kdumpsize, sizeof(kdumpsize), 606 dumplo + ok(dump_nl[X_DUMPSIZE].n_value), SEEK_SET); 607 dumpsize = (off_t)kdumpsize * getpagesize(); 608} 609 610/* 611 * Check that sufficient space is available on the disk that holds the 612 * save directory. 613 */ 614int 615check_space() 616{
|
617 register FILE *fp;
| 617 FILE *fp;
|
618 const char *tkernel; 619 off_t minfree, spacefree, totfree, kernelsize, needed; 620 struct stat st; 621 struct statfs fsbuf; 622 char buf[100], path[MAXPATHLEN]; 623 624 tkernel = kernel ? kernel : getbootfile(); 625 if (stat(tkernel, &st) < 0) { 626 syslog(LOG_ERR, "%s: %m", tkernel); 627 exit(1); 628 } 629 kernelsize = st.st_blocks * S_BLKSIZE; 630 631 if (statfs(savedir, &fsbuf) < 0) { 632 syslog(LOG_ERR, "%s: %m", savedir); 633 exit(1); 634 } 635 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 636 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 637 638 (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 639 if ((fp = fopen(path, "r")) == NULL) 640 minfree = 0; 641 else { 642 if (fgets(buf, sizeof(buf), fp) == NULL) 643 minfree = 0; 644 else 645 minfree = atoi(buf); 646 (void)fclose(fp); 647 } 648 649 needed = (dumpsize + kernelsize) / 1024; 650 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 651 syslog(LOG_WARNING, 652 "no dump, not enough free space on device (%lld available, need %lld)", 653 (long long)(minfree > 0 ? spacefree : totfree), 654 (long long)needed); 655 return (0); 656 } 657 if (spacefree - needed < 0) 658 syslog(LOG_WARNING, 659 "dump performed, but free space threshold crossed"); 660 return (1); 661} 662 663int 664Open(name, rw) 665 const char *name; 666 int rw; 667{ 668 int fd; 669 670 fd = open(name, rw, 0); 671 if (fd < 0) { 672 syslog(LOG_ERR, "%s: %m", name); 673 exit(1); 674 } 675 return (fd); 676} 677 678int 679Read(fd, bp, size) 680 int fd, size; 681 void *bp; 682{ 683 int nr; 684 685 nr = read(fd, bp, size); 686 if (nr != size) { 687 syslog(LOG_ERR, "read: %m"); 688 exit(1); 689 } 690 return (nr); 691} 692 693void 694Lseek(fd, off, flag) 695 int fd, flag; 696 off_t off; 697{ 698 off_t ret; 699 700 ret = lseek(fd, off, flag); 701 if (ret == -1) { 702 syslog(LOG_ERR, "lseek: %m"); 703 exit(1); 704 } 705} 706 707/* 708 * DumpWrite and DumpRead block io requests to the * dump device. 709 */ 710#define DUMPBUFSIZE 8192 711void 712DumpWrite(fd, bp, size, off, flag) 713 int fd, size, flag; 714 void *bp; 715 off_t off; 716{ 717 unsigned char buf[DUMPBUFSIZE], *p, *q; 718 off_t pos; 719 int i, j; 720 721 if (flag != SEEK_SET) { 722 syslog(LOG_ERR, "lseek: not SEEK_SET"); 723 exit(2); 724 } 725 q = bp; 726 while (size) { 727 pos = off & ~(DUMPBUFSIZE - 1); 728 Lseek(fd, pos, flag); 729 (void)Read(fd, buf, sizeof(buf)); 730 j = off & (DUMPBUFSIZE - 1); 731 p = buf + j; 732 i = size; 733 if (i > DUMPBUFSIZE - j) 734 i = DUMPBUFSIZE - j; 735 memcpy(p, q, i); 736 Lseek(fd, pos, flag); 737 (void)Write(fd, buf, sizeof(buf)); 738 size -= i; 739 q += i; 740 off += i; 741 } 742} 743 744void 745DumpRead(fd, bp, size, off, flag) 746 int fd, size, flag; 747 void *bp; 748 off_t off; 749{ 750 unsigned char buf[DUMPBUFSIZE], *p, *q; 751 off_t pos; 752 int i, j; 753 754 if (flag != SEEK_SET) { 755 syslog(LOG_ERR, "lseek: not SEEK_SET"); 756 exit(2); 757 } 758 q = bp; 759 while (size) { 760 pos = off & ~(DUMPBUFSIZE - 1); 761 Lseek(fd, pos, flag); 762 (void)Read(fd, buf, sizeof(buf)); 763 j = off & (DUMPBUFSIZE - 1); 764 p = buf + j; 765 i = size; 766 if (i > DUMPBUFSIZE - j) 767 i = DUMPBUFSIZE - j; 768 memcpy(q, p, i); 769 size -= i; 770 q += i; 771 off += i; 772 } 773} 774 775void 776Write(fd, bp, size) 777 int fd, size; 778 void *bp; 779{ 780 int n; 781 782 n = write(fd, bp, size); 783 if (n < size) { 784 syslog(LOG_ERR, "write: %m"); 785 exit(1); 786 } 787} 788 789void 790usage() 791{ 792 (void)syslog(LOG_ERR, "usage: savecore [-cfkvz] [-N system] directory"); 793 exit(1); 794}
| 618 const char *tkernel; 619 off_t minfree, spacefree, totfree, kernelsize, needed; 620 struct stat st; 621 struct statfs fsbuf; 622 char buf[100], path[MAXPATHLEN]; 623 624 tkernel = kernel ? kernel : getbootfile(); 625 if (stat(tkernel, &st) < 0) { 626 syslog(LOG_ERR, "%s: %m", tkernel); 627 exit(1); 628 } 629 kernelsize = st.st_blocks * S_BLKSIZE; 630 631 if (statfs(savedir, &fsbuf) < 0) { 632 syslog(LOG_ERR, "%s: %m", savedir); 633 exit(1); 634 } 635 spacefree = ((off_t) fsbuf.f_bavail * fsbuf.f_bsize) / 1024; 636 totfree = ((off_t) fsbuf.f_bfree * fsbuf.f_bsize) / 1024; 637 638 (void)snprintf(path, sizeof(path), "%s/minfree", savedir); 639 if ((fp = fopen(path, "r")) == NULL) 640 minfree = 0; 641 else { 642 if (fgets(buf, sizeof(buf), fp) == NULL) 643 minfree = 0; 644 else 645 minfree = atoi(buf); 646 (void)fclose(fp); 647 } 648 649 needed = (dumpsize + kernelsize) / 1024; 650 if (((minfree > 0) ? spacefree : totfree) - needed < minfree) { 651 syslog(LOG_WARNING, 652 "no dump, not enough free space on device (%lld available, need %lld)", 653 (long long)(minfree > 0 ? spacefree : totfree), 654 (long long)needed); 655 return (0); 656 } 657 if (spacefree - needed < 0) 658 syslog(LOG_WARNING, 659 "dump performed, but free space threshold crossed"); 660 return (1); 661} 662 663int 664Open(name, rw) 665 const char *name; 666 int rw; 667{ 668 int fd; 669 670 fd = open(name, rw, 0); 671 if (fd < 0) { 672 syslog(LOG_ERR, "%s: %m", name); 673 exit(1); 674 } 675 return (fd); 676} 677 678int 679Read(fd, bp, size) 680 int fd, size; 681 void *bp; 682{ 683 int nr; 684 685 nr = read(fd, bp, size); 686 if (nr != size) { 687 syslog(LOG_ERR, "read: %m"); 688 exit(1); 689 } 690 return (nr); 691} 692 693void 694Lseek(fd, off, flag) 695 int fd, flag; 696 off_t off; 697{ 698 off_t ret; 699 700 ret = lseek(fd, off, flag); 701 if (ret == -1) { 702 syslog(LOG_ERR, "lseek: %m"); 703 exit(1); 704 } 705} 706 707/* 708 * DumpWrite and DumpRead block io requests to the * dump device. 709 */ 710#define DUMPBUFSIZE 8192 711void 712DumpWrite(fd, bp, size, off, flag) 713 int fd, size, flag; 714 void *bp; 715 off_t off; 716{ 717 unsigned char buf[DUMPBUFSIZE], *p, *q; 718 off_t pos; 719 int i, j; 720 721 if (flag != SEEK_SET) { 722 syslog(LOG_ERR, "lseek: not SEEK_SET"); 723 exit(2); 724 } 725 q = bp; 726 while (size) { 727 pos = off & ~(DUMPBUFSIZE - 1); 728 Lseek(fd, pos, flag); 729 (void)Read(fd, buf, sizeof(buf)); 730 j = off & (DUMPBUFSIZE - 1); 731 p = buf + j; 732 i = size; 733 if (i > DUMPBUFSIZE - j) 734 i = DUMPBUFSIZE - j; 735 memcpy(p, q, i); 736 Lseek(fd, pos, flag); 737 (void)Write(fd, buf, sizeof(buf)); 738 size -= i; 739 q += i; 740 off += i; 741 } 742} 743 744void 745DumpRead(fd, bp, size, off, flag) 746 int fd, size, flag; 747 void *bp; 748 off_t off; 749{ 750 unsigned char buf[DUMPBUFSIZE], *p, *q; 751 off_t pos; 752 int i, j; 753 754 if (flag != SEEK_SET) { 755 syslog(LOG_ERR, "lseek: not SEEK_SET"); 756 exit(2); 757 } 758 q = bp; 759 while (size) { 760 pos = off & ~(DUMPBUFSIZE - 1); 761 Lseek(fd, pos, flag); 762 (void)Read(fd, buf, sizeof(buf)); 763 j = off & (DUMPBUFSIZE - 1); 764 p = buf + j; 765 i = size; 766 if (i > DUMPBUFSIZE - j) 767 i = DUMPBUFSIZE - j; 768 memcpy(q, p, i); 769 size -= i; 770 q += i; 771 off += i; 772 } 773} 774 775void 776Write(fd, bp, size) 777 int fd, size; 778 void *bp; 779{ 780 int n; 781 782 n = write(fd, bp, size); 783 if (n < size) { 784 syslog(LOG_ERR, "write: %m"); 785 exit(1); 786 } 787} 788 789void 790usage() 791{ 792 (void)syslog(LOG_ERR, "usage: savecore [-cfkvz] [-N system] directory"); 793 exit(1); 794}
|