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.
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.
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]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
33 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/fssnap_if.h>
37 #include <sys/filio.h>
42 #include <libdevinfo.h>
43 #include <sys/sysmacros.h>
44 #include <sys/fs/ufs_fs.h>
45 #include <sys/fs/ufs_snap.h>
47 #define SNAP_CTL_PATH "/dev/" SNAP_CTL_NAME
49 #define MAX_SUFFIX 6 /* '.' + 4 chars of number + trailing '\0' */
51 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
53 static int max_uniq
= 9999;
55 void create_snap(int, char *, u_offset_t
, uint_t
, int, int);
56 void delete_snap(int);
57 void stats_snap(char *, char *);
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);
66 void die_perror(char *);
67 void die_errno(int, char *, ...);
68 void die_create_error(int error
);
70 void die(char *, ...);
71 void warn_errno(int, char *, ...);
74 static char *subopts
[] = {
92 static jmp_buf err_main
;
93 static char *progname
= NULL
;
94 static int backout_snap_fd
= -1;
96 extern void fssnap_show_status(char *mountpoint
, char *opts
, int labels
,
97 int brief
); /* in ../../fssnapsup.c */
100 main(int argc
, char *argv
[])
103 char *suboptions
= NULL
;
107 char *volatile mountpoint
= NULL
;
108 int volatile mountfd
= -1;
109 char *volatile backpath
= NULL
;
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;
118 if ((progname
= strrchr(argv
[0], '/')) != NULL
)
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
);
130 return (longjmp_return
);
133 while ((c
= getopt(argc
, argv
, "dio:")) != EOF
) {
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') {
156 switch ((getsubopt(&suboptions
, subopts
, &value
))) {
162 backpath
= strdup(value
);
163 if (backpath
== NULL
) {
164 die_perror("strdup");
169 maxsize
= spec_to_bytes(value
);
173 chunksize
= spec_to_bytes(value
);
190 /* -d and -i can not be specified together or more than once each */
191 if ((delete + stats
) > 1)
194 /* If no mount point is specified then -i is the only valid option. */
195 if ((optind
>= argc
) && (stats
== 0))
199 * If anything but the mount point or device is specified at the end
202 if (optind
!= (argc
- 1)) {
206 /* Otherwise, the last option is the mountpoint. */
207 mountpoint
= argv
[optind
];
208 if ((mountfd
= open(mountpoint
, O_RDONLY
)) < 0)
209 die_perror(mountpoint
);
213 stats_snap(mountpoint
, suboptions
);
214 } else if (delete != 0) {
215 delete_snap(mountfd
);
218 * backpath may be invalid upon return of create_snap call.
220 create_snap(mountfd
, backpath
, maxsize
, chunksize
,
228 create_snap(int mountfd
, char *backpath
, u_offset_t maxsize
, uint_t chunksize
,
229 int rawfile
, int dounlink
)
231 struct fiosnapcreate_multi
*enable
;
234 char *unlinkpath
= NULL
;
235 di_devlink_handle_t hdl
;
237 u_offset_t max_bf_size
;
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.)
250 if (chunksize
!= 0 && !POWEROF2(chunksize
))
251 max_bf_size
= (UFS_MAX_SNAPBACKFILESIZE
/chunksize
) * chunksize
;
253 max_bf_size
= UFS_MAX_SNAPBACKFILESIZE
;
256 * open_backpath() only returns on success, and
257 * can change the value of backpath when backpath
258 * references a directory.
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
);
266 * Only need backcount - 1 spaces for fd's since
267 * fiosnapcreate_multi struct contains space for the
270 if ((enable
= calloc(1, sizeof (struct fiosnapcreate_multi
) +
271 (backcount
- 1) * sizeof (int))) == NULL
)
272 die(gettext("Insufficient memory.\n"));
274 enable
->backfilecount
= backcount
;
275 bcopy(fd_array
, &(enable
->backfiledesc
), backcount
* sizeof (int));
277 enable
->rootfiledesc
= mountfd
;
279 enable
->maxsize
= maxsize
;
280 enable
->chunksize
= chunksize
;
281 enable
->backfilesize
= max_bf_size
;
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.
288 if (backpath
!= NULL
) {
290 (void) snprintf(enable
->backfilename
,
291 sizeof (enable
->backfilename
) - 1, "%s <UNLINKED>",
294 (void) strncpy(enable
->backfilename
, backpath
,
295 sizeof (enable
->backfilename
) - 1);
296 enable
->backfilename
[sizeof (enable
->backfilename
)-1] = '\0';
299 if ((ctlfd
= open(SNAP_CTL_PATH
, O_RDONLY
| O_EXCL
)) == -1) {
300 unlink_all(unlinkpath
, backcount
);
301 die_perror(SNAP_CTL_PATH
);
304 if (ioctl(ctlfd
, _FIOSNAPSHOTCREATE_MULTI
, enable
) == -1) {
305 unlink_all(unlinkpath
, backcount
);
306 if (enable
->error
!= 0) {
307 die_create_error(enable
->error
);
313 backout_snap_fd
= mountfd
;
315 unlink_all(unlinkpath
, backcount
);
317 if (close(ctlfd
) != 0) {
319 die_errno(save_errno
, gettext("close of control file (%s)"),
323 close_all(unlinkpath
, backcount
, fd_array
);
325 if ((hdl
= di_devlink_init("fssnap", DI_MAKE_LINK
)) == NULL
) {
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
);
332 (void) di_devlink_fini(&hdl
);
335 /* intentionally not internationalized */
336 printf("/dev/%s/%d\n", (rawfile
) ? SNAP_CHAR_NAME
: SNAP_BLOCK_NAME
,
337 enable
->snapshotnumber
);
343 delete_snap(int mountfd
)
345 struct fiosnapdelete disable
;
349 bzero(&disable
, sizeof (disable
));
350 if ((ctlfd
= open(SNAP_CTL_PATH
, O_RDONLY
| O_EXCL
)) == -1)
351 die_perror(SNAP_CTL_PATH
);
353 disable
.rootfiledesc
= mountfd
;
354 if (ioctl(ctlfd
, _FIOSNAPSHOTDELETE
, &disable
) == -1) {
356 die(gettext("error %d"), disable
.error
);
362 if (close(ctlfd
) != 0) {
364 die_errno(save_errno
, gettext("close of control file (%s)"),
368 printf(gettext("Deleted snapshot %d.\n"), disable
.snapshotnumber
);
372 stats_snap(char *mountpath
, char *opts
)
374 fssnap_show_status(mountpath
, opts
, ((opts
!= NULL
) ? 0 : 1), 0);
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.
388 open_backpath(int mountfd
, u_offset_t max_bf_size
, char **path
,
389 char **unlinkpath
, int **fd_array
)
394 int ret_errno
, i
, num_back_files
;
395 offset_t fssize
, backfilesize
;
396 char *locpath
= NULL
;
401 /* determine size of the file system to be snapped */
402 if (fstatvfs(mountfd
, &vfs
) == -1)
403 die_perror("statvfs");
405 fssize
= vfs
.f_blocks
* vfs
.f_frsize
;
406 num_back_files
= howmany(fssize
, max_bf_size
);
408 if (stat(*path
, &st
) < 0) {
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.
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
];
421 /* remove a trailing slash from the name */
422 len
= strlen(*path
) - 1;
423 if ((*path
)[len
] == '/')
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",
431 ret_errno
= open_multi_backfile(temppath
,
432 num_back_files
, fd_array
, 0);
436 if (uniq
> max_uniq
) {
437 die(gettext("Could not find unique name in %s"), *path
);
439 *unlinkpath
= strdup(temppath
);
442 } else if (S_ISREG(st
.st_mode
)) {
443 die(gettext("%s already exists."), *path
);
445 die(gettext("%s: must be either the name of a file to create "
446 "or a directory."), *path
);
450 * write a block to the end to bump up the file size and ensure the
451 * entire range needed can be written to.
453 for (i
= 0; i
< num_back_files
; i
++) {
455 if (i
== num_back_files
- 1 && fssize
% max_bf_size
!= 0)
456 backfilesize
= fssize
% max_bf_size
;
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");
464 if (write(fd
, "0", 1) == -1) {
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
);
474 return (num_back_files
);
478 spec_to_bytes(char *spec
)
482 base
= strtoull(spec
, NULL
, 10);
483 if ((base
== 0LL) && (spec
[0] != '0'))
484 die(gettext("Numeric option value expected"));
486 spec
+= strspn(spec
, "0123456789");
488 if ((spec
== NULL
) || strlen(spec
) != 1)
489 die(gettext("Only one of b, k, m, or g may be used"));
506 base
*= 1024 * 1024 * 1024;
509 die(gettext("Must specify one of b, k, m, or g on size"));
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.
523 gen_backing_store_path(char *basepath
, int num
, char **outpath
)
525 if (*outpath
== NULL
) {
526 *outpath
= malloc(strlen(basepath
) + MAX_SUFFIX
);
527 if (*outpath
== NULL
)
528 die_perror("malloc");
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.
538 (void) strcpy(*outpath
, basepath
);
540 (void) sprintf(*outpath
, "%s.%d", basepath
, num
);
544 unlink_all(char *unlinkpath
, int count
)
550 for (i
= 1; i
<= count
; i
++) {
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.
558 gen_backing_store_path(unlinkpath
, i
, &bspath
);
559 if (unlink(bspath
) < 0) {
561 warn_errno(save_errno
,
562 gettext("could not unlink %s"), bspath
);
569 close_all(char *closepath
, int count
, int *fd_array
)
575 for (i
= 1; i
<= count
; i
++) {
576 if (close(fd_array
[i
- 1]) != 0) {
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.
585 gen_backing_store_path(closepath
, i
, &bspath
);
586 die_errno(save_errno
, gettext(
587 "close of backing-store (%s)"), bspath
);
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.)
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.
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.
615 open_multi_backfile(char *backpath
, int count
, int **fd_array
,
616 int file_exists_is_fatal
)
618 char *wpath
= NULL
; /* working path */
621 int stat_succeeded
= 0;
624 *fd_array
= (int *)malloc(count
* sizeof (int));
625 if (*fd_array
== NULL
)
626 die_perror("malloc");
628 for (i
= 0; i
< count
; i
++) {
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.
636 gen_backing_store_path(backpath
, i
+ 1, &wpath
);
637 if (stat(wpath
, &st
) == 0)
640 fd
= open(wpath
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
641 if (stat_succeeded
|| fd
< 0) {
643 for (j
= 0; j
< i
- 1; j
++)
644 (void) close((*fd_array
)[j
]);
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.
651 unlink_all(backpath
, i
);
653 if (stat_succeeded
|| errno
== EEXIST
) {
654 if (file_exists_is_fatal
)
655 die(gettext("%s exists, please specify"
656 " a nonexistent backing store."),
662 die_errno(save_errno
,
663 gettext("Could not create"
664 " backing file %s"), wpath
);
675 die_perror(char *string
)
680 if (string
== NULL
) {
681 string
= gettext("Fatal");
683 errstr
= strerror(en
);
684 if (errstr
== NULL
) {
685 errstr
= gettext("Unknown error");
688 fprintf(stderr
, gettext("%s: %s: error %d: %s\n"),
689 progname
, string
, en
, errstr
);
691 longjmp(err_main
, 2);
699 longjmp(err_main
, 1);
703 warn_errno(int en
, char *fmt
, ...)
708 errstr
= strerror(en
);
709 if (errstr
== NULL
) {
710 errstr
= gettext("Unknown error");
714 fprintf(stderr
, gettext("%s: Warning: "), progname
);
715 vfprintf(stderr
, fmt
, ap
);
716 fprintf(stderr
, ": %s\n", errstr
);
721 die_errno(int en
, char *fmt
, ...)
726 errstr
= strerror(en
);
727 if (errstr
== NULL
) {
728 errstr
= gettext("Unknown error");
732 fprintf(stderr
, gettext("%s: Fatal: "), progname
);
733 vfprintf(stderr
, fmt
, ap
);
734 fprintf(stderr
, ": %s\n", errstr
);
737 longjmp(err_main
, 2);
741 die_create_error(int error
)
743 fprintf(stderr
, gettext("snapshot error: "));
745 case FIOCOW_EREADONLY
:
746 fprintf(stderr
, gettext("Read only file system\n"));
749 fprintf(stderr
, gettext("Snapshot already enabled\n"));
752 fprintf(stderr
, gettext("File system is locked\n"));
756 gettext("File system could not be write locked\n"));
759 fprintf(stderr
, gettext("File system could not be flushed\n"));
762 fprintf(stderr
, gettext("File system may not be stable\n"));
764 case FIOCOW_ENOULOCK
:
765 fprintf(stderr
, gettext("File system could not be unlocked\n"));
767 case FIOCOW_ECHUNKSZ
:
768 fprintf(stderr
, gettext("Chunk size must be a multiple of the "
772 fprintf(stderr
, gettext("Could not allocate or create "
773 "a new snapshot\n"));
777 gettext("Error scanning file system bitmaps\n"));
779 case FIOCOW_EBACKFILE
:
780 fprintf(stderr
, gettext("Invalid backing file path\n"));
783 fprintf(stderr
, gettext("Unknown create error\n"));
787 longjmp(err_main
, 2);
796 fprintf(stderr
, gettext("%s: Fatal: "), progname
);
797 vfprintf(stderr
, fmt
, ap
);
798 fprintf(stderr
, "\n");
801 longjmp(err_main
, 2);
809 " %s [-F ufs] [-V] -o backing-store=path,[special_options] "
811 " %s -d [-F ufs] [-V] /mount/point | dev\n",
812 " %s -i [-F ufS] [-V] [-o special-options] /mount/point "
816 fprintf(stderr
, gettext("Usage:\n"));
817 for (i
= 0; use_str
[i
] != NULL
; i
++)
818 fprintf(stderr
, gettext(use_str
[i
]), progname
);