1 1.90 maxv /* $NetBSD: savecore.c,v 1.90 2020/04/03 19:09:43 maxv Exp $ */ 2 1.21 cgd 3 1.13 pk /*- 4 1.13 pk * Copyright (c) 1986, 1992, 1993 5 1.13 pk * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.61 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.32 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.74 lukem __COPYRIGHT("@(#) Copyright (c) 1986, 1992, 1993\ 35 1.74 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.21 cgd #if 0 40 1.34 lukem static char sccsid[] = "@(#)savecore.c 8.5 (Berkeley) 4/28/95"; 41 1.21 cgd #else 42 1.90 maxv __RCSID("$NetBSD: savecore.c,v 1.90 2020/04/03 19:09:43 maxv Exp $"); 43 1.21 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.76 ad #define _KSYMS_PRIVATE 47 1.76 ad 48 1.76 ad #include <stdbool.h> 49 1.76 ad 50 1.1 cgd #include <sys/param.h> 51 1.1 cgd #include <sys/mount.h> 52 1.51 simonb #include <sys/msgbuf.h> 53 1.13 pk #include <sys/syslog.h> 54 1.1 cgd #include <sys/time.h> 55 1.76 ad #include <sys/ksyms.h> 56 1.13 pk 57 1.1 cgd #include <dirent.h> 58 1.7 cgd #include <errno.h> 59 1.13 pk #include <fcntl.h> 60 1.1 cgd #include <nlist.h> 61 1.1 cgd #include <paths.h> 62 1.51 simonb #include <stddef.h> 63 1.7 cgd #include <stdio.h> 64 1.7 cgd #include <stdlib.h> 65 1.13 pk #include <string.h> 66 1.36 kleink #include <time.h> 67 1.13 pk #include <tzfile.h> 68 1.7 cgd #include <unistd.h> 69 1.52 wiz #include <util.h> 70 1.25 leo #include <limits.h> 71 1.83 christos #include <stdarg.h> 72 1.25 leo #include <kvm.h> 73 1.18 cgd 74 1.49 joda extern FILE *zopen(const char *fname, const char *mode); 75 1.1 cgd 76 1.87 mrg /* 77 1.89 mrg * Note that KREAD_LOGWARN and KREAD_ERR take a variable name, not 78 1.89 mrg * pointer to it, unlike KREAD() itself. 79 1.87 mrg */ 80 1.51 simonb #define KREAD(kd, addr, p)\ 81 1.25 leo (kvm_read(kd, addr, (char *)(p), sizeof(*(p))) != sizeof(*(p))) 82 1.89 mrg #define KREAD_ERR(kd, addr, p, err) \ 83 1.89 mrg do { \ 84 1.89 mrg if (KREAD(kd, addr, &(p)) != 0) { \ 85 1.89 mrg err; \ 86 1.89 mrg } \ 87 1.89 mrg } while (0) 88 1.87 mrg #define KREAD_LOGWARN(kd, addr, p, err) \ 89 1.87 mrg do { \ 90 1.87 mrg if (KREAD(kd, addr, &(p)) != 0) { \ 91 1.87 mrg syslog(LOG_WARNING, "%s:%d: kvm_read " #p ": %s", \ 92 1.87 mrg __func__, __LINE__, kvm_geterr(kd)); \ 93 1.87 mrg err; \ 94 1.87 mrg } \ 95 1.87 mrg } while (0) 96 1.1 cgd 97 1.82 joerg static struct nlist current_nl[] = { /* Namelist for currently running system. */ 98 1.51 simonb #define X_DUMPDEV 0 99 1.69 christos { .n_name = "_dumpdev" }, 100 1.51 simonb #define X_DUMPLO 1 101 1.69 christos { .n_name = "_dumplo" }, 102 1.67 kardel #define X_TIME_SECOND 2 103 1.69 christos { .n_name = "_time_second" }, 104 1.68 kardel #define X_TIME 3 105 1.69 christos { .n_name = "_time" }, 106 1.68 kardel #define X_DUMPSIZE 4 107 1.69 christos { .n_name = "_dumpsize" }, 108 1.68 kardel #define X_VERSION 5 109 1.69 christos { .n_name = "_version" }, 110 1.68 kardel #define X_DUMPMAG 6 111 1.69 christos { .n_name = "_dumpmag" }, 112 1.68 kardel #define X_PANICSTR 7 113 1.69 christos { .n_name = "_panicstr" }, 114 1.68 kardel #define X_PANICSTART 8 115 1.69 christos { .n_name = "_panicstart" }, 116 1.68 kardel #define X_PANICEND 9 117 1.69 christos { .n_name = "_panicend" }, 118 1.68 kardel #define X_MSGBUF 10 119 1.69 christos { .n_name = "_msgbufp" }, 120 1.72 ad #define X_DUMPCDEV 11 121 1.72 ad { .n_name = "_dumpcdev" }, 122 1.76 ad #define X_SYMSZ 12 123 1.76 ad { .n_name = "_ksyms_symsz" }, 124 1.76 ad #define X_STRSZ 13 125 1.76 ad { .n_name = "_ksyms_strsz" }, 126 1.76 ad #define X_KHDR 14 127 1.76 ad { .n_name = "_ksyms_hdr" }, 128 1.76 ad #define X_SYMTABS 15 129 1.76 ad { .n_name = "_ksyms_symtabs" }, 130 1.69 christos { .n_name = NULL }, 131 1.1 cgd }; 132 1.82 joerg static int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, X_DUMPCDEV, -1 }; 133 1.82 joerg static int dumpsyms[] = { X_TIME_SECOND, X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, 134 1.76 ad X_DUMPMAG, X_SYMSZ, X_STRSZ, X_KHDR, X_SYMTABS, -1 }; 135 1.1 cgd 136 1.82 joerg static struct nlist dump_nl[] = { /* Name list for dumped system. */ 137 1.69 christos { .n_name = "_dumpdev" }, /* Entries MUST be the same as */ 138 1.69 christos { .n_name = "_dumplo" }, /* those in current_nl[]. */ 139 1.69 christos { .n_name = "_time_second" }, 140 1.69 christos { .n_name = "_time" }, 141 1.69 christos { .n_name = "_dumpsize" }, 142 1.69 christos { .n_name = "_version" }, 143 1.69 christos { .n_name = "_dumpmag" }, 144 1.69 christos { .n_name = "_panicstr" }, 145 1.69 christos { .n_name = "_panicstart" }, 146 1.69 christos { .n_name = "_panicend" }, 147 1.69 christos { .n_name = "_msgbufp" }, 148 1.72 ad { .n_name = "_dumpcdev" }, 149 1.76 ad { .n_name = "_ksyms_symsz" }, 150 1.76 ad { .n_name = "_ksyms_strsz" }, 151 1.76 ad { .n_name = "_ksyms_hdr" }, 152 1.76 ad { .n_name = "_ksyms_symtabs" }, 153 1.69 christos { .n_name = NULL }, 154 1.1 cgd }; 155 1.1 cgd 156 1.13 pk /* Types match kernel declarations. */ 157 1.82 joerg static off_t dumplo; /* where dump starts on dumpdev */ 158 1.82 joerg static u_int32_t dumpmag; /* magic number in dump */ 159 1.82 joerg static int dumpsize; /* amount of memory dumped */ 160 1.82 joerg static off_t dumpbytes; /* in bytes */ 161 1.82 joerg 162 1.82 joerg static const char *kernel; /* name of used kernel */ 163 1.83 christos static const char *dirname; /* directory to save dumps in */ 164 1.82 joerg static char *ddname; /* name of dump device */ 165 1.82 joerg static dev_t dumpdev; /* dump device */ 166 1.82 joerg static dev_t dumpcdev = NODEV; /* dump device (char equivalent) */ 167 1.82 joerg static int dumpfd; /* read/write descriptor on dev */ 168 1.82 joerg static kvm_t *kd_dump; /* kvm descriptor on dev */ 169 1.82 joerg static time_t now; /* current date */ 170 1.82 joerg static char panic_mesg[1024]; 171 1.82 joerg static long panicstr; 172 1.82 joerg static char vers[1024]; 173 1.82 joerg static char gzmode[3]; 174 1.7 cgd 175 1.82 joerg static void check_kmem(void); 176 1.82 joerg static int check_space(void); 177 1.82 joerg static void clear_dump(void); 178 1.82 joerg static int Create(char *, int); 179 1.86 christos static int dump_exists(int); 180 1.82 joerg static char *find_dev(dev_t, mode_t); 181 1.82 joerg static int get_crashtime(void); 182 1.86 christos static void kmem_setup(int); 183 1.82 joerg static void Lseek(int, off_t, int); 184 1.82 joerg static int Open(const char *, int rw); 185 1.86 christos static void save_core(int); 186 1.83 christos __dead static void usage(const char *fmt, ...) __printflike(1, 2); 187 1.1 cgd 188 1.13 pk int 189 1.45 wiz main(int argc, char *argv[]) 190 1.1 cgd { 191 1.86 christos int ch, level, testonly, compress, force, clear, verbose; 192 1.53 lukem char *ep; 193 1.44 wiz 194 1.44 wiz kernel = NULL; 195 1.54 lukem level = 1; /* default to fastest gzip compression */ 196 1.86 christos force = 0; 197 1.86 christos clear = 0; 198 1.65 dsainty testonly = 0; 199 1.86 christos verbose = 0; 200 1.86 christos compress = 0; 201 1.53 lukem gzmode[0] = 'w'; 202 1.1 cgd 203 1.13 pk openlog("savecore", LOG_PERROR, LOG_DAEMON); 204 1.13 pk 205 1.65 dsainty while ((ch = getopt(argc, argv, "cdfnN:vzZ:")) != -1) 206 1.1 cgd switch(ch) { 207 1.1 cgd case 'c': 208 1.1 cgd clear = 1; 209 1.1 cgd break; 210 1.13 pk case 'd': /* Not documented. */ 211 1.1 cgd case 'v': 212 1.1 cgd verbose = 1; 213 1.1 cgd break; 214 1.1 cgd case 'f': 215 1.1 cgd force = 1; 216 1.1 cgd break; 217 1.65 dsainty case 'n': 218 1.65 dsainty testonly = 1; 219 1.65 dsainty break; 220 1.13 pk case 'N': 221 1.15 mycroft kernel = optarg; 222 1.13 pk break; 223 1.13 pk case 'z': 224 1.13 pk compress = 1; 225 1.13 pk break; 226 1.53 lukem case 'Z': 227 1.53 lukem level = (int)strtol(optarg, &ep, 10); 228 1.83 christos if (level < 0 || level > 9) 229 1.83 christos usage("Invalid compression `%s'", optarg); 230 1.53 lukem break; 231 1.1 cgd case '?': 232 1.84 christos usage("Missing argument for flag `%c'", optopt); 233 1.1 cgd default: 234 1.83 christos usage("Unknown flag `%c'", ch); 235 1.1 cgd } 236 1.1 cgd argc -= optind; 237 1.1 cgd argv += optind; 238 1.1 cgd 239 1.83 christos if (argc != 0) 240 1.83 christos dirname = argv[0]; 241 1.83 christos else 242 1.83 christos dirname = "/var/crash"; 243 1.44 wiz 244 1.54 lukem gzmode[1] = level + '0'; 245 1.44 wiz 246 1.13 pk (void)time(&now); 247 1.86 christos kmem_setup(verbose); 248 1.1 cgd 249 1.65 dsainty if (clear && !testonly) { 250 1.1 cgd clear_dump(); 251 1.1 cgd exit(0); 252 1.1 cgd } 253 1.13 pk 254 1.86 christos if (!dump_exists(verbose) && !force) 255 1.13 pk exit(1); 256 1.13 pk 257 1.65 dsainty if (testonly) 258 1.65 dsainty /* If -n was passed and there was a dump, exit at level 0 */ 259 1.65 dsainty exit(0); 260 1.65 dsainty 261 1.1 cgd check_kmem(); 262 1.13 pk 263 1.1 cgd if (panicstr) 264 1.13 pk syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg); 265 1.1 cgd else 266 1.13 pk syslog(LOG_ALERT, "reboot"); 267 1.1 cgd 268 1.1 cgd if ((!get_crashtime() || !check_space()) && !force) 269 1.1 cgd exit(1); 270 1.1 cgd 271 1.86 christos save_core(compress); 272 1.1 cgd 273 1.13 pk clear_dump(); 274 1.13 pk exit(0); 275 1.1 cgd } 276 1.1 cgd 277 1.82 joerg static void 278 1.90 maxv read_string(kvm_t *kd, u_long kva, char *buf, size_t size) 279 1.90 maxv { 280 1.90 maxv size_t i; 281 1.90 maxv 282 1.90 maxv for (i = 0; i < size - 1; i++) { 283 1.90 maxv (void)kvm_read(kd, kva + i, buf + i, 1); 284 1.90 maxv if (buf[i] == '\0') 285 1.90 maxv return; 286 1.90 maxv } 287 1.90 maxv 288 1.90 maxv buf[size - 1] = '\0'; 289 1.90 maxv } 290 1.90 maxv 291 1.90 maxv static void 292 1.86 christos kmem_setup(int verbose) 293 1.1 cgd { 294 1.87 mrg long l_dumplo; 295 1.45 wiz kvm_t *kd_kern; 296 1.45 wiz char errbuf[_POSIX2_LINE_MAX]; 297 1.45 wiz int i, hdrsz; 298 1.1 cgd 299 1.1 cgd /* 300 1.13 pk * Some names we need for the currently running system, others for 301 1.13 pk * the system that was running when the dump was made. The values 302 1.13 pk * obtained from the current system are used to look for things in 303 1.43 darrenr * /dev/kmem that cannot be found in the kernel namelist, but are 304 1.13 pk * presumed to be the same (since the disk partitions are probably 305 1.13 pk * the same!) 306 1.1 cgd */ 307 1.42 darrenr kd_kern = kvm_openfiles(kernel, NULL, NULL, O_RDONLY, errbuf); 308 1.25 leo if (kd_kern == NULL) { 309 1.44 wiz syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 310 1.25 leo exit(1); 311 1.25 leo } 312 1.25 leo if (kvm_nlist(kd_kern, current_nl) == -1) 313 1.44 wiz syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 314 1.45 wiz kvm_geterr(kd_kern)); 315 1.25 leo 316 1.72 ad for (i = 0; cursyms[i] != -1; i++) { 317 1.72 ad if (current_nl[cursyms[i]].n_value != 0) 318 1.72 ad continue; 319 1.72 ad switch (cursyms[i]) { 320 1.72 ad case X_TIME_SECOND: 321 1.72 ad case X_TIME: 322 1.72 ad case X_DUMPCDEV: 323 1.72 ad break; 324 1.72 ad default: 325 1.13 pk syslog(LOG_ERR, "%s: %s not in namelist", 326 1.44 wiz kernel, current_nl[cursyms[i]].n_name); 327 1.1 cgd exit(1); 328 1.1 cgd } 329 1.72 ad } 330 1.13 pk 331 1.87 mrg KREAD_LOGWARN(kd_kern, current_nl[X_DUMPDEV].n_value, dumpdev, exit(1)); 332 1.5 pk if (dumpdev == NODEV) { 333 1.13 pk syslog(LOG_WARNING, "no core dump (no dumpdev)"); 334 1.13 pk exit(1); 335 1.5 pk } 336 1.87 mrg KREAD_LOGWARN(kd_kern, current_nl[X_DUMPLO].n_value, l_dumplo, exit(1)); 337 1.87 mrg if (l_dumplo == -1) { 338 1.57 christos syslog(LOG_WARNING, "no core dump (invalid dumplo)"); 339 1.30 pk exit(1); 340 1.46 wiz } 341 1.87 mrg dumplo = DEV_BSIZE * (off_t) l_dumplo; 342 1.57 christos 343 1.1 cgd if (verbose) 344 1.57 christos (void)printf("dumplo = %lld (%ld * %ld)\n", 345 1.57 christos (long long)dumplo, (long)(dumplo / DEV_BSIZE), (long)DEV_BSIZE); 346 1.87 mrg KREAD_LOGWARN(kd_kern, current_nl[X_DUMPMAG].n_value, dumpmag, exit(1)); 347 1.25 leo 348 1.90 maxv read_string(kd_kern, current_nl[X_VERSION].n_value, vers, 349 1.45 wiz sizeof(vers)); 350 1.25 leo 351 1.72 ad if (current_nl[X_DUMPCDEV].n_value != 0) { 352 1.87 mrg KREAD_LOGWARN(kd_kern, current_nl[X_DUMPCDEV].n_value, dumpcdev, 353 1.87 mrg exit(1)); 354 1.72 ad ddname = find_dev(dumpcdev, S_IFCHR); 355 1.72 ad } else 356 1.72 ad ddname = find_dev(dumpdev, S_IFBLK); 357 1.75 joerg if (strncmp(ddname, "/dev/cons", 8) == 0 || 358 1.75 joerg strncmp(ddname, "/dev/tty", 7) == 0 || 359 1.75 joerg strncmp(ddname, "/dev/pty", 7) == 0 || 360 1.75 joerg strncmp(ddname, "/dev/pts", 7) == 0) { 361 1.75 joerg syslog(LOG_ERR, "dumpdev %s is tty; override kernel", ddname); 362 1.75 joerg exit(1); 363 1.75 joerg } 364 1.1 cgd dumpfd = Open(ddname, O_RDWR); 365 1.25 leo 366 1.43 darrenr kd_dump = kvm_openfiles(kernel, ddname, NULL, O_RDWR, errbuf); 367 1.25 leo if (kd_dump == NULL) { 368 1.43 darrenr syslog(LOG_ERR, "%s: kvm_openfiles: %s", kernel, errbuf); 369 1.1 cgd exit(1); 370 1.1 cgd } 371 1.13 pk 372 1.25 leo if (kvm_nlist(kd_dump, dump_nl) == -1) 373 1.43 darrenr syslog(LOG_ERR, "%s: kvm_nlist: %s", kernel, 374 1.44 wiz kvm_geterr(kd_dump)); 375 1.25 leo 376 1.25 leo for (i = 0; dumpsyms[i] != -1; i++) 377 1.68 kardel if (dump_nl[dumpsyms[i]].n_value == 0 && 378 1.68 kardel dumpsyms[i] != X_TIME_SECOND && 379 1.68 kardel dumpsyms[i] != X_TIME) { 380 1.25 leo syslog(LOG_ERR, "%s: %s not in namelist", 381 1.43 darrenr kernel, dump_nl[dumpsyms[i]].n_name); 382 1.25 leo exit(1); 383 1.25 leo } 384 1.57 christos hdrsz = kvm_dump_mkheader(kd_dump, dumplo); 385 1.27 leo 386 1.27 leo /* 387 1.27 leo * If 'hdrsz' == 0, kvm_dump_mkheader() failed on the magic-number 388 1.27 leo * checks, ergo no dump is present... 389 1.27 leo */ 390 1.27 leo if (hdrsz == 0) { 391 1.27 leo syslog(LOG_WARNING, "no core dump"); 392 1.27 leo exit(1); 393 1.27 leo } 394 1.25 leo if (hdrsz == -1) { 395 1.43 darrenr syslog(LOG_ERR, "%s: kvm_dump_mkheader: %s", kernel, 396 1.45 wiz kvm_geterr(kd_dump)); 397 1.25 leo exit(1); 398 1.25 leo } 399 1.25 leo dumplo += hdrsz; 400 1.25 leo kvm_close(kd_kern); 401 1.1 cgd } 402 1.1 cgd 403 1.82 joerg static void 404 1.45 wiz check_kmem(void) 405 1.1 cgd { 406 1.51 simonb char *cp, *bufdata; 407 1.51 simonb struct kern_msgbuf msgbuf, *bufp; 408 1.51 simonb long panicloc, panicstart, panicend; 409 1.13 pk char core_vers[1024]; 410 1.1 cgd 411 1.90 maxv read_string(kd_dump, dump_nl[X_VERSION].n_value, core_vers, 412 1.45 wiz sizeof(core_vers)); 413 1.25 leo 414 1.52 wiz if (strcmp(vers, core_vers) != 0) 415 1.13 pk syslog(LOG_WARNING, 416 1.13 pk "warning: %s version mismatch:\n\t%s\nand\t%s\n", 417 1.83 christos kvm_getkernelname(kd_dump), vers, core_vers); 418 1.25 leo 419 1.51 simonb panicstart = panicend = 0; 420 1.87 mrg KREAD_LOGWARN(kd_dump, dump_nl[X_PANICSTART].n_value, panicstart, 421 1.87 mrg goto nomsguf); 422 1.87 mrg KREAD_LOGWARN(kd_dump, dump_nl[X_PANICEND].n_value, panicend, 423 1.87 mrg goto nomsguf); 424 1.87 mrg 425 1.51 simonb if (panicstart != 0 && panicend != 0) { 426 1.87 mrg KREAD_LOGWARN(kd_dump, dump_nl[X_MSGBUF].n_value, bufp, 427 1.87 mrg goto nomsguf); 428 1.87 mrg /* Reads msg_bufs[1], but doesn't matter. */ 429 1.87 mrg KREAD_LOGWARN(kd_dump, (long)bufp, msgbuf, 430 1.87 mrg goto nomsguf); 431 1.51 simonb if (msgbuf.msg_magic != MSG_MAGIC) { 432 1.87 mrg syslog(LOG_WARNING, "msgbuf magic incorrect (%lx != %lx)", 433 1.87 mrg msgbuf.msg_magic, (long)MSG_MAGIC); 434 1.51 simonb goto nomsguf; 435 1.51 simonb } 436 1.51 simonb bufdata = malloc(msgbuf.msg_bufs); 437 1.51 simonb if (bufdata == NULL) { 438 1.83 christos syslog(LOG_WARNING, "couldn't allocate space for msgbuf data"); 439 1.51 simonb goto nomsguf; 440 1.51 simonb } 441 1.51 simonb if (kvm_read(kd_dump, (long)&bufp->msg_bufc, bufdata, 442 1.51 simonb msgbuf.msg_bufs) != msgbuf.msg_bufs) { 443 1.87 mrg syslog(LOG_WARNING, "kvm_read dmesg buffer: %s", 444 1.87 mrg kvm_geterr(kd_dump)); 445 1.66 hubertf free(bufdata); 446 1.51 simonb goto nomsguf; 447 1.51 simonb } 448 1.51 simonb cp = panic_mesg; 449 1.51 simonb while (panicstart != panicend && cp < &panic_mesg[sizeof(panic_mesg)-1]) { 450 1.51 simonb *cp++ = bufdata[panicstart]; 451 1.51 simonb panicstart++; 452 1.51 simonb if (panicstart >= msgbuf.msg_bufs) 453 1.51 simonb panicstart = 0; 454 1.51 simonb } 455 1.51 simonb /* Don't end in a new-line */ 456 1.51 simonb cp = &panic_mesg[strlen(panic_mesg)] - 1; 457 1.51 simonb if (*cp == '\n') 458 1.51 simonb *cp = '\0'; 459 1.51 simonb panic_mesg[sizeof(panic_mesg) - 1] = '\0'; 460 1.66 hubertf free(bufdata); 461 1.51 simonb 462 1.51 simonb panicstr = 1; /* anything not zero */ 463 1.51 simonb return; 464 1.51 simonb } 465 1.51 simonb nomsguf: 466 1.87 mrg KREAD_LOGWARN(kd_dump, dump_nl[X_PANICSTR].n_value, panicstr, 467 1.88 mrg return); 468 1.1 cgd if (panicstr) { 469 1.45 wiz cp = panic_mesg; 470 1.25 leo panicloc = panicstr; 471 1.25 leo do { 472 1.30 pk if (KREAD(kd_dump, panicloc, cp) != 0) { 473 1.87 mrg syslog(LOG_WARNING, "kvm_read msgbuf: %s", 474 1.83 christos kvm_geterr(kd_dump)); 475 1.30 pk break; 476 1.30 pk } 477 1.25 leo panicloc++; 478 1.30 pk } while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)-1]); 479 1.30 pk panic_mesg[sizeof(panic_mesg) - 1] = '\0'; 480 1.1 cgd } 481 1.1 cgd } 482 1.1 cgd 483 1.82 joerg static int 484 1.86 christos dump_exists(int verbose) 485 1.1 cgd { 486 1.56 tsutsui u_int32_t newdumpmag; 487 1.1 cgd 488 1.87 mrg /* Read the dump magic and size. */ 489 1.89 mrg KREAD_ERR(kd_dump, dump_nl[X_DUMPMAG].n_value, newdumpmag, return 0); 490 1.89 mrg KREAD_ERR(kd_dump, dump_nl[X_DUMPSIZE].n_value, dumpsize, return 0); 491 1.23 cgd 492 1.64 tls dumpbytes = (off_t)dumpsize * getpagesize(); 493 1.23 cgd 494 1.23 cgd /* 495 1.23 cgd * Return zero if core dump doesn't seem to be there, and note 496 1.23 cgd * it for syslog. This check and return happens after the dump size 497 1.23 cgd * is read, so dumpsize is whether or not the core is valid (for -f). 498 1.23 cgd */ 499 1.13 pk if (newdumpmag != dumpmag) { 500 1.1 cgd if (verbose) 501 1.83 christos syslog(LOG_WARNING, "magic number mismatch " 502 1.87 mrg "(%#x != %#x)", newdumpmag, dumpmag); 503 1.13 pk syslog(LOG_WARNING, "no core dump"); 504 1.1 cgd return (0); 505 1.1 cgd } 506 1.13 pk return (1); 507 1.13 pk } 508 1.13 pk 509 1.82 joerg static void 510 1.45 wiz clear_dump(void) 511 1.25 leo { 512 1.25 leo if (kvm_dump_inval(kd_dump) == -1) 513 1.72 ad syslog(LOG_ERR, "%s: kvm_dump_inval: %s", ddname, 514 1.45 wiz kvm_geterr(kd_dump)); 515 1.25 leo 516 1.25 leo } 517 1.25 leo 518 1.82 joerg static char buf[1024 * 1024]; 519 1.16 deraadt 520 1.76 ad static void 521 1.86 christos save_kernel(FILE *fp, char *path) 522 1.76 ad { 523 1.76 ad int nw, nr, ifd; 524 1.76 ad 525 1.76 ad ifd = Open(kernel, O_RDONLY); 526 1.76 ad while ((nr = read(ifd, buf, sizeof(buf))) > 0) { 527 1.86 christos nw = fwrite(buf, 1, nr, fp); 528 1.76 ad if (nw != nr) { 529 1.76 ad syslog(LOG_ERR, "%s: %s", 530 1.76 ad path, strerror(nw == 0 ? EIO : errno)); 531 1.76 ad syslog(LOG_WARNING, 532 1.76 ad "WARNING: kernel may be incomplete"); 533 1.76 ad exit(1); 534 1.76 ad } 535 1.76 ad } 536 1.76 ad if (nr < 0) { 537 1.76 ad syslog(LOG_ERR, "%s: %m", kernel); 538 1.76 ad syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); 539 1.76 ad exit(1); 540 1.76 ad } 541 1.76 ad } 542 1.76 ad 543 1.76 ad static int 544 1.76 ad ksymsget(u_long addr, void *ptr, size_t size) 545 1.76 ad { 546 1.76 ad 547 1.80 lukem if ((size_t)kvm_read(kd_dump, addr, ptr, size) != size) { 548 1.87 mrg syslog(LOG_WARNING, "kvm_read ksyms: %s", kvm_geterr(kd_dump)); 549 1.76 ad return 1; 550 1.76 ad } 551 1.76 ad return 0; 552 1.76 ad } 553 1.76 ad 554 1.76 ad static int 555 1.86 christos save_ksyms(FILE *fp, char *path) 556 1.76 ad { 557 1.76 ad struct ksyms_hdr khdr; 558 1.76 ad int nw, symsz, strsz; 559 1.76 ad TAILQ_HEAD(, ksyms_symtab) symtabs; 560 1.76 ad struct ksyms_symtab st, *stptr; 561 1.76 ad void *p; 562 1.76 ad 563 1.76 ad /* Get basic info and ELF headers, check if ksyms was on. */ 564 1.76 ad if (ksymsget(dump_nl[X_KHDR].n_value, &khdr, sizeof(khdr))) 565 1.76 ad return 1; 566 1.76 ad if (ksymsget(dump_nl[X_SYMSZ].n_value, &symsz, sizeof(symsz))) 567 1.76 ad return 1; 568 1.76 ad if (ksymsget(dump_nl[X_STRSZ].n_value, &strsz, sizeof(strsz))) 569 1.76 ad return 1; 570 1.76 ad if (symsz == 0 || strsz == 0) 571 1.76 ad return 1; 572 1.76 ad 573 1.76 ad /* Update the ELF section headers for symbols/strings. */ 574 1.76 ad khdr.kh_shdr[SYMTAB].sh_size = symsz; 575 1.76 ad khdr.kh_shdr[SYMTAB].sh_info = symsz / sizeof(Elf_Sym); 576 1.76 ad khdr.kh_shdr[STRTAB].sh_offset = symsz + 577 1.76 ad khdr.kh_shdr[SYMTAB].sh_offset; 578 1.76 ad khdr.kh_shdr[STRTAB].sh_size = strsz; 579 1.76 ad 580 1.76 ad /* Write out the ELF headers. */ 581 1.86 christos nw = fwrite(&khdr, 1, sizeof(khdr), fp); 582 1.76 ad if (nw != sizeof(khdr)) { 583 1.76 ad syslog(LOG_ERR, "%s: %s", 584 1.76 ad path, strerror(nw == 0 ? EIO : errno)); 585 1.76 ad syslog(LOG_WARNING, 586 1.76 ad "WARNING: kernel may be incomplete"); 587 1.76 ad exit(1); 588 1.76 ad } 589 1.76 ad 590 1.76 ad /* Dump symbol table. */ 591 1.76 ad if (ksymsget(dump_nl[X_SYMTABS].n_value, &symtabs, sizeof(symtabs))) 592 1.76 ad return 1; 593 1.76 ad stptr = TAILQ_FIRST(&symtabs); 594 1.76 ad while (stptr != NULL) { 595 1.76 ad if (ksymsget((u_long)stptr, &st, sizeof(st))) 596 1.76 ad return 1; 597 1.76 ad stptr = TAILQ_NEXT(&st, sd_queue); 598 1.76 ad if ((p = malloc(st.sd_symsize)) == NULL) 599 1.76 ad return 1; 600 1.76 ad if (ksymsget((u_long)st.sd_symstart, p, st.sd_symsize)) { 601 1.76 ad free(p); 602 1.76 ad return 1; 603 1.76 ad } 604 1.86 christos nw = fwrite(p, 1, st.sd_symsize, fp); 605 1.76 ad free(p); 606 1.76 ad if (nw != st.sd_symsize) { 607 1.76 ad syslog(LOG_ERR, "%s: %s", 608 1.76 ad path, strerror(nw == 0 ? EIO : errno)); 609 1.76 ad syslog(LOG_WARNING, 610 1.76 ad "WARNING: kernel may be incomplete"); 611 1.76 ad exit(1); 612 1.76 ad } 613 1.76 ad } 614 1.76 ad 615 1.76 ad /* Dump string table. */ 616 1.76 ad if (ksymsget(dump_nl[X_SYMTABS].n_value, &symtabs, sizeof(symtabs))) 617 1.76 ad return 1; 618 1.76 ad stptr = TAILQ_FIRST(&symtabs); 619 1.76 ad while (stptr != NULL) { 620 1.76 ad if (ksymsget((u_long)stptr, &st, sizeof(st))) 621 1.76 ad return 1; 622 1.76 ad stptr = TAILQ_NEXT(&st, sd_queue); 623 1.76 ad if ((p = malloc(st.sd_symsize)) == NULL) 624 1.76 ad return 1; 625 1.76 ad if (ksymsget((u_long)st.sd_strstart, p, st.sd_strsize)) { 626 1.76 ad free(p); 627 1.76 ad return 1; 628 1.76 ad } 629 1.86 christos nw = fwrite(p, 1, st.sd_strsize, fp); 630 1.76 ad free(p); 631 1.76 ad if (nw != st.sd_strsize) { 632 1.76 ad syslog(LOG_ERR, "%s: %s", 633 1.76 ad path, strerror(nw == 0 ? EIO : errno)); 634 1.76 ad syslog(LOG_WARNING, 635 1.76 ad "WARNING: kernel may be incomplete"); 636 1.76 ad exit(1); 637 1.76 ad } 638 1.76 ad } 639 1.76 ad 640 1.76 ad return 0; 641 1.76 ad } 642 1.76 ad 643 1.82 joerg static void 644 1.86 christos save_core(int compress) 645 1.13 pk { 646 1.32 lukem FILE *fp; 647 1.76 ad int bounds, ifd, nr, nw, ofd, tryksyms; 648 1.85 christos char path[MAXPATHLEN], rbuf[MAXPATHLEN]; 649 1.85 christos const char *rawp; 650 1.13 pk 651 1.32 lukem ofd = -1; 652 1.13 pk /* 653 1.13 pk * Get the current number and update the bounds file. Do the update 654 1.13 pk * now, because may fail later and don't want to overwrite anything. 655 1.13 pk */ 656 1.38 sommerfe umask(066); 657 1.13 pk (void)snprintf(path, sizeof(path), "%s/bounds", dirname); 658 1.13 pk if ((fp = fopen(path, "r")) == NULL) 659 1.13 pk goto err1; 660 1.13 pk if (fgets(buf, sizeof(buf), fp) == NULL) { 661 1.13 pk if (ferror(fp)) 662 1.45 wiz err1: syslog(LOG_WARNING, "%s: %m", path); 663 1.13 pk bounds = 0; 664 1.13 pk } else 665 1.13 pk bounds = atoi(buf); 666 1.13 pk if (fp != NULL) 667 1.13 pk (void)fclose(fp); 668 1.13 pk if ((fp = fopen(path, "w")) == NULL) 669 1.13 pk syslog(LOG_ERR, "%s: %m", path); 670 1.13 pk else { 671 1.13 pk (void)fprintf(fp, "%d\n", bounds + 1); 672 1.13 pk (void)fclose(fp); 673 1.13 pk } 674 1.13 pk 675 1.13 pk /* Create the core file. */ 676 1.24 mycroft (void)snprintf(path, sizeof(path), "%s/netbsd.%d.core%s", 677 1.49 joda dirname, bounds, compress ? ".gz" : ""); 678 1.13 pk if (compress) { 679 1.53 lukem if ((fp = zopen(path, gzmode)) == NULL) { 680 1.45 wiz syslog(LOG_ERR, "%s: %m", path); 681 1.13 pk exit(1); 682 1.13 pk } 683 1.25 leo } else { 684 1.13 pk ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 685 1.25 leo fp = fdopen(ofd, "w"); 686 1.25 leo if (fp == NULL) { 687 1.45 wiz syslog(LOG_ERR, "%s: fdopen: %m", path); 688 1.25 leo exit(1); 689 1.25 leo } 690 1.25 leo } 691 1.13 pk 692 1.72 ad if (dumpcdev == NODEV) { 693 1.72 ad /* Open the raw device. */ 694 1.85 christos rawp = getdiskrawname(rbuf, sizeof(rbuf), ddname); 695 1.85 christos if (rawp == NULL) { 696 1.85 christos syslog(LOG_WARNING, "%s: %m; can't convert to raw", 697 1.85 christos ddname); 698 1.85 christos rawp = ddname; 699 1.85 christos } 700 1.72 ad if ((ifd = open(rawp, O_RDONLY)) == -1) { 701 1.72 ad syslog(LOG_WARNING, "%s: %m; using block device", 702 1.72 ad rawp); 703 1.72 ad ifd = dumpfd; 704 1.72 ad } 705 1.72 ad } else { 706 1.72 ad rawp = ddname; 707 1.13 pk ifd = dumpfd; 708 1.13 pk } 709 1.13 pk 710 1.13 pk /* Seek to the start of the core. */ 711 1.57 christos Lseek(ifd, dumplo, SEEK_SET); 712 1.13 pk 713 1.64 tls if (kvm_dump_wrtheader(kd_dump, fp, (int32_t)dumpbytes) == -1) { 714 1.25 leo syslog(LOG_ERR, "kvm_dump_wrtheader: %s : %s", path, 715 1.45 wiz kvm_geterr(kd_dump)); 716 1.25 leo exit(1); 717 1.25 leo } 718 1.25 leo 719 1.13 pk /* Copy the core file. */ 720 1.13 pk syslog(LOG_NOTICE, "writing %score to %s", 721 1.13 pk compress ? "compressed " : "", path); 722 1.64 tls for (; dumpbytes > (off_t)0; dumpbytes -= (off_t)nr) { 723 1.58 drochner char nbuf[7]; 724 1.64 tls humanize_number(nbuf, 7, dumpbytes, "", HN_AUTOSCALE, 0); 725 1.58 drochner (void)printf("%7s\r", nbuf); 726 1.13 pk (void)fflush(stdout); 727 1.80 lukem nr = read(ifd, buf, MIN(dumpbytes, (off_t)sizeof(buf))); 728 1.13 pk if (nr <= 0) { 729 1.13 pk if (nr == 0) 730 1.13 pk syslog(LOG_WARNING, 731 1.13 pk "WARNING: EOF on dump device"); 732 1.13 pk else 733 1.13 pk syslog(LOG_ERR, "%s: %m", rawp); 734 1.13 pk goto err2; 735 1.13 pk } 736 1.25 leo nw = fwrite(buf, 1, nr, fp); 737 1.13 pk if (nw != nr) { 738 1.13 pk syslog(LOG_ERR, "%s: %s", 739 1.13 pk path, strerror(nw == 0 ? EIO : errno)); 740 1.13 pk err2: syslog(LOG_WARNING, 741 1.15 mycroft "WARNING: core may be incomplete"); 742 1.13 pk (void)printf("\n"); 743 1.13 pk exit(1); 744 1.13 pk } 745 1.13 pk } 746 1.72 ad if (dumpcdev == NODEV) 747 1.72 ad (void)close(ifd); 748 1.25 leo (void)fclose(fp); 749 1.13 pk 750 1.76 ad /* Create a kernel. */ 751 1.13 pk (void)snprintf(path, sizeof(path), "%s/netbsd.%d%s", 752 1.49 joda dirname, bounds, compress ? ".gz" : ""); 753 1.13 pk syslog(LOG_NOTICE, "writing %skernel to %s", 754 1.13 pk compress ? "compressed " : "", path); 755 1.77 ad for (tryksyms = 1;; tryksyms = 0) { 756 1.76 ad if (compress) { 757 1.76 ad if ((fp = zopen(path, gzmode)) == NULL) { 758 1.76 ad syslog(LOG_ERR, "%s: %m", path); 759 1.76 ad exit(1); 760 1.76 ad } 761 1.86 christos } else { 762 1.76 ad ofd = Create(path, S_IRUSR | S_IWUSR); 763 1.86 christos fp = fdopen(ofd, "w"); 764 1.86 christos if (fp == NULL) { 765 1.86 christos syslog(LOG_ERR, "fdopen: %m"); 766 1.86 christos exit(1); 767 1.86 christos } 768 1.86 christos } 769 1.76 ad if (tryksyms) { 770 1.86 christos if (!save_ksyms(fp, path)) 771 1.76 ad break; 772 1.86 christos (void)fclose(fp); 773 1.76 ad unlink(path); 774 1.76 ad } else { 775 1.86 christos save_kernel(fp, path); 776 1.76 ad break; 777 1.13 pk } 778 1.13 pk } 779 1.86 christos (void)fclose(fp); 780 1.73 ad 781 1.73 ad /* 782 1.73 ad * For development systems where the crash occurs during boot 783 1.73 ad * to multiuser. 784 1.73 ad */ 785 1.73 ad sync(); 786 1.73 ad sleep(1); 787 1.73 ad sync(); 788 1.73 ad sleep(1); 789 1.1 cgd } 790 1.1 cgd 791 1.82 joerg static char * 792 1.80 lukem find_dev(dev_t dev, mode_t type) 793 1.1 cgd { 794 1.32 lukem DIR *dfd; 795 1.13 pk struct dirent *dir; 796 1.13 pk struct stat sb; 797 1.60 itojun char *dp, device[MAXPATHLEN + 1], *p; 798 1.60 itojun size_t l; 799 1.1 cgd 800 1.13 pk if ((dfd = opendir(_PATH_DEV)) == NULL) { 801 1.45 wiz syslog(LOG_ERR, "%s: %m", _PATH_DEV); 802 1.13 pk exit(1); 803 1.13 pk } 804 1.60 itojun strlcpy(device, _PATH_DEV, sizeof(device)); 805 1.60 itojun p = &device[strlen(device)]; 806 1.60 itojun l = sizeof(device) - strlen(device); 807 1.13 pk while ((dir = readdir(dfd))) { 808 1.60 itojun strlcpy(p, dir->d_name, l); 809 1.55 lukem if (lstat(device, &sb)) { 810 1.55 lukem syslog(LOG_ERR, "%s: %m", device); 811 1.13 pk continue; 812 1.13 pk } 813 1.13 pk if ((sb.st_mode & S_IFMT) != type) 814 1.13 pk continue; 815 1.13 pk if (dev == sb.st_rdev) { 816 1.13 pk closedir(dfd); 817 1.55 lukem if ((dp = strdup(device)) == NULL) { 818 1.45 wiz syslog(LOG_ERR, "%m"); 819 1.13 pk exit(1); 820 1.13 pk } 821 1.13 pk return (dp); 822 1.13 pk } 823 1.13 pk } 824 1.13 pk closedir(dfd); 825 1.78 christos syslog(LOG_ERR, "can't find device %lld/%lld", 826 1.78 christos (long long)major(dev), (long long)minor(dev)); 827 1.13 pk exit(1); 828 1.1 cgd } 829 1.1 cgd 830 1.82 joerg static int 831 1.45 wiz get_crashtime(void) 832 1.1 cgd { 833 1.67 kardel time_t dumptime; /* Time the dump was taken. */ 834 1.45 wiz struct timeval dtime; 835 1.1 cgd 836 1.67 kardel if (KREAD(kd_dump, dump_nl[X_TIME_SECOND].n_value, &dumptime) != 0) { 837 1.68 kardel if (KREAD(kd_dump, dump_nl[X_TIME].n_value, &dtime) != 0) { 838 1.87 mrg syslog(LOG_WARNING, "kvm_read dumptime: %s (and _time_second " 839 1.83 christos "is not defined also)", kvm_geterr(kd_dump)); 840 1.68 kardel return (0); 841 1.68 kardel } 842 1.68 kardel dumptime = dtime.tv_sec; 843 1.30 pk } 844 1.13 pk if (dumptime == 0) { 845 1.83 christos syslog(LOG_WARNING, "dump time is zero"); 846 1.1 cgd return (0); 847 1.13 pk } 848 1.83 christos syslog(LOG_INFO, "system went down at %s", ctime(&dumptime)); 849 1.62 christos #define LEEWAY (60 * SECSPERDAY) 850 1.13 pk if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) { 851 1.83 christos syslog(LOG_WARNING, "dump time is unreasonable"); 852 1.1 cgd return (0); 853 1.1 cgd } 854 1.13 pk return (1); 855 1.1 cgd } 856 1.1 cgd 857 1.82 joerg static int 858 1.45 wiz check_space(void) 859 1.1 cgd { 860 1.32 lukem FILE *fp; 861 1.15 mycroft off_t minfree, spacefree, kernelsize, needed; 862 1.13 pk struct stat st; 863 1.63 christos struct statvfs fsbuf; 864 1.45 wiz char mbuf[100], path[MAXPATHLEN]; 865 1.35 thorpej 866 1.81 dogcow /* XXX assume a reasonable default, unless we find a kernel. */ 867 1.81 dogcow kernelsize = 20 * 1024 * 1024; 868 1.81 dogcow if (!stat(kernel, &st)) kernelsize = st.st_blocks * S_BLKSIZE; 869 1.63 christos if (statvfs(dirname, &fsbuf) < 0) { 870 1.13 pk syslog(LOG_ERR, "%s: %m", dirname); 871 1.13 pk exit(1); 872 1.13 pk } 873 1.37 sommerfe spacefree = fsbuf.f_bavail; 874 1.63 christos spacefree *= fsbuf.f_frsize; 875 1.37 sommerfe spacefree /= 1024; 876 1.1 cgd 877 1.13 pk (void)snprintf(path, sizeof(path), "%s/minfree", dirname); 878 1.13 pk if ((fp = fopen(path, "r")) == NULL) 879 1.13 pk minfree = 0; 880 1.13 pk else { 881 1.45 wiz if (fgets(mbuf, sizeof(mbuf), fp) == NULL) 882 1.13 pk minfree = 0; 883 1.13 pk else 884 1.45 wiz minfree = atoi(mbuf); 885 1.13 pk (void)fclose(fp); 886 1.1 cgd } 887 1.13 pk 888 1.64 tls needed = (dumpbytes + kernelsize) / 1024; 889 1.13 pk if (minfree > 0 && spacefree - needed < minfree) { 890 1.13 pk syslog(LOG_WARNING, 891 1.40 mycroft "no dump, not enough free space in %s", dirname); 892 1.13 pk return (0); 893 1.1 cgd } 894 1.13 pk if (spacefree - needed < minfree) 895 1.13 pk syslog(LOG_WARNING, 896 1.13 pk "dump performed, but free space threshold crossed"); 897 1.13 pk return (1); 898 1.1 cgd } 899 1.1 cgd 900 1.82 joerg static int 901 1.52 wiz Open(const char *name, int rw) 902 1.1 cgd { 903 1.1 cgd int fd; 904 1.1 cgd 905 1.13 pk if ((fd = open(name, rw, 0)) < 0) { 906 1.13 pk syslog(LOG_ERR, "%s: %m", name); 907 1.1 cgd exit(1); 908 1.1 cgd } 909 1.1 cgd return (fd); 910 1.1 cgd } 911 1.1 cgd 912 1.82 joerg static void 913 1.45 wiz Lseek(int fd, off_t off, int flag) 914 1.1 cgd { 915 1.13 pk off_t ret; 916 1.1 cgd 917 1.1 cgd ret = lseek(fd, off, flag); 918 1.1 cgd if (ret == -1) { 919 1.13 pk syslog(LOG_ERR, "lseek: %m"); 920 1.1 cgd exit(1); 921 1.1 cgd } 922 1.1 cgd } 923 1.1 cgd 924 1.82 joerg static int 925 1.45 wiz Create(char *file, int mode) 926 1.1 cgd { 927 1.32 lukem int fd; 928 1.1 cgd 929 1.17 mycroft fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode); 930 1.1 cgd if (fd < 0) { 931 1.13 pk syslog(LOG_ERR, "%s: %m", file); 932 1.1 cgd exit(1); 933 1.1 cgd } 934 1.1 cgd return (fd); 935 1.1 cgd } 936 1.1 cgd 937 1.82 joerg static void 938 1.83 christos usage(const char *fmt, ...) 939 1.1 cgd { 940 1.83 christos va_list ap; 941 1.83 christos va_start(ap, fmt); 942 1.83 christos (void)vsyslog(LOG_ERR, fmt, ap); 943 1.83 christos va_end(ap); 944 1.53 lukem (void)syslog(LOG_ERR, 945 1.83 christos "Usage: %s [-cfnvz] [-N system] [-Z level] [directory]", 946 1.83 christos getprogname()); 947 1.1 cgd exit(1); 948 1.1 cgd } 949