Print this page
FITS: generating send-streams in portable format
This commit adds the command 'zfs fits-send', analogous to zfs send. The
generated send stream is compatible with the stream generated with that
from 'btrfs send' and can in principle easily be received to any filesystem.

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zfs/zfs_main.c
          +++ new/usr/src/cmd/zfs/zfs_main.c
↓ open down ↓ 81 lines elided ↑ open up ↑
  82   82  static int zfs_do_mount(int argc, char **argv);
  83   83  static int zfs_do_rename(int argc, char **argv);
  84   84  static int zfs_do_rollback(int argc, char **argv);
  85   85  static int zfs_do_set(int argc, char **argv);
  86   86  static int zfs_do_upgrade(int argc, char **argv);
  87   87  static int zfs_do_snapshot(int argc, char **argv);
  88   88  static int zfs_do_unmount(int argc, char **argv);
  89   89  static int zfs_do_share(int argc, char **argv);
  90   90  static int zfs_do_unshare(int argc, char **argv);
  91   91  static int zfs_do_send(int argc, char **argv);
       92 +static int zfs_do_fits_send(int argc, char **argv);
  92   93  static int zfs_do_receive(int argc, char **argv);
  93   94  static int zfs_do_promote(int argc, char **argv);
  94   95  static int zfs_do_userspace(int argc, char **argv);
  95   96  static int zfs_do_allow(int argc, char **argv);
  96   97  static int zfs_do_unallow(int argc, char **argv);
  97   98  static int zfs_do_hold(int argc, char **argv);
  98   99  static int zfs_do_holds(int argc, char **argv);
  99  100  static int zfs_do_release(int argc, char **argv);
 100  101  static int zfs_do_diff(int argc, char **argv);
 101  102  
↓ open down ↓ 22 lines elided ↑ open up ↑
 124  125          HELP_GET,
 125  126          HELP_INHERIT,
 126  127          HELP_UPGRADE,
 127  128          HELP_LIST,
 128  129          HELP_MOUNT,
 129  130          HELP_PROMOTE,
 130  131          HELP_RECEIVE,
 131  132          HELP_RENAME,
 132  133          HELP_ROLLBACK,
 133  134          HELP_SEND,
      135 +        HELP_FITS_SEND,
 134  136          HELP_SET,
 135  137          HELP_SHARE,
 136  138          HELP_SNAPSHOT,
 137  139          HELP_UNMOUNT,
 138  140          HELP_UNSHARE,
 139  141          HELP_ALLOW,
 140  142          HELP_UNALLOW,
 141  143          HELP_USERSPACE,
 142  144          HELP_GROUPSPACE,
 143  145          HELP_HOLD,
↓ open down ↓ 37 lines elided ↑ open up ↑
 181  183          { "groupspace", zfs_do_userspace,       HELP_GROUPSPACE         },
 182  184          { NULL },
 183  185          { "mount",      zfs_do_mount,           HELP_MOUNT              },
 184  186          { "unmount",    zfs_do_unmount,         HELP_UNMOUNT            },
 185  187          { "share",      zfs_do_share,           HELP_SHARE              },
 186  188          { "unshare",    zfs_do_unshare,         HELP_UNSHARE            },
 187  189          { NULL },
 188  190          { "send",       zfs_do_send,            HELP_SEND               },
 189  191          { "receive",    zfs_do_receive,         HELP_RECEIVE            },
 190  192          { NULL },
      193 +        { "fits-send",  zfs_do_fits_send,       HELP_FITS_SEND          },
      194 +        { NULL },
 191  195          { "allow",      zfs_do_allow,           HELP_ALLOW              },
 192  196          { NULL },
 193  197          { "unallow",    zfs_do_unallow,         HELP_UNALLOW            },
 194  198          { NULL },
 195  199          { "hold",       zfs_do_hold,            HELP_HOLD               },
 196  200          { "holds",      zfs_do_holds,           HELP_HOLDS              },
 197  201          { "release",    zfs_do_release,         HELP_RELEASE            },
 198  202          { "diff",       zfs_do_diff,            HELP_DIFF               },
 199  203  };
 200  204  
↓ open down ↓ 46 lines elided ↑ open up ↑
 247  251          case HELP_RENAME:
 248  252                  return (gettext("\trename [-f] <filesystem|volume|snapshot> "
 249  253                      "<filesystem|volume|snapshot>\n"
 250  254                      "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
 251  255                      "\trename -r <snapshot> <snapshot>"));
 252  256          case HELP_ROLLBACK:
 253  257                  return (gettext("\trollback [-rRf] <snapshot>\n"));
 254  258          case HELP_SEND:
 255  259                  return (gettext("\tsend [-DnPpRv] [-[iI] snapshot] "
 256  260                      "<snapshot>\n"));
      261 +        case HELP_FITS_SEND:
      262 +                return (gettext("\tfits-send [-v] [-i snapshot] "
      263 +                    "<snapshot>\n"));
 257  264          case HELP_SET:
 258  265                  return (gettext("\tset <property=value> "
 259  266                      "<filesystem|volume|snapshot> ...\n"));
 260  267          case HELP_SHARE:
 261  268                  return (gettext("\tshare <-a | filesystem>\n"));
 262  269          case HELP_SNAPSHOT:
 263  270                  return (gettext("\tsnapshot [-r] [-o property=value] ... "
 264  271                      "<filesystem@snapname|volume@snapname> ...\n"));
 265  272          case HELP_UNMOUNT:
 266  273                  return (gettext("\tunmount [-f] "
↓ open down ↓ 3451 lines elided ↑ open up ↑
3718 3725                      "You must redirect standard input.\n"));
3719 3726                  return (1);
3720 3727          }
3721 3728  
3722 3729          err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
3723 3730  
3724 3731          return (err != 0);
3725 3732  }
3726 3733  
3727 3734  /*
     3735 + * Send a backup stream to stdout in fits format.
     3736 + */
     3737 +static int
     3738 +zfs_do_fits_send(int argc, char **argv)
     3739 +{
     3740 +        char *fromname = NULL;
     3741 +        char *toname = NULL;
     3742 +        char *cp;
     3743 +        zfs_handle_t *zhp;
     3744 +        sendflags_t flags = { 0 };
     3745 +        int c, err;
     3746 +
     3747 +        /* check options */
     3748 +        while ((c = getopt(argc, argv, ":i:v")) != -1) {
     3749 +                switch (c) {
     3750 +                case 'i':
     3751 +                        if (fromname)
     3752 +                                usage(B_FALSE);
     3753 +                        fromname = optarg;
     3754 +                        break;
     3755 +                case 'v':
     3756 +                        flags.verbose = B_TRUE;
     3757 +                        break;
     3758 +                case ':':
     3759 +                        (void) fprintf(stderr, gettext("missing argument for "
     3760 +                            "'%c' option\n"), optopt);
     3761 +                        usage(B_FALSE);
     3762 +                        break;
     3763 +                case '?':
     3764 +                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     3765 +                            optopt);
     3766 +                        usage(B_FALSE);
     3767 +                }
     3768 +        }
     3769 +
     3770 +        argc -= optind;
     3771 +        argv += optind;
     3772 +
     3773 +        /* check number of arguments */
     3774 +        if (argc < 1) {
     3775 +                (void) fprintf(stderr, gettext("missing snapshot argument\n"));
     3776 +                usage(B_FALSE);
     3777 +        }
     3778 +        if (argc > 1) {
     3779 +                (void) fprintf(stderr, gettext("too many arguments\n"));
     3780 +                usage(B_FALSE);
     3781 +        }
     3782 +
     3783 +        if (isatty(STDOUT_FILENO)) {
     3784 +                (void) fprintf(stderr,
     3785 +                    gettext("Error: Stream can not be written to a terminal.\n"
     3786 +                    "You must redirect standard output.\n"));
     3787 +                return (1);
     3788 +        }
     3789 +
     3790 +        cp = strchr(argv[0], '@');
     3791 +        if (cp == NULL) {
     3792 +                (void) fprintf(stderr,
     3793 +                    gettext("argument must be a snapshot\n"));
     3794 +                usage(B_FALSE);
     3795 +        }
     3796 +        *cp = '\0';
     3797 +        toname = cp + 1;
     3798 +        zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM);
     3799 +        if (zhp == NULL)
     3800 +                return (1);
     3801 +
     3802 +        /*
     3803 +         * If they specified the full path to the snapshot, chop off
     3804 +         * everything except the short name of the snapshot, but special
     3805 +         * case if they specify the origin.
     3806 +         */
     3807 +        if (fromname && (cp = strchr(fromname, '@')) != NULL) {
     3808 +                char origin[ZFS_MAXNAMELEN];
     3809 +                zprop_source_t src;
     3810 +
     3811 +                (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
     3812 +                    origin, sizeof (origin), &src, NULL, 0, B_FALSE);
     3813 +
     3814 +                if (strcmp(origin, fromname) == 0) {
     3815 +                        fromname = NULL;
     3816 +                        flags.fromorigin = B_TRUE;
     3817 +                } else {
     3818 +                        *cp = '\0';
     3819 +                        if (cp != fromname && strcmp(argv[0], fromname)) {
     3820 +                                (void) fprintf(stderr,
     3821 +                                    gettext("incremental source must be "
     3822 +                                    "in same filesystem\n"));
     3823 +                                usage(B_FALSE);
     3824 +                        }
     3825 +                        fromname = cp + 1;
     3826 +                        if (strchr(fromname, '@') || strchr(fromname, '/')) {
     3827 +                                (void) fprintf(stderr,
     3828 +                                    gettext("invalid incremental source\n"));
     3829 +                                usage(B_FALSE);
     3830 +                        }
     3831 +                }
     3832 +        }
     3833 +
     3834 +        err = zfs_fits_send(zhp, fromname, toname, &flags, STDOUT_FILENO,
     3835 +            NULL, 0);
     3836 +
     3837 +        zfs_close(zhp);
     3838 +
     3839 +        return (err != 0);
     3840 +}
     3841 +
     3842 +/*
3728 3843   * allow/unallow stuff
3729 3844   */
3730 3845  /* copied from zfs/sys/dsl_deleg.h */
3731 3846  #define ZFS_DELEG_PERM_CREATE           "create"
3732 3847  #define ZFS_DELEG_PERM_DESTROY          "destroy"
3733 3848  #define ZFS_DELEG_PERM_SNAPSHOT         "snapshot"
3734 3849  #define ZFS_DELEG_PERM_ROLLBACK         "rollback"
3735 3850  #define ZFS_DELEG_PERM_CLONE            "clone"
3736 3851  #define ZFS_DELEG_PERM_PROMOTE          "promote"
3737 3852  #define ZFS_DELEG_PERM_RENAME           "rename"
↓ open down ↓ 2851 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX