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