git: e51036fbf3f8 - main - gvinum(8): Remove userland tool for managing vinum volumes

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 23 Jan 2025 16:21:05 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=e51036fbf3f896e8802ed0a5ef06ae1bcd7c0737

commit e51036fbf3f896e8802ed0a5ef06ae1bcd7c0737
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-01-23 15:32:49 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-01-23 16:20:43 +0000

    gvinum(8): Remove userland tool for managing vinum volumes
    
    Reviewed by:    imp, emaste
    Differential Revision:  https://reviews.freebsd.org/D48542
---
 ObsoleteFiles.inc                       |    4 +
 sbin/Makefile                           |    1 -
 sbin/geom/core/geom.8                   |    3 -
 sbin/gvinum/Makefile                    |   13 -
 sbin/gvinum/Makefile.depend             |   18 -
 sbin/gvinum/gvinum.8                    |  460 ----------
 sbin/gvinum/gvinum.c                    | 1450 -------------------------------
 sbin/gvinum/gvinum.h                    |   41 -
 targets/pseudo/userland/Makefile.depend |    1 -
 9 files changed, 4 insertions(+), 1987 deletions(-)

diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index afb71c46a459..eea25cc2e489 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,10 @@
 #   xargs -n1 | sort | uniq -d;
 # done
 
+# 20250123: Remove gvinum(8)
+OLD_FILES+=sbin/gvinum
+OLD_FILES+=usr/share/man/man8/gvinum.8.gz
+
 # 20250122: Remove publickey(5) stuff
 OLD_FILES+=usr/bin/chkey
 OLD_FILES+=usr/bin/keylogin
diff --git a/sbin/Makefile b/sbin/Makefile
index 5e5a8943c67a..ef953e80ba1e 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -24,7 +24,6 @@ SUBDIR=adjkerntz \
 	geom \
 	ggate \
 	growfs \
-	gvinum \
 	ifconfig \
 	init \
 	kldconfig \
diff --git a/sbin/geom/core/geom.8 b/sbin/geom/core/geom.8
index 7f0f0b2911b3..b864b3b238f5 100644
--- a/sbin/geom/core/geom.8
+++ b/sbin/geom/core/geom.8
@@ -168,8 +168,6 @@ STRIPE
 .It
 UNION
 .It
-VINUM (deprecated)
-.It
 VIRSTOR
 .El
 .Sh ENVIRONMENT
@@ -221,7 +219,6 @@ geom md unload
 .Xr gshsec 8 ,
 .Xr gstripe 8 ,
 .Xr gunion 8 ,
-.Xr gvinum 8 ,
 .Xr gvirstor 8
 .Sh HISTORY
 The
diff --git a/sbin/gvinum/Makefile b/sbin/gvinum/Makefile
deleted file mode 100644
index 7e7066964514..000000000000
--- a/sbin/gvinum/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-PACKAGE=geom
-PROG=	gvinum
-SRCS=	gvinum.c gvinum.h geom_vinum_share.c
-MAN=	gvinum.8
-
-WARNS?=		2
-CFLAGS+=	-I${SRCTOP}/sys -I${SYSROOT:U${DESTDIR}}/${INCLUDEDIR}/edit
-
-LIBADD=	edit geom
-
-.PATH: ${SRCTOP}/sys/geom/vinum
-
-.include <bsd.prog.mk>
diff --git a/sbin/gvinum/Makefile.depend b/sbin/gvinum/Makefile.depend
deleted file mode 100644
index 8d1c78126db9..000000000000
--- a/sbin/gvinum/Makefile.depend
+++ /dev/null
@@ -1,18 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
-	include \
-	include/xlocale \
-	lib/${CSU_DIR} \
-	lib/libc \
-	lib/libcompiler_rt \
-	lib/libedit \
-	lib/libedit/readline \
-	lib/libgeom \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/gvinum/gvinum.8 b/sbin/gvinum/gvinum.8
deleted file mode 100644
index e861681203c6..000000000000
--- a/sbin/gvinum/gvinum.8
+++ /dev/null
@@ -1,460 +0,0 @@
-.\"  Copyright (c) 2005 Chris Jones
-.\"  All rights reserved.
-.\"
-.\" This software was developed for the FreeBSD Project by Chris Jones
-.\" thanks to the support of Google's Summer of Code program and
-.\" mentoring by Lukas Ertl.
-.\"
-.\" 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 AUTHOR 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 AUTHOR 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.
-.\"
-.Dd January 23, 2025
-.Dt GVINUM 8
-.Os
-.Sh NAME
-.Nm gvinum
-.Nd Logical Volume Manager control program
-.Sh DEPRECATION NOTICE
-.Nm
-and associated
-.Xr geom 4
-kernel support is deprecated, and is not be available in
-.Fx 15.0
-and later.
-Users are advised to migrate to
-.Xr gconcat 8 ,
-.Xr gmirror 8 ,
-.Xr gstripe 8 ,
-.Xr graid 8 ,
-or
-.Xr zfs 8 .
-More information is available at
-.Pa https://wiki.freebsd.org/DeprecationPlan/gvinum .
-.Sh SYNOPSIS
-.Nm
-.Op Ar command
-.Op Fl options
-.Sh COMMANDS
-.Bl -tag -width indent
-.It Ic attach Ar plex volume Op Cm rename
-.It Ic attach Ar subdisk plex Oo Ar offset Oc Op Cm rename
-Attach a plex to a volume, or a subdisk to a plex.
-If offset is specified, the subdisk will be attached to the given offset within
-the plex.
-If rename is specified, the subdisk or plex will change name according to the
-object it attaches to.
-.It Ic checkparity Oo Fl f Oc Ar plex
-Check the parity blocks of a RAID-5 plex.
-The parity check will start at the
-beginning of the plex if the
-.Fl f
-flag is specified, or otherwise at the location of the parity check pointer,
-the first location at which plex's parity is incorrect.
-All subdisks in the
-plex must be up for a parity check.
-.It Ic concat Oo Fl fv Oc Oo Fl n Ar name Oc Ar drives
-Create a concatenated volume from the specified drives.
-If no name is specified, a unique name will be set by
-.Ic gvinum .
-.It Ic create Oo Fl f Oc Op Ar description-file
-Create a volume as described in
-.Ar description-file .
-If no
-.Ar description-file
-provided, opens an editor and provides the current
-.Nm
-configuration for editing.
-The
-.Fl f
-flag will make gvinum ignore any errors regarding creating objects that already
-exists.
-However, in contrast to vinum, objects that are not properly named in the
-.Ar description-file
-will not be created when the
-.Fl f
-flag is given.
-.It Ic detach Oo Fl f Oc Op Ar plex | subdisk
-Detach a plex or subdisk from the volume or plex to which it is
-attached.
-.It Ic grow Ar plex device
-Grow a plex by creating a gvinum drive and subdisk on device and attach it to
-the plex.
-If required by the plex organization, it will be put into the growable state.
-.It Ic help
-Provides a synopsis of
-.Nm
-commands and arguments.
-.It Ic l | list Oo Fl rvV Oc Op Ar volume | plex | subdisk
-.It Ic ld Oo Fl rvV Oc Op Ar drive ...
-.It Ic ls Oo Fl rvV Oc Op Ar subdisk ...
-.It Ic lp Oo Fl rvV Oc Op Ar plex ...
-.It Ic lv Oo Fl rvV Oc Op Ar volume ...
-List information about the relevant object(s).
-The
-.Fl r
-flag provides recursive display, showing each object's subordinate objects in
-proper relation.
-The
-.Fl v
-and
-.Fl V
-flags provide progressively more detailed output.
-.It Ic mirror Oo Fl fsv Oc Oo Fl n Ar name Oc Ar drives
-Create a mirrored volume from the specified drives.
-It requires at least a multiple of 2 drives.
-If no name is specified, a unique name will be set by gvinum.
-If the
-.Fl s
-flag is specified, a striped mirror will be created, and thus requires a
-multiple of 4 drives.
-.It Ic move | mv Fl f Ar drive subdisk Op Ar ...
-Move the subdisk(s) to the specified drive.
-The
-.Fl f
-flag is required, as all data on the indicated subdisk(s) will be destroyed as
-part of the move.
-This can currently only be done when the subdisk is
-not being accessed.
-.Pp
-If a single subdisk is moved, and it forms a part of a RAID-5 plex, the moved
-subdisks will need to be set to the
-.Dq stale
-state, and the plex will require a
-.Ic start
-command.
-If multiple subdisk(s) is moved, and form part of a RAID-5 plex, the
-moved disk(s) will need to be set to the
-.Dq up
-state and the plex will require a
-.Ic rebuildparity
-command.
-If the subdisk(s) form part of a plex that is mirrored with other
-plexes, the plex will require restarting and will sync once restarted.
-Moving
-more than one subdisk in a RAID-5 plex or subdisks from both sides of a
-mirrored plex volume will destroy data.
-Note that parity rebuilds and syncing
-must be started manually after a move.
-.It Ic printconfig
-Write a copy of the current configuration to standard output.
-.It Ic quit
-Exit
-.Nm
-when running in interactive mode.
-Normally this would be done by entering the
-EOF character.
-.It Ic raid5 Oo Fl fv Oc Oo Fl s Ar stripesize Oc Oo Fl n Ar name Oc Ar drives
-Create a RAID-5 volume from the specified drives.
-If no name is specified, a unique name will be set by
-.Ic gvinum .
-This organization requires at least three drives.
-.It Ic rename Oo Fl r Oc Ar drive | subdisk | plex | volume newname
-Change the name of the specified object.
-The
-.Fl r
-flag will recursively rename subordinate objects.
-.Pp
-Note that device nodes will not be renamed until
-.Nm
-is restarted.
-.It Ic rebuildparity Oo Fl f Oc Ar plex
-Rebuild the parity blocks of a RAID-5 plex.
-The parity rebuild will start at
-the beginning of the plex if the
-.Fl f
-flag is specified, or otherwise at the location of the parity check pointer.
-All subdisks in the plex must be up for a parity check.
-.It Ic resetconfig Oo Fl f Oc
-Reset the complete
-.Nm
-configuration.
-.It Ic rm Oo Fl r Oc Ar volume | plex | subdisk
-Remove an object and, if
-.Fl r
-is specified, its subordinate objects.
-.It Ic saveconfig
-Save
-.Nm
-configuration to disk after configuration failures.
-.It Ic setstate Oo Fl f Oc Ar state volume | plex | subdisk | drive
-Set state without influencing other objects, for diagnostic purposes
-only.
-The
-.Fl f
-flag forces state changes regardless of whether they are legal.
-.It Ic start
-Read configuration from all vinum drives.
-.It Ic start Oo Fl S Ar size Oc Ar volume | plex | subdisk
-Allow the system to access the objects.
-If necessary, plexes will be synced and rebuilt.
-If a subdisk was added to a running RAID-5 or striped plex, gvinum will
-expand into this subdisk and grow the whole RAID-5 array.
-This can be done without unmounting your filesystem.
-The
-.Fl S
-flag is currently ignored.
-.It Ic stop Oo Fl f Oc Op Ar volume | plex | subdisk
-Terminate access to the objects, or stop
-.Nm
-if no parameters are specified.
-.It Ic stripe Oo Fl fv Oc Oo Fl n Ar name Oc Ar drives
-Create a striped volume from the specified drives.
-If no name is specified, a unique name will be set by
-.Ic gvinum .
-This organization requires at least two drives.
-.El
-.Sh DESCRIPTION
-The
-.Nm
-utility communicates with the kernel component of the GVinum logical volume
-manager.
-It is designed either for interactive use, when started without
-command line arguments, or to execute a single command if the command is
-supplied on the command line.
-In interactive mode,
-.Nm
-maintains a command line history.
-.Sh OPTIONS
-The
-.Nm
-commands may be followed by an option.
-.Bl -tag -width indent
-.It Fl f
-The
-.Fl f
-.Pq Dq force
-option overrides safety checks.
-It should be used with extreme caution.
-This
-option is required in order to use the
-.Ic move
-command.
-.It Fl r
-The
-.Fl r
-.Pq Dq recursive
-option applies the command recursively to subordinate objects.
-For example, in
-conjunction with the
-.Ic lv
-command, the
-.Fl r
-option will also show information about the plexes and subdisks belonging to
-the volume.
-It is also used by the
-.Ic rename
-command to indicate that subordinate objects such as subdisks should be renamed
-to match the object(s) specified and by the
-.Ic rm
-command to delete plexes belonging to a volume and so on.
-.It Fl v
-The
-.Fl v
-.Pq Dq verbose
-option provides more detailed output.
-.It Fl V
-The
-.Fl V
-.Pq Dq "very verbose"
-option provides even more detailed output than
-.Fl v .
-.El
-.Sh ENVIRONMENT
-.Bl -tag -width ".Ev EDITOR"
-.It Ev EDITOR
-The name of the editor to use for editing configuration files, by
-default
-.Xr vi 1
-is invoked.
-.El
-.Sh FILES
-.Bl -tag -width ".Pa /dev/gvinum/plex"
-.It Pa /dev/gvinum
-directory with device nodes for
-.Nm
-objects
-.El
-.Sh EXAMPLES
-To create a mirror on disks /dev/ada1 and /dev/ada2, create a filesystem,
-mount, unmount and then stop
-.Ic gvinum :
-.Pp
-.Dl "gvinum mirror /dev/ada1 /dev/ada2"
-.Dl "newfs /dev/gvinum/gvinumvolume0"
-.Dl "mount /dev/gvinum/gvinumvolume0 /mnt"
-.Dl "..."
-.Dl "unmount /mnt"
-.Dl "gvinum stop"
-.Pp
-To create a striped mirror on disks /dev/ada1 /dev/ada2 /dev/ada3 and
-/dev/ada4 named "data" and create a filesystem:
-.Pp
-.Dl "gvinum mirror -s -n data /dev/ada1 /dev/ada2 /dev/ada3 /dev/ada4"
-.Dl "newfs /dev/gvinum/data"
-.Pp
-To create a raid5 array on disks /dev/ada1 /dev/ada2 and /dev/ada3,
-with stripesize 493k you can use the raid5 command:
-.Pp
-.Dl "gvinum raid5 -s 493k /dev/ada1 /dev/ada2 /dev/ada3"
-.Pp
-Then the volume will be created automatically.
-Afterwards, you have to initialize the volume:
-.Pp
-.Dl "gvinum start myraid5vol"
-.Pp
-The initialization will start, and the states will be updated when it's
-finished.
-The list command will give you information about its progress.
-.Pp
-Imagine that one of the drives fails, and the output of 'printconfig' looks
-something like this:
-.Pp
-.Dl "drive gvinumdrive1 device /dev/ada2"
-.Dl "drive gvinumdrive2 device /dev/???"
-.Dl "drive gvinumdrive0 device /dev/ada1"
-.Dl "volume myraid5vol"
-.Dl "plex name myraid5vol.p0 org raid5 986s vol myraid5vol"
-.Dl "sd name myraid5vol.p0.s2 drive gvinumdrive2 len 32538s driveoffset 265s"
-.Dl "plex myraid5vol.p0 plexoffset 1972s"
-.Dl "sd name myraid5vol.p0.s1 drive gvinumdrive1 len 32538s driveoffset 265s"
-.Dl "plex myraid5vol.p0 plexoffset 986s"
-.Dl "sd name myraid5vol.p0.s0 drive gvinumdrive0 len 32538s driveoffset 265s"
-.Dl "plex myraid5vol.p0 plexoffset 0s"
-.Pp
-Create a new drive with this configuration:
-.Pp
-.Dl "drive gdrive4 device /dev/ada4"
-.Pp
-Then move the stale subdisk to the new drive:
-.Pp
-.Dl "gvinum move gdrive4 myraid5vol.p0.s2"
-.Pp
-Then, initiate the rebuild:
-.Pp
-.Dl "gvinum start myraid5vol.p0"
-.Pp
-The plex will go up from degraded mode after the rebuild is finished.
-The plex can still be used while the rebuild is in progress, although requests
-might be delayed.
-.Pp
-Given the configuration as in the previous example, growing a RAID-5 or STRIPED
-array is accomplished by using the grow command:
-.Pp
-.Dl "gvinum grow myraid5vol.p0 /dev/ada4"
-.Pp
-If everything went ok, the plex state should now be set to growable.
-You can then start the growing with the
-.Ic start
-command:
-.Pp
-.Dl "gvinum start myraid5vol.p0"
-.Pp
-As with rebuilding, you can watch the progress using the
-.Ic list
-command.
-.Pp
-For a more advanced usage and detailed explanation of gvinum, the
-handbook is recommended.
-.Sh SEE ALSO
-.Xr geom 4 ,
-.Xr geom 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 5.3 .
-The
-.Nm vinum
-utility, on which
-.Nm
-is based, was written by
-.An "Greg Lehey" .
-.Pp
-The
-.Nm
-utility
-was written by
-.An "Lukas Ertl" .
-The
-.Ic move
-and
-.Ic rename
-commands and
-documentation were added by
-.An "Chris Jones"
-through the 2005 Google Summer
-of Code program.
-A partial rewrite of gvinum was done by
-.An "Lukas Ertl"
-and
-.An "Ulf Lilleengen"
-through the 2007 Google Summer of Code program.
-The documentation have been updated to reflect the new functionality.
-.Sh AUTHORS
-.An Lukas Ertl Aq Mt le@FreeBSD.org
-.An Chris Jones Aq Mt soc-cjones@FreeBSD.org
-.An Ulf Lilleengen Aq Mt lulf@FreeBSD.org
-.Sh BUGS
-Currently,
-.Nm
-does not rename devices in
-.Pa /dev/gvinum
-until reloaded.
-.Pp
-The
-.Fl S
-initsize flag to
-.Ic start
-is ignored.
-.Pp
-Moving subdisks that are not part of a mirrored or RAID-5 volume will
-destroy data.
-It is perhaps a bug to permit this.
-.Pp
-Plexes in which subdisks have been moved do not automatically sync or
-rebuild parity.
-This may leave data unprotected and is perhaps unwise.
-.Pp
-Currently,
-.Nm
-does not yet fully implement all of the functions found in
-.Nm vinum .
-Specifically, the following commands from
-.Nm vinum
-are not supported:
-.Bl -tag -width indent
-.It Ic debug
-Cause the volume manager to enter the kernel debugger.
-.It Ic debug Ar flags
-Set debugging flags.
-.It Ic dumpconfig Op Ar drive ...
-List the configuration information stored on the specified drives, or all
-drives in the system if no drive names are specified.
-.It Ic info Op Fl vV
-List information about volume manager state.
-.It Ic label Ar volume
-Create a volume label.
-.It Ic resetstats Oo Fl r Oc Op Ar volume | plex | subdisk
-Reset statistics counters for the specified objects, or for all objects if none
-are specified.
-.It Ic setdaemon Op Ar value
-Set daemon configuration.
-.El
diff --git a/sbin/gvinum/gvinum.c b/sbin/gvinum/gvinum.c
deleted file mode 100644
index c391f5d61c65..000000000000
--- a/sbin/gvinum/gvinum.c
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- *  Copyright (c) 2004 Lukas Ertl
- *  Copyright (c) 2005 Chris Jones
- *  Copyright (c) 2007 Ulf Lilleengen
- *  All rights reserved.
- *
- * Portions of this software were developed for the FreeBSD Project
- * by Chris Jones thanks to the support of Google's Summer of Code
- * program and mentoring by Lukas Ertl.
- *
- * 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 AUTHOR 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 AUTHOR 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 <sys/param.h>
-#include <sys/linker.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/queue.h>
-#include <sys/utsname.h>
-
-#include <geom/vinum/geom_vinum_var.h>
-#include <geom/vinum/geom_vinum_share.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <libgeom.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <paths.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-#include <unistd.h>
-
-#include "gvinum.h"
-
-static void gvinum_attach(int, char * const *);
-static void gvinum_concat(int, char * const *);
-static void gvinum_create(int, char * const *);
-static void gvinum_detach(int, char * const *);
-static void gvinum_grow(int, char * const *);
-static void gvinum_help(void);
-static void gvinum_list(int, char * const *);
-static void gvinum_move(int, char * const *);
-static void gvinum_mirror(int, char * const *);
-static void gvinum_parityop(int, char * const * , int);
-static void gvinum_printconfig(int, char * const *);
-static void gvinum_raid5(int, char * const *);
-static void gvinum_rename(int, char * const *);
-static void gvinum_resetconfig(int, char * const *);
-static void gvinum_rm(int, char * const *);
-static void gvinum_saveconfig(void);
-static void gvinum_setstate(int, char * const *);
-static void gvinum_start(int, char * const *);
-static void gvinum_stop(int, char * const *);
-static void gvinum_stripe(int, char * const *);
-static void parseline(int, char * const *);
-static void printconfig(FILE *, const char *);
-
-static char *create_drive(const char *);
-static void create_volume(int, char * const * , const char *);
-static char *find_name(const char *, int, int);
-static const char *find_pattern(char *, const char *);
-static void copy_device(struct gv_drive *, const char *);
-#define	find_drive()							\
-    find_name("gvinumdrive", GV_TYPE_DRIVE, GV_MAXDRIVENAME)
-
-int
-main(int argc, char **argv)
-{
-	int tokens;
-	char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS];
-
-	/* Load the module if necessary. */
-	if (modfind(GVINUMMOD) < 0) {
-		if (kldload(GVINUMKLD) < 0 && modfind(GVINUMMOD) < 0)
-			err(1, GVINUMKLD ": Kernel module not available");
-	}
-
-	/* Arguments given on the command line. */
-	if (argc > 1) {
-		argc--;
-		argv++;
-		parseline(argc, argv);
-
-	/* Interactive mode. */
-	} else {
-		for (;;) {
-			inputline = readline("gvinum -> ");
-			if (inputline == NULL) {
-				if (ferror(stdin)) {
-					err(1, "can't read input");
-				} else {
-					printf("\n");
-					exit(0);
-				}
-			} else if (*inputline) {
-				add_history(inputline);
-				strcpy(buffer, inputline);
-				free(inputline);
-				tokens = gv_tokenize(buffer, token, GV_MAXARGS);
-				if (tokens)
-					parseline(tokens, token);
-			}
-		}
-	}
-	exit(0);
-}
-
-/* Attach a plex to a volume or a subdisk to a plex. */
-static void
-gvinum_attach(int argc, char * const *argv)
-{
-	struct gctl_req *req;
-	const char *errstr;
-	int rename;
-	off_t offset;
-
-	rename = 0;
-	offset = -1;
-	if (argc < 3) {
-		warnx("usage:\tattach <subdisk> <plex> [rename] "
-		    "[<plexoffset>]\n"
-		    "\tattach <plex> <volume> [rename]");
-		return;
-	}
-	if (argc > 3) {
-		if (!strcmp(argv[3], "rename")) {
-			rename = 1;
-			if (argc == 5)
-				offset = strtol(argv[4], NULL, 0);
-		} else
-			offset = strtol(argv[3], NULL, 0);
-	}
-	req = gctl_get_handle();
-	gctl_ro_param(req, "class", -1, "VINUM");
-	gctl_ro_param(req, "verb", -1, "attach");
-	gctl_ro_param(req, "child", -1, argv[1]);
-	gctl_ro_param(req, "parent", -1, argv[2]);
-	gctl_ro_param(req, "offset", sizeof(off_t), &offset);
-	gctl_ro_param(req, "rename", sizeof(int), &rename);
-	errstr = gctl_issue(req);
-	if (errstr != NULL)
-		warnx("attach failed: %s", errstr);
-	gctl_free(req);
-}
-
-static void
-gvinum_create(int argc, char * const *argv)
-{
-	struct gctl_req *req;
-	struct gv_drive *d;
-	struct gv_plex *p;
-	struct gv_sd *s;
-	struct gv_volume *v;
-	FILE *tmp;
-	int drives, errors, fd, flags, i, line, plexes, plex_in_volume;
-	int sd_in_plex, status, subdisks, tokens, undeffd, volumes;
-	const char *errstr;
-	char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *sdname;
-	const char *ed;
-	char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS];
-	char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME];
-
-	tmp = NULL;
-	flags = 0;
-	for (i = 1; i < argc; i++) {
-		/* Force flag used to ignore already created drives. */
-		if (!strcmp(argv[i], "-f")) {
-			flags |= GV_FLAG_F;
-		/* Else it must be a file. */
-		} else {
-			if ((tmp = fopen(argv[i], "r")) == NULL) {
-				warn("can't open '%s' for reading", argv[i]);
-				return;
-			}
-		}	
-	}
-
-	/* We didn't get a file. */
-	if (tmp == NULL) {
-		snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX");
-		
-		if ((fd = mkstemp(tmpfile)) == -1) {
-			warn("temporary file not accessible");
-			return;
-		}
-		if ((tmp = fdopen(fd, "w")) == NULL) {
-			warn("can't open '%s' for writing", tmpfile);
-			return;
-		}
-		printconfig(tmp, "# ");
-		fclose(tmp);
-		
-		ed = getenv("EDITOR");
-		if (ed == NULL)
-			ed = _PATH_VI;
-		
-		snprintf(commandline, sizeof(commandline), "%s %s", ed,
-		    tmpfile);
-		status = system(commandline);
-		if (status != 0) {
-			warn("couldn't exec %s; status: %d", ed, status);
-			return;
-		}
-		
-		if ((tmp = fopen(tmpfile, "r")) == NULL) {
-			warn("can't open '%s' for reading", tmpfile);
-			return;
-		}
-	}
-
-	req = gctl_get_handle();
-	gctl_ro_param(req, "class", -1, "VINUM");
-	gctl_ro_param(req, "verb", -1, "create");
-	gctl_ro_param(req, "flags", sizeof(int), &flags);
-
-	drives = volumes = plexes = subdisks = 0;
-	plex_in_volume = sd_in_plex = undeffd = 0;
-	plex[0] = '\0';
-	errors = 0;
-	line = 1;
-	while ((fgets(buf, BUFSIZ, tmp)) != NULL) {
-
-		/* Skip empty lines and comments. */
-		if (*buf == '\0' || *buf == '#') {
-			line++;
-			continue;
-		}
-
-		/* Kill off the newline. */
-		buf[strlen(buf) - 1] = '\0';
-
-		/*
-		 * Copy the original input line in case we need it for error
-		 * output.
-		 */
-		strlcpy(original, buf, sizeof(original));
-
-		tokens = gv_tokenize(buf, token, GV_MAXARGS);
-		if (tokens <= 0) {
-			line++;
-			continue;
-		}
-
-		/* Volume definition. */
-		if (!strcmp(token[0], "volume")) {
-			v = gv_new_volume(tokens, token);
-			if (v == NULL) {
-				warnx("line %d: invalid volume definition",
-				    line);
-				warnx("line %d: '%s'", line, original);
-				errors++;
-				line++;
-				continue;
-			}
-
-			/* Reset plex count for this volume. */
-			plex_in_volume = 0;
-
-			/*
-			 * Set default volume name for following plex
-			 * definitions.
-			 */
-			strlcpy(volume, v->name, sizeof(volume));
-
-			snprintf(buf1, sizeof(buf1), "volume%d", volumes);
-			gctl_ro_param(req, buf1, sizeof(*v), v);
-			volumes++;
-
-		/* Plex definition. */
-		} else if (!strcmp(token[0], "plex")) {
-			p = gv_new_plex(tokens, token);
-			if (p == NULL) {
-				warnx("line %d: invalid plex definition", line);
-				warnx("line %d: '%s'", line, original);
-				errors++;
-				line++;
-				continue;
-			}
-
-			/* Reset subdisk count for this plex. */
-			sd_in_plex = 0;
-
-			/* Default name. */
-			if (strlen(p->name) == 0) {
-				snprintf(p->name, sizeof(p->name), "%s.p%d",
-				    volume, plex_in_volume++);
-			}
-
-			/* Default volume. */
-			if (strlen(p->volume) == 0) {
-				snprintf(p->volume, sizeof(p->volume), "%s",
-				    volume);
-			}
-
-			/*
-			 * Set default plex name for following subdisk
-			 * definitions.
-			 */
-			strlcpy(plex, p->name, sizeof(plex));
-
-			snprintf(buf1, sizeof(buf1), "plex%d", plexes);
-			gctl_ro_param(req, buf1, sizeof(*p), p);
-			plexes++;
-
-		/* Subdisk definition. */
-		} else if (!strcmp(token[0], "sd")) {
-			s = gv_new_sd(tokens, token);
-			if (s == NULL) {
-				warnx("line %d: invalid subdisk "
-				    "definition:", line);
-				warnx("line %d: '%s'", line, original);
-				errors++;
-				line++;
-				continue;
-			}
-
-			/* Default name. */
-			if (strlen(s->name) == 0) {
-				if (strlen(plex) == 0) {
-					sdname = find_name("gvinumsubdisk.p",
-					    GV_TYPE_SD, GV_MAXSDNAME);
-					snprintf(s->name, sizeof(s->name),
-					    "%s.s%d", sdname, undeffd++);
-					free(sdname);
-				} else {
-					snprintf(s->name, sizeof(s->name),
-					    "%s.s%d",plex, sd_in_plex++);
-				}
-			}
-
-			/* Default plex. */
-			if (strlen(s->plex) == 0)
-				snprintf(s->plex, sizeof(s->plex), "%s", plex);
-
-			snprintf(buf1, sizeof(buf1), "sd%d", subdisks);
-			gctl_ro_param(req, buf1, sizeof(*s), s);
-			subdisks++;
-
-		/* Subdisk definition. */
-		} else if (!strcmp(token[0], "drive")) {
-			d = gv_new_drive(tokens, token);
-			if (d == NULL) {
-				warnx("line %d: invalid drive definition:",
-				    line);
-				warnx("line %d: '%s'", line, original);
-				errors++;
-				line++;
-				continue;
-			}
-
-			snprintf(buf1, sizeof(buf1), "drive%d", drives);
-			gctl_ro_param(req, buf1, sizeof(*d), d);
-			drives++;
-
-		/* Everything else is bogus. */
-		} else {
-			warnx("line %d: invalid definition:", line);
-			warnx("line %d: '%s'", line, original);
-			errors++;
-		}
-		line++;
-	}
-
-	fclose(tmp);
-	unlink(tmpfile);
-
-	if (!errors && (volumes || plexes || subdisks || drives)) {
-		gctl_ro_param(req, "volumes", sizeof(int), &volumes);
-		gctl_ro_param(req, "plexes", sizeof(int), &plexes);
-		gctl_ro_param(req, "subdisks", sizeof(int), &subdisks);
-		gctl_ro_param(req, "drives", sizeof(int), &drives);
*** 1112 LINES SKIPPED ***