xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fssnap/fssnap.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <sys/fssnap_if.h>
39 #include <sys/filio.h>
40 #include <setjmp.h>
41 #include <stdarg.h>
42 #include <kstat.h>
43 #include <libintl.h>
44 #include <libdevinfo.h>
45 #include <sys/sysmacros.h>
46 #include <sys/fs/ufs_fs.h>
47 #include <sys/fs/ufs_snap.h>
48 
49 #define	SNAP_CTL_PATH	"/dev/" SNAP_CTL_NAME
50 
51 #define	MAX_SUFFIX	6	/* '.' + 4 chars of number + trailing '\0' */
52 
53 #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
54 
55 static int max_uniq = 9999;
56 
57 void create_snap(int, char *, u_offset_t, uint_t, int, int);
58 void delete_snap(int);
59 void stats_snap(char *, char *);
60 
61 int open_backpath(int, u_offset_t, char **, char **, int **);
62 u_offset_t spec_to_bytes(char *);
63 void gen_backing_store_path(char *basepath, int num, char **outpath);
64 void unlink_all(char *, int);
65 void close_all(char *, int, int *);
66 int open_multi_backfile(char *, int, int **, int);
67 
68 void die_perror(char *);
69 void die_errno(int, char *, ...);
70 void die_create_error(int error);
71 void die_usage(void);
72 void die(char *, ...);
73 void warn_errno(int, char *,  ...);
74 void usage(void);
75 
76 static char *subopts[] = {
77 #define	BACKPATH	(0)
78 	"backing-store",
79 #define	BACKPATH2	(1)
80 	"bs",
81 #define	BACKPATH3	(2)
82 	"bf",
83 #define	MAXSIZE		(3)
84 	"maxsize",
85 #define	CHUNKSIZE	(4)
86 	"chunksize",
87 #define	RAWFILE		(5)
88 	"raw",
89 #define	UNLINK		(6)
90 	"unlink",
91 	NULL
92 };
93 
94 static jmp_buf err_main;
95 static char *progname = NULL;
96 static int backout_snap_fd = -1;
97 
98 extern void fssnap_show_status(char *mountpoint, char *opts, int labels,
99     int brief); /* in ../../fssnapsup.c */
100 
101 int
102 main(int argc, char *argv[])
103 {
104 	int c;
105 	char *suboptions = NULL;
106 	char *value;
107 	int longjmp_return;
108 
109 	char *mountpoint = NULL;
110 	int mountfd = -1;
111 	char *backpath = NULL;
112 
113 	int delete = 0;
114 	int stats = 0;
115 	u_offset_t maxsize = 0;
116 	uint_t chunksize = 0;
117 	int rawfile = 0;
118 	int dounlink = 0;
119 
120 	if ((progname = strrchr(argv[0], '/')) != NULL)
121 		++progname;
122 	else
123 		progname = argv[0];
124 
125 	if ((longjmp_return = setjmp(err_main)) != 0) {
126 		if (backout_snap_fd >= 0) {
127 			mountfd = backout_snap_fd;
128 			backout_snap_fd = -1; /* prevent infinite loop */
129 			delete_snap(mountfd);
130 		}
131 
132 		return (longjmp_return);
133 	}
134 
135 	while ((c = getopt(argc, argv, "dio:")) != EOF) {
136 		switch (c) {
137 		case 'd':
138 			++delete;
139 			break;
140 
141 		case 'i':
142 			++stats;
143 			break;
144 
145 		case 'o':
146 			suboptions = optarg;
147 			break;
148 
149 		default:
150 			die_usage();
151 		}
152 	}
153 
154 	/* if -i or -d are not specified then interpret the create options */
155 	if ((stats == 0) && (delete == 0) && (suboptions != NULL)) {
156 		while (*suboptions != '\0') {
157 
158 			switch ((getsubopt(&suboptions, subopts, &value))) {
159 			case BACKPATH:
160 			case BACKPATH2:
161 			case BACKPATH3:
162 				if (value == NULL)
163 					die_usage();
164 				backpath = strdup(value);
165 				if (backpath == NULL) {
166 					die_perror("strdup");
167 				}
168 				break;
169 
170 			case MAXSIZE:
171 				maxsize = spec_to_bytes(value);
172 				break;
173 
174 			case CHUNKSIZE:
175 				chunksize = spec_to_bytes(value);
176 				break;
177 
178 			case RAWFILE:
179 				++rawfile;
180 				break;
181 
182 			case UNLINK:
183 				++dounlink;
184 				break;
185 
186 			default:
187 				die_usage();
188 			}
189 		}
190 	}
191 
192 	/* -d and -i can not be specified together or more than once each */
193 	if ((delete + stats) > 1)
194 		die_usage();
195 
196 	/* If no mount point is specified then -i is the only valid option. */
197 	if ((optind >= argc) && (stats == 0))
198 		die_usage();
199 
200 	/*
201 	 * If anything but the mount point or device is specified at the end
202 	 * it's an error.
203 	 */
204 	if (optind != (argc - 1)) {
205 		if (!stats)
206 			die_usage();
207 	} else {
208 		/* Otherwise, the last option is the mountpoint. */
209 		mountpoint = argv[optind];
210 		if ((mountfd = open(mountpoint, O_RDONLY)) < 0)
211 			die_perror(mountpoint);
212 	}
213 
214 	if (stats != 0) {
215 		stats_snap(mountpoint, suboptions);
216 	} else if (delete != 0) {
217 		delete_snap(mountfd);
218 	} else {
219 		/*
220 		 * backpath may be invalid upon return of create_snap call.
221 		 */
222 		create_snap(mountfd, backpath, maxsize, chunksize,
223 		    rawfile, dounlink);
224 	}
225 
226 	return (0);
227 }
228 
229 void
230 create_snap(int mountfd, char *backpath, u_offset_t maxsize, uint_t chunksize,
231     int rawfile, int dounlink)
232 {
233 	struct fiosnapcreate_multi *enable;
234 	int backcount;
235 	int ctlfd;
236 	char *unlinkpath = NULL;
237 	di_devlink_handle_t hdl;
238 	int *fd_array;
239 	u_offset_t max_bf_size;
240 	int save_errno;
241 
242 	/*
243 	 * If chunksize is not a power of 2, the maximum size of a
244 	 * backing store file might not be UFS_MAX_SNAPBACKFILESIZE,
245 	 * since the size of the backing store files must be an
246 	 * integral number of chunks (except for the last one).  So
247 	 * calculate the actual maximum backing store file size.
248 	 * (It would be nice if we could assume that the chunksize
249 	 * was a power of 2, but we can't.)
250 	 */
251 
252 	if (chunksize != 0 && !POWEROF2(chunksize))
253 		max_bf_size = (UFS_MAX_SNAPBACKFILESIZE/chunksize) * chunksize;
254 	else
255 		max_bf_size = UFS_MAX_SNAPBACKFILESIZE;
256 
257 	/*
258 	 * open_backpath() only returns on success, and
259 	 * can change the value of backpath when backpath
260 	 * references a directory.
261 	 */
262 	if (backpath == NULL)
263 		die(gettext("No backing store path specified.\n"));
264 	backcount = open_backpath(mountfd, max_bf_size, &backpath,
265 	    &unlinkpath, &fd_array);
266 
267 	/*
268 	 * Only need backcount - 1 spaces for fd's since
269 	 * fiosnapcreate_multi struct contains space for the
270 	 * first one.
271 	 */
272 	if ((enable = calloc(1, sizeof (struct fiosnapcreate_multi) +
273 	    (backcount - 1) * sizeof (int))) == NULL)
274 		die(gettext("Insufficient memory.\n"));
275 
276 	enable->backfilecount = backcount;
277 	bcopy(fd_array, &(enable->backfiledesc), backcount * sizeof (int));
278 
279 	enable->rootfiledesc = mountfd;
280 
281 	enable->maxsize = maxsize;
282 	enable->chunksize = chunksize;
283 	enable->backfilesize = max_bf_size;
284 
285 	/*
286 	 * enable.backfilename is advisory only.  So, we don't overflow
287 	 * the buffer, but we don't give an error if the backpath does not
288 	 * fit.  Instead, it is truncated, and the kstat shows all it can.
289 	 */
290 	if (backpath != NULL) {
291 		if (dounlink)
292 			(void) snprintf(enable->backfilename,
293 			    sizeof (enable->backfilename) - 1, "%s <UNLINKED>",
294 			    backpath);
295 		else
296 			(void) strncpy(enable->backfilename, backpath,
297 			    sizeof (enable->backfilename) - 1);
298 		enable->backfilename[sizeof (enable->backfilename)-1] = '\0';
299 	}
300 
301 	if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) {
302 		unlink_all(unlinkpath, backcount);
303 		die_perror(SNAP_CTL_PATH);
304 	}
305 
306 	if (ioctl(ctlfd, _FIOSNAPSHOTCREATE_MULTI, enable) == -1) {
307 		unlink_all(unlinkpath, backcount);
308 		if (enable->error != 0) {
309 			die_create_error(enable->error);
310 		} else {
311 			die_perror("ioctl");
312 		}
313 	}
314 
315 	backout_snap_fd = mountfd;
316 	if (dounlink != 0)
317 		unlink_all(unlinkpath, backcount);
318 
319 	if (close(ctlfd) != 0) {
320 		save_errno = errno;
321 		die_errno(save_errno, gettext("close of control file (%s)"),
322 		    SNAP_CTL_PATH);
323 	}
324 
325 	close_all(unlinkpath, backcount, fd_array);
326 
327 	if ((hdl = di_devlink_init("fssnap", DI_MAKE_LINK)) == NULL) {
328 		save_errno = errno;
329 		warn_errno(save_errno,
330 		    gettext("/dev/%s/%d may not be immediately available\n"),
331 		    (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME,
332 		    enable->snapshotnumber);
333 	} else {
334 		(void) di_devlink_fini(&hdl);
335 	}
336 
337 	/* intentionally not internationalized */
338 	printf("/dev/%s/%d\n", (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME,
339 	    enable->snapshotnumber);
340 
341 	free(enable);
342 }
343 
344 void
345 delete_snap(int mountfd)
346 {
347 	struct fiosnapdelete disable;
348 	int ctlfd;
349 	int save_errno;
350 
351 	bzero(&disable, sizeof (disable));
352 	if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1)
353 		die_perror(SNAP_CTL_PATH);
354 
355 	disable.rootfiledesc = mountfd;
356 	if (ioctl(ctlfd, _FIOSNAPSHOTDELETE, &disable) == -1) {
357 		if (disable.error) {
358 			die(gettext("error %d"), disable.error);
359 		} else {
360 			die_perror("ioctl");
361 		}
362 	}
363 
364 	if (close(ctlfd) != 0) {
365 		save_errno = errno;
366 		die_errno(save_errno, gettext("close of control file (%s)"),
367 		    SNAP_CTL_PATH);
368 	}
369 
370 	printf(gettext("Deleted snapshot %d.\n"), disable.snapshotnumber);
371 }
372 
373 void
374 stats_snap(char *mountpath, char *opts)
375 {
376 	fssnap_show_status(mountpath, opts, ((opts != NULL) ? 0 : 1), 0);
377 }
378 
379 /*
380  * Open as many backing files as necessary for this snapshot.
381  * There will be one backing file for each max_bf_size
382  * number of bytes in the file system being snapped.
383  * The array of file descriptors for the backing files is returned in
384  * fd_array.  The number of backing files is the return value of the
385  * function.  The name of the first backing file is returned in
386  * unlinkpath.  The subsequent backing files are assumed to have the
387  * same name as the first, but with suffixes, .2, .3, etc.
388  */
389 int
390 open_backpath(int mountfd, u_offset_t max_bf_size, char **path,
391     char **unlinkpath, int **fd_array)
392 {
393 	struct stat st;
394 	struct statvfs vfs;
395 	int fd, uniq, len;
396 	int ret_errno, i, num_back_files;
397 	offset_t fssize, backfilesize;
398 	char *locpath = NULL;
399 	int save_errno;
400 
401 	*unlinkpath = NULL;
402 
403 	/* determine size of the file system to be snapped */
404 	if (fstatvfs(mountfd, &vfs) == -1)
405 		die_perror("statvfs");
406 
407 	fssize = vfs.f_blocks * vfs.f_frsize;
408 	num_back_files = howmany(fssize, max_bf_size);
409 
410 	if (stat(*path, &st) < 0) {
411 		/*
412 		 * Since we set the file_exists_is_fatal argument to 1,
413 		 * if we return at all, it will be with all the backing
414 		 * files successfully created and opened.
415 		 */
416 		(void) open_multi_backfile(*path, num_back_files, fd_array, 1);
417 		*unlinkpath = strdup(*path);
418 		if (unlinkpath == NULL)
419 			die_perror("strdup");
420 	} else if (S_ISDIR(st.st_mode)) {
421 		char temppath[MAXPATHLEN];
422 
423 		/* remove a trailing slash from the name */
424 		len = strlen(*path) - 1;
425 		if ((*path)[len] == '/')
426 			(*path)[len] = '\0';
427 
428 		/* find a unique name */
429 		for (uniq = 0; uniq <= max_uniq; uniq++) {
430 			/* cannot use tempnam, since TMPDIR overrides path */
431 			(void) snprintf(temppath, MAXPATHLEN, "%s/snapshot%d",
432 			    *path, uniq);
433 			ret_errno = open_multi_backfile(temppath,
434 			    num_back_files, fd_array, 0);
435 			if (ret_errno == 0)
436 				break;
437 		}
438 		if (uniq > max_uniq) {
439 			die(gettext("Could not find unique name in %s"), *path);
440 		}
441 		*unlinkpath = strdup(temppath);
442 		free(*path);
443 		*path = *unlinkpath;
444 	} else if (S_ISREG(st.st_mode)) {
445 		die(gettext("%s already exists."), *path);
446 	} else {
447 		die(gettext("%s: must be either the name of a file to create "
448 		    "or a directory."), *path);
449 	}
450 
451 	/*
452 	 * write a block to the end to bump up the file size and ensure the
453 	 * entire range needed can be written to.
454 	 */
455 	for (i = 0; i < num_back_files; i++) {
456 		fd = (*fd_array)[i];
457 		if (i == num_back_files - 1 && fssize % max_bf_size != 0)
458 			backfilesize = fssize % max_bf_size;
459 		else
460 			backfilesize = max_bf_size;
461 		if (llseek(fd, backfilesize - 1, SEEK_SET) == -1) {
462 			unlink_all(*unlinkpath, num_back_files);
463 			die_perror("llseek");
464 		}
465 
466 		if (write(fd, "0", 1) == -1) {
467 			save_errno = errno;
468 			unlink_all(*unlinkpath, num_back_files);
469 			if (save_errno == EFBIG)
470 				die(gettext("File system %s "
471 				    "does not support large files.\n"), *path);
472 			else
473 				die_perror("write");
474 		}
475 	}
476 	return (num_back_files);
477 }
478 
479 u_offset_t
480 spec_to_bytes(char *spec)
481 {
482 	u_offset_t base;
483 
484 	base = strtoull(spec, NULL, 10);
485 	if ((base == 0LL) && (spec[0] != '0'))
486 		die(gettext("Numeric option value expected"));
487 
488 	spec += strspn(spec, "0123456789");
489 
490 	if ((spec == NULL) || strlen(spec) != 1)
491 		die(gettext("Only one of b, k, m, or g may be used"));
492 
493 	switch (spec[0]) {
494 	case 'B':
495 	case 'b':
496 		base *= 512;
497 		break;
498 	case 'K':
499 	case 'k':
500 		base *= 1024;
501 		break;
502 	case 'M':
503 	case 'm':
504 		base *= 1024 * 1024;
505 		break;
506 	case 'G':
507 	case 'g':
508 		base *= 1024 * 1024 * 1024;
509 		break;
510 	default:
511 		die(gettext("Must specify one of b, k, m, or g on size"));
512 	}
513 
514 	return (base);
515 }
516 
517 /*
518  * Make sure that the first call to gen_backing_store() in a loop
519  * starts with a null pointer in the outpath argument
520  * and continues to pass in that same argument until
521  * the loop is complete, at which point the string
522  * pointed to by that argument must be freed by the caller.
523  */
524 void
525 gen_backing_store_path(char *basepath, int num, char **outpath)
526 {
527 	if (*outpath == NULL) {
528 		*outpath = malloc(strlen(basepath) + MAX_SUFFIX);
529 		if (*outpath == NULL)
530 			die_perror("malloc");
531 	}
532 
533 	/*
534 	 * Security note:  We use strcpy here, instead of the safer
535 	 * strncpy, because the string pointed to by outpath has
536 	 * been generated by THIS code, above.  Hence it is impossible
537 	 * for the strcpy to overrun the buffer.
538 	 */
539 	if (num == 1)
540 		(void) strcpy(*outpath, basepath);
541 	else
542 		(void) sprintf(*outpath, "%s.%d", basepath, num);
543 }
544 
545 void
546 unlink_all(char *unlinkpath, int count)
547 {
548 	char	*bspath = NULL;
549 	int 	i;
550 	int	save_errno;
551 
552 	for (i = 1; i <= count; i++) {
553 		/*
554 		 * Make sure that the first call to gen_backing_store()
555 		 * starts with a null pointer in the third argument
556 		 * and continues to pass in that same argument until
557 		 * the loop is complete, at which point the string
558 		 * pointed to by that argument must be freed.
559 		 */
560 		gen_backing_store_path(unlinkpath, i, &bspath);
561 		if (unlink(bspath) < 0) {
562 			save_errno = errno;
563 			warn_errno(save_errno,
564 			    gettext("could not unlink %s"), bspath);
565 		}
566 	}
567 	free(bspath);
568 }
569 
570 void
571 close_all(char *closepath, int count, int *fd_array)
572 {
573 	char	*bspath = NULL;
574 	int 	i;
575 	int	save_errno;
576 
577 	for (i = 1; i <= count; i++) {
578 		if (close(fd_array[i - 1]) != 0) {
579 			save_errno = errno;
580 			/*
581 			 * Make sure that the first call to gen_backing_store()
582 			 * starts with a null pointer in the third argument
583 			 * and continues to pass in that same argument until
584 			 * the loop is complete, at which point the string
585 			 * pointed to by that argument must be freed.
586 			 */
587 			gen_backing_store_path(closepath, i, &bspath);
588 			die_errno(save_errno, gettext(
589 			    "close of backing-store (%s)"), bspath);
590 		}
591 	}
592 	if (bspath != NULL)
593 		free(bspath);
594 }
595 
596 /*
597  * Create "count" files starting with name backpath ("backpath",
598  * "backpath".2, "backpath".3, etc.  When this function returns,
599  * either all of the files will exist and be opened (and their
600  * file descriptors will be in fd_array), or NONE of will exist
601  * (if they had to be created) and opened (that is, if we created a file,
602  * and then failed to create a later file, the earlier files will
603  * be closed and unlinked.)
604  *
605  * If file_exists_is_fatal is set, it is a fatal error (resulting in
606  * an error message and termination) if any of the backing files to
607  * be created already exists.  Otherwise, if one of the backing
608  * files already exists, we close and unlink all the files we already
609  * created, and return an error to the caller, but we don't print
610  * an error or terminate.
611  *
612  * If there is any failure other than EEXIST when attempting to
613  * create the file, the routine prints an error and terminates the
614  * program, regardless of the setting of file_exists_is_fatal.
615  */
616 int
617 open_multi_backfile(char *backpath, int count, int **fd_array,
618     int file_exists_is_fatal)
619 {
620 	char	*wpath = NULL;		/* working path */
621 	int	i, j, fd;
622 	struct stat st;
623 	int	stat_succeeded = 0;
624 	int	save_errno;
625 
626 	*fd_array = (int *)malloc(count * sizeof (int));
627 	if (*fd_array == NULL)
628 		die_perror("malloc");
629 
630 	for (i = 0; i < count; i++) {
631 		/*
632 		 * Make sure that the first call to gen_backing_store()
633 		 * starts with a null pointer in the third argument
634 		 * and continues to pass in that same argument until
635 		 * the loop is complete, at which point the string
636 		 * pointed to by that argument must be freed.
637 		 */
638 		gen_backing_store_path(backpath, i + 1, &wpath);
639 		if (stat(wpath, &st) == 0)
640 			stat_succeeded = 1;
641 		else
642 			fd = open(wpath, O_RDWR | O_CREAT | O_EXCL, 0600);
643 		if (stat_succeeded || fd < 0) {
644 			if (i > 0) {
645 				for (j = 0; j < i - 1; j++)
646 					(void) close((*fd_array)[j]);
647 				/*
648 				 * unlink_all's second argument is the number
649 				 * of files to be removed, NOT the offset
650 				 * into the array of fd's of the last
651 				 * successfully created file.
652 				 */
653 				unlink_all(backpath, i);
654 			}
655 			if (stat_succeeded || errno == EEXIST) {
656 				if (file_exists_is_fatal)
657 					die(gettext("%s exists, please specify"
658 					    " a nonexistent backing store."),
659 					    wpath);
660 				else
661 					return (1);
662 			} else {
663 					save_errno = errno;
664 					die_errno(save_errno,
665 					    gettext("Could not create"
666 					    " backing file %s"), wpath);
667 			}
668 		}
669 		(*fd_array)[i] = fd;
670 	}
671 	if (wpath != NULL)
672 		free(wpath);
673 	return (0);
674 }
675 
676 void
677 die_perror(char *string)
678 {
679 	int en = errno;
680 	char *errstr;
681 
682 	if (string == NULL) {
683 		string = gettext("Fatal");
684 	}
685 	errstr = strerror(en);
686 	if (errstr == NULL) {
687 		errstr = gettext("Unknown error");
688 	}
689 
690 	fprintf(stderr, gettext("%s: %s: error %d: %s\n"),
691 	    progname, string, en, errstr);
692 
693 	longjmp(err_main, 2);
694 }
695 
696 void
697 die_usage(void)
698 {
699 	usage();
700 
701 	longjmp(err_main, 1);
702 }
703 
704 void
705 warn_errno(int en, char *fmt, ...)
706 {
707 	va_list ap;
708 	char *errstr;
709 
710 	errstr = strerror(en);
711 	if (errstr == NULL) {
712 		errstr = gettext("Unknown error");
713 	}
714 
715 	va_start(ap, fmt);
716 	fprintf(stderr, gettext("%s: Warning: "), progname);
717 	vfprintf(stderr, fmt, ap);
718 	fprintf(stderr, ": %s\n", errstr);
719 	va_end(ap);
720 }
721 
722 void
723 die_errno(int en, char *fmt, ...)
724 {
725 	va_list ap;
726 	char *errstr;
727 
728 	errstr = strerror(en);
729 	if (errstr == NULL) {
730 		errstr = gettext("Unknown error");
731 	}
732 
733 	va_start(ap, fmt);
734 	fprintf(stderr, gettext("%s: Fatal: "), progname);
735 	vfprintf(stderr, fmt, ap);
736 	fprintf(stderr, ": %s\n", errstr);
737 	va_end(ap);
738 
739 	longjmp(err_main, 2);
740 }
741 
742 void
743 die_create_error(int error)
744 {
745 	fprintf(stderr, gettext("snapshot error: "));
746 	switch (error) {
747 	case FIOCOW_EREADONLY:
748 		fprintf(stderr, gettext("Read only file system\n"));
749 		break;
750 	case FIOCOW_EBUSY:
751 		fprintf(stderr, gettext("Snapshot already enabled\n"));
752 		break;
753 	case FIOCOW_EULOCK:
754 		fprintf(stderr, gettext("File system is locked\n"));
755 		break;
756 	case FIOCOW_EWLOCK:
757 		fprintf(stderr,
758 		    gettext("File system could not be write locked\n"));
759 		break;
760 	case FIOCOW_EFLUSH:
761 		fprintf(stderr, gettext("File system could not be flushed\n"));
762 		break;
763 	case FIOCOW_ECLEAN:
764 		fprintf(stderr, gettext("File system may not be stable\n"));
765 		break;
766 	case FIOCOW_ENOULOCK:
767 		fprintf(stderr, gettext("File system could not be unlocked\n"));
768 		break;
769 	case FIOCOW_ECHUNKSZ:
770 		fprintf(stderr, gettext("Chunk size must be a multiple of the "
771 		    "fragment size\n"));
772 		break;
773 	case FIOCOW_ECREATE:
774 		fprintf(stderr, gettext("Could not allocate or create "
775 		    "a new snapshot\n"));
776 		break;
777 	case FIOCOW_EBITMAP:
778 		fprintf(stderr,
779 		    gettext("Error scanning file system bitmaps\n"));
780 		break;
781 	case FIOCOW_EBACKFILE:
782 		fprintf(stderr, gettext("Invalid backing file path\n"));
783 		break;
784 	default:
785 		fprintf(stderr, gettext("Unknown create error\n"));
786 		break;
787 	}
788 
789 	longjmp(err_main, 2);
790 }
791 
792 void
793 die(char *fmt, ...)
794 {
795 	va_list ap;
796 
797 	va_start(ap, fmt);
798 	fprintf(stderr, gettext("%s: Fatal: "), progname);
799 	vfprintf(stderr, fmt, ap);
800 	fprintf(stderr, "\n");
801 	va_end(ap);
802 
803 	longjmp(err_main, 2);
804 }
805 
806 void
807 usage(void)
808 {
809 	int  i;
810 	char *use_str[] = {
811 		"   %s [-F ufs] [-V] -o backing-store=path,[special_options] "
812 		    "/mount/point\n",
813 		"   %s -d [-F ufs] [-V] /mount/point | dev\n",
814 		"   %s -i [-F ufS] [-V] [-o special-options] /mount/point "
815 		    "| dev\n",
816 		NULL
817 	};
818 	fprintf(stderr, gettext("Usage:\n"));
819 	for (i = 0; use_str[i] != NULL; i++)
820 		fprintf(stderr, gettext(use_str[i]), progname);
821 }
822