17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*d1a180b0Smaheshvs * Common Development and Distribution License (the "License").
6*d1a180b0Smaheshvs * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*d1a180b0Smaheshvs * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
387c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h>
397c478bd9Sstevel@tonic-gate #include <sys/filio.h>
407c478bd9Sstevel@tonic-gate #include <setjmp.h>
417c478bd9Sstevel@tonic-gate #include <stdarg.h>
427c478bd9Sstevel@tonic-gate #include <kstat.h>
437c478bd9Sstevel@tonic-gate #include <libintl.h>
447c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_snap.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #define SNAP_CTL_PATH "/dev/" SNAP_CTL_NAME
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #define MAX_SUFFIX 6 /* '.' + 4 chars of number + trailing '\0' */
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate static int max_uniq = 9999;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate void create_snap(int, char *, u_offset_t, uint_t, int, int);
587c478bd9Sstevel@tonic-gate void delete_snap(int);
597c478bd9Sstevel@tonic-gate void stats_snap(char *, char *);
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate int open_backpath(int, u_offset_t, char **, char **, int **);
627c478bd9Sstevel@tonic-gate u_offset_t spec_to_bytes(char *);
637c478bd9Sstevel@tonic-gate void gen_backing_store_path(char *basepath, int num, char **outpath);
647c478bd9Sstevel@tonic-gate void unlink_all(char *, int);
657c478bd9Sstevel@tonic-gate void close_all(char *, int, int *);
667c478bd9Sstevel@tonic-gate int open_multi_backfile(char *, int, int **, int);
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate void die_perror(char *);
697c478bd9Sstevel@tonic-gate void die_errno(int, char *, ...);
707c478bd9Sstevel@tonic-gate void die_create_error(int error);
717c478bd9Sstevel@tonic-gate void die_usage(void);
727c478bd9Sstevel@tonic-gate void die(char *, ...);
737c478bd9Sstevel@tonic-gate void warn_errno(int, char *, ...);
747c478bd9Sstevel@tonic-gate void usage(void);
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate static char *subopts[] = {
777c478bd9Sstevel@tonic-gate #define BACKPATH (0)
787c478bd9Sstevel@tonic-gate "backing-store",
797c478bd9Sstevel@tonic-gate #define BACKPATH2 (1)
807c478bd9Sstevel@tonic-gate "bs",
817c478bd9Sstevel@tonic-gate #define BACKPATH3 (2)
827c478bd9Sstevel@tonic-gate "bf",
837c478bd9Sstevel@tonic-gate #define MAXSIZE (3)
847c478bd9Sstevel@tonic-gate "maxsize",
857c478bd9Sstevel@tonic-gate #define CHUNKSIZE (4)
867c478bd9Sstevel@tonic-gate "chunksize",
877c478bd9Sstevel@tonic-gate #define RAWFILE (5)
887c478bd9Sstevel@tonic-gate "raw",
897c478bd9Sstevel@tonic-gate #define UNLINK (6)
907c478bd9Sstevel@tonic-gate "unlink",
917c478bd9Sstevel@tonic-gate NULL
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate static jmp_buf err_main;
957c478bd9Sstevel@tonic-gate static char *progname = NULL;
96*d1a180b0Smaheshvs static int backout_snap_fd = -1;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate extern void fssnap_show_status(char *mountpoint, char *opts, int labels,
997c478bd9Sstevel@tonic-gate int brief); /* in ../../fssnapsup.c */
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])1027c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate int c;
1057c478bd9Sstevel@tonic-gate char *suboptions = NULL;
1067c478bd9Sstevel@tonic-gate char *value;
1077c478bd9Sstevel@tonic-gate int longjmp_return;
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate char *mountpoint = NULL;
1107c478bd9Sstevel@tonic-gate int mountfd = -1;
1117c478bd9Sstevel@tonic-gate char *backpath = NULL;
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate int delete = 0;
1147c478bd9Sstevel@tonic-gate int stats = 0;
1157c478bd9Sstevel@tonic-gate u_offset_t maxsize = 0;
1167c478bd9Sstevel@tonic-gate uint_t chunksize = 0;
1177c478bd9Sstevel@tonic-gate int rawfile = 0;
1187c478bd9Sstevel@tonic-gate int dounlink = 0;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) != NULL)
1217c478bd9Sstevel@tonic-gate ++progname;
1227c478bd9Sstevel@tonic-gate else
1237c478bd9Sstevel@tonic-gate progname = argv[0];
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate if ((longjmp_return = setjmp(err_main)) != 0) {
1267c478bd9Sstevel@tonic-gate if (backout_snap_fd >= 0) {
1277c478bd9Sstevel@tonic-gate mountfd = backout_snap_fd;
1287c478bd9Sstevel@tonic-gate backout_snap_fd = -1; /* prevent infinite loop */
1297c478bd9Sstevel@tonic-gate delete_snap(mountfd);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate return (longjmp_return);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "dio:")) != EOF) {
1367c478bd9Sstevel@tonic-gate switch (c) {
1377c478bd9Sstevel@tonic-gate case 'd':
1387c478bd9Sstevel@tonic-gate ++delete;
1397c478bd9Sstevel@tonic-gate break;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate case 'i':
1427c478bd9Sstevel@tonic-gate ++stats;
1437c478bd9Sstevel@tonic-gate break;
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate case 'o':
1467c478bd9Sstevel@tonic-gate suboptions = optarg;
1477c478bd9Sstevel@tonic-gate break;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate default:
1507c478bd9Sstevel@tonic-gate die_usage();
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate /* if -i or -d are not specified then interpret the create options */
1557c478bd9Sstevel@tonic-gate if ((stats == 0) && (delete == 0) && (suboptions != NULL)) {
1567c478bd9Sstevel@tonic-gate while (*suboptions != '\0') {
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate switch ((getsubopt(&suboptions, subopts, &value))) {
1597c478bd9Sstevel@tonic-gate case BACKPATH:
1607c478bd9Sstevel@tonic-gate case BACKPATH2:
1617c478bd9Sstevel@tonic-gate case BACKPATH3:
1627c478bd9Sstevel@tonic-gate if (value == NULL)
1637c478bd9Sstevel@tonic-gate die_usage();
1647c478bd9Sstevel@tonic-gate backpath = strdup(value);
1657c478bd9Sstevel@tonic-gate if (backpath == NULL) {
1667c478bd9Sstevel@tonic-gate die_perror("strdup");
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate break;
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate case MAXSIZE:
1717c478bd9Sstevel@tonic-gate maxsize = spec_to_bytes(value);
1727c478bd9Sstevel@tonic-gate break;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate case CHUNKSIZE:
1757c478bd9Sstevel@tonic-gate chunksize = spec_to_bytes(value);
1767c478bd9Sstevel@tonic-gate break;
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate case RAWFILE:
1797c478bd9Sstevel@tonic-gate ++rawfile;
1807c478bd9Sstevel@tonic-gate break;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate case UNLINK:
1837c478bd9Sstevel@tonic-gate ++dounlink;
1847c478bd9Sstevel@tonic-gate break;
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate default:
1877c478bd9Sstevel@tonic-gate die_usage();
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /* -d and -i can not be specified together or more than once each */
1937c478bd9Sstevel@tonic-gate if ((delete + stats) > 1)
1947c478bd9Sstevel@tonic-gate die_usage();
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /* If no mount point is specified then -i is the only valid option. */
1977c478bd9Sstevel@tonic-gate if ((optind >= argc) && (stats == 0))
1987c478bd9Sstevel@tonic-gate die_usage();
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate * If anything but the mount point or device is specified at the end
2027c478bd9Sstevel@tonic-gate * it's an error.
2037c478bd9Sstevel@tonic-gate */
2047c478bd9Sstevel@tonic-gate if (optind != (argc - 1)) {
2057c478bd9Sstevel@tonic-gate if (!stats)
2067c478bd9Sstevel@tonic-gate die_usage();
2077c478bd9Sstevel@tonic-gate } else {
2087c478bd9Sstevel@tonic-gate /* Otherwise, the last option is the mountpoint. */
2097c478bd9Sstevel@tonic-gate mountpoint = argv[optind];
2107c478bd9Sstevel@tonic-gate if ((mountfd = open(mountpoint, O_RDONLY)) < 0)
2117c478bd9Sstevel@tonic-gate die_perror(mountpoint);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate if (stats != 0) {
2157c478bd9Sstevel@tonic-gate stats_snap(mountpoint, suboptions);
2167c478bd9Sstevel@tonic-gate } else if (delete != 0) {
2177c478bd9Sstevel@tonic-gate delete_snap(mountfd);
2187c478bd9Sstevel@tonic-gate } else {
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate * backpath may be invalid upon return of create_snap call.
2217c478bd9Sstevel@tonic-gate */
2227c478bd9Sstevel@tonic-gate create_snap(mountfd, backpath, maxsize, chunksize,
2237c478bd9Sstevel@tonic-gate rawfile, dounlink);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate void
create_snap(int mountfd,char * backpath,u_offset_t maxsize,uint_t chunksize,int rawfile,int dounlink)2307c478bd9Sstevel@tonic-gate create_snap(int mountfd, char *backpath, u_offset_t maxsize, uint_t chunksize,
2317c478bd9Sstevel@tonic-gate int rawfile, int dounlink)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate struct fiosnapcreate_multi *enable;
2347c478bd9Sstevel@tonic-gate int backcount;
2357c478bd9Sstevel@tonic-gate int ctlfd;
2367c478bd9Sstevel@tonic-gate char *unlinkpath = NULL;
2377c478bd9Sstevel@tonic-gate di_devlink_handle_t hdl;
2387c478bd9Sstevel@tonic-gate int *fd_array;
2397c478bd9Sstevel@tonic-gate u_offset_t max_bf_size;
2407c478bd9Sstevel@tonic-gate int save_errno;
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * If chunksize is not a power of 2, the maximum size of a
2447c478bd9Sstevel@tonic-gate * backing store file might not be UFS_MAX_SNAPBACKFILESIZE,
2457c478bd9Sstevel@tonic-gate * since the size of the backing store files must be an
2467c478bd9Sstevel@tonic-gate * integral number of chunks (except for the last one). So
2477c478bd9Sstevel@tonic-gate * calculate the actual maximum backing store file size.
2487c478bd9Sstevel@tonic-gate * (It would be nice if we could assume that the chunksize
2497c478bd9Sstevel@tonic-gate * was a power of 2, but we can't.)
2507c478bd9Sstevel@tonic-gate */
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate if (chunksize != 0 && !POWEROF2(chunksize))
2537c478bd9Sstevel@tonic-gate max_bf_size = (UFS_MAX_SNAPBACKFILESIZE/chunksize) * chunksize;
2547c478bd9Sstevel@tonic-gate else
2557c478bd9Sstevel@tonic-gate max_bf_size = UFS_MAX_SNAPBACKFILESIZE;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * open_backpath() only returns on success, and
2597c478bd9Sstevel@tonic-gate * can change the value of backpath when backpath
2607c478bd9Sstevel@tonic-gate * references a directory.
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate if (backpath == NULL)
2637c478bd9Sstevel@tonic-gate die(gettext("No backing store path specified.\n"));
2647c478bd9Sstevel@tonic-gate backcount = open_backpath(mountfd, max_bf_size, &backpath,
2657c478bd9Sstevel@tonic-gate &unlinkpath, &fd_array);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate * Only need backcount - 1 spaces for fd's since
2697c478bd9Sstevel@tonic-gate * fiosnapcreate_multi struct contains space for the
2707c478bd9Sstevel@tonic-gate * first one.
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@tonic-gate if ((enable = calloc(1, sizeof (struct fiosnapcreate_multi) +
2737c478bd9Sstevel@tonic-gate (backcount - 1) * sizeof (int))) == NULL)
2747c478bd9Sstevel@tonic-gate die(gettext("Insufficient memory.\n"));
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate enable->backfilecount = backcount;
2777c478bd9Sstevel@tonic-gate bcopy(fd_array, &(enable->backfiledesc), backcount * sizeof (int));
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate enable->rootfiledesc = mountfd;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate enable->maxsize = maxsize;
2827c478bd9Sstevel@tonic-gate enable->chunksize = chunksize;
2837c478bd9Sstevel@tonic-gate enable->backfilesize = max_bf_size;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate * enable.backfilename is advisory only. So, we don't overflow
2877c478bd9Sstevel@tonic-gate * the buffer, but we don't give an error if the backpath does not
2887c478bd9Sstevel@tonic-gate * fit. Instead, it is truncated, and the kstat shows all it can.
2897c478bd9Sstevel@tonic-gate */
2907c478bd9Sstevel@tonic-gate if (backpath != NULL) {
2917c478bd9Sstevel@tonic-gate if (dounlink)
2927c478bd9Sstevel@tonic-gate (void) snprintf(enable->backfilename,
2937c478bd9Sstevel@tonic-gate sizeof (enable->backfilename) - 1, "%s <UNLINKED>",
2947c478bd9Sstevel@tonic-gate backpath);
2957c478bd9Sstevel@tonic-gate else
2967c478bd9Sstevel@tonic-gate (void) strncpy(enable->backfilename, backpath,
2977c478bd9Sstevel@tonic-gate sizeof (enable->backfilename) - 1);
2987c478bd9Sstevel@tonic-gate enable->backfilename[sizeof (enable->backfilename)-1] = '\0';
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1) {
3027c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount);
3037c478bd9Sstevel@tonic-gate die_perror(SNAP_CTL_PATH);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate if (ioctl(ctlfd, _FIOSNAPSHOTCREATE_MULTI, enable) == -1) {
3077c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount);
3087c478bd9Sstevel@tonic-gate if (enable->error != 0) {
3097c478bd9Sstevel@tonic-gate die_create_error(enable->error);
3107c478bd9Sstevel@tonic-gate } else {
3117c478bd9Sstevel@tonic-gate die_perror("ioctl");
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate backout_snap_fd = mountfd;
3167c478bd9Sstevel@tonic-gate if (dounlink != 0)
3177c478bd9Sstevel@tonic-gate unlink_all(unlinkpath, backcount);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if (close(ctlfd) != 0) {
3207c478bd9Sstevel@tonic-gate save_errno = errno;
3217c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext("close of control file (%s)"),
3227c478bd9Sstevel@tonic-gate SNAP_CTL_PATH);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate close_all(unlinkpath, backcount, fd_array);
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate if ((hdl = di_devlink_init("fssnap", DI_MAKE_LINK)) == NULL) {
3287c478bd9Sstevel@tonic-gate save_errno = errno;
3297c478bd9Sstevel@tonic-gate warn_errno(save_errno,
3307c478bd9Sstevel@tonic-gate gettext("/dev/%s/%d may not be immediately available\n"),
3317c478bd9Sstevel@tonic-gate (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME,
3327c478bd9Sstevel@tonic-gate enable->snapshotnumber);
3337c478bd9Sstevel@tonic-gate } else {
3347c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&hdl);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /* intentionally not internationalized */
3387c478bd9Sstevel@tonic-gate printf("/dev/%s/%d\n", (rawfile) ? SNAP_CHAR_NAME : SNAP_BLOCK_NAME,
3397c478bd9Sstevel@tonic-gate enable->snapshotnumber);
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate free(enable);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate void
delete_snap(int mountfd)3457c478bd9Sstevel@tonic-gate delete_snap(int mountfd)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate struct fiosnapdelete disable;
3487c478bd9Sstevel@tonic-gate int ctlfd;
3497c478bd9Sstevel@tonic-gate int save_errno;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate bzero(&disable, sizeof (disable));
3527c478bd9Sstevel@tonic-gate if ((ctlfd = open(SNAP_CTL_PATH, O_RDONLY | O_EXCL)) == -1)
3537c478bd9Sstevel@tonic-gate die_perror(SNAP_CTL_PATH);
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate disable.rootfiledesc = mountfd;
3567c478bd9Sstevel@tonic-gate if (ioctl(ctlfd, _FIOSNAPSHOTDELETE, &disable) == -1) {
3577c478bd9Sstevel@tonic-gate if (disable.error) {
3587c478bd9Sstevel@tonic-gate die(gettext("error %d"), disable.error);
3597c478bd9Sstevel@tonic-gate } else {
3607c478bd9Sstevel@tonic-gate die_perror("ioctl");
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate if (close(ctlfd) != 0) {
3657c478bd9Sstevel@tonic-gate save_errno = errno;
3667c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext("close of control file (%s)"),
3677c478bd9Sstevel@tonic-gate SNAP_CTL_PATH);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate printf(gettext("Deleted snapshot %d.\n"), disable.snapshotnumber);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate void
stats_snap(char * mountpath,char * opts)3747c478bd9Sstevel@tonic-gate stats_snap(char *mountpath, char *opts)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate fssnap_show_status(mountpath, opts, ((opts != NULL) ? 0 : 1), 0);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * Open as many backing files as necessary for this snapshot.
3817c478bd9Sstevel@tonic-gate * There will be one backing file for each max_bf_size
3827c478bd9Sstevel@tonic-gate * number of bytes in the file system being snapped.
3837c478bd9Sstevel@tonic-gate * The array of file descriptors for the backing files is returned in
3847c478bd9Sstevel@tonic-gate * fd_array. The number of backing files is the return value of the
3857c478bd9Sstevel@tonic-gate * function. The name of the first backing file is returned in
3867c478bd9Sstevel@tonic-gate * unlinkpath. The subsequent backing files are assumed to have the
3877c478bd9Sstevel@tonic-gate * same name as the first, but with suffixes, .2, .3, etc.
3887c478bd9Sstevel@tonic-gate */
3897c478bd9Sstevel@tonic-gate int
open_backpath(int mountfd,u_offset_t max_bf_size,char ** path,char ** unlinkpath,int ** fd_array)3907c478bd9Sstevel@tonic-gate open_backpath(int mountfd, u_offset_t max_bf_size, char **path,
3917c478bd9Sstevel@tonic-gate char **unlinkpath, int **fd_array)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate struct stat st;
3947c478bd9Sstevel@tonic-gate struct statvfs vfs;
3957c478bd9Sstevel@tonic-gate int fd, uniq, len;
3967c478bd9Sstevel@tonic-gate int ret_errno, i, num_back_files;
3977c478bd9Sstevel@tonic-gate offset_t fssize, backfilesize;
3987c478bd9Sstevel@tonic-gate char *locpath = NULL;
3997c478bd9Sstevel@tonic-gate int save_errno;
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate *unlinkpath = NULL;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /* determine size of the file system to be snapped */
4047c478bd9Sstevel@tonic-gate if (fstatvfs(mountfd, &vfs) == -1)
4057c478bd9Sstevel@tonic-gate die_perror("statvfs");
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate fssize = vfs.f_blocks * vfs.f_frsize;
4087c478bd9Sstevel@tonic-gate num_back_files = howmany(fssize, max_bf_size);
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate if (stat(*path, &st) < 0) {
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * Since we set the file_exists_is_fatal argument to 1,
4137c478bd9Sstevel@tonic-gate * if we return at all, it will be with all the backing
4147c478bd9Sstevel@tonic-gate * files successfully created and opened.
4157c478bd9Sstevel@tonic-gate */
4167c478bd9Sstevel@tonic-gate (void) open_multi_backfile(*path, num_back_files, fd_array, 1);
4177c478bd9Sstevel@tonic-gate *unlinkpath = strdup(*path);
4187c478bd9Sstevel@tonic-gate if (unlinkpath == NULL)
4197c478bd9Sstevel@tonic-gate die_perror("strdup");
4207c478bd9Sstevel@tonic-gate } else if (S_ISDIR(st.st_mode)) {
4217c478bd9Sstevel@tonic-gate char temppath[MAXPATHLEN];
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /* remove a trailing slash from the name */
4247c478bd9Sstevel@tonic-gate len = strlen(*path) - 1;
4257c478bd9Sstevel@tonic-gate if ((*path)[len] == '/')
4267c478bd9Sstevel@tonic-gate (*path)[len] = '\0';
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate /* find a unique name */
4297c478bd9Sstevel@tonic-gate for (uniq = 0; uniq <= max_uniq; uniq++) {
4307c478bd9Sstevel@tonic-gate /* cannot use tempnam, since TMPDIR overrides path */
4317c478bd9Sstevel@tonic-gate (void) snprintf(temppath, MAXPATHLEN, "%s/snapshot%d",
4327c478bd9Sstevel@tonic-gate *path, uniq);
4337c478bd9Sstevel@tonic-gate ret_errno = open_multi_backfile(temppath,
4347c478bd9Sstevel@tonic-gate num_back_files, fd_array, 0);
4357c478bd9Sstevel@tonic-gate if (ret_errno == 0)
4367c478bd9Sstevel@tonic-gate break;
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate if (uniq > max_uniq) {
4397c478bd9Sstevel@tonic-gate die(gettext("Could not find unique name in %s"), *path);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate *unlinkpath = strdup(temppath);
4427c478bd9Sstevel@tonic-gate free(*path);
4437c478bd9Sstevel@tonic-gate *path = *unlinkpath;
4447c478bd9Sstevel@tonic-gate } else if (S_ISREG(st.st_mode)) {
4457c478bd9Sstevel@tonic-gate die(gettext("%s already exists."), *path);
4467c478bd9Sstevel@tonic-gate } else {
4477c478bd9Sstevel@tonic-gate die(gettext("%s: must be either the name of a file to create "
4487c478bd9Sstevel@tonic-gate "or a directory."), *path);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate * write a block to the end to bump up the file size and ensure the
4537c478bd9Sstevel@tonic-gate * entire range needed can be written to.
4547c478bd9Sstevel@tonic-gate */
4557c478bd9Sstevel@tonic-gate for (i = 0; i < num_back_files; i++) {
4567c478bd9Sstevel@tonic-gate fd = (*fd_array)[i];
4577c478bd9Sstevel@tonic-gate if (i == num_back_files - 1 && fssize % max_bf_size != 0)
4587c478bd9Sstevel@tonic-gate backfilesize = fssize % max_bf_size;
4597c478bd9Sstevel@tonic-gate else
4607c478bd9Sstevel@tonic-gate backfilesize = max_bf_size;
4617c478bd9Sstevel@tonic-gate if (llseek(fd, backfilesize - 1, SEEK_SET) == -1) {
4627c478bd9Sstevel@tonic-gate unlink_all(*unlinkpath, num_back_files);
4637c478bd9Sstevel@tonic-gate die_perror("llseek");
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (write(fd, "0", 1) == -1) {
4677c478bd9Sstevel@tonic-gate save_errno = errno;
4687c478bd9Sstevel@tonic-gate unlink_all(*unlinkpath, num_back_files);
4697c478bd9Sstevel@tonic-gate if (save_errno == EFBIG)
4707c478bd9Sstevel@tonic-gate die(gettext("File system %s "
4717c478bd9Sstevel@tonic-gate "does not support large files.\n"), *path);
4727c478bd9Sstevel@tonic-gate else
4737c478bd9Sstevel@tonic-gate die_perror("write");
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate return (num_back_files);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate u_offset_t
spec_to_bytes(char * spec)4807c478bd9Sstevel@tonic-gate spec_to_bytes(char *spec)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate u_offset_t base;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate base = strtoull(spec, NULL, 10);
4857c478bd9Sstevel@tonic-gate if ((base == 0LL) && (spec[0] != '0'))
4867c478bd9Sstevel@tonic-gate die(gettext("Numeric option value expected"));
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate spec += strspn(spec, "0123456789");
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate if ((spec == NULL) || strlen(spec) != 1)
4917c478bd9Sstevel@tonic-gate die(gettext("Only one of b, k, m, or g may be used"));
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate switch (spec[0]) {
4947c478bd9Sstevel@tonic-gate case 'B':
4957c478bd9Sstevel@tonic-gate case 'b':
4967c478bd9Sstevel@tonic-gate base *= 512;
4977c478bd9Sstevel@tonic-gate break;
4987c478bd9Sstevel@tonic-gate case 'K':
4997c478bd9Sstevel@tonic-gate case 'k':
5007c478bd9Sstevel@tonic-gate base *= 1024;
5017c478bd9Sstevel@tonic-gate break;
5027c478bd9Sstevel@tonic-gate case 'M':
5037c478bd9Sstevel@tonic-gate case 'm':
5047c478bd9Sstevel@tonic-gate base *= 1024 * 1024;
5057c478bd9Sstevel@tonic-gate break;
5067c478bd9Sstevel@tonic-gate case 'G':
5077c478bd9Sstevel@tonic-gate case 'g':
5087c478bd9Sstevel@tonic-gate base *= 1024 * 1024 * 1024;
5097c478bd9Sstevel@tonic-gate break;
5107c478bd9Sstevel@tonic-gate default:
5117c478bd9Sstevel@tonic-gate die(gettext("Must specify one of b, k, m, or g on size"));
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate return (base);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store() in a loop
5197c478bd9Sstevel@tonic-gate * starts with a null pointer in the outpath argument
5207c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until
5217c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string
5227c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed by the caller.
5237c478bd9Sstevel@tonic-gate */
5247c478bd9Sstevel@tonic-gate void
gen_backing_store_path(char * basepath,int num,char ** outpath)5257c478bd9Sstevel@tonic-gate gen_backing_store_path(char *basepath, int num, char **outpath)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate if (*outpath == NULL) {
5287c478bd9Sstevel@tonic-gate *outpath = malloc(strlen(basepath) + MAX_SUFFIX);
5297c478bd9Sstevel@tonic-gate if (*outpath == NULL)
5307c478bd9Sstevel@tonic-gate die_perror("malloc");
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate * Security note: We use strcpy here, instead of the safer
5357c478bd9Sstevel@tonic-gate * strncpy, because the string pointed to by outpath has
5367c478bd9Sstevel@tonic-gate * been generated by THIS code, above. Hence it is impossible
5377c478bd9Sstevel@tonic-gate * for the strcpy to overrun the buffer.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate if (num == 1)
5407c478bd9Sstevel@tonic-gate (void) strcpy(*outpath, basepath);
5417c478bd9Sstevel@tonic-gate else
5427c478bd9Sstevel@tonic-gate (void) sprintf(*outpath, "%s.%d", basepath, num);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate void
unlink_all(char * unlinkpath,int count)5467c478bd9Sstevel@tonic-gate unlink_all(char *unlinkpath, int count)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate char *bspath = NULL;
5497c478bd9Sstevel@tonic-gate int i;
5507c478bd9Sstevel@tonic-gate int save_errno;
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate for (i = 1; i <= count; i++) {
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store()
5557c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument
5567c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until
5577c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string
5587c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed.
5597c478bd9Sstevel@tonic-gate */
5607c478bd9Sstevel@tonic-gate gen_backing_store_path(unlinkpath, i, &bspath);
5617c478bd9Sstevel@tonic-gate if (unlink(bspath) < 0) {
5627c478bd9Sstevel@tonic-gate save_errno = errno;
5637c478bd9Sstevel@tonic-gate warn_errno(save_errno,
5647c478bd9Sstevel@tonic-gate gettext("could not unlink %s"), bspath);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate free(bspath);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate void
close_all(char * closepath,int count,int * fd_array)5717c478bd9Sstevel@tonic-gate close_all(char *closepath, int count, int *fd_array)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate char *bspath = NULL;
5747c478bd9Sstevel@tonic-gate int i;
5757c478bd9Sstevel@tonic-gate int save_errno;
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate for (i = 1; i <= count; i++) {
5787c478bd9Sstevel@tonic-gate if (close(fd_array[i - 1]) != 0) {
5797c478bd9Sstevel@tonic-gate save_errno = errno;
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store()
5827c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument
5837c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until
5847c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string
5857c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed.
5867c478bd9Sstevel@tonic-gate */
5877c478bd9Sstevel@tonic-gate gen_backing_store_path(closepath, i, &bspath);
5887c478bd9Sstevel@tonic-gate die_errno(save_errno, gettext(
5897c478bd9Sstevel@tonic-gate "close of backing-store (%s)"), bspath);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate if (bspath != NULL)
5937c478bd9Sstevel@tonic-gate free(bspath);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * Create "count" files starting with name backpath ("backpath",
5987c478bd9Sstevel@tonic-gate * "backpath".2, "backpath".3, etc. When this function returns,
5997c478bd9Sstevel@tonic-gate * either all of the files will exist and be opened (and their
6007c478bd9Sstevel@tonic-gate * file descriptors will be in fd_array), or NONE of will exist
6017c478bd9Sstevel@tonic-gate * (if they had to be created) and opened (that is, if we created a file,
6027c478bd9Sstevel@tonic-gate * and then failed to create a later file, the earlier files will
6037c478bd9Sstevel@tonic-gate * be closed and unlinked.)
6047c478bd9Sstevel@tonic-gate *
6057c478bd9Sstevel@tonic-gate * If file_exists_is_fatal is set, it is a fatal error (resulting in
6067c478bd9Sstevel@tonic-gate * an error message and termination) if any of the backing files to
6077c478bd9Sstevel@tonic-gate * be created already exists. Otherwise, if one of the backing
6087c478bd9Sstevel@tonic-gate * files already exists, we close and unlink all the files we already
6097c478bd9Sstevel@tonic-gate * created, and return an error to the caller, but we don't print
6107c478bd9Sstevel@tonic-gate * an error or terminate.
6117c478bd9Sstevel@tonic-gate *
6127c478bd9Sstevel@tonic-gate * If there is any failure other than EEXIST when attempting to
6137c478bd9Sstevel@tonic-gate * create the file, the routine prints an error and terminates the
6147c478bd9Sstevel@tonic-gate * program, regardless of the setting of file_exists_is_fatal.
6157c478bd9Sstevel@tonic-gate */
6167c478bd9Sstevel@tonic-gate int
open_multi_backfile(char * backpath,int count,int ** fd_array,int file_exists_is_fatal)6177c478bd9Sstevel@tonic-gate open_multi_backfile(char *backpath, int count, int **fd_array,
6187c478bd9Sstevel@tonic-gate int file_exists_is_fatal)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate char *wpath = NULL; /* working path */
6217c478bd9Sstevel@tonic-gate int i, j, fd;
6227c478bd9Sstevel@tonic-gate struct stat st;
6237c478bd9Sstevel@tonic-gate int stat_succeeded = 0;
6247c478bd9Sstevel@tonic-gate int save_errno;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate *fd_array = (int *)malloc(count * sizeof (int));
6277c478bd9Sstevel@tonic-gate if (*fd_array == NULL)
6287c478bd9Sstevel@tonic-gate die_perror("malloc");
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) {
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate * Make sure that the first call to gen_backing_store()
6337c478bd9Sstevel@tonic-gate * starts with a null pointer in the third argument
6347c478bd9Sstevel@tonic-gate * and continues to pass in that same argument until
6357c478bd9Sstevel@tonic-gate * the loop is complete, at which point the string
6367c478bd9Sstevel@tonic-gate * pointed to by that argument must be freed.
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate gen_backing_store_path(backpath, i + 1, &wpath);
6397c478bd9Sstevel@tonic-gate if (stat(wpath, &st) == 0)
6407c478bd9Sstevel@tonic-gate stat_succeeded = 1;
6417c478bd9Sstevel@tonic-gate else
6427c478bd9Sstevel@tonic-gate fd = open(wpath, O_RDWR | O_CREAT | O_EXCL, 0600);
6437c478bd9Sstevel@tonic-gate if (stat_succeeded || fd < 0) {
6447c478bd9Sstevel@tonic-gate if (i > 0) {
6457c478bd9Sstevel@tonic-gate for (j = 0; j < i - 1; j++)
6467c478bd9Sstevel@tonic-gate (void) close((*fd_array)[j]);
6477c478bd9Sstevel@tonic-gate /*
6487c478bd9Sstevel@tonic-gate * unlink_all's second argument is the number
6497c478bd9Sstevel@tonic-gate * of files to be removed, NOT the offset
6507c478bd9Sstevel@tonic-gate * into the array of fd's of the last
6517c478bd9Sstevel@tonic-gate * successfully created file.
6527c478bd9Sstevel@tonic-gate */
6537c478bd9Sstevel@tonic-gate unlink_all(backpath, i);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate if (stat_succeeded || errno == EEXIST) {
6567c478bd9Sstevel@tonic-gate if (file_exists_is_fatal)
6577c478bd9Sstevel@tonic-gate die(gettext("%s exists, please specify"
6587c478bd9Sstevel@tonic-gate " a nonexistent backing store."),
6597c478bd9Sstevel@tonic-gate wpath);
6607c478bd9Sstevel@tonic-gate else
6617c478bd9Sstevel@tonic-gate return (1);
6627c478bd9Sstevel@tonic-gate } else {
6637c478bd9Sstevel@tonic-gate save_errno = errno;
6647c478bd9Sstevel@tonic-gate die_errno(save_errno,
6657c478bd9Sstevel@tonic-gate gettext("Could not create"
6667c478bd9Sstevel@tonic-gate " backing file %s"), wpath);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate (*fd_array)[i] = fd;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate if (wpath != NULL)
6727c478bd9Sstevel@tonic-gate free(wpath);
6737c478bd9Sstevel@tonic-gate return (0);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate void
die_perror(char * string)6777c478bd9Sstevel@tonic-gate die_perror(char *string)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate int en = errno;
6807c478bd9Sstevel@tonic-gate char *errstr;
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate if (string == NULL) {
6837c478bd9Sstevel@tonic-gate string = gettext("Fatal");
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate errstr = strerror(en);
6867c478bd9Sstevel@tonic-gate if (errstr == NULL) {
6877c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error");
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: %s: error %d: %s\n"),
6917c478bd9Sstevel@tonic-gate progname, string, en, errstr);
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate longjmp(err_main, 2);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate void
die_usage(void)6977c478bd9Sstevel@tonic-gate die_usage(void)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate usage();
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate longjmp(err_main, 1);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate void
warn_errno(int en,char * fmt,...)7057c478bd9Sstevel@tonic-gate warn_errno(int en, char *fmt, ...)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate va_list ap;
7087c478bd9Sstevel@tonic-gate char *errstr;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate errstr = strerror(en);
7117c478bd9Sstevel@tonic-gate if (errstr == NULL) {
7127c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error");
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate va_start(ap, fmt);
7167c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Warning: "), progname);
7177c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap);
7187c478bd9Sstevel@tonic-gate fprintf(stderr, ": %s\n", errstr);
7197c478bd9Sstevel@tonic-gate va_end(ap);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate void
die_errno(int en,char * fmt,...)7237c478bd9Sstevel@tonic-gate die_errno(int en, char *fmt, ...)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate va_list ap;
7267c478bd9Sstevel@tonic-gate char *errstr;
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate errstr = strerror(en);
7297c478bd9Sstevel@tonic-gate if (errstr == NULL) {
7307c478bd9Sstevel@tonic-gate errstr = gettext("Unknown error");
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate va_start(ap, fmt);
7347c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Fatal: "), progname);
7357c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap);
7367c478bd9Sstevel@tonic-gate fprintf(stderr, ": %s\n", errstr);
7377c478bd9Sstevel@tonic-gate va_end(ap);
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate longjmp(err_main, 2);
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate void
die_create_error(int error)7437c478bd9Sstevel@tonic-gate die_create_error(int error)
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("snapshot error: "));
7467c478bd9Sstevel@tonic-gate switch (error) {
7477c478bd9Sstevel@tonic-gate case FIOCOW_EREADONLY:
7487c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Read only file system\n"));
7497c478bd9Sstevel@tonic-gate break;
7507c478bd9Sstevel@tonic-gate case FIOCOW_EBUSY:
7517c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Snapshot already enabled\n"));
7527c478bd9Sstevel@tonic-gate break;
7537c478bd9Sstevel@tonic-gate case FIOCOW_EULOCK:
7547c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system is locked\n"));
7557c478bd9Sstevel@tonic-gate break;
7567c478bd9Sstevel@tonic-gate case FIOCOW_EWLOCK:
7577c478bd9Sstevel@tonic-gate fprintf(stderr,
7587c478bd9Sstevel@tonic-gate gettext("File system could not be write locked\n"));
7597c478bd9Sstevel@tonic-gate break;
7607c478bd9Sstevel@tonic-gate case FIOCOW_EFLUSH:
7617c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system could not be flushed\n"));
7627c478bd9Sstevel@tonic-gate break;
7637c478bd9Sstevel@tonic-gate case FIOCOW_ECLEAN:
7647c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system may not be stable\n"));
7657c478bd9Sstevel@tonic-gate break;
7667c478bd9Sstevel@tonic-gate case FIOCOW_ENOULOCK:
7677c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("File system could not be unlocked\n"));
7687c478bd9Sstevel@tonic-gate break;
7697c478bd9Sstevel@tonic-gate case FIOCOW_ECHUNKSZ:
7707c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Chunk size must be a multiple of the "
7717c478bd9Sstevel@tonic-gate "fragment size\n"));
7727c478bd9Sstevel@tonic-gate break;
7737c478bd9Sstevel@tonic-gate case FIOCOW_ECREATE:
7747c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Could not allocate or create "
7757c478bd9Sstevel@tonic-gate "a new snapshot\n"));
7767c478bd9Sstevel@tonic-gate break;
7777c478bd9Sstevel@tonic-gate case FIOCOW_EBITMAP:
7787c478bd9Sstevel@tonic-gate fprintf(stderr,
7797c478bd9Sstevel@tonic-gate gettext("Error scanning file system bitmaps\n"));
7807c478bd9Sstevel@tonic-gate break;
7817c478bd9Sstevel@tonic-gate case FIOCOW_EBACKFILE:
7827c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Invalid backing file path\n"));
7837c478bd9Sstevel@tonic-gate break;
7847c478bd9Sstevel@tonic-gate default:
7857c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Unknown create error\n"));
7867c478bd9Sstevel@tonic-gate break;
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate longjmp(err_main, 2);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate void
die(char * fmt,...)7937c478bd9Sstevel@tonic-gate die(char *fmt, ...)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate va_list ap;
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate va_start(ap, fmt);
7987c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: Fatal: "), progname);
7997c478bd9Sstevel@tonic-gate vfprintf(stderr, fmt, ap);
8007c478bd9Sstevel@tonic-gate fprintf(stderr, "\n");
8017c478bd9Sstevel@tonic-gate va_end(ap);
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate longjmp(err_main, 2);
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate void
usage(void)8077c478bd9Sstevel@tonic-gate usage(void)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate int i;
8107c478bd9Sstevel@tonic-gate char *use_str[] = {
8117c478bd9Sstevel@tonic-gate " %s [-F ufs] [-V] -o backing-store=path,[special_options] "
8127c478bd9Sstevel@tonic-gate "/mount/point\n",
8137c478bd9Sstevel@tonic-gate " %s -d [-F ufs] [-V] /mount/point | dev\n",
8147c478bd9Sstevel@tonic-gate " %s -i [-F ufS] [-V] [-o special-options] /mount/point "
8157c478bd9Sstevel@tonic-gate "| dev\n",
8167c478bd9Sstevel@tonic-gate NULL
8177c478bd9Sstevel@tonic-gate };
8187c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Usage:\n"));
8197c478bd9Sstevel@tonic-gate for (i = 0; use_str[i] != NULL; i++)
8207c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(use_str[i]), progname);
8217c478bd9Sstevel@tonic-gate }
822