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