xref: /openbsd-src/sbin/savecore/savecore.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: savecore.c,v 1.48 2009/10/27 23:59:34 deraadt Exp $	*/
2 /*	$NetBSD: savecore.c,v 1.26 1996/03/18 21:16:05 leo Exp $	*/
3 
4 /*-
5  * Copyright (c) 1986, 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/mount.h>
36 #include <sys/syslog.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <sys/resource.h>
40 
41 #include <dirent.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <nlist.h>
45 #include <paths.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <tzfile.h>
50 #include <unistd.h>
51 #include <limits.h>
52 #include <zlib.h>
53 #include <kvm.h>
54 #include <vis.h>
55 
56 extern FILE *zopen(const char *fname, const char *mode, int bits);
57 
58 #define KREAD(kd, addr, p)\
59 	(kvm_read(kd, addr, (char *)(p), sizeof(*(p))) != sizeof(*(p)))
60 
61 struct nlist current_nl[] = {	/* Namelist for currently running system. */
62 #define X_DUMPDEV	0
63 	{ "_dumpdev" },
64 #define X_DUMPLO	1
65 	{ "_dumplo" },
66 #define X_TIME		2
67 	{ "_time_second" },
68 #define	X_DUMPSIZE	3
69 	{ "_dumpsize" },
70 #define X_VERSION	4
71 	{ "_version" },
72 #define X_PANICSTR	5
73 	{ "_panicstr" },
74 #define	X_DUMPMAG	6
75 	{ "_dumpmag" },
76 	{ NULL },
77 };
78 int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
79 int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
80 
81 struct nlist dump_nl[] = {	/* Name list for dumped system. */
82 	{ "_dumpdev" },		/* Entries MUST be the same as */
83 	{ "_dumplo" },		/*	those in current_nl[].  */
84 	{ "_time_second" },
85 	{ "_dumpsize" },
86 	{ "_version" },
87 	{ "_panicstr" },
88 	{ "_dumpmag" },
89 	{ NULL },
90 };
91 
92 /* Types match kernel declarations. */
93 long	dumplo;			/* where dump starts on dumpdev (in blocks) */
94 off_t	dumpoff;		/* where dump starts on dumpdev (in bytes) */
95 u_long	dumpmag;		/* magic number in dump */
96 int	dumppages;		/* amount of memory dumped (in pages) */
97 u_long	dumpsize;		/* amount of memory dumped */
98 
99 char	*kernel;
100 char	*dirn;			/* directory to save dumps in */
101 char	*ddname;			/* name of dump device */
102 dev_t	dumpdev;			/* dump device */
103 int	dumpfd;				/* read/write descriptor on block dev */
104 kvm_t	*kd_dump;			/* kvm descriptor on block dev	*/
105 time_t	now;				/* current date */
106 char	panic_mesg[1024];
107 int	panicstr;
108 char	vers[1024];
109 
110 int	clear, zcompress, force, verbose;	/* flags */
111 
112 void	 check_kmem(void);
113 int	 check_space(void);
114 void	 clear_dump(void);
115 int	 Create(char *, int);
116 int	 dump_exists(void);
117 char	*find_dev(dev_t, int);
118 int	 get_crashtime(void);
119 void	 kmem_setup(void);
120 void	 Lseek(int, off_t, int);
121 int	 Open(char *, int rw);
122 char	*rawname(char *s);
123 void	 save_core(void);
124 void	 usage(void);
125 
126 int
127 main(int argc, char *argv[])
128 {
129 	struct rlimit rl;
130 	int ch;
131 
132 	openlog("savecore", LOG_PERROR, LOG_DAEMON);
133 
134 	/* Increase our data size to the max if we can. */
135 	if (getrlimit(RLIMIT_DATA, &rl) == 0) {
136 		rl.rlim_cur = rl.rlim_max;
137 		if (setrlimit(RLIMIT_DATA, &rl) < 0)
138 			syslog(LOG_WARNING, "can't set rlimit data size: %m");
139 	}
140 
141 	while ((ch = getopt(argc, argv, "cdfN:vz")) != -1)
142 		switch(ch) {
143 		case 'c':
144 			clear = 1;
145 			break;
146 		case 'd':		/* Not documented. */
147 		case 'v':
148 			verbose = 1;
149 			break;
150 		case 'f':
151 			force = 1;
152 			break;
153 		case 'N':
154 			kernel = optarg;
155 			break;
156 		case 'z':
157 			zcompress = 1;
158 			break;
159 		case '?':
160 		default:
161 			usage();
162 		}
163 	argc -= optind;
164 	argv += optind;
165 
166 	if (!clear) {
167 		if (argc != 1 && argc != 2)
168 			usage();
169 		dirn = argv[0];
170 	}
171 	if (argc == 2)
172 		kernel = argv[1];
173 
174 	(void)time(&now);
175 	kmem_setup();
176 
177 	if (clear) {
178 		clear_dump();
179 		return (0);
180 	}
181 
182 	if (!dump_exists() && !force)
183 		return (1);
184 
185 	check_kmem();
186 
187 	if (panicstr)
188 		syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
189 	else
190 		syslog(LOG_ALERT, "reboot");
191 
192 	if ((!get_crashtime() || !check_space()) && !force)
193 		return (1);
194 
195 	save_core();
196 
197 	clear_dump();
198 	return (0);
199 }
200 
201 char	*dump_sys;
202 
203 void
204 kmem_setup(void)
205 {
206 	kvm_t	*kd_kern;
207 	char	errbuf[_POSIX2_LINE_MAX];
208 	int	i, hdrsz;
209 
210 	/*
211 	 * Some names we need for the currently running system, others for
212 	 * the system that was running when the dump was made.  The values
213 	 * obtained from the current system are used to look for things in
214 	 * /dev/kmem that cannot be found in the dump_sys namelist, but are
215 	 * presumed to be the same (since the disk partitions are probably
216 	 * the same!)
217 	 */
218 	kd_kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
219 	if (kd_kern == NULL) {
220 		syslog(LOG_ERR, "%s: kvm_openfiles: %s", _PATH_UNIX, errbuf);
221 		exit(1);
222 	}
223 	if (kvm_nlist(kd_kern, current_nl) == -1)
224 		syslog(LOG_ERR, "%s: kvm_nlist: %s", _PATH_UNIX,
225 			kvm_geterr(kd_kern));
226 
227 	for (i = 0; cursyms[i] != -1; i++)
228 		if (current_nl[cursyms[i]].n_value == 0) {
229 			syslog(LOG_ERR, "%s: %s not in namelist",
230 			    _PATH_UNIX, current_nl[cursyms[i]].n_name);
231 			exit(1);
232 		}
233 
234 	(void)KREAD(kd_kern, current_nl[X_DUMPDEV].n_value, &dumpdev);
235 	if (dumpdev == NODEV) {
236 		syslog(LOG_WARNING, "no core dump (no dumpdev)");
237 		exit(1);
238 	}
239 	(void)KREAD(kd_kern, current_nl[X_DUMPLO].n_value, &dumplo);
240 	dumpoff = (off_t)dumplo * DEV_BSIZE;
241 	if (verbose)
242 		(void)printf("dumpoff = %lld (%ld * %d)\n",
243 		    (long long)dumpoff, dumplo, DEV_BSIZE);
244 	(void) KREAD(kd_kern, current_nl[X_DUMPMAG].n_value, &dumpmag);
245 
246 	if (kernel == NULL) {
247 		if (kvm_read(kd_kern, current_nl[X_VERSION].n_value,
248 		    vers, sizeof(vers)) == -1) {
249 			syslog(LOG_ERR, "%s: kvm_read: version misread", _PATH_UNIX);
250 			exit(1);
251 		}
252 		vers[sizeof(vers) - 1] = '\0';
253 	}
254 
255 	ddname = find_dev(dumpdev, S_IFBLK);
256 	dumpfd = Open(ddname, O_RDWR);
257 
258 	dump_sys = kernel ? kernel : _PATH_UNIX;
259 	kd_dump = kvm_openfiles(kernel, ddname, NULL, O_RDWR, errbuf);
260 	if (kd_dump == NULL) {
261 		syslog(LOG_ERR, "%s: kvm_openfiles: %s", dump_sys, errbuf);
262 		exit(1);
263 	}
264 
265 	if (kvm_nlist(kd_dump, dump_nl) == -1)
266 		syslog(LOG_ERR, "%s: kvm_nlist: %s", dump_sys,
267 			kvm_geterr(kd_dump));
268 
269 	for (i = 0; dumpsyms[i] != -1; i++)
270 		if (dump_nl[dumpsyms[i]].n_value == 0) {
271 			syslog(LOG_ERR, "%s: %s not in namelist",
272 			    dump_sys, dump_nl[dumpsyms[i]].n_name);
273 			exit(1);
274 		}
275 	hdrsz = kvm_dump_mkheader(kd_dump, dumpoff);
276 	if (hdrsz == -1) {
277 		if(verbose)
278 			syslog(LOG_ERR, "%s: kvm_dump_mkheader: %s", dump_sys,
279 				kvm_geterr(kd_dump));
280 		syslog(LOG_WARNING, "no core dump");
281 		exit(1);
282 	}
283 	dumpoff += hdrsz;
284 	kvm_close(kd_kern);
285 }
286 
287 void
288 check_kmem(void)
289 {
290 	char	*cp;
291 	int	panicloc;
292 	char core_vers[1024];
293 
294 	if (kvm_read(kd_dump, dump_nl[X_VERSION].n_value, core_vers,
295 	    sizeof(core_vers)) != sizeof(core_vers)) {
296 		syslog(LOG_ERR, "%s: kvm_read: version misread", dump_sys);
297 		exit(1);
298 	}
299 	core_vers[sizeof(core_vers) - 1] = '\0';
300 
301 	if (strcmp(vers, core_vers) && kernel == 0) {
302 		vers[strcspn(vers, "\n")] = '\0';
303 		core_vers[strcspn(core_vers, "\n")] = '\0';
304 
305 		syslog(LOG_WARNING,
306 		    "warning: %s version mismatch:\n\t%s\nand\t%s\n",
307 		    _PATH_UNIX, vers, core_vers);
308 	}
309 
310 	(void)KREAD(kd_dump, dump_nl[X_PANICSTR].n_value, &panicstr);
311 	if (panicstr) {
312 		char	c, visout[5];
313 		size_t	vislen;
314 
315 		cp       = panic_mesg;
316 		panicloc = panicstr;
317 		for (;;) {
318 			if (KREAD(kd_dump, panicloc, &c) != 0 || c == '\0')
319 				break;
320 			panicloc++;
321 
322 			vis(visout, c, VIS_SAFE|VIS_NOSLASH, 0);
323 			vislen = strlen(visout);
324 			if (cp - panic_mesg + vislen >= sizeof(panic_mesg))
325 				break;
326 			strlcat(cp, visout,
327 			    panic_mesg + sizeof panic_mesg - cp);
328 			cp += strlen(cp);
329 		}
330 	}
331 }
332 
333 int
334 dump_exists(void)
335 {
336 	u_long newdumpmag;
337 
338 	(void)KREAD(kd_dump, dump_nl[X_DUMPMAG].n_value, &newdumpmag);
339 
340 	/* Read the dump size. */
341 	(void)KREAD(kd_dump, dump_nl[X_DUMPSIZE].n_value, &dumppages);
342 	dumpsize = (u_long)dumppages * getpagesize();
343 
344 	/*
345 	 * Return zero if core dump doesn't seem to be there, and note
346 	 * it for syslog.  This check and return happens after the dump size
347 	 * is read, so dumpsize is whether or not the core is valid (for -f).
348 	 */
349 	if (newdumpmag != dumpmag) {
350 		if (verbose)
351 			syslog(LOG_WARNING,
352 			    "magic number mismatch (%lx != %lx)",
353 			    newdumpmag, dumpmag);
354 		syslog(LOG_WARNING, "no core dump");
355 		return (0);
356 	}
357 	return (1);
358 }
359 
360 void
361 clear_dump(void)
362 {
363 	if (kvm_dump_inval(kd_dump) == -1)
364 		syslog(LOG_ERR, "%s: kvm_clear_dump: %s", ddname,
365 			kvm_geterr(kd_dump));
366 
367 }
368 
369 char buf[1024 * 1024];
370 
371 void
372 save_core(void)
373 {
374 	FILE *fp;
375 	int bounds, ifd, nr, nw, ofd = -1;
376 	char *rawp, path[MAXPATHLEN];
377 	mode_t um;
378 
379 	um = umask(S_IRWXG|S_IRWXO);
380 
381 	/*
382 	 * Get the current number and update the bounds file.  Do the update
383 	 * now, because may fail later and don't want to overwrite anything.
384 	 */
385 	(void)snprintf(path, sizeof(path), "%s/bounds", dirn);
386 	if ((fp = fopen(path, "r")) == NULL)
387 		goto err1;
388 	if (fgets(buf, sizeof(buf), fp) == NULL) {
389 		if (ferror(fp))
390 err1:			syslog(LOG_WARNING, "%s: %s", path, strerror(errno));
391 		bounds = 0;
392 	} else
393 		bounds = atoi(buf);
394 	if (fp != NULL)
395 		(void)fclose(fp);
396 	if ((fp = fopen(path, "w")) == NULL)
397 		syslog(LOG_ERR, "%s: %m", path);
398 	else {
399 		(void)fprintf(fp, "%d\n", bounds + 1);
400 		(void)fclose(fp);
401 	}
402 
403 	/* Create the core file. */
404 	(void)snprintf(path, sizeof(path), "%s%s.%d.core%s",
405 	    dirn, _PATH_UNIX, bounds, zcompress ? ".Z" : "");
406 	if (zcompress) {
407 		if ((fp = zopen(path, "w", 0)) == NULL) {
408 			syslog(LOG_ERR, "%s: %s", path, strerror(errno));
409 			exit(1);
410 		}
411 	} else {
412 		ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
413 		fp  = fdopen(ofd, "w");
414 		if (fp == NULL) {
415 			syslog(LOG_ERR, "%s: fdopen: %s", path, strerror(errno));
416 			exit(1);
417 		}
418 	}
419 
420 	/* Open the raw device. */
421 	rawp = rawname(ddname);
422 	if ((ifd = open(rawp, O_RDONLY)) == -1) {
423 		syslog(LOG_WARNING, "%s: %m; using block device", rawp);
424 		ifd = dumpfd;
425 	}
426 
427 	/* Seek to the start of the core. */
428 	Lseek(ifd, dumpoff, SEEK_SET);
429 
430 	if (kvm_dump_wrtheader(kd_dump, fp, dumpsize) == -1) {
431 		syslog(LOG_ERR, "kvm_dump_wrtheader: %s : %s", path,
432 			kvm_geterr(kd_dump));
433 		exit(1);
434 	}
435 
436 	/* Copy the core file. */
437 	syslog(LOG_NOTICE, "writing %score to %s",
438 	    zcompress ? "compressed " : "", path);
439 	for (; dumpsize != 0; dumpsize -= nr) {
440 		(void)printf("%8luK\r", dumpsize / 1024);
441 		(void)fflush(stdout);
442 		nr = read(ifd, buf, MIN(dumpsize, sizeof(buf)));
443 		if (nr <= 0) {
444 			if (nr == 0)
445 				syslog(LOG_WARNING,
446 				    "WARNING: EOF on dump device");
447 			else
448 				syslog(LOG_ERR, "%s: %m", rawp);
449 			goto err2;
450 		}
451 		nw = fwrite(buf, 1, nr, fp);
452 		if (nw != nr) {
453 			syslog(LOG_ERR, "%s: %s",
454 			    path, strerror(nw == 0 ? EIO : errno));
455 err2:			syslog(LOG_WARNING,
456 			    "WARNING: core may be incomplete");
457 			(void)printf("\n");
458 			exit(1);
459 		}
460 	}
461 	(void)close(ifd);
462 	(void)fclose(fp);
463 
464 	/* Copy the kernel. */
465 	ifd = Open(kernel ? kernel : _PATH_UNIX, O_RDONLY);
466 	(void)snprintf(path, sizeof(path), "%s%s.%d%s",
467 	    dirn, _PATH_UNIX, bounds, zcompress ? ".Z" : "");
468 	if (zcompress) {
469 		if ((fp = zopen(path, "w", 0)) == NULL) {
470 			syslog(LOG_ERR, "%s: %s", path, strerror(errno));
471 			exit(1);
472 		}
473 	} else
474 		ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
475 	syslog(LOG_NOTICE, "writing %skernel to %s",
476 	    zcompress ? "compressed " : "", path);
477 	while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
478 		if (zcompress)
479 			nw = fwrite(buf, 1, nr, fp);
480 		else
481 			nw = write(ofd, buf, nr);
482 		if (nw != nr) {
483 			syslog(LOG_ERR, "%s: %s",
484 			    path, strerror(nw == 0 ? EIO : errno));
485 			syslog(LOG_WARNING,
486 			    "WARNING: kernel may be incomplete");
487 			exit(1);
488 		}
489 	}
490 	if (nr < 0) {
491 		syslog(LOG_ERR, "%s: %s",
492 		    kernel ? kernel : _PATH_UNIX, strerror(errno));
493 		syslog(LOG_WARNING,
494 		    "WARNING: kernel may be incomplete");
495 		exit(1);
496 	}
497 	if (zcompress)
498 		(void)fclose(fp);
499 	else
500 		(void)close(ofd);
501 	(void)umask(um);
502 }
503 
504 char *
505 find_dev(dev_t dev, int type)
506 {
507 	DIR *dfd;
508 	struct dirent *dir;
509 	struct stat sb;
510 	char *dp, devname[MAXPATHLEN];
511 
512 	if ((dfd = opendir(_PATH_DEV)) == NULL) {
513 		syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno));
514 		exit(1);
515 	}
516 	(void)strlcpy(devname, _PATH_DEV, sizeof devname);
517 	while ((dir = readdir(dfd))) {
518 		(void)strlcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name,
519 		    sizeof devname - (sizeof(_PATH_DEV) - 1));
520 		if (lstat(devname, &sb)) {
521 			syslog(LOG_ERR, "%s: %s", devname, strerror(errno));
522 			continue;
523 		}
524 		if ((sb.st_mode & S_IFMT) != type)
525 			continue;
526 		if (dev == sb.st_rdev) {
527 			closedir(dfd);
528 			if ((dp = strdup(devname)) == NULL) {
529 				syslog(LOG_ERR, "%s", strerror(errno));
530 				exit(1);
531 			}
532 			return (dp);
533 		}
534 	}
535 	closedir(dfd);
536 	syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev));
537 	exit(1);
538 }
539 
540 char *
541 rawname(char *s)
542 {
543 	char *sl, name[MAXPATHLEN];
544 
545 	if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') {
546 		syslog(LOG_ERR,
547 		    "can't make raw dump device name from %s", s);
548 		return (s);
549 	}
550 	(void)snprintf(name, sizeof(name), "%.*s/r%s", (int)(sl - s), s, sl + 1);
551 	if ((sl = strdup(name)) == NULL) {
552 		syslog(LOG_ERR, "%s", strerror(errno));
553 		exit(1);
554 	}
555 	return (sl);
556 }
557 
558 int
559 get_crashtime(void)
560 {
561 	time_t dumptime;			/* Time the dump was taken. */
562 
563 	(void)KREAD(kd_dump, dump_nl[X_TIME].n_value, &dumptime);
564 	if (dumptime == 0) {
565 		if (verbose)
566 			syslog(LOG_ERR, "dump time is zero");
567 		return (0);
568 	}
569 	(void)printf("savecore: system went down at %s", ctime(&dumptime));
570 #define	LEEWAY	(7 * SECSPERDAY)
571 	if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
572 		(void)printf("dump time is unreasonable\n");
573 		return (0);
574 	}
575 	return (1);
576 }
577 
578 int
579 check_space(void)
580 {
581 	FILE *fp;
582 	char *tkernel;
583 	off_t minfree, spacefree, kernelsize, needed;
584 	struct stat st;
585 	struct statfs fsbuf;
586 	char buf[100], path[MAXPATHLEN];
587 	int fd;
588 
589 	tkernel = kernel ? kernel : _PATH_UNIX;
590 	if (stat(tkernel, &st) < 0) {
591 		syslog(LOG_ERR, "%s: %m", tkernel);
592 		exit(1);
593 	}
594 	kernelsize = st.st_blocks * S_BLKSIZE;
595 	if ((fd = open(dirn, O_RDONLY, 0)) < 0 || fstatfs(fd, &fsbuf) < 0) {
596 		syslog(LOG_ERR, "%s: %m", dirn);
597 		exit(1);
598 	}
599 	close(fd);
600 	spacefree = ((off_t)fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
601 
602 	(void)snprintf(path, sizeof(path), "%s/minfree", dirn);
603 	if ((fp = fopen(path, "r")) == NULL)
604 		minfree = 0;
605 	else {
606 		if (fgets(buf, sizeof(buf), fp) == NULL)
607 			minfree = 0;
608 		else
609 			minfree = atoi(buf);
610 		(void)fclose(fp);
611 	}
612 
613 	needed = (dumpsize + kernelsize) / 1024;
614 	if (minfree > 0 && spacefree - needed < minfree) {
615 		syslog(LOG_WARNING,
616 		    "no dump, not enough free space on device");
617 		return (0);
618 	}
619 	if (spacefree - needed < minfree)
620 		syslog(LOG_WARNING,
621 		    "dump performed, but free space threshold crossed");
622 	return (1);
623 }
624 
625 int
626 Open(char *name, int rw)
627 {
628 	int fd;
629 
630 	if ((fd = open(name, rw, 0)) < 0) {
631 		syslog(LOG_ERR, "%s: %m", name);
632 		exit(1);
633 	}
634 	return (fd);
635 }
636 
637 void
638 Lseek(int fd, off_t off, int flag)
639 {
640 	off_t ret;
641 
642 	ret = lseek(fd, off, flag);
643 	if (ret == -1) {
644 		syslog(LOG_ERR, "lseek: %m");
645 		exit(1);
646 	}
647 }
648 
649 int
650 Create(char *file, int mode)
651 {
652 	int fd;
653 
654 	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
655 	if (fd < 0) {
656 		syslog(LOG_ERR, "%s: %m", file);
657 		exit(1);
658 	}
659 	return (fd);
660 }
661 
662 void
663 usage(void)
664 {
665 	extern char *__progname;
666 	fprintf(stderr, "usage: %s [-cfvz] [-N system] directory\n",
667 		__progname);
668 	exit(1);
669 }
670