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
main(int argc,char * argv[])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
create_snap(int mountfd,char * backpath,u_offset_t maxsize,uint_t chunksize,int rawfile,int dounlink)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
delete_snap(int mountfd)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
stats_snap(char * mountpath,char * opts)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
open_backpath(int mountfd,u_offset_t max_bf_size,char ** path,char ** unlinkpath,int ** fd_array)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
spec_to_bytes(char * spec)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
gen_backing_store_path(char * basepath,int num,char ** outpath)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
unlink_all(char * unlinkpath,int count)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
close_all(char * closepath,int count,int * fd_array)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
open_multi_backfile(char * backpath,int count,int ** fd_array,int file_exists_is_fatal)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
die_perror(char * string)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
die_usage(void)697 die_usage(void)
698 {
699 usage();
700
701 longjmp(err_main, 1);
702 }
703
704 void
warn_errno(int en,char * fmt,...)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
die_errno(int en,char * fmt,...)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
die_create_error(int error)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
die(char * fmt,...)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
usage(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