Index: projects/bectl/sbin/be/be.1 =================================================================== --- projects/bectl/sbin/be/be.1 (revision 336668) +++ projects/bectl/sbin/be/be.1 (nonexistent) @@ -1,220 +0,0 @@ -.\" -.\" be - Utility to manage Boot Environments on the ZFS filesystem -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" -.\" @(#)be.1 -.\" $FreeBSD$ -.\" -.Dd June 15, 2017 -.Dt BE 1 -.Os FreeBSD -.Sh NAME -.Nm be -.Nd Utility to manage Boot Environments on ZFS -.Sh SYNOPSIS -.Nm -activate -.Op Fl t -.Ao Ar beName Ac -.Nm -create -.Op Fl r -.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot -.Ao Ar beName Ac -.Nm -create -.Op Fl r -.Ao Ar beName@snapshot Ac -.Nm -destroy -.Op Fl F -.Ao Ar beName | beName@snapshot Ac -.Nm -jail -.Ao Ar jailID | jailName Ac -.Ao Ar bootenv Ac -.Nm -list -.Op Fl a -.Op Fl D -.Op Fl H -.Op Fl s -.Nm -mount -.Ao Ar beName Ac -.Op mountpoint -.Nm -rename -.Ao Ar origBeName Ac -.Ao Ar newBeName Ac -.Nm -{ ujail | unjail } -.Ao Ar jailID | jailName Ac -.Ao Ar bootenv Ac -.Nm -{ umount | unmount } -.Op Fl f -.Ao Ar beName Ac -.Sh DESCRIPTION -The -.Nm -command is used to setup and interact with ZFS boot environments, which are bootable clones of datasets. -.Pp -.Em Boot Environments -allows the system to be upgraded, while preserving the old system environment in a separate ZFS dataset. -.Pp -.Sh COMMANDS -The following commands are supported by -.Nm : -.Bl -tag -width activate -.It Ic activate -.Op Fl t -.Ar -.Pp -Activate the given -.Ar beName -as the default boot filesystem. If the -.Op Fl t -flag is given, this takes effect only for the next boot. -.Pp -.It Ic create -.Op Fl r -.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot -.Ao Ar beName Ac -.Pp -Creates a new boot environment named -.Ar beName . -If the -e param is specified, the new environment will be cloned from the given -.Ar nonActiveBe | Ar beName@snapshot . -If the -.Op Fl r -flag is given, a recursive boot environment will be made. -.Pp -.It Ic create -.Op Fl r -.Ao Ar beName@snapshot Ac -.Pp -Creates a snapshot of the existing boot environment named -.Ar beName . -If the -.Op Fl r -flag is given, a recursive boot environment will be made. -.Pp -.It Ic destroy -.Op Fl F -.Ao Ar beName | beName@snapshot Ac -.Pp -Destroys the given -.Ar beName -boot environment or -.Ar beName@snapshot -snapshot. -Specifying -.Fl F -will automatically unmount without confirmation. -.Pp -.It Ic jail -.Ao Ar jailID | jailName Ac -.Ao Ar bootenv Ac -.Pp -Creates a jail of the given boot environment. -.Pp -.It Ic list -.Op Fl a -.Op Fl D -.Op Fl H -.Op Fl s -.Pp -Displays all boot environments. -The Active field indicates whether the boot environment is active now (N); active on reboot (R); or both (NR). -.Pp -If -.Fl a -is used, display all datasets. -If -.Fl D -is used, display the full space usage for each boot environment, assuming all other boot environments were destroyed. -The -.Fl H -option is used for scripting. It does not print headers and separate fields by a single tab instead of arbitrary white space. -If -.Fl s -is used, display all snapshots as well. -.Pp -.It Ic mount -.Ao Ar beName Ac -.Op mountpoint -.Pp -Temporarily mount the boot environment. -Mount at the specified -.Ar mountpoint -if provided. -.Pp -.It Ic rename Ao Ar origBeName Ac Ao Ar newBeName Ac -.Pp -Renames the given nonactive -.Ar origBeName -to the given -.Ar newBeName -.Pp -.It Ic unmount -.Op Fl f -.Ao Ar beName Ac -.Pp -Unmount the given boot environment, if it is mounted. -Specifying -.Fl f -will force the unmount if busy. -.Pp -.It Ic unjail -.Ao Ar beName Ac -.Pp -Destroys the jail created from the given boot environment. -.Pp -.El -.Sh EXAMPLES -.Bl -bullet -.It -To fill in with jail upgrade example when behavior is firm. -.Pp -.Sh SEE ALSO -.Xr jail 8 , -.Xr zfs 8 , -.Xr zpool 8 -.Sh HISTORY -.Nm -is based on -.Xr beadm 1 -and was implemented as a project for the 2017 Summer of Code, along with -.Xr libbe 3 . -.Sh AUTHORS -.Bl -bullet -.It -Kyle Kneitinger (kneitinger) -.Ar kyle@kneit.in -.Pp -Creator of -.Nm . -.It -Slawomir Wojciech Wojtczak (vermaden) -.Ar vermaden@interia.pl -.Pp -Creator and maintainer of -.Xr beadm 1 . -.It -Bryan Drewery (bdrewery) -.Ar bryan@shatow.net -.Pp -Wrote the original -.Xr beadm 1 -manual page that this one is derived from. -.El Property changes on: projects/bectl/sbin/be/be.1 ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/bectl/sbin/be/be.c =================================================================== --- projects/bectl/sbin/be/be.c (revision 336668) +++ projects/bectl/sbin/be/be.c (nonexistent) @@ -1,664 +0,0 @@ -/* - * be.c - * - * Copyright (c) 2017 Kyle J. Kneitinger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int be_cmd_activate(int argc, char *argv[]); -static int be_cmd_create(int argc, char *argv[]); -static int be_cmd_destroy(int argc, char *argv[]); -static int be_cmd_export(int argc, char *argv[]); -static int be_cmd_import(int argc, char *argv[]); -static int be_cmd_add(int argc, char *argv[]); -static int be_cmd_jail(int argc, char *argv[]); -static int be_cmd_list(int argc, char *argv[]); -static int be_cmd_mount(int argc, char *argv[]); -static int be_cmd_rename(int argc, char *argv[]); -static int be_cmd_unjail(int argc, char *argv[]); -static int be_cmd_unmount(int argc, char *argv[]); - -libbe_handle_t *be; - -static int -usage(bool explicit) -{ - FILE *fp = explicit ? stdout : stderr; - - fprintf(fp, - "usage:\tbe ( -h | -? | subcommand [args...] )\n" - "\tbe activate [-t] beName\n" - "\tbe create [-e nonActiveBe | -e beName@snapshot] beName\n" - "\tbe create beName@snapshot\n" - "\tbe destroy [-F] beName | beName@snapshot⟩\n" - "\tbe export sourceBe\n" - "\tbe import targetBe\n" - "\tbe add (path)*\n" - "\tbe jail bootenv\n" - "\tbe list [-a] [-D] [-H] [-s]\n" - "\tbe mount beName [mountpoint]\n" - "\tbe rename origBeName newBeName\n" - "\tbe { ujail | unjail } ⟨jailID | jailName⟩ bootenv\n" - "\tbe { umount | unmount } [-f] beName\n"); - - return (explicit ? 0 : EX_USAGE); -} - - -/* - * Represents a relationship between the command name and the parser action - * that handles it. - */ -struct command_map_entry { - const char *command; - int (*fn)(int argc, char *argv[]); -}; - -static struct command_map_entry command_map[] = -{ - { "activate", be_cmd_activate }, - { "create", be_cmd_create }, - { "destroy", be_cmd_destroy }, - { "export", be_cmd_export }, - { "import", be_cmd_import }, - { "add", be_cmd_add }, - { "jail", be_cmd_jail }, - { "list", be_cmd_list }, - { "mount", be_cmd_mount }, - { "rename", be_cmd_rename }, - { "unjail", be_cmd_unjail }, - { "unmount", be_cmd_unmount }, -}; - -static int -get_cmd_index(char *cmd, int *index) -{ - int map_size = sizeof(command_map) / sizeof(struct command_map_entry); - - for (int i = 0; i < map_size; ++i) { - if (strcmp(cmd, command_map[i].command) == 0) { - *index = i; - return (0); - } - } - - return (1); -} - - -static int -be_cmd_activate(int argc, char *argv[]) -{ - int err, opt; - bool temp; - char *bootenv; - - temp = false; - while ((opt = getopt(argc, argv, "t")) != -1) { - switch (opt) { - case 't': - temp = true; - break; - default: - fprintf(stderr, "be activate: unknown option '-%c'\n", - optopt); - return (usage(false)); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "be activate: wrong number of arguments\n"); - return (usage(false)); - } - - - /* activate logic goes here */ - if ((err = be_activate(be, argv[0], temp)) != 0) { - // TODO: more specific error msg based on err - printf("did not successfully activate boot environment %s\n", - argv[0]); - } else { - printf("successfully activated boot environment %s\n", argv[0]); - } - - if (temp) { - printf("for next boot\n"); - } - - return (err); -} - - -// TODO: when only one arg is given, and it contains an "@" the this should -// create that snapshot -static int -be_cmd_create(int argc, char *argv[]) -{ - int err, opt; - char *snapname; - char *bootenv; - char *source; - - snapname = NULL; - while ((opt = getopt(argc, argv, "e:")) != -1) { - switch (opt) { - case 'e': - snapname = optarg; - break; - default: - fprintf(stderr, "be create: unknown option '-%c'\n", - optopt); - return (usage(false)); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "be create: wrong number of arguments\n"); - return (usage(false)); - } - - bootenv = *argv; - - - if (snapname != NULL) { - if (strchr(snapname, '@') != NULL) { - err = be_create_from_existing_snap(be, bootenv, - snapname); - } else { - err = be_create_from_existing(be, bootenv, snapname); - } - } else { - if ((snapname = strchr(bootenv, '@')) != NULL) { - *(snapname++) = '\0'; - if ((err = be_snapshot(be, (char *)be_active_path(be), - snapname, true, NULL)) != BE_ERR_SUCCESS) { - fprintf(stderr, "failed to create snapshot\n"); - } - asprintf(&source, "%s@%s", be_active_path(be), snapname); - err = be_create_from_existing_snap(be, bootenv, - source); - return (err); - } else { - err = be_create(be, bootenv); - } - } - - switch (err) { - case BE_ERR_SUCCESS: - break; - default: - if (snapname == NULL) { - fprintf(stderr, - "failed to create bootenv %s\n", bootenv); - } else { - fprintf(stderr, - "failed to create bootenv %s from snapshot %s\n", - bootenv, snapname); - } - } - - return (err); -} - - -static int -be_cmd_export(int argc, char *argv[]) -{ - int opt; - char *bootenv; - - - if (argc == 1) { - fprintf(stderr, "be export: missing boot environment name\n"); - return (usage(false)); - } - - if (argc > 2) { - fprintf(stderr, "be export: extra arguments provided\n"); - return (usage(false)); - } - - bootenv = argv[1]; - - if (isatty(STDOUT_FILENO)) { - fprintf(stderr, "be export: must redirect output\n"); - return (EX_USAGE); - } - - be_export(be, bootenv, STDOUT_FILENO); - - return (0); -} - - -static int -be_cmd_import(int argc, char *argv[]) -{ - char *bootenv; - int err; - - - if (argc == 1) { - fprintf(stderr, "be import: missing boot environment name\n"); - return (usage(false)); - } - - - if (argc > 2) { - fprintf(stderr, "be import: extra arguments provided\n"); - return (usage(false)); - } - - bootenv = argv[1]; - - if (isatty(STDIN_FILENO)) { - fprintf(stderr, "be import: input can not be from terminal\n"); - return (EX_USAGE); - } - - err = be_import(be, bootenv, STDIN_FILENO); - - return (err); -} - - -static int -be_cmd_add(int argc, char *argv[]) -{ - char *bootenv; - - if (argc < 2) { - fprintf(stderr, "be add: must provide at least one path\n"); - return (usage(false)); - } - - for (int i = 1; i < argc; ++i) { - printf("arg %d: %s\n", i, argv[i]); - // TODO catch err - be_add_child(be, argv[i], true); - } - - return (0); -} - - -static int -be_cmd_destroy(int argc, char *argv[]) -{ - int opt, err; - bool force; - char *target; - - force = false; - while ((opt = getopt(argc, argv, "F")) != -1) { - switch (opt) { - case 'F': - force = true; - break; - default: - fprintf(stderr, "be destroy: unknown option '-%c'\n", - optopt); - return (usage(false)); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "be destroy: wrong number of arguments\n"); - return (usage(false)); - } - - target = argv[0]; - - err = be_destroy(be, target, force); - - return (err); -} - - -static int -be_cmd_jail(int argc, char *argv[]) -{ - char *bootenv; - char mnt_loc[BE_MAXPATHLEN]; - char buf[BE_MAXPATHLEN*2]; - int err, jid; - - //struct jail be_jail = { 0 }; - - if (argc == 1) { - fprintf(stderr, "be jail: missing boot environment name\n"); - return (usage(false)); - } - if (argc > 2) { - fprintf(stderr, "be jail: too many arguments\n"); - return (usage(false)); - } - - bootenv = argv[1]; - - // TODO: if its already mounted, perhaps there should be a flag to - // indicate its okay to proceed?? - if ((err = be_mount(be, bootenv, NULL, 0, mnt_loc)) != BE_ERR_SUCCESS) { - fprintf(stderr, "could not mount bootenv\n"); - } - - // NOTE: this is not quite functional: - // see https://github.com/vermaden/beadm/blob/master/HOWTO.htm on - // neccesary modifications to correctly boot the jail - - //snprintf(buf, BE_MAXPATHLEN*2, "jail %s %s %s /bin/sh /etc/rc", mnt_loc, bootenv, "192.168.1.123"); - snprintf(buf, BE_MAXPATHLEN*2, "jail %s %s %s /bin/sh", mnt_loc, - bootenv, "192.168.1.123"); - system(buf); - - unmount(mnt_loc, 0); - - /* - * be_jail.version = JAIL_API_VERSION; - * be_jail.path = "/tmp/be_mount.hCCk"; - * be_jail.jailname = "sdfs"; - * - * if ((jid = jail(&be_jail)) != -1) { - * printf("jail %d created at %s\n", jid, mnt_loc); - * err = 0; - * } else { - * fprintf(stderr, "unable to create jail. error: %d\n", errno); - * err = errno; - * } - */ - - return (0); -} - - -static int -be_cmd_list(int argc, char *argv[]) -{ - int opt; - bool show_all_datasets, show_space, hide_headers, show_snaps; - char *bootenv; - nvlist_t *props; - - show_all_datasets = show_space = hide_headers = show_snaps = false; - while ((opt = getopt(argc, argv, "aDHs")) != -1) { - switch (opt) { - case 'a': - show_all_datasets = true; - break; - case 'D': - show_space = true; - break; - case 'H': - hide_headers = true; - break; - case 's': - show_space = true; - break; - default: - fprintf(stderr, "be list: unknown option '-%c'\n", - optopt); - return (usage(false)); - } - } - - argc -= optind; - - if (argc != 0) { - fprintf(stderr, "be list: extra argument provided\n"); - return (usage(false)); - } - - //props = be_get_bootenv_props(be); - - return (0); -} - - -static int -be_cmd_mount(int argc, char *argv[]) -{ - int err; - char result_loc[BE_MAXPATHLEN]; - char *bootenv; - char *mountpoint; - - if (argc < 2) { - fprintf(stderr, "be mount: missing argument(s)\n"); - return (usage(false)); - } - - if (argc > 3) { - fprintf(stderr, "be mount: too many arguments\n"); - return (usage(false)); - } - - bootenv = argv[1]; - mountpoint = ((argc == 3) ? argv[2] : NULL); - - - err = be_mount(be, bootenv, mountpoint, 0, result_loc); - - switch (err) { - case BE_ERR_SUCCESS: - printf("successfully mounted %s at %s\n", bootenv, result_loc); - break; - default: - fprintf(stderr, - (argc == 3) ? "failed to mount bootenv %s at %s\n" : - "failed to mount bootenv %s at temporary path %s\n", - bootenv, mountpoint); - } - - return (err); -} - - -static int -be_cmd_rename(int argc, char *argv[]) -{ - char *src; - char *dest; - int err; - - if (argc < 3) { - fprintf(stderr, "be rename: missing argument\n"); - return (usage(false)); - } - - if (argc > 3) { - fprintf(stderr, "be rename: too many arguments\n"); - return (usage(false)); - } - - src = argv[1]; - dest = argv[2]; - - err = be_rename(be, src, dest); - - switch (err) { - case BE_ERR_SUCCESS: - break; - default: - fprintf(stderr, "failed to rename bootenv %s to %s\n", - src, dest); - } - - return (0); -} - - -static int -be_cmd_unjail(int argc, char *argv[]) -{ - int opt; - char *cmd, *target; - bool force; - - /* Store alias used */ - cmd = argv[0]; - - force = false; - while ((opt = getopt(argc, argv, "f")) != -1) { - switch (opt) { - case 'f': - force = true; - break; - default: - fprintf(stderr, "be %s: unknown option '-%c'\n", - cmd, optopt); - return (usage(false)); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "be %s: wrong number of arguments\n", cmd); - return (usage(false)); - } - - target = argv[0]; - - /* unjail logic goes here */ - - return (0); -} - - -static int -be_cmd_unmount(int argc, char *argv[]) -{ - int err, flags, opt; - char *cmd, *bootenv; - - /* Store alias used */ - cmd = argv[0]; - - flags = 0; - while ((opt = getopt(argc, argv, "f")) != -1) { - switch (opt) { - case 'f': - flags |= BE_MNT_FORCE; - break; - default: - fprintf(stderr, "be %s: unknown option '-%c'\n", - cmd, optopt); - return (usage(false)); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "be %s: wrong number of arguments\n", cmd); - return (usage(false)); - } - - bootenv = argv[0]; - - err = be_unmount(be, bootenv, flags); - - switch (err) { - case BE_ERR_SUCCESS: - break; - default: - fprintf(stderr, "failed to unmount bootenv %s\n", bootenv); - } - - return (err); -} - - -int -main(int argc, char *argv[]) -{ - char *command; - int command_index, rc; - - if (argc < 2) { - fprintf(stderr, "missing command\n"); - return (usage(false)); - } - - command = argv[1]; - - /* Handle command aliases */ - if (strcmp(command, "umount") == 0) { - command = "unmount"; - } - - if (strcmp(command, "ujail") == 0) { - command = "unjail"; - } - - if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0)) { - return (usage(true)); - } - - if (get_cmd_index(command, &command_index)) { - fprintf(stderr, "unknown command: %s\n", command); - return (usage(false)); - } - - - if ((be = libbe_init()) == NULL) { - return (-1); - } - - libbe_print_on_error(be, true); - - /* TODO: can be simplified if offset by 2 instead of one */ - rc = command_map[command_index].fn(argc-1, argv+1); - - libbe_close(be); - - - return (rc); -} Property changes on: projects/bectl/sbin/be/be.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/bectl/sbin/be/Makefile =================================================================== --- projects/bectl/sbin/be/Makefile (revision 336668) +++ projects/bectl/sbin/be/Makefile (nonexistent) @@ -1,10 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 - -PROG= be -WARNS?= 1 -MAN= be.1 - -LIBADD+= be -LIBADD+= nvpair - -.include Property changes on: projects/bectl/sbin/be/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/bectl/sbin/Makefile =================================================================== --- projects/bectl/sbin/Makefile (revision 336668) +++ projects/bectl/sbin/Makefile (revision 336669) @@ -1,98 +1,98 @@ # @(#)Makefile 8.5 (Berkeley) 3/31/94 # $FreeBSD$ .include SUBDIR=adjkerntz \ camcontrol \ clri \ comcontrol \ conscontrol \ ddb \ devfs \ devmatch \ dhclient \ dmesg \ dump \ dumpfs \ dumpon \ etherswitchcfg \ ffsinfo \ fsck \ fsck_ffs \ fsck_msdosfs \ fsdb \ fsirand \ gbde \ geom \ ggate \ growfs \ gvinum \ ifconfig \ init \ kldconfig \ kldload \ kldstat \ kldunload \ ldconfig \ md5 \ mdconfig \ mdmfs \ mknod \ mksnap_ffs \ mount \ mount_cd9660 \ mount_fusefs \ mount_msdosfs \ mount_nfs \ mount_nullfs \ mount_udf \ mount_unionfs \ newfs \ newfs_msdos \ nfsiod \ nos-tun \ ping \ rcorder \ reboot \ recoverdisk \ resolvconf \ restore \ route \ savecore \ setkey \ shutdown \ spppcontrol \ swapon \ sysctl \ tunefs \ umount SUBDIR.${MK_CCD}+= ccdconfig SUBDIR.${MK_CXX}+= devd SUBDIR.${MK_HAST}+= hastctl SUBDIR.${MK_HAST}+= hastd SUBDIR.${MK_INET6}+= ping6 SUBDIR.${MK_INET6}+= rtsol SUBDIR.${MK_IPFILTER}+= ipf SUBDIR.${MK_IPFW}+= ipfw SUBDIR.${MK_IPFW}+= natd SUBDIR.${MK_ISCSI}+= iscontrol SUBDIR.${MK_NAND}+= nandfs SUBDIR.${MK_NAND}+= newfs_nandfs SUBDIR.${MK_NVME}+= nvmecontrol SUBDIR.${MK_OPENSSL}+= decryptcore SUBDIR.${MK_PF}+= pfctl SUBDIR.${MK_PF}+= pflogd SUBDIR.${MK_QUOTAS}+= quotacheck SUBDIR.${MK_ROUTED}+= routed -SUBDIR.${MK_ZFS}+= be +SUBDIR.${MK_ZFS}+= bectl SUBDIR.${MK_ZFS}+= zfsbootcfg SUBDIR.${MK_TESTS}+= tests .include SUBDIR_PARALLEL= .include Index: projects/bectl/sbin/bectl/Makefile =================================================================== --- projects/bectl/sbin/bectl/Makefile (nonexistent) +++ projects/bectl/sbin/bectl/Makefile (revision 336669) @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= bectl +WARNS?= 1 +MAN= bectl.8 + +LIBADD+= be +LIBADD+= nvpair + +.include Property changes on: projects/bectl/sbin/bectl/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/bectl/sbin/bectl/bectl.8 =================================================================== --- projects/bectl/sbin/bectl/bectl.8 (nonexistent) +++ projects/bectl/sbin/bectl/bectl.8 (revision 336669) @@ -0,0 +1,220 @@ +.\" +.\" be - Utility to manage Boot Environments on the ZFS filesystem +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" +.\" @(#)be.1 +.\" $FreeBSD$ +.\" +.Dd June 15, 2017 +.Dt BE 1 +.Os FreeBSD +.Sh NAME +.Nm be +.Nd Utility to manage Boot Environments on ZFS +.Sh SYNOPSIS +.Nm +activate +.Op Fl t +.Ao Ar beName Ac +.Nm +create +.Op Fl r +.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot +.Ao Ar beName Ac +.Nm +create +.Op Fl r +.Ao Ar beName@snapshot Ac +.Nm +destroy +.Op Fl F +.Ao Ar beName | beName@snapshot Ac +.Nm +jail +.Ao Ar jailID | jailName Ac +.Ao Ar bootenv Ac +.Nm +list +.Op Fl a +.Op Fl D +.Op Fl H +.Op Fl s +.Nm +mount +.Ao Ar beName Ac +.Op mountpoint +.Nm +rename +.Ao Ar origBeName Ac +.Ao Ar newBeName Ac +.Nm +{ ujail | unjail } +.Ao Ar jailID | jailName Ac +.Ao Ar bootenv Ac +.Nm +{ umount | unmount } +.Op Fl f +.Ao Ar beName Ac +.Sh DESCRIPTION +The +.Nm +command is used to setup and interact with ZFS boot environments, which are bootable clones of datasets. +.Pp +.Em Boot Environments +allows the system to be upgraded, while preserving the old system environment in a separate ZFS dataset. +.Pp +.Sh COMMANDS +The following commands are supported by +.Nm : +.Bl -tag -width activate +.It Ic activate +.Op Fl t +.Ar +.Pp +Activate the given +.Ar beName +as the default boot filesystem. If the +.Op Fl t +flag is given, this takes effect only for the next boot. +.Pp +.It Ic create +.Op Fl r +.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot +.Ao Ar beName Ac +.Pp +Creates a new boot environment named +.Ar beName . +If the -e param is specified, the new environment will be cloned from the given +.Ar nonActiveBe | Ar beName@snapshot . +If the +.Op Fl r +flag is given, a recursive boot environment will be made. +.Pp +.It Ic create +.Op Fl r +.Ao Ar beName@snapshot Ac +.Pp +Creates a snapshot of the existing boot environment named +.Ar beName . +If the +.Op Fl r +flag is given, a recursive boot environment will be made. +.Pp +.It Ic destroy +.Op Fl F +.Ao Ar beName | beName@snapshot Ac +.Pp +Destroys the given +.Ar beName +boot environment or +.Ar beName@snapshot +snapshot. +Specifying +.Fl F +will automatically unmount without confirmation. +.Pp +.It Ic jail +.Ao Ar jailID | jailName Ac +.Ao Ar bootenv Ac +.Pp +Creates a jail of the given boot environment. +.Pp +.It Ic list +.Op Fl a +.Op Fl D +.Op Fl H +.Op Fl s +.Pp +Displays all boot environments. +The Active field indicates whether the boot environment is active now (N); active on reboot (R); or both (NR). +.Pp +If +.Fl a +is used, display all datasets. +If +.Fl D +is used, display the full space usage for each boot environment, assuming all other boot environments were destroyed. +The +.Fl H +option is used for scripting. It does not print headers and separate fields by a single tab instead of arbitrary white space. +If +.Fl s +is used, display all snapshots as well. +.Pp +.It Ic mount +.Ao Ar beName Ac +.Op mountpoint +.Pp +Temporarily mount the boot environment. +Mount at the specified +.Ar mountpoint +if provided. +.Pp +.It Ic rename Ao Ar origBeName Ac Ao Ar newBeName Ac +.Pp +Renames the given nonactive +.Ar origBeName +to the given +.Ar newBeName +.Pp +.It Ic unmount +.Op Fl f +.Ao Ar beName Ac +.Pp +Unmount the given boot environment, if it is mounted. +Specifying +.Fl f +will force the unmount if busy. +.Pp +.It Ic unjail +.Ao Ar beName Ac +.Pp +Destroys the jail created from the given boot environment. +.Pp +.El +.Sh EXAMPLES +.Bl -bullet +.It +To fill in with jail upgrade example when behavior is firm. +.Pp +.Sh SEE ALSO +.Xr jail 8 , +.Xr zfs 8 , +.Xr zpool 8 +.Sh HISTORY +.Nm +is based on +.Xr beadm 1 +and was implemented as a project for the 2017 Summer of Code, along with +.Xr libbe 3 . +.Sh AUTHORS +.Bl -bullet +.It +Kyle Kneitinger (kneitinger) +.Ar kyle@kneit.in +.Pp +Creator of +.Nm . +.It +Slawomir Wojciech Wojtczak (vermaden) +.Ar vermaden@interia.pl +.Pp +Creator and maintainer of +.Xr beadm 1 . +.It +Bryan Drewery (bdrewery) +.Ar bryan@shatow.net +.Pp +Wrote the original +.Xr beadm 1 +manual page that this one is derived from. +.El Property changes on: projects/bectl/sbin/bectl/bectl.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/bectl/sbin/bectl/bectl.c =================================================================== --- projects/bectl/sbin/bectl/bectl.c (nonexistent) +++ projects/bectl/sbin/bectl/bectl.c (revision 336669) @@ -0,0 +1,664 @@ +/* + * be.c + * + * Copyright (c) 2017 Kyle J. Kneitinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int be_cmd_activate(int argc, char *argv[]); +static int be_cmd_create(int argc, char *argv[]); +static int be_cmd_destroy(int argc, char *argv[]); +static int be_cmd_export(int argc, char *argv[]); +static int be_cmd_import(int argc, char *argv[]); +static int be_cmd_add(int argc, char *argv[]); +static int be_cmd_jail(int argc, char *argv[]); +static int be_cmd_list(int argc, char *argv[]); +static int be_cmd_mount(int argc, char *argv[]); +static int be_cmd_rename(int argc, char *argv[]); +static int be_cmd_unjail(int argc, char *argv[]); +static int be_cmd_unmount(int argc, char *argv[]); + +libbe_handle_t *be; + +static int +usage(bool explicit) +{ + FILE *fp = explicit ? stdout : stderr; + + fprintf(fp, + "usage:\tbe ( -h | -? | subcommand [args...] )\n" + "\tbe activate [-t] beName\n" + "\tbe create [-e nonActiveBe | -e beName@snapshot] beName\n" + "\tbe create beName@snapshot\n" + "\tbe destroy [-F] beName | beName@snapshot⟩\n" + "\tbe export sourceBe\n" + "\tbe import targetBe\n" + "\tbe add (path)*\n" + "\tbe jail bootenv\n" + "\tbe list [-a] [-D] [-H] [-s]\n" + "\tbe mount beName [mountpoint]\n" + "\tbe rename origBeName newBeName\n" + "\tbe { ujail | unjail } ⟨jailID | jailName⟩ bootenv\n" + "\tbe { umount | unmount } [-f] beName\n"); + + return (explicit ? 0 : EX_USAGE); +} + + +/* + * Represents a relationship between the command name and the parser action + * that handles it. + */ +struct command_map_entry { + const char *command; + int (*fn)(int argc, char *argv[]); +}; + +static struct command_map_entry command_map[] = +{ + { "activate", be_cmd_activate }, + { "create", be_cmd_create }, + { "destroy", be_cmd_destroy }, + { "export", be_cmd_export }, + { "import", be_cmd_import }, + { "add", be_cmd_add }, + { "jail", be_cmd_jail }, + { "list", be_cmd_list }, + { "mount", be_cmd_mount }, + { "rename", be_cmd_rename }, + { "unjail", be_cmd_unjail }, + { "unmount", be_cmd_unmount }, +}; + +static int +get_cmd_index(char *cmd, int *index) +{ + int map_size = sizeof(command_map) / sizeof(struct command_map_entry); + + for (int i = 0; i < map_size; ++i) { + if (strcmp(cmd, command_map[i].command) == 0) { + *index = i; + return (0); + } + } + + return (1); +} + + +static int +be_cmd_activate(int argc, char *argv[]) +{ + int err, opt; + bool temp; + char *bootenv; + + temp = false; + while ((opt = getopt(argc, argv, "t")) != -1) { + switch (opt) { + case 't': + temp = true; + break; + default: + fprintf(stderr, "be activate: unknown option '-%c'\n", + optopt); + return (usage(false)); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "be activate: wrong number of arguments\n"); + return (usage(false)); + } + + + /* activate logic goes here */ + if ((err = be_activate(be, argv[0], temp)) != 0) { + // TODO: more specific error msg based on err + printf("did not successfully activate boot environment %s\n", + argv[0]); + } else { + printf("successfully activated boot environment %s\n", argv[0]); + } + + if (temp) { + printf("for next boot\n"); + } + + return (err); +} + + +// TODO: when only one arg is given, and it contains an "@" the this should +// create that snapshot +static int +be_cmd_create(int argc, char *argv[]) +{ + int err, opt; + char *snapname; + char *bootenv; + char *source; + + snapname = NULL; + while ((opt = getopt(argc, argv, "e:")) != -1) { + switch (opt) { + case 'e': + snapname = optarg; + break; + default: + fprintf(stderr, "be create: unknown option '-%c'\n", + optopt); + return (usage(false)); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "be create: wrong number of arguments\n"); + return (usage(false)); + } + + bootenv = *argv; + + + if (snapname != NULL) { + if (strchr(snapname, '@') != NULL) { + err = be_create_from_existing_snap(be, bootenv, + snapname); + } else { + err = be_create_from_existing(be, bootenv, snapname); + } + } else { + if ((snapname = strchr(bootenv, '@')) != NULL) { + *(snapname++) = '\0'; + if ((err = be_snapshot(be, (char *)be_active_path(be), + snapname, true, NULL)) != BE_ERR_SUCCESS) { + fprintf(stderr, "failed to create snapshot\n"); + } + asprintf(&source, "%s@%s", be_active_path(be), snapname); + err = be_create_from_existing_snap(be, bootenv, + source); + return (err); + } else { + err = be_create(be, bootenv); + } + } + + switch (err) { + case BE_ERR_SUCCESS: + break; + default: + if (snapname == NULL) { + fprintf(stderr, + "failed to create bootenv %s\n", bootenv); + } else { + fprintf(stderr, + "failed to create bootenv %s from snapshot %s\n", + bootenv, snapname); + } + } + + return (err); +} + + +static int +be_cmd_export(int argc, char *argv[]) +{ + int opt; + char *bootenv; + + + if (argc == 1) { + fprintf(stderr, "be export: missing boot environment name\n"); + return (usage(false)); + } + + if (argc > 2) { + fprintf(stderr, "be export: extra arguments provided\n"); + return (usage(false)); + } + + bootenv = argv[1]; + + if (isatty(STDOUT_FILENO)) { + fprintf(stderr, "be export: must redirect output\n"); + return (EX_USAGE); + } + + be_export(be, bootenv, STDOUT_FILENO); + + return (0); +} + + +static int +be_cmd_import(int argc, char *argv[]) +{ + char *bootenv; + int err; + + + if (argc == 1) { + fprintf(stderr, "be import: missing boot environment name\n"); + return (usage(false)); + } + + + if (argc > 2) { + fprintf(stderr, "be import: extra arguments provided\n"); + return (usage(false)); + } + + bootenv = argv[1]; + + if (isatty(STDIN_FILENO)) { + fprintf(stderr, "be import: input can not be from terminal\n"); + return (EX_USAGE); + } + + err = be_import(be, bootenv, STDIN_FILENO); + + return (err); +} + + +static int +be_cmd_add(int argc, char *argv[]) +{ + char *bootenv; + + if (argc < 2) { + fprintf(stderr, "be add: must provide at least one path\n"); + return (usage(false)); + } + + for (int i = 1; i < argc; ++i) { + printf("arg %d: %s\n", i, argv[i]); + // TODO catch err + be_add_child(be, argv[i], true); + } + + return (0); +} + + +static int +be_cmd_destroy(int argc, char *argv[]) +{ + int opt, err; + bool force; + char *target; + + force = false; + while ((opt = getopt(argc, argv, "F")) != -1) { + switch (opt) { + case 'F': + force = true; + break; + default: + fprintf(stderr, "be destroy: unknown option '-%c'\n", + optopt); + return (usage(false)); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "be destroy: wrong number of arguments\n"); + return (usage(false)); + } + + target = argv[0]; + + err = be_destroy(be, target, force); + + return (err); +} + + +static int +be_cmd_jail(int argc, char *argv[]) +{ + char *bootenv; + char mnt_loc[BE_MAXPATHLEN]; + char buf[BE_MAXPATHLEN*2]; + int err, jid; + + //struct jail be_jail = { 0 }; + + if (argc == 1) { + fprintf(stderr, "be jail: missing boot environment name\n"); + return (usage(false)); + } + if (argc > 2) { + fprintf(stderr, "be jail: too many arguments\n"); + return (usage(false)); + } + + bootenv = argv[1]; + + // TODO: if its already mounted, perhaps there should be a flag to + // indicate its okay to proceed?? + if ((err = be_mount(be, bootenv, NULL, 0, mnt_loc)) != BE_ERR_SUCCESS) { + fprintf(stderr, "could not mount bootenv\n"); + } + + // NOTE: this is not quite functional: + // see https://github.com/vermaden/beadm/blob/master/HOWTO.htm on + // neccesary modifications to correctly boot the jail + + //snprintf(buf, BE_MAXPATHLEN*2, "jail %s %s %s /bin/sh /etc/rc", mnt_loc, bootenv, "192.168.1.123"); + snprintf(buf, BE_MAXPATHLEN*2, "jail %s %s %s /bin/sh", mnt_loc, + bootenv, "192.168.1.123"); + system(buf); + + unmount(mnt_loc, 0); + + /* + * be_jail.version = JAIL_API_VERSION; + * be_jail.path = "/tmp/be_mount.hCCk"; + * be_jail.jailname = "sdfs"; + * + * if ((jid = jail(&be_jail)) != -1) { + * printf("jail %d created at %s\n", jid, mnt_loc); + * err = 0; + * } else { + * fprintf(stderr, "unable to create jail. error: %d\n", errno); + * err = errno; + * } + */ + + return (0); +} + + +static int +be_cmd_list(int argc, char *argv[]) +{ + int opt; + bool show_all_datasets, show_space, hide_headers, show_snaps; + char *bootenv; + nvlist_t *props; + + show_all_datasets = show_space = hide_headers = show_snaps = false; + while ((opt = getopt(argc, argv, "aDHs")) != -1) { + switch (opt) { + case 'a': + show_all_datasets = true; + break; + case 'D': + show_space = true; + break; + case 'H': + hide_headers = true; + break; + case 's': + show_space = true; + break; + default: + fprintf(stderr, "be list: unknown option '-%c'\n", + optopt); + return (usage(false)); + } + } + + argc -= optind; + + if (argc != 0) { + fprintf(stderr, "be list: extra argument provided\n"); + return (usage(false)); + } + + //props = be_get_bootenv_props(be); + + return (0); +} + + +static int +be_cmd_mount(int argc, char *argv[]) +{ + int err; + char result_loc[BE_MAXPATHLEN]; + char *bootenv; + char *mountpoint; + + if (argc < 2) { + fprintf(stderr, "be mount: missing argument(s)\n"); + return (usage(false)); + } + + if (argc > 3) { + fprintf(stderr, "be mount: too many arguments\n"); + return (usage(false)); + } + + bootenv = argv[1]; + mountpoint = ((argc == 3) ? argv[2] : NULL); + + + err = be_mount(be, bootenv, mountpoint, 0, result_loc); + + switch (err) { + case BE_ERR_SUCCESS: + printf("successfully mounted %s at %s\n", bootenv, result_loc); + break; + default: + fprintf(stderr, + (argc == 3) ? "failed to mount bootenv %s at %s\n" : + "failed to mount bootenv %s at temporary path %s\n", + bootenv, mountpoint); + } + + return (err); +} + + +static int +be_cmd_rename(int argc, char *argv[]) +{ + char *src; + char *dest; + int err; + + if (argc < 3) { + fprintf(stderr, "be rename: missing argument\n"); + return (usage(false)); + } + + if (argc > 3) { + fprintf(stderr, "be rename: too many arguments\n"); + return (usage(false)); + } + + src = argv[1]; + dest = argv[2]; + + err = be_rename(be, src, dest); + + switch (err) { + case BE_ERR_SUCCESS: + break; + default: + fprintf(stderr, "failed to rename bootenv %s to %s\n", + src, dest); + } + + return (0); +} + + +static int +be_cmd_unjail(int argc, char *argv[]) +{ + int opt; + char *cmd, *target; + bool force; + + /* Store alias used */ + cmd = argv[0]; + + force = false; + while ((opt = getopt(argc, argv, "f")) != -1) { + switch (opt) { + case 'f': + force = true; + break; + default: + fprintf(stderr, "be %s: unknown option '-%c'\n", + cmd, optopt); + return (usage(false)); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "be %s: wrong number of arguments\n", cmd); + return (usage(false)); + } + + target = argv[0]; + + /* unjail logic goes here */ + + return (0); +} + + +static int +be_cmd_unmount(int argc, char *argv[]) +{ + int err, flags, opt; + char *cmd, *bootenv; + + /* Store alias used */ + cmd = argv[0]; + + flags = 0; + while ((opt = getopt(argc, argv, "f")) != -1) { + switch (opt) { + case 'f': + flags |= BE_MNT_FORCE; + break; + default: + fprintf(stderr, "be %s: unknown option '-%c'\n", + cmd, optopt); + return (usage(false)); + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "be %s: wrong number of arguments\n", cmd); + return (usage(false)); + } + + bootenv = argv[0]; + + err = be_unmount(be, bootenv, flags); + + switch (err) { + case BE_ERR_SUCCESS: + break; + default: + fprintf(stderr, "failed to unmount bootenv %s\n", bootenv); + } + + return (err); +} + + +int +main(int argc, char *argv[]) +{ + char *command; + int command_index, rc; + + if (argc < 2) { + fprintf(stderr, "missing command\n"); + return (usage(false)); + } + + command = argv[1]; + + /* Handle command aliases */ + if (strcmp(command, "umount") == 0) { + command = "unmount"; + } + + if (strcmp(command, "ujail") == 0) { + command = "unjail"; + } + + if ((strcmp(command, "-?") == 0) || (strcmp(command, "-h") == 0)) { + return (usage(true)); + } + + if (get_cmd_index(command, &command_index)) { + fprintf(stderr, "unknown command: %s\n", command); + return (usage(false)); + } + + + if ((be = libbe_init()) == NULL) { + return (-1); + } + + libbe_print_on_error(be, true); + + /* TODO: can be simplified if offset by 2 instead of one */ + rc = command_map[command_index].fn(argc-1, argv+1); + + libbe_close(be); + + + return (rc); +} Property changes on: projects/bectl/sbin/bectl/bectl.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property