2017-02-10 20:36:11 +03:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 - 2017 Red Hat , Inc . All rights reserved .
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <asm/types.h>
# include <sys/types.h>
# include <sys/ioctl.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <sys/wait.h>
# include <fcntl.h>
# include <stdio.h>
# include <errno.h>
# include <string.h>
# include <stdlib.h>
# include <stddef.h>
# include <stdint.h>
# include <stdarg.h>
# include <limits.h>
# include <unistd.h>
# include <syslog.h>
# include <sched.h>
# include <dirent.h>
# include <ctype.h>
# include <getopt.h>
/*
* This file can be compiled by itself as a man page generator .
*/
# ifdef MAN_PAGE_GENERATOR
# define log_error(fmt, args...) \
do { \
printf ( fmt " \n " , # # args ) ; \
} while ( 0 )
2017-02-16 00:49:18 +03:00
# define dm_malloc malloc
# define dm_free free
# define dm_strdup strdup
2017-02-17 15:36:57 +03:00
# define dm_snprintf snprintf
static int dm_strncpy ( char * dest , const char * src , size_t n )
{
if ( memccpy ( dest , src , 0 , n ) )
return 1 ;
if ( n > 0 )
dest [ n - 1 ] = ' \0 ' ;
return 0 ;
}
2017-02-16 00:49:18 +03:00
2017-02-10 20:36:11 +03:00
/* needed to include args.h */
# define ARG_COUNTABLE 0x00000001
# define ARG_GROUPABLE 0x00000002
struct cmd_context ;
struct arg_values ;
/* needed to include args.h */
static inline int yes_no_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int activation_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int cachemode_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int discards_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int mirrorlog_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int size_kb_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-03-02 21:53:01 +03:00
static inline int ssize_kb_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-10 20:36:11 +03:00
static inline int size_mb_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-03-02 21:53:01 +03:00
static inline int ssize_mb_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-10 20:36:11 +03:00
static inline int int_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int uint32_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int int_arg_with_sign ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-24 22:44:05 +03:00
static inline int extents_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-10 20:36:11 +03:00
static inline int major_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int minor_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int string_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int tag_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int permission_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int metadatatype_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int units_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int segtype_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int alloc_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int locktype_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
static inline int readahead_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-08 00:12:24 +03:00
static inline int regionsize_arg ( struct cmd_context * cmd , struct arg_values * av ) { return 0 ; }
2017-02-10 20:36:11 +03:00
static inline int vgmetadatacopies_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int pvmetadatacopies_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int metadatacopies_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int polloperation_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int writemostly_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int syncaction_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int reportformat_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int configreport_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
static inline int configtype_arg ( struct cmd_context * cmd __attribute__ ( ( unused ) ) , struct arg_values * av ) { return 0 ; }
/* needed to include commands.h when building man page generator */
# define CACHE_VGMETADATA 0x00000001
# define PERMITTED_READ_ONLY 0x00000002
# define ALL_VGS_IS_DEFAULT 0x00000004
# define ENABLE_ALL_DEVS 0x00000008
# define ALLOW_UUID_AS_NAME 0x00000010
# define LOCKD_VG_SH 0x00000020
# define NO_METADATA_PROCESSING 0x00000040
# define REQUIRES_FULL_LABEL_SCAN 0x00000080
# define MUST_USE_ALL_ARGS 0x00000100
# define NO_LVMETAD_AUTOSCAN 0x00000200
# define ENABLE_DUPLICATE_DEVS 0x00000400
# define DISALLOW_TAG_ARGS 0x00000800
# define GET_VGNAME_FROM_OPTIONS 0x00001000
/* create foo_CMD enums for command def ID's in command-lines.in */
enum {
# define cmd(a, b) a ,
# include "cmds.h"
# undef cmd
} ;
/* create foo_VAL enums for option and position values */
enum {
# define val(a, b, c, d) a ,
# include "vals.h"
# undef val
} ;
/* create foo_ARG enums for --option's */
enum {
# define arg(a, b, c, d, e, f, g) a ,
# include "args.h"
# undef arg
} ;
/* create foo_LVP enums for LV properties */
enum {
# define lvp(a, b, c) a,
# include "lv_props.h"
# undef lvp
} ;
/* create foo_LVT enums for LV types */
enum {
# define lvt(a, b, c) a,
# include "lv_types.h"
# undef lvt
} ;
2017-02-17 13:51:24 +03:00
# else /* MAN_PAGE_GENERATOR */
2017-02-10 20:36:11 +03:00
# include "tools.h"
2017-02-17 13:51:24 +03:00
# endif /* MAN_PAGE_GENERATOR */
2017-02-10 20:36:11 +03:00
# include "command.h" /* defines struct command */
# include "command-count.h" /* defines COMMAND_COUNT */
/* see opt_names[] below, also see arg_props[] in tools.h and args.h */
struct opt_name {
const char * name ; /* "foo_ARG" */
int opt_enum ; /* foo_ARG */
const char short_opt ; /* -f */
char _padding [ 7 ] ;
const char * long_opt ; /* --foo */
int val_enum ; /* xyz_VAL when --foo takes a val like "--foo xyz" */
2017-02-23 01:38:54 +03:00
uint32_t flags ;
uint32_t prio ;
2017-02-10 20:36:11 +03:00
const char * desc ;
} ;
/* see val_names[] below, also see val_props[] in tools.h and vals.h */
struct val_name {
const char * enum_name ; /* "foo_VAL" */
int val_enum ; /* foo_VAL */
int ( * fn ) ( struct cmd_context * cmd , struct arg_values * av ) ; /* foo_arg() */
const char * name ; /* FooVal */
const char * usage ;
} ;
/* see lvp_names[] below, also see lv_props[] in tools.h and lv_props.h */
struct lvp_name {
const char * enum_name ; /* "is_foo_LVP" */
int lvp_enum ; /* is_foo_LVP */
const char * name ; /* "lv_is_foo" */
} ;
/* see lvt_names[] below, also see lv_types[] in tools.h and lv_types.h */
struct lvt_name {
const char * enum_name ; /* "foo_LVT" */
int lvt_enum ; /* foo_LVT */
const char * name ; /* "foo" */
} ;
/* see cmd_names[] below, one for each unique "ID" in command-lines.in */
struct cmd_name {
const char * enum_name ; /* "foo_CMD" */
int cmd_enum ; /* foo_CMD */
const char * name ; /* "foo" from string after ID: */
} ;
/* create table of value names, e.g. String, and corresponding enum from vals.h */
struct val_name val_names [ VAL_COUNT + 1 ] = {
# define val(a, b, c, d) { # a, a, b, c, d },
# include "vals.h"
# undef val
} ;
/* create table of option names, e.g. --foo, and corresponding enum from args.h */
struct opt_name opt_names [ ARG_COUNT + 1 ] = {
# define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
# include "args.h"
# undef arg
} ;
/* create table of lv property names, e.g. lv_is_foo, and corresponding enum from lv_props.h */
struct lvp_name lvp_names [ LVP_COUNT + 1 ] = {
# define lvp(a, b, c) { # a, a, b },
# include "lv_props.h"
# undef lvp
} ;
/* create table of lv type names, e.g. linear and corresponding enum from lv_types.h */
struct lvt_name lvt_names [ LVT_COUNT + 1 ] = {
# define lvt(a, b, c) { # a, a, b },
# include "lv_types.h"
# undef lvt
} ;
/* create table of command IDs */
struct cmd_name cmd_names [ CMD_COUNT + 1 ] = {
# define cmd(a, b) { # a, a, # b },
# include "cmds.h"
# undef cmd
} ;
/*
* command_names [ ] and commands [ ] are defined in lvmcmdline . c when building lvm ,
* but need to be defined here when building the stand - alone man page generator .
*/
# ifdef MAN_PAGE_GENERATOR
struct command_name command_names [ MAX_COMMAND_NAMES ] = {
# define xx(a, b, c...) { # a, b, c },
# include "commands.h"
# undef xx
} ;
struct command commands [ COMMAND_COUNT ] ;
# else
extern struct command_name command_names [ MAX_COMMAND_NAMES ] ; /* defined in lvmcmdline.c */
extern struct command commands [ COMMAND_COUNT ] ; /* defined in lvmcmdline.c */
# endif
/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
struct opt_name * opt_names_alpha [ ARG_COUNT + 1 ] ;
/* lvm_all is for recording options that are common for all lvm commands */
struct command lvm_all ;
/* saves OO_FOO lines (groups of optional options) to include in multiple defs */
static int oo_line_count ;
# define MAX_OO_LINES 256
struct oo_line {
char * name ;
char * line ;
} ;
static struct oo_line oo_lines [ MAX_OO_LINES ] ;
# define REQUIRED 1 /* required option */
# define OPTIONAL 0 /* optional option */
# define IGNORE -1 /* ignore option */
# define MAX_LINE 1024
# define MAX_LINE_ARGC 256
# define DESC_LINE 1024
/*
* Contains _command_input [ ] which is command - lines . in with comments
* removed and wrapped as a string . The _command_input [ ] string is
* used to populate commands [ ] .
*/
# include "command-lines-input.h"
static void add_optional_opt_line ( struct command * cmd , int argc , char * argv [ ] ) ;
/*
* modifies buf , replacing the sep characters with \ 0
* argv pointers point to positions in buf
*/
static char * split_line ( char * buf , int * argc , char * * argv , char sep )
{
char * p = buf , * rp = NULL ;
int i ;
argv [ 0 ] = p ;
for ( i = 1 ; i < MAX_LINE_ARGC ; i + + ) {
p = strchr ( buf , sep ) ;
if ( ! p )
break ;
* p = ' \0 ' ;
argv [ i ] = p + 1 ;
buf = p + 1 ;
}
* argc = i ;
/* we ended by hitting \0, return the point following that */
if ( ! rp )
rp = strchr ( buf , ' \0 ' ) + 1 ;
return rp ;
}
/* convert value string, e.g. Number, to foo_VAL enum */
static int val_str_to_num ( char * str )
{
2017-02-17 11:59:29 +03:00
char name [ 32 ] ;
2017-02-10 20:36:11 +03:00
char * new ;
int i ;
/* compare the name before any suffix like _new or _<lvtype> */
2017-02-17 11:59:29 +03:00
dm_strncpy ( name , str , sizeof ( name ) ) ;
2017-02-17 15:09:06 +03:00
if ( ( new = strchr ( name , ' _ ' ) ) )
2017-02-10 20:36:11 +03:00
* new = ' \0 ' ;
for ( i = 0 ; i < VAL_COUNT ; i + + ) {
if ( ! val_names [ i ] . name )
break ;
if ( ! strncmp ( name , val_names [ i ] . name , strlen ( val_names [ i ] . name ) ) )
return val_names [ i ] . val_enum ;
}
return 0 ;
}
/* convert "--option" to foo_ARG enum */
2017-02-14 01:11:04 +03:00
# define MAX_LONG_OPT_NAME_LEN 32
2017-02-17 00:26:42 +03:00
static int opt_str_to_num ( struct command * cmd , char * str )
2017-02-10 20:36:11 +03:00
{
2017-02-14 01:11:04 +03:00
char long_name [ MAX_LONG_OPT_NAME_LEN ] ;
2017-02-10 20:36:11 +03:00
char * p ;
int i ;
2017-02-17 12:00:43 +03:00
int first = 0 , last = ARG_COUNT - 1 , middle ;
2017-02-10 20:36:11 +03:00
2017-02-17 12:00:43 +03:00
dm_strncpy ( long_name , str , sizeof ( long_name ) ) ;
2017-02-10 20:36:11 +03:00
2017-02-17 12:00:43 +03:00
if ( ( p = strstr ( long_name , " _long " ) ) )
/*
* - - foo_long means there are two args entries
* for - - foo , one with a short option and one
* without , and we want the one without the
* short option ( = = 0 ) .
*/
* p = ' \0 ' ;
2017-02-10 20:36:11 +03:00
2017-02-17 12:00:43 +03:00
/* Binary search in sorted array of long options (with duplicates) */
while ( first < = last ) {
middle = first + ( last - first ) / 2 ;
if ( ( i = strcmp ( opt_names_alpha [ middle ] - > long_opt , long_name ) ) < 0 )
first = middle + 1 ;
else if ( i > 0 )
last = middle - 1 ;
else {
/* Matching long option string found.
* As sorted array contains duplicates , we need to also
* check left & right side for possible match
*/
for ( i = middle ; ; ) {
if ( ( ! p & & ! strstr ( opt_names_alpha [ i ] - > name , " _long_ARG " ) ) | |
( p & & ! opt_names_alpha [ i ] - > short_opt ) )
return opt_names_alpha [ i ] - > opt_enum ; /* Found */
/* Check if there is something on the 'left-side' */
if ( ( i < = first ) | | strcmp ( opt_names_alpha [ - - i ] - > long_opt , long_name ) )
break ;
}
/* Nothing on the left, so look on the 'right-side' */
for ( i = middle + 1 ; i < = last ; + + i ) {
if ( strcmp ( opt_names_alpha [ i ] - > long_opt , long_name ) )
break ;
if ( ( ! p & & ! strstr ( opt_names_alpha [ i ] - > name , " _long_ARG " ) ) | |
( p & & ! opt_names_alpha [ i ] - > short_opt ) )
return opt_names_alpha [ i ] - > opt_enum ; /* Found */
}
break ; /* Nothing... */
}
2017-02-10 20:36:11 +03:00
}
2017-02-17 12:00:43 +03:00
log_error ( " Parsing command defs: unknown opt str: \" %s \" %s%s. " ,
str , p ? " " : " " , p ? long_name : " " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
2017-02-17 12:00:43 +03:00
2017-02-17 00:26:42 +03:00
return ARG_UNUSED ;
2017-02-10 20:36:11 +03:00
}
/* "foo" string to foo_CMD int */
int command_id_to_enum ( const char * str )
{
int i ;
for ( i = 1 ; i < CMD_COUNT ; i + + ) {
if ( ! strcmp ( str , cmd_names [ i ] . name ) )
return cmd_names [ i ] . cmd_enum ;
}
2017-02-17 00:26:42 +03:00
return CMD_NONE ;
2017-02-10 20:36:11 +03:00
}
/* "lv_is_prop" to is_prop_LVP */
2017-02-17 00:26:42 +03:00
static int lvp_name_to_enum ( struct command * cmd , char * str )
2017-02-10 20:36:11 +03:00
{
int i ;
for ( i = 1 ; i < LVP_COUNT ; i + + ) {
if ( ! strcmp ( str , lvp_names [ i ] . name ) )
return lvp_names [ i ] . lvp_enum ;
}
2017-02-17 00:26:42 +03:00
2017-02-10 20:36:11 +03:00
log_error ( " Parsing command defs: unknown lv property %s " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return LVP_NONE ;
2017-02-10 20:36:11 +03:00
}
/* "type" to type_LVT */
2017-02-17 00:26:42 +03:00
static int lvt_name_to_enum ( struct command * cmd , char * str )
2017-02-10 20:36:11 +03:00
{
int i ;
for ( i = 1 ; i < LVT_COUNT ; i + + ) {
if ( ! strcmp ( str , lvt_names [ i ] . name ) )
return lvt_names [ i ] . lvt_enum ;
}
2017-02-17 00:26:42 +03:00
2017-02-10 20:36:11 +03:00
log_error ( " Parsing command defs: unknown lv type %s " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return LVT_NONE ;
2017-02-10 20:36:11 +03:00
}
/* LV_<type> to <type>_LVT */
2017-02-17 00:26:42 +03:00
static int lv_to_enum ( struct command * cmd , char * name )
2017-02-10 20:36:11 +03:00
{
2017-02-17 00:26:42 +03:00
return lvt_name_to_enum ( cmd , name + 3 ) ;
2017-02-10 20:36:11 +03:00
}
/*
* LV_ < type1 > _ < type2 > to lvt_bits
*
* type1 to lvt_enum
* lvt_bits | = lvt_enum_to_bit ( lvt_enum )
* type2 to lvt_enum
* lvt_bits | = lvt_enum_to_bit ( lvt_enum )
*/
2017-02-14 01:11:04 +03:00
# define LVTYPE_LEN 64
2017-02-17 00:26:42 +03:00
static uint64_t lv_to_bits ( struct command * cmd , char * name )
2017-02-10 20:36:11 +03:00
{
2017-02-14 01:11:04 +03:00
char buf [ LVTYPE_LEN ] ;
2017-02-10 20:36:11 +03:00
char * argv [ MAX_LINE_ARGC ] ;
uint64_t lvt_bits = 0 ;
int lvt_enum ;
int argc ;
int i ;
2017-02-14 01:11:04 +03:00
memset ( buf , 0 , sizeof ( buf ) ) ;
strncpy ( buf , name , LVTYPE_LEN - 1 ) ;
2017-02-10 20:36:11 +03:00
split_line ( buf , & argc , argv , ' _ ' ) ;
/* 0 is "LV" */
for ( i = 1 ; i < argc ; i + + ) {
if ( ! strcmp ( argv [ i ] , " new " ) )
continue ;
2017-02-17 00:26:42 +03:00
lvt_enum = lvt_name_to_enum ( cmd , argv [ i ] ) ;
2017-02-10 20:36:11 +03:00
lvt_bits | = lvt_enum_to_bit ( lvt_enum ) ;
}
return lvt_bits ;
}
static struct command_name * find_command_name ( const char * name )
{
int i ;
2017-02-17 13:52:37 +03:00
if ( ! islower ( name [ 0 ] ) )
return NULL ; /* Commands starts with lower-case */
2017-02-10 20:36:11 +03:00
for ( i = 0 ; i < MAX_COMMAND_NAMES ; i + + ) {
if ( ! command_names [ i ] . name )
break ;
if ( ! strcmp ( command_names [ i ] . name , name ) )
return & command_names [ i ] ;
}
2017-02-17 13:52:37 +03:00
2017-02-10 20:36:11 +03:00
return NULL ;
}
static const char * is_command_name ( char * str )
{
2017-02-17 13:52:37 +03:00
const struct command_name * c ;
if ( ( c = find_command_name ( str ) ) )
return c - > name ;
2017-02-10 20:36:11 +03:00
return NULL ;
}
static int is_opt_name ( char * str )
{
2017-02-17 13:52:37 +03:00
if ( ( str [ 0 ] = = ' - ' ) & & ( str [ 1 ] = = ' - ' ) )
2017-02-10 20:36:11 +03:00
return 1 ;
2017-02-17 00:26:42 +03:00
if ( ( str [ 0 ] = = ' - ' ) & & ( str [ 1 ] ! = ' - ' ) )
2017-02-10 20:36:11 +03:00
log_error ( " Parsing command defs: options must be specified in long form: %s " , str ) ;
return 0 ;
}
/*
* " Select " as a pos name means that the position
* can be empty if the - - select option is used .
*/
static int is_pos_name ( char * str )
{
2017-02-17 13:52:37 +03:00
switch ( str [ 0 ] ) {
case ' V ' : return ( str [ 1 ] = = ' G ' ) ; /* VG */
case ' L ' : return ( str [ 1 ] = = ' V ' ) ; /* LV */
case ' P ' : return ( str [ 1 ] = = ' V ' ) ; /* PV */
case ' T ' : return ( strncmp ( str , " Tag " , 3 ) = = 0 ) ;
case ' S ' : return ( ( strncmp ( str , " String " , 6 ) = = 0 ) | |
( strncmp ( str , " Select " , 6 ) = = 0 ) ) ;
}
2017-02-10 20:36:11 +03:00
return 0 ;
}
static int is_oo_definition ( char * str )
{
2017-02-17 15:09:06 +03:00
if ( ! strncmp ( str , " OO_ " , 3 ) & & strchr ( str , ' : ' ) )
2017-02-10 20:36:11 +03:00
return 1 ;
return 0 ;
}
static int is_oo_line ( char * str )
{
if ( ! strncmp ( str , " OO: " , 3 ) )
return 1 ;
return 0 ;
}
static int is_io_line ( char * str )
{
if ( ! strncmp ( str , " IO: " , 3 ) )
return 1 ;
return 0 ;
}
static int is_op_line ( char * str )
{
if ( ! strncmp ( str , " OP: " , 3 ) )
return 1 ;
return 0 ;
}
static int is_desc_line ( char * str )
{
if ( ! strncmp ( str , " DESC: " , 5 ) )
return 1 ;
return 0 ;
}
static int is_flags_line ( char * str )
{
if ( ! strncmp ( str , " FLAGS: " , 6 ) )
return 1 ;
return 0 ;
}
static int is_rule_line ( char * str )
{
if ( ! strncmp ( str , " RULE: " , 5 ) )
return 1 ;
return 0 ;
}
static int is_id_line ( char * str )
{
if ( ! strncmp ( str , " ID: " , 3 ) )
return 1 ;
return 0 ;
}
/*
* Save a positional arg in a struct arg_def .
* Parse str for anything that can appear in a position ,
* like VG , VG | LV , VG | LV_linear | LV_striped , etc .
*/
static void set_pos_def ( struct command * cmd , char * str , struct arg_def * def )
{
char * argv [ MAX_LINE_ARGC ] ;
int argc ;
char * name ;
int val_enum ;
int i ;
split_line ( str , & argc , argv , ' | ' ) ;
for ( i = 0 ; i < argc ; i + + ) {
name = argv [ i ] ;
val_enum = val_str_to_num ( name ) ;
if ( ! val_enum ) {
log_error ( " Parsing command defs: unknown pos arg: %s " , name ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
def - > val_bits | = val_enum_to_bit ( val_enum ) ;
2017-02-17 15:09:06 +03:00
if ( ( val_enum = = lv_VAL ) & & strchr ( name , ' _ ' ) )
2017-02-17 00:26:42 +03:00
def - > lvt_bits = lv_to_bits ( cmd , name ) ;
2017-02-10 20:36:11 +03:00
if ( strstr ( name , " _new " ) ) {
if ( val_enum = = lv_VAL )
def - > flags | = ARG_DEF_FLAG_NEW_LV ;
else if ( val_enum = = vg_VAL )
def - > flags | = ARG_DEF_FLAG_NEW_VG ;
}
}
}
/*
* Save an option arg in a struct arg_def .
* Parse str for anything that can follow - - option .
*/
static void set_opt_def ( struct command * cmd , char * str , struct arg_def * def )
{
char * argv [ MAX_LINE_ARGC ] ;
int argc ;
char * name ;
int val_enum ;
int i ;
split_line ( str , & argc , argv , ' | ' ) ;
for ( i = 0 ; i < argc ; i + + ) {
name = argv [ i ] ;
val_enum = val_str_to_num ( name ) ;
if ( ! val_enum ) {
/* a literal number or string */
if ( isdigit ( name [ 0 ] ) )
val_enum = constnum_VAL ;
else if ( isalpha ( name [ 0 ] ) )
val_enum = conststr_VAL ;
else {
log_error ( " Parsing command defs: unknown opt arg: %s " , name ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
}
def - > val_bits | = val_enum_to_bit ( val_enum ) ;
if ( val_enum = = constnum_VAL )
def - > num = ( uint64_t ) atoi ( name ) ;
if ( val_enum = = conststr_VAL )
2017-02-16 00:49:18 +03:00
def - > str = dm_strdup ( name ) ;
2017-02-10 20:36:11 +03:00
if ( val_enum = = lv_VAL ) {
2017-02-17 15:09:06 +03:00
if ( strchr ( name , ' _ ' ) )
2017-02-17 00:26:42 +03:00
def - > lvt_bits = lv_to_bits ( cmd , name ) ;
2017-02-10 20:36:11 +03:00
}
if ( strstr ( name , " _new " ) ) {
if ( val_enum = = lv_VAL )
def - > flags | = ARG_DEF_FLAG_NEW_LV ;
else if ( val_enum = = vg_VAL )
def - > flags | = ARG_DEF_FLAG_NEW_VG ;
}
}
}
/*
* Save a set of common options so they can be included in
* multiple command defs .
*
* OO_FOO : - - opt1 . . .
*
* oo - > name = " OO_FOO " ;
* oo - > line = " --opt1 ... " ;
*/
2017-02-17 00:26:42 +03:00
static void add_oo_definition_line ( struct command * cmd , const char * name , const char * line )
2017-02-10 20:36:11 +03:00
{
struct oo_line * oo ;
char * colon ;
char * start ;
oo = & oo_lines [ oo_line_count + + ] ;
2017-02-16 00:49:18 +03:00
oo - > name = dm_strdup ( name ) ;
2017-02-10 20:36:11 +03:00
2017-02-17 15:09:06 +03:00
if ( ( colon = strchr ( oo - > name , ' : ' ) ) )
2017-02-10 20:36:11 +03:00
* colon = ' \0 ' ;
else {
log_error ( " Parsing command defs: invalid OO definition " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
2017-02-17 15:09:06 +03:00
start = strchr ( line , ' : ' ) + 2 ;
2017-02-16 00:49:18 +03:00
oo - > line = dm_strdup ( start ) ;
2017-02-10 20:36:11 +03:00
}
/* Support OO_FOO: continuing on multiple lines. */
2017-02-17 00:26:42 +03:00
static void append_oo_definition_line ( struct command * cmd , const char * new_line )
2017-02-10 20:36:11 +03:00
{
struct oo_line * oo ;
char * old_line ;
char * line ;
int len ;
oo = & oo_lines [ oo_line_count - 1 ] ;
old_line = oo - > line ;
/* +2 = 1 space between old and new + 1 terminating \0 */
len = strlen ( old_line ) + strlen ( new_line ) + 2 ;
2017-02-16 00:49:18 +03:00
line = dm_malloc ( len ) ;
2017-02-14 01:11:04 +03:00
if ( ! line ) {
log_error ( " Parsing command defs: no memory " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-14 01:11:04 +03:00
}
2017-02-10 20:36:11 +03:00
2017-02-17 11:59:29 +03:00
( void ) dm_snprintf ( line , len , " %s %s " , old_line , new_line ) ;
2017-02-16 00:49:18 +03:00
dm_free ( oo - > line ) ;
2017-02-10 20:36:11 +03:00
oo - > line = line ;
}
/* Find a saved OO_FOO definition. */
2017-02-14 01:11:04 +03:00
# define OO_NAME_LEN 64
2017-02-10 20:36:11 +03:00
static char * get_oo_line ( const char * str )
{
char * name ;
char * end ;
2017-02-14 01:11:04 +03:00
char str2 [ OO_NAME_LEN ] ;
2017-02-10 20:36:11 +03:00
int i ;
2017-02-17 11:59:29 +03:00
dm_strncpy ( str2 , str , sizeof ( str2 ) ) ;
2017-02-17 15:09:06 +03:00
if ( ( end = strchr ( str2 , ' : ' ) ) )
2017-02-10 20:36:11 +03:00
* end = ' \0 ' ;
2017-02-17 15:09:06 +03:00
if ( ( end = strchr ( str2 , ' , ' ) ) )
2017-02-10 20:36:11 +03:00
* end = ' \0 ' ;
for ( i = 0 ; i < oo_line_count ; i + + ) {
name = oo_lines [ i ] . name ;
if ( ! strcmp ( name , str2 ) )
return oo_lines [ i ] . line ;
}
return NULL ;
}
/*
* Add optional_opt_args entries when OO_FOO appears on OO : line ,
* i . e . include common options from an OO_FOO definition .
*/
static void include_optional_opt_args ( struct command * cmd , const char * str )
{
char * oo_line ;
char * line ;
char * line_argv [ MAX_LINE_ARGC ] ;
int line_argc ;
if ( ! ( oo_line = get_oo_line ( str ) ) ) {
log_error ( " Parsing command defs: no OO line found for %s " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
2017-02-17 00:26:42 +03:00
if ( ! ( line = dm_strdup ( oo_line ) ) ) {
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
}
2017-02-10 20:36:11 +03:00
split_line ( line , & line_argc , line_argv , ' ' ) ;
add_optional_opt_line ( cmd , line_argc , line_argv ) ;
2017-02-16 00:49:18 +03:00
dm_free ( line ) ;
2017-02-10 20:36:11 +03:00
}
/*
* When an - - option is seen , add a new opt_args entry for it .
* This function sets the opt_args . opt value for it .
*/
2017-03-02 22:52:06 +03:00
static void add_opt_arg ( struct command * cmd , char * str ,
int * takes_arg , int * already , int required )
2017-02-10 20:36:11 +03:00
{
char * comma ;
int opt ;
2017-03-02 22:52:06 +03:00
int i ;
2017-02-10 20:36:11 +03:00
/* opt_arg.opt set here */
/* opt_arg.def will be set in update_prev_opt_arg() if needed */
2017-02-17 15:09:06 +03:00
if ( ( comma = strchr ( str , ' , ' ) ) )
2017-02-10 20:36:11 +03:00
* comma = ' \0 ' ;
/*
* Work around nasty hack where - - uuid is used for both uuid_ARG
* and uuidstr_ARG . The input uses - - uuidstr , where an actual
* command uses - - uuid string .
*/
if ( ! strcmp ( str , " --uuidstr " ) ) {
opt = uuidstr_ARG ;
goto skip ;
}
2017-02-17 00:26:42 +03:00
opt = opt_str_to_num ( cmd , str ) ;
2017-02-17 15:57:59 +03:00
/* If the binary-search finds uuidstr_ARG switch to uuid_ARG */
if ( opt = = uuidstr_ARG )
opt = uuid_ARG ;
2017-03-02 22:52:06 +03:00
/* Skip adding an optional opt if it is already included. */
if ( already & & ! required ) {
for ( i = 0 ; i < cmd - > oo_count ; i + + ) {
if ( cmd - > optional_opt_args [ i ] . opt = = opt ) {
* already = 1 ;
* takes_arg = opt_names [ opt ] . val_enum ? 1 : 0 ;
return ;
}
}
}
2017-02-10 20:36:11 +03:00
skip :
if ( required > 0 )
cmd - > required_opt_args [ cmd - > ro_count + + ] . opt = opt ;
else if ( ! required )
cmd - > optional_opt_args [ cmd - > oo_count + + ] . opt = opt ;
else if ( required < 0 )
cmd - > ignore_opt_args [ cmd - > io_count + + ] . opt = opt ;
* takes_arg = opt_names [ opt ] . val_enum ? 1 : 0 ;
}
/*
* After - - option has been seen , this function sets opt_args . def value
* for the value that appears after - - option .
*/
static void update_prev_opt_arg ( struct command * cmd , char * str , int required )
{
struct arg_def def = { 0 } ;
char * comma ;
if ( str [ 0 ] = = ' - ' ) {
log_error ( " Parsing command defs: option %s must be followed by an arg. " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
/* opt_arg.def set here */
/* opt_arg.opt was previously set in add_opt_arg() when --foo was read */
2017-02-17 15:09:06 +03:00
if ( ( comma = strchr ( str , ' , ' ) ) )
2017-02-10 20:36:11 +03:00
* comma = ' \0 ' ;
set_opt_def ( cmd , str , & def ) ;
if ( required > 0 )
cmd - > required_opt_args [ cmd - > ro_count - 1 ] . def = def ;
else if ( ! required )
cmd - > optional_opt_args [ cmd - > oo_count - 1 ] . def = def ;
else if ( required < 0 )
cmd - > ignore_opt_args [ cmd - > io_count - 1 ] . def = def ;
}
/*
* When an position arg is seen , add a new pos_args entry for it .
* This function sets the pos_args . pos and pos_args . def .
*/
static void add_pos_arg ( struct command * cmd , char * str , int required )
{
struct arg_def def = { 0 } ;
/* pos_arg.pos and pos_arg.def are set here */
set_pos_def ( cmd , str , & def ) ;
if ( required ) {
cmd - > required_pos_args [ cmd - > rp_count ] . pos = cmd - > pos_count + + ;
cmd - > required_pos_args [ cmd - > rp_count ] . def = def ;
cmd - > rp_count + + ;
} else {
cmd - > optional_pos_args [ cmd - > op_count ] . pos = cmd - > pos_count + + ; ;
cmd - > optional_pos_args [ cmd - > op_count ] . def = def ;
cmd - > op_count + + ;
}
}
/* Process something that follows a pos arg, which is not a new pos arg. */
static void update_prev_pos_arg ( struct command * cmd , char * str , int required )
{
struct arg_def * def ;
/* a previous pos_arg.def is modified here */
if ( required )
def = & cmd - > required_pos_args [ cmd - > rp_count - 1 ] . def ;
else
def = & cmd - > optional_pos_args [ cmd - > op_count - 1 ] . def ;
if ( ! strcmp ( str , " ... " ) )
def - > flags | = ARG_DEF_FLAG_MAY_REPEAT ;
else {
log_error ( " Parsing command defs: unknown pos arg: %s " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
}
/* Process what follows OO:, which are the optional opt args for the cmd def. */
static void add_optional_opt_line ( struct command * cmd , int argc , char * argv [ ] )
{
2017-02-14 01:11:04 +03:00
int takes_arg = 0 ;
2017-03-02 22:52:06 +03:00
int already ;
2017-02-10 20:36:11 +03:00
int i ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! i & & ! strncmp ( argv [ i ] , " OO: " , 3 ) )
continue ;
2017-03-02 22:52:06 +03:00
already = 0 ;
2017-02-10 20:36:11 +03:00
if ( is_opt_name ( argv [ i ] ) )
2017-03-02 22:52:06 +03:00
add_opt_arg ( cmd , argv [ i ] , & takes_arg , & already , OPTIONAL ) ;
2017-02-10 20:36:11 +03:00
else if ( ! strncmp ( argv [ i ] , " OO_ " , 3 ) )
include_optional_opt_args ( cmd , argv [ i ] ) ;
else if ( takes_arg )
update_prev_opt_arg ( cmd , argv [ i ] , OPTIONAL ) ;
else {
log_error ( " Parsing command defs: can't parse argc %d argv %s prev %s " ,
i , argv [ i ] , argv [ i - 1 ] ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
2017-03-02 22:52:06 +03:00
if ( already & & takes_arg )
i + + ;
2017-02-10 20:36:11 +03:00
}
}
/* Process what follows IO:, which are the ignore options for the cmd def. */
static void add_ignore_opt_line ( struct command * cmd , int argc , char * argv [ ] )
{
2017-02-14 01:11:04 +03:00
int takes_arg = 0 ;
2017-02-10 20:36:11 +03:00
int i ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! i & & ! strncmp ( argv [ i ] , " IO: " , 3 ) )
continue ;
if ( is_opt_name ( argv [ i ] ) )
2017-03-02 22:52:06 +03:00
add_opt_arg ( cmd , argv [ i ] , & takes_arg , NULL , IGNORE ) ;
2017-02-10 20:36:11 +03:00
else if ( takes_arg )
update_prev_opt_arg ( cmd , argv [ i ] , IGNORE ) ;
else {
log_error ( " Parsing command defs: can't parse argc %d argv %s prev %s " ,
i , argv [ i ] , argv [ i - 1 ] ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
}
}
/* Process what follows OP:, which are optional pos args for the cmd def. */
static void add_optional_pos_line ( struct command * cmd , int argc , char * argv [ ] )
{
int i ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! i & & ! strncmp ( argv [ i ] , " OP: " , 3 ) )
continue ;
if ( is_pos_name ( argv [ i ] ) )
add_pos_arg ( cmd , argv [ i ] , OPTIONAL ) ;
else
update_prev_pos_arg ( cmd , argv [ i ] , OPTIONAL ) ;
}
}
static void add_required_opt_line ( struct command * cmd , int argc , char * argv [ ] )
{
2017-02-14 01:11:04 +03:00
int takes_arg = 0 ;
2017-02-10 20:36:11 +03:00
int i ;
for ( i = 0 ; i < argc ; i + + ) {
if ( is_opt_name ( argv [ i ] ) )
2017-03-02 22:52:06 +03:00
add_opt_arg ( cmd , argv [ i ] , & takes_arg , NULL , REQUIRED ) ;
2017-02-10 20:36:11 +03:00
else if ( takes_arg )
update_prev_opt_arg ( cmd , argv [ i ] , REQUIRED ) ;
else {
log_error ( " Parsing command defs: can't parse argc %d argv %s prev %s " ,
i , argv [ i ] , argv [ i - 1 ] ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
}
}
/*
* Add to required_opt_args from an OO_FOO definition .
* ( This is the special case of vgchange / lvchange where one
* optional option is required , and others are then optional . )
* The set of options from OO_FOO are saved in required_opt_args ,
* and flag CMD_FLAG_ONE_REQUIRED_OPT is set on the cmd indicating
* this special case .
*/
static void include_required_opt_args ( struct command * cmd , char * str )
{
char * oo_line ;
char * line ;
char * line_argv [ MAX_LINE_ARGC ] ;
int line_argc ;
if ( ! ( oo_line = get_oo_line ( str ) ) ) {
log_error ( " Parsing command defs: no OO line found for %s " , str ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
2017-02-17 00:26:42 +03:00
if ( ! ( line = dm_strdup ( oo_line ) ) ) {
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
}
2017-02-10 20:36:11 +03:00
split_line ( line , & line_argc , line_argv , ' ' ) ;
add_required_opt_line ( cmd , line_argc , line_argv ) ;
2017-02-16 00:49:18 +03:00
dm_free ( line ) ;
2017-02-10 20:36:11 +03:00
}
/* Process what follows command_name, which are required opt/pos args. */
static void add_required_line ( struct command * cmd , int argc , char * argv [ ] )
{
int i ;
int takes_arg ;
int prev_was_opt = 0 , prev_was_pos = 0 ;
/* argv[0] is command name */
for ( i = 1 ; i < argc ; i + + ) {
if ( is_opt_name ( argv [ i ] ) ) {
/* add new required_opt_arg */
2017-03-02 22:52:06 +03:00
add_opt_arg ( cmd , argv [ i ] , & takes_arg , NULL , REQUIRED ) ;
2017-02-10 20:36:11 +03:00
prev_was_opt = 1 ;
prev_was_pos = 0 ;
} else if ( prev_was_opt & & takes_arg ) {
/* set value for previous required_opt_arg */
update_prev_opt_arg ( cmd , argv [ i ] , REQUIRED ) ;
prev_was_opt = 0 ;
prev_was_pos = 0 ;
} else if ( is_pos_name ( argv [ i ] ) ) {
/* add new required_pos_arg */
add_pos_arg ( cmd , argv [ i ] , REQUIRED ) ;
prev_was_opt = 0 ;
prev_was_pos = 1 ;
} else if ( ! strncmp ( argv [ i ] , " OO_ " , 3 ) ) {
/* one required_opt_arg is required, special case lv/vgchange */
cmd - > cmd_flags | = CMD_FLAG_ONE_REQUIRED_OPT ;
include_required_opt_args ( cmd , argv [ i ] ) ;
} else if ( prev_was_pos ) {
/* set property for previous required_pos_arg */
update_prev_pos_arg ( cmd , argv [ i ] , REQUIRED ) ;
} else {
log_error ( " Parsing command defs: can't parse argc %d argv %s prev %s " ,
i , argv [ i ] , argv [ i - 1 ] ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
}
}
static void add_flags ( struct command * cmd , char * line )
{
if ( strstr ( line , " SECONDARY_SYNTAX " ) )
cmd - > cmd_flags | = CMD_FLAG_SECONDARY_SYNTAX ;
2017-02-17 20:45:13 +03:00
if ( strstr ( line , " PREVIOUS_SYNTAX " ) )
cmd - > cmd_flags | = CMD_FLAG_PREVIOUS_SYNTAX ;
2017-02-10 20:36:11 +03:00
}
# define MAX_RULE_OPTS 64
static void add_rule ( struct command * cmd , char * line )
{
struct cmd_rule * rule ;
char * line_argv [ MAX_LINE_ARGC ] ;
char * arg ;
int line_argc ;
int i , lvt_enum , lvp_enum ;
int check = 0 ;
if ( cmd - > rule_count = = CMD_MAX_RULES ) {
log_error ( " Parsing command defs: too many rules for cmd " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
rule = & cmd - > rules [ cmd - > rule_count + + ] ;
split_line ( line , & line_argc , line_argv , ' ' ) ;
for ( i = 0 ; i < line_argc ; i + + ) {
arg = line_argv [ i ] ;
if ( ! strcmp ( arg , " not " ) ) {
rule - > rule = RULE_INVALID ;
check = 1 ;
}
else if ( ! strcmp ( arg , " and " ) ) {
rule - > rule = RULE_REQUIRE ;
check = 1 ;
}
else if ( ! strncmp ( arg , " all " , 3 ) ) {
/* opt/lvt_bits/lvp_bits all remain 0 to mean all */
continue ;
}
else if ( ! strncmp ( arg , " -- " , 2 ) ) {
if ( ! rule - > opts ) {
2017-02-16 00:49:18 +03:00
if ( ! ( rule - > opts = dm_malloc ( MAX_RULE_OPTS * sizeof ( int ) ) ) ) {
2017-02-10 20:36:11 +03:00
log_error ( " Parsing command defs: no mem " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
memset ( rule - > opts , 0 , MAX_RULE_OPTS * sizeof ( int ) ) ;
}
if ( ! rule - > check_opts ) {
2017-02-16 00:49:18 +03:00
if ( ! ( rule - > check_opts = dm_malloc ( MAX_RULE_OPTS * sizeof ( int ) ) ) ) {
2017-02-10 20:36:11 +03:00
log_error ( " Parsing command defs: no mem " ) ;
2017-02-17 00:26:42 +03:00
cmd - > cmd_flags | = CMD_FLAG_PARSE_ERROR ;
return ;
2017-02-10 20:36:11 +03:00
}
memset ( rule - > check_opts , 0 , MAX_RULE_OPTS * sizeof ( int ) ) ;
}
if ( check )
2017-02-17 00:26:42 +03:00
rule - > check_opts [ rule - > check_opts_count + + ] = opt_str_to_num ( cmd , arg ) ;
2017-02-10 20:36:11 +03:00
else
2017-02-17 00:26:42 +03:00
rule - > opts [ rule - > opts_count + + ] = opt_str_to_num ( cmd , arg ) ;
2017-02-10 20:36:11 +03:00
}
else if ( ! strncmp ( arg , " LV_ " , 3 ) ) {
2017-02-17 00:26:42 +03:00
lvt_enum = lv_to_enum ( cmd , arg ) ;
2017-02-10 20:36:11 +03:00
if ( check )
rule - > check_lvt_bits | = lvt_enum_to_bit ( lvt_enum ) ;
else
rule - > lvt_bits | = lvt_enum_to_bit ( lvt_enum ) ;
}
else if ( ! strncmp ( arg , " lv_is_ " , 6 ) ) {
2017-02-17 00:26:42 +03:00
lvp_enum = lvp_name_to_enum ( cmd , arg ) ;
2017-02-10 20:36:11 +03:00
if ( check )
rule - > check_lvp_bits | = lvp_enum_to_bit ( lvp_enum ) ;
else
rule - > lvp_bits | = lvp_enum_to_bit ( lvp_enum ) ;
}
}
}
/* The given option is common to all lvm commands (set in lvm_all). */
static int is_lvm_all_opt ( int opt )
{
int oo ;
for ( oo = 0 ; oo < lvm_all . oo_count ; oo + + ) {
if ( lvm_all . optional_opt_args [ oo ] . opt = = opt )
return 1 ;
}
return 0 ;
}
/* Find common options for all variants of each command name. */
2017-02-21 20:40:51 +03:00
void factor_common_options ( void )
2017-02-10 20:36:11 +03:00
{
int cn , opt_enum , ci , oo , ro , found ;
struct command * cmd ;
for ( cn = 0 ; cn < MAX_COMMAND_NAMES ; cn + + ) {
if ( ! command_names [ cn ] . name )
break ;
2017-02-16 18:36:55 +03:00
/* already factored */
if ( command_names [ cn ] . variants )
continue ;
2017-02-10 20:36:11 +03:00
for ( ci = 0 ; ci < COMMAND_COUNT ; ci + + ) {
cmd = & commands [ ci ] ;
if ( strcmp ( cmd - > name , command_names [ cn ] . name ) )
continue ;
command_names [ cn ] . variants + + ;
}
for ( opt_enum = 0 ; opt_enum < ARG_COUNT ; opt_enum + + ) {
for ( ci = 0 ; ci < COMMAND_COUNT ; ci + + ) {
cmd = & commands [ ci ] ;
if ( strcmp ( cmd - > name , command_names [ cn ] . name ) )
continue ;
if ( cmd - > ro_count )
command_names [ cn ] . variant_has_ro = 1 ;
if ( cmd - > rp_count )
command_names [ cn ] . variant_has_rp = 1 ;
if ( cmd - > oo_count )
command_names [ cn ] . variant_has_oo = 1 ;
if ( cmd - > op_count )
command_names [ cn ] . variant_has_op = 1 ;
for ( ro = 0 ; ro < cmd - > ro_count ; ro + + ) {
command_names [ cn ] . all_options [ cmd - > required_opt_args [ ro ] . opt ] = 1 ;
if ( ( cmd - > required_opt_args [ ro ] . opt = = size_ARG ) & & ! strncmp ( cmd - > name , " lv " , 2 ) )
command_names [ cn ] . all_options [ extents_ARG ] = 1 ;
}
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + )
command_names [ cn ] . all_options [ cmd - > optional_opt_args [ oo ] . opt ] = 1 ;
found = 0 ;
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt = = opt_enum ) {
found = 1 ;
break ;
}
}
if ( ! found )
goto next_opt ;
}
/* all commands starting with this name use this option */
command_names [ cn ] . common_options [ opt_enum ] = 1 ;
next_opt :
;
}
}
}
static int long_name_compare ( const void * on1 , const void * on2 )
{
2017-02-18 20:50:22 +03:00
const struct opt_name * const * optname1 = ( const void * ) on1 ;
const struct opt_name * const * optname2 = ( const void * ) on2 ;
2017-02-10 20:36:11 +03:00
return strcmp ( ( * optname1 ) - > long_opt + 2 , ( * optname2 ) - > long_opt + 2 ) ;
}
/* Create list of option names for printing alphabetically. */
static void create_opt_names_alpha ( void )
{
int i ;
for ( i = 0 ; i < ARG_COUNT ; i + + )
opt_names_alpha [ i ] = & opt_names [ i ] ;
qsort ( opt_names_alpha , ARG_COUNT , sizeof ( long ) , long_name_compare ) ;
}
static int copy_line ( char * line , int max_line , int * position )
{
int p = * position ;
int i = 0 ;
memset ( line , 0 , max_line ) ;
while ( 1 ) {
line [ i ] = _command_input [ p ] ;
i + + ;
p + + ;
if ( _command_input [ p ] = = ' \n ' ) {
p + + ;
break ;
}
if ( i = = ( max_line - 1 ) )
break ;
}
* position = p ;
return 1 ;
}
2017-02-14 19:16:13 +03:00
int define_commands ( char * run_name )
2017-02-10 20:36:11 +03:00
{
2017-02-17 15:16:27 +03:00
struct command * cmd = NULL ;
2017-02-10 20:36:11 +03:00
char line [ MAX_LINE ] ;
char line_orig [ MAX_LINE ] ;
char * line_argv [ MAX_LINE_ARGC ] ;
const char * name ;
char * n ;
int line_argc ;
int cmd_count = 0 ;
int prev_was_oo_def = 0 ;
int prev_was_oo = 0 ;
int prev_was_op = 0 ;
int copy_pos = 0 ;
2017-02-14 19:16:13 +03:00
int skip = 0 ;
2017-02-17 00:26:42 +03:00
int i ;
2017-02-14 19:16:13 +03:00
if ( run_name & & ! strcmp ( run_name , " help " ) )
run_name = NULL ;
2017-02-10 20:36:11 +03:00
create_opt_names_alpha ( ) ;
/* Process each line of command-lines-input.h (from command-lines.in) */
while ( copy_line ( line , MAX_LINE , & copy_pos ) ) {
if ( line [ 0 ] = = ' \n ' )
break ;
if ( ( n = strchr ( line , ' \n ' ) ) )
* n = ' \0 ' ;
memcpy ( line_orig , line , sizeof ( line ) ) ;
split_line ( line , & line_argc , line_argv , ' ' ) ;
if ( ! line_argc )
continue ;
/* New cmd def begins: command_name <required opt/pos args> */
if ( ( name = is_command_name ( line_argv [ 0 ] ) ) ) {
if ( cmd_count > = COMMAND_COUNT ) {
return 0 ;
}
/*
* FIXME : when running one specific command name ,
* we can optimize by not parsing command defs
* that don ' t start with that command name .
*/
cmd = & commands [ cmd_count ] ;
cmd - > command_index = cmd_count ;
cmd_count + + ;
2017-02-16 00:49:18 +03:00
cmd - > name = dm_strdup ( name ) ;
2017-02-14 19:16:13 +03:00
if ( run_name & & strcmp ( run_name , name ) ) {
skip = 1 ;
prev_was_oo_def = 0 ;
prev_was_oo = 0 ;
prev_was_op = 0 ;
continue ;
}
skip = 0 ;
2017-02-10 20:36:11 +03:00
cmd - > pos_count = 1 ;
add_required_line ( cmd , line_argc , line_argv ) ;
/* Every cmd gets the OO_ALL options */
include_optional_opt_args ( cmd , " OO_ALL: " ) ;
continue ;
}
/*
* All other kinds of lines are processed in the
* context of the existing command [ ] .
*/
2017-02-14 19:16:13 +03:00
if ( is_desc_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-16 00:49:18 +03:00
char * desc = dm_strdup ( line_orig ) ;
2017-02-10 20:36:11 +03:00
if ( cmd - > desc ) {
int newlen = strlen ( cmd - > desc ) + strlen ( desc ) + 2 ;
2017-02-16 00:49:18 +03:00
char * newdesc = dm_malloc ( newlen ) ;
2017-02-14 01:11:04 +03:00
if ( newdesc ) {
memset ( newdesc , 0 , newlen ) ;
snprintf ( newdesc , newlen , " %s %s " , cmd - > desc , desc ) ;
cmd - > desc = newdesc ;
2017-02-16 00:49:18 +03:00
dm_free ( desc ) ;
2017-02-14 01:11:04 +03:00
}
2017-02-10 20:36:11 +03:00
} else
cmd - > desc = desc ;
continue ;
}
2017-02-14 19:16:13 +03:00
if ( is_flags_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-10 20:36:11 +03:00
add_flags ( cmd , line_orig ) ;
continue ;
}
2017-02-14 19:16:13 +03:00
if ( is_rule_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-10 20:36:11 +03:00
add_rule ( cmd , line_orig ) ;
continue ;
}
if ( is_id_line ( line_argv [ 0 ] ) ) {
2017-02-16 00:49:18 +03:00
cmd - > command_id = dm_strdup ( line_argv [ 1 ] ) ;
2017-02-10 20:36:11 +03:00
continue ;
}
/* OO_FOO: ... */
if ( is_oo_definition ( line_argv [ 0 ] ) ) {
2017-02-17 00:26:42 +03:00
add_oo_definition_line ( cmd , line_argv [ 0 ] , line_orig ) ;
2017-02-10 20:36:11 +03:00
prev_was_oo_def = 1 ;
prev_was_oo = 0 ;
prev_was_op = 0 ;
continue ;
}
/* OO: ... */
2017-02-14 19:16:13 +03:00
if ( is_oo_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-10 20:36:11 +03:00
add_optional_opt_line ( cmd , line_argc , line_argv ) ;
prev_was_oo_def = 0 ;
prev_was_oo = 1 ;
prev_was_op = 0 ;
continue ;
}
/* OP: ... */
2017-02-14 19:16:13 +03:00
if ( is_op_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-10 20:36:11 +03:00
add_optional_pos_line ( cmd , line_argc , line_argv ) ;
prev_was_oo_def = 0 ;
prev_was_oo = 0 ;
prev_was_op = 1 ;
continue ;
}
/* IO: ... */
2017-02-14 19:16:13 +03:00
if ( is_io_line ( line_argv [ 0 ] ) & & ! skip ) {
2017-02-10 20:36:11 +03:00
add_ignore_opt_line ( cmd , line_argc , line_argv ) ;
prev_was_oo = 0 ;
prev_was_op = 0 ;
continue ;
}
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
if ( prev_was_oo_def ) {
2017-02-17 00:26:42 +03:00
append_oo_definition_line ( cmd , line_orig ) ;
2017-02-10 20:36:11 +03:00
continue ;
}
if ( prev_was_oo ) {
add_optional_opt_line ( cmd , line_argc , line_argv ) ;
continue ;
}
if ( prev_was_op ) {
add_optional_pos_line ( cmd , line_argc , line_argv ) ;
continue ;
}
}
2017-02-17 00:26:42 +03:00
for ( i = 0 ; i < COMMAND_COUNT ; i + + ) {
if ( commands [ i ] . cmd_flags & CMD_FLAG_PARSE_ERROR )
return 0 ;
}
2017-02-21 23:32:54 +03:00
include_optional_opt_args ( & lvm_all , " OO_ALL " ) ;
2017-02-10 20:36:11 +03:00
return 1 ;
}
/* type_LVT to "type" */
static const char * lvt_enum_to_name ( int lvt_enum )
{
return lvt_names [ lvt_enum ] . name ;
}
static void _print_usage_description ( struct command * cmd )
{
const char * desc = cmd - > desc ;
char buf [ MAX_LINE ] = { 0 } ;
2017-02-18 21:45:17 +03:00
unsigned di = 0 ;
2017-02-10 20:36:11 +03:00
int bi = 0 ;
for ( di = 0 ; di < strlen ( desc ) ; di + + ) {
if ( ! strncmp ( & desc [ di ] , " DESC: " , 5 ) ) {
if ( bi ) {
buf [ bi ] = ' \0 ' ;
printf ( " %s \n " , buf ) ;
memset ( buf , 0 , sizeof ( buf ) ) ;
bi = 0 ;
}
/* skip DESC: */
di + = 5 ;
continue ;
}
if ( ! bi & & desc [ di ] = = ' ' )
continue ;
buf [ bi + + ] = desc [ di ] ;
if ( bi = = ( MAX_LINE - 1 ) )
break ;
}
if ( bi ) {
buf [ bi ] = ' \0 ' ;
printf ( " %s \n " , buf ) ;
}
}
static void print_usage_def ( struct arg_def * def )
{
int val_enum ;
int lvt_enum ;
int sep = 0 ;
for ( val_enum = 0 ; val_enum < VAL_COUNT ; val_enum + + ) {
if ( def - > val_bits & val_enum_to_bit ( val_enum ) ) {
if ( val_enum = = conststr_VAL )
printf ( " %s " , def - > str ) ;
else if ( val_enum = = constnum_VAL )
printf ( " %llu " , ( unsigned long long ) def - > num ) ;
else {
if ( sep ) printf ( " | " ) ;
if ( ! val_names [ val_enum ] . usage )
printf ( " %s " , val_names [ val_enum ] . name ) ;
else
printf ( " %s " , val_names [ val_enum ] . usage ) ;
sep = 1 ;
}
if ( val_enum = = lv_VAL & & def - > lvt_bits ) {
for ( lvt_enum = 1 ; lvt_enum < LVT_COUNT ; lvt_enum + + ) {
if ( lvt_bit_is_set ( def - > lvt_bits , lvt_enum ) )
printf ( " _%s " , lvt_enum_to_name ( lvt_enum ) ) ;
}
}
if ( ( val_enum = = vg_VAL ) & & ( def - > flags & ARG_DEF_FLAG_NEW_VG ) )
printf ( " _new " ) ;
if ( ( val_enum = = lv_VAL ) & & ( def - > flags & ARG_DEF_FLAG_NEW_LV ) )
printf ( " _new " ) ;
}
}
if ( def - > flags & ARG_DEF_FLAG_MAY_REPEAT )
printf ( " ... " ) ;
}
2017-03-02 18:37:54 +03:00
void print_usage ( struct command * cmd , int longhelp , int desc_first )
2017-02-10 20:36:11 +03:00
{
struct command_name * cname = find_command_name ( cmd - > name ) ;
int onereq = ( cmd - > cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT ) ? 1 : 0 ;
int ro , rp , oo , op , opt_enum , first ;
2017-02-16 18:36:55 +03:00
/*
* Looks at all variants of each command name and figures out
* which options are common to all variants ( for compact output )
*/
factor_common_options ( ) ;
2017-03-02 18:37:54 +03:00
if ( desc_first & & cmd - > desc )
2017-02-10 20:36:11 +03:00
_print_usage_description ( cmd ) ;
printf ( " %s " , cmd - > name ) ;
if ( cmd - > ro_count ) {
first = 1 ;
for ( ro = 0 ; ro < cmd - > ro_count ; ro + + ) {
if ( onereq ) {
if ( first )
printf ( " \n \t ( " ) ;
else
printf ( " , \n \t " ) ;
first = 0 ;
}
printf ( " %s " , opt_names [ cmd - > required_opt_args [ ro ] . opt ] . long_opt ) ;
if ( cmd - > required_opt_args [ ro ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & cmd - > required_opt_args [ ro ] . def ) ;
}
}
if ( onereq )
printf ( " ) \n " ) ;
}
if ( cmd - > rp_count ) {
if ( onereq )
printf ( " \t " ) ;
for ( rp = 0 ; rp < cmd - > rp_count ; rp + + ) {
if ( cmd - > required_pos_args [ rp ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & cmd - > required_pos_args [ rp ] . def ) ;
}
}
}
2017-02-21 20:40:51 +03:00
if ( ! longhelp )
goto done ;
2017-02-10 20:36:11 +03:00
if ( ! cmd - > oo_count )
goto op_count ;
if ( cmd - > oo_count ) {
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
opt_enum = cmd - > optional_opt_args [ oo ] . opt ;
/*
2017-02-21 23:32:54 +03:00
* Skip common lvm options in lvm_all which
* are printed at the end under " Common options for lvm "
* see print_common_options_lvm ( )
2017-02-10 20:36:11 +03:00
*/
if ( is_lvm_all_opt ( opt_enum ) )
continue ;
2017-02-21 23:32:54 +03:00
/*
* When there is more than one variant ,
* skip common command options from
* cname - > common_options ( options common
* to all variants ) , which are printed at
* the end under " Common options for command "
* see print_common_options_cmd ( )
*/
2017-02-10 20:36:11 +03:00
if ( ( cname - > variants > 1 ) & & cname - > common_options [ opt_enum ] )
continue ;
2017-02-21 23:59:52 +03:00
printf ( " \n \t [ " ) ;
2017-02-10 20:36:11 +03:00
printf ( " %s " , opt_names [ opt_enum ] . long_opt ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & cmd - > optional_opt_args [ oo ] . def ) ;
}
2017-02-21 23:59:52 +03:00
printf ( " ] " ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-21 23:59:52 +03:00
printf ( " \n \t [ COMMON_OPTIONS ] " ) ;
2017-02-10 20:36:11 +03:00
}
op_count :
if ( ! cmd - > op_count )
goto done ;
printf ( " \n \t [ " ) ;
if ( cmd - > op_count ) {
for ( op = 0 ; op < cmd - > op_count ; op + + ) {
if ( cmd - > optional_pos_args [ op ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & cmd - > optional_pos_args [ op ] . def ) ;
}
}
}
printf ( " ] " ) ;
done :
2017-03-02 18:37:54 +03:00
printf ( " \n " ) ;
if ( ! desc_first & & cmd - > desc )
_print_usage_description ( cmd ) ;
printf ( " \n " ) ;
2017-02-10 20:36:11 +03:00
return ;
}
2017-02-21 23:32:54 +03:00
void print_usage_common_lvm ( struct command_name * cname , struct command * cmd )
2017-02-10 20:36:11 +03:00
{
2017-02-21 23:59:52 +03:00
int oo , opt_enum ;
2017-02-10 20:36:11 +03:00
2017-02-21 23:32:54 +03:00
printf ( " Common options for lvm: " ) ;
for ( oo = 0 ; oo < lvm_all . oo_count ; oo + + ) {
opt_enum = lvm_all . optional_opt_args [ oo ] . opt ;
2017-02-21 23:59:52 +03:00
printf ( " \n \t [ " ) ;
2017-02-21 23:32:54 +03:00
printf ( " %s " , opt_names [ opt_enum ] . long_opt ) ;
if ( lvm_all . optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & lvm_all . optional_opt_args [ oo ] . def ) ;
}
2017-02-21 23:59:52 +03:00
printf ( " ] " ) ;
2017-02-21 23:32:54 +03:00
}
printf ( " \n \n " ) ;
}
void print_usage_common_cmd ( struct command_name * cname , struct command * cmd )
{
2017-02-21 23:59:52 +03:00
int oo , opt_enum ;
2017-02-10 20:36:11 +03:00
/*
* when there ' s more than one variant , options that
* are common to all commands with a common name .
*/
if ( cname - > variants < 2 )
2017-02-21 23:32:54 +03:00
return ;
printf ( " Common options for command: " ) ;
2017-02-10 20:36:11 +03:00
for ( opt_enum = 0 ; opt_enum < ARG_COUNT ; opt_enum + + ) {
if ( ! cname - > common_options [ opt_enum ] )
continue ;
if ( is_lvm_all_opt ( opt_enum ) )
continue ;
2017-02-21 23:59:52 +03:00
printf ( " \n \t [ " ) ;
2017-02-10 20:36:11 +03:00
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt ! = opt_enum )
continue ;
printf ( " %s " , opt_names [ opt_enum ] . long_opt ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
print_usage_def ( & cmd - > optional_opt_args [ oo ] . def ) ;
}
break ;
}
2017-02-21 23:59:52 +03:00
printf ( " ] " ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-14 18:49:26 +03:00
printf ( " \n \n " ) ;
2017-02-10 20:36:11 +03:00
}
# ifdef MAN_PAGE_GENERATOR
2017-03-02 21:53:01 +03:00
static void print_val_man ( struct command_name * cname , const char * str )
2017-02-10 20:36:11 +03:00
{
char * line ;
char * line_argv [ MAX_LINE_ARGC ] ;
int line_argc ;
int i ;
2017-03-02 21:53:01 +03:00
/*
* FIXME : this is a terrible hack that needs to be fixed .
* lvcreate and lvresize both use - - size , and - - size
* accepts a signed number , and a signed number is
* printed with a [ + | - ] prefix . But lvcreate does not
* accept negative numbers . We need to do something to
* have two ( or more ) variants of - - size , one that can
* accept a sign and one that cannot . For now , this
* hack just detects when we ' re going to print
* [ + | - ] Size for " lvcreate " and overrides it to
* omit the + | - .
*/
if ( ! strcmp ( cname - > name , " lvcreate " ) & & ! strcmp ( str , " [+|-]Size[m|UNIT] " ) ) {
printf ( " \\ fISize \\ fP[m|UNIT] " ) ;
return ;
}
2017-02-21 21:05:36 +03:00
/*
2017-02-23 23:24:28 +03:00
* Doing bold k before UNIT creates a lot of
2017-02-23 01:50:30 +03:00
* visual " noise " that makes the text hard to read .
2017-02-21 21:05:36 +03:00
* The extra markup in this case doesn ' t add anything
* that isn ' t already obvious .
*/
2017-02-24 22:44:05 +03:00
if ( ! strcmp ( str , " Size[k|UNIT] " ) ) {
printf ( " \\ fISize \\ fP[k|UNIT] " ) ;
2017-02-21 21:05:36 +03:00
return ;
}
2017-02-24 22:44:05 +03:00
if ( ! strcmp ( str , " Size[m|UNIT] " ) ) {
printf ( " \\ fISize \\ fP[m|UNIT] " ) ;
2017-02-21 21:05:36 +03:00
return ;
}
2017-03-02 21:53:01 +03:00
if ( ! strcmp ( str , " [+|-]Size[k|UNIT] " ) ) {
printf ( " [ \\ fB+ \\ fP| \\ fB- \\ fP] \\ fISize \\ fP[k|UNIT] " ) ;
return ;
}
if ( ! strcmp ( str , " [+|-]Size[m|UNIT] " ) ) {
printf ( " [ \\ fB+ \\ fP| \\ fB- \\ fP] \\ fISize \\ fP[m|UNIT] " ) ;
return ;
}
2017-02-21 21:05:36 +03:00
if ( ! strcmp ( str , " [+|-]Number " ) ) {
printf ( " [ \\ fB+ \\ fP| \\ fB- \\ fP] \\ fINumber \\ fP " ) ;
return ;
}
if ( ! strcmp ( str , " [+|-]Number[%VG|%PVS|%FREE] " ) ) {
printf ( " [ \\ fB+ \\ fP| \\ fB- \\ fP] \\ fINumber \\ fP[ \\ fB%%VG \\ fP| \\ fB%%PVS \\ fP| \\ fB%%FREE \\ fP] " ) ;
return ;
}
2017-02-23 00:20:44 +03:00
if ( ! strcmp ( str , " PV[:t|n|y] " ) ) {
printf ( " \\ fIPV \\ fP[ \\ fB:t \\ fP| \\ fBn \\ fP| \\ fBy \\ fP] " ) ;
return ;
}
2017-02-21 21:05:36 +03:00
/*
* I think this bit is almost unnecessary with the specific
* ones checked above .
*/
2017-02-10 20:36:11 +03:00
if ( strstr ( str , " Number[ " ) | | strstr ( str , " ]Number " ) ) {
for ( i = 0 ; i < strlen ( str ) ; i + + ) {
if ( str [ i ] = = ' N ' )
printf ( " \\ fI " ) ;
if ( str [ i ] = = ' r ' ) {
printf ( " %c " , str [ i ] ) ;
printf ( " \\ fP " ) ;
continue ;
}
printf ( " %c " , str [ i ] ) ;
}
return ;
}
2017-02-23 00:20:44 +03:00
if ( ! strcmp ( str , " Number " ) | |
! strcmp ( str , " String " ) | |
! strncmp ( str , " VG " , 2 ) | |
! strncmp ( str , " LV " , 2 ) | |
! strncmp ( str , " PV " , 2 ) | |
! strcmp ( str , " Tag " ) ) {
printf ( " \\ fI%s \\ fP " , str ) ;
return ;
}
2017-02-17 15:09:06 +03:00
if ( strchr ( str , ' | ' ) ) {
2017-02-10 20:36:11 +03:00
int len = strlen ( str ) ;
2017-02-16 00:49:18 +03:00
line = dm_strdup ( str ) ;
2017-02-10 20:36:11 +03:00
split_line ( line , & line_argc , line_argv , ' | ' ) ;
for ( i = 0 ; i < line_argc ; i + + ) {
2017-02-24 02:06:42 +03:00
if ( i )
2017-02-10 20:36:11 +03:00
printf ( " | " ) ;
if ( strstr ( line_argv [ i ] , " Number " ) )
printf ( " \\ fI%s \\ fP " , line_argv [ i ] ) ;
else
2017-02-24 02:06:42 +03:00
printf ( " \\ % \\ fB%s \\ fP " , line_argv [ i ] ) ;
2017-02-10 20:36:11 +03:00
}
return ;
}
printf ( " \\ fB%s \\ fP " , str ) ;
}
2017-03-02 21:53:01 +03:00
static void print_def_man ( struct command_name * cname , struct arg_def * def , int usage )
2017-02-10 20:36:11 +03:00
{
int val_enum ;
int lvt_enum ;
int sep = 0 ;
for ( val_enum = 0 ; val_enum < VAL_COUNT ; val_enum + + ) {
if ( def - > val_bits & val_enum_to_bit ( val_enum ) ) {
if ( val_enum = = conststr_VAL ) {
printf ( " \\ fB " ) ;
printf ( " %s " , def - > str ) ;
printf ( " \\ fP " ) ;
}
else if ( val_enum = = constnum_VAL ) {
printf ( " \\ fB " ) ;
printf ( " %llu " , ( unsigned long long ) def - > num ) ;
printf ( " \\ fP " ) ;
}
else {
if ( sep ) printf ( " | " ) ;
if ( ! usage | | ! val_names [ val_enum ] . usage ) {
printf ( " \\ fI " ) ;
printf ( " %s " , val_names [ val_enum ] . name ) ;
printf ( " \\ fP " ) ;
} else {
2017-03-02 21:53:01 +03:00
print_val_man ( cname , val_names [ val_enum ] . usage ) ;
2017-02-10 20:36:11 +03:00
}
sep = 1 ;
}
if ( val_enum = = lv_VAL & & def - > lvt_bits ) {
printf ( " \\ fI " ) ;
for ( lvt_enum = 1 ; lvt_enum < LVT_COUNT ; lvt_enum + + ) {
if ( lvt_bit_is_set ( def - > lvt_bits , lvt_enum ) )
printf ( " _%s " , lvt_enum_to_name ( lvt_enum ) ) ;
}
printf ( " \\ fP " ) ;
}
if ( ( val_enum = = vg_VAL ) & & ( def - > flags & ARG_DEF_FLAG_NEW_VG ) ) {
printf ( " \\ fI " ) ;
printf ( " _new " ) ;
printf ( " \\ fP " ) ;
}
if ( ( val_enum = = lv_VAL ) & & ( def - > flags & ARG_DEF_FLAG_NEW_LV ) ) {
printf ( " \\ fI " ) ;
printf ( " _new " ) ;
printf ( " \\ fP " ) ;
}
}
}
if ( def - > flags & ARG_DEF_FLAG_MAY_REPEAT )
printf ( " ... " ) ;
}
static char * man_long_opt_name ( const char * cmdname , int opt_enum )
{
static char long_opt_name [ 64 ] ;
memset ( & long_opt_name , 0 , sizeof ( long_opt_name ) ) ;
switch ( opt_enum ) {
case syncaction_ARG :
strncpy ( long_opt_name , " --[raid]syncaction " , 63 ) ;
break ;
case writemostly_ARG :
strncpy ( long_opt_name , " --[raid]writemostly " , 63 ) ;
break ;
case minrecoveryrate_ARG :
strncpy ( long_opt_name , " --[raid]minrecoveryrate " , 63 ) ;
break ;
case maxrecoveryrate_ARG :
strncpy ( long_opt_name , " --[raid]maxrecoveryrate " , 63 ) ;
break ;
case writebehind_ARG :
strncpy ( long_opt_name , " --[raid]writebehind " , 63 ) ;
break ;
case vgmetadatacopies_ARG :
if ( ! strncmp ( cmdname , " vg " , 2 ) )
strncpy ( long_opt_name , " --[vg]metadatacopies " , 63 ) ;
else
strncpy ( long_opt_name , " --vgmetadatacopies " , 63 ) ;
break ;
case pvmetadatacopies_ARG :
if ( ! strncmp ( cmdname , " pv " , 2 ) )
strncpy ( long_opt_name , " --[pv]metadatacopies " , 63 ) ;
else
strncpy ( long_opt_name , " --pvmetadatacopies " , 63 ) ;
break ;
default :
strncpy ( long_opt_name , opt_names [ opt_enum ] . long_opt , 63 ) ;
break ;
}
return long_opt_name ;
}
void print_man_usage ( char * lvmname , struct command * cmd )
{
struct command_name * cname ;
int onereq = ( cmd - > cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT ) ? 1 : 0 ;
2017-02-17 15:16:27 +03:00
int sep , ro , rp , oo , op , opt_enum ;
2017-02-10 20:36:11 +03:00
int need_ro_indent_end = 0 ;
if ( ! ( cname = find_command_name ( cmd - > name ) ) )
return ;
printf ( " \\ fB%s \\ fP " , lvmname ) ;
if ( ! onereq )
goto ro_normal ;
/*
* one required option in a set , print as :
* ( - a | - - a ,
* - b | - - b ,
* - - c ,
* - - d )
*
* First loop through ro prints those with short opts ,
* and the second loop prints those without short opts .
*/
if ( cmd - > ro_count ) {
printf ( " \n " ) ;
printf ( " .RS 4 \n " ) ;
printf ( " ( " ) ;
sep = 0 ;
/* print required options with a short opt */
for ( ro = 0 ; ro < cmd - > ro_count ; ro + + ) {
opt_enum = cmd - > required_opt_args [ ro ] . opt ;
if ( ! opt_names [ opt_enum ] . short_opt )
continue ;
if ( sep ) {
2017-02-24 02:06:42 +03:00
printf ( " , \n " ) ;
printf ( " .ad b \n " ) ;
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " " ) ;
}
if ( opt_names [ opt_enum ] . short_opt ) {
printf ( " \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cmd - > name , opt_enum ) ) ;
} else {
printf ( " " ) ;
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cmd - > name , opt_enum ) ) ;
}
if ( cmd - > required_opt_args [ ro ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > required_opt_args [ ro ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
sep + + ;
}
/* print required options without a short opt */
for ( ro = 0 ; ro < cmd - > ro_count ; ro + + ) {
opt_enum = cmd - > required_opt_args [ ro ] . opt ;
if ( opt_names [ opt_enum ] . short_opt )
continue ;
if ( sep ) {
2017-02-24 02:06:42 +03:00
printf ( " , \n " ) ;
printf ( " .ad b \n " ) ;
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " " ) ;
2017-02-24 02:06:42 +03:00
} else
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " " ) ;
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > required_opt_args [ ro ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > required_opt_args [ ro ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
sep + + ;
}
printf ( " ) \n " ) ;
printf ( " .RE \n " ) ;
}
/* print required position args on a new line after the onereq set */
if ( cmd - > rp_count ) {
printf ( " .RS 4 \n " ) ;
for ( rp = 0 ; rp < cmd - > rp_count ; rp + + ) {
if ( cmd - > required_pos_args [ rp ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > required_pos_args [ rp ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
}
printf ( " \n " ) ;
printf ( " .RE \n " ) ;
} else {
/* printf("\n"); */
}
printf ( " .br \n " ) ;
goto oo_count ;
ro_normal :
/*
* all are required options , print as :
* - a | - - aaa < val > - b | - - bbb < val >
*/
if ( cmd - > ro_count ) {
sep = 0 ;
for ( ro = 0 ; ro < cmd - > ro_count ; ro + + ) {
/* avoid long line wrapping */
if ( ( cmd - > ro_count > 2 ) & & ( sep = = 2 ) ) {
printf ( " \n .RS 5 \n " ) ;
need_ro_indent_end = 1 ;
}
opt_enum = cmd - > required_opt_args [ ro ] . opt ;
if ( opt_names [ opt_enum ] . short_opt ) {
printf ( " \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cmd - > name , opt_enum ) ) ;
} else {
printf ( " \\ fB%s \\ fP " , opt_names [ cmd - > required_opt_args [ ro ] . opt ] . long_opt ) ;
}
if ( cmd - > required_opt_args [ ro ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > required_opt_args [ ro ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
sep + + ;
}
}
/* print required position args on the same line as the required options */
if ( cmd - > rp_count ) {
for ( rp = 0 ; rp < cmd - > rp_count ; rp + + ) {
if ( cmd - > required_pos_args [ rp ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > required_pos_args [ rp ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
}
printf ( " \n " ) ;
} else {
printf ( " \n " ) ;
}
if ( need_ro_indent_end )
printf ( " .RE \n " ) ;
printf ( " .br \n " ) ;
oo_count :
if ( ! cmd - > oo_count )
goto op_count ;
sep = 0 ;
if ( cmd - > oo_count ) {
printf ( " .RS 4 \n " ) ;
/* print optional options with short opts */
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
opt_enum = cmd - > optional_opt_args [ oo ] . opt ;
if ( ! opt_names [ opt_enum ] . short_opt )
continue ;
if ( is_lvm_all_opt ( opt_enum ) )
continue ;
if ( ( cname - > variants > 1 ) & & cname - > common_options [ opt_enum ] )
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
2017-02-21 23:59:52 +03:00
printf ( " [ \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
2017-02-10 20:36:11 +03:00
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
}
/* print optional options without short opts */
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
opt_enum = cmd - > optional_opt_args [ oo ] . opt ;
if ( opt_names [ opt_enum ] . short_opt )
continue ;
if ( is_lvm_all_opt ( opt_enum ) )
continue ;
if ( ( cname - > variants > 1 ) & & cname - > common_options [ opt_enum ] )
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
/* space alignment without short opt */
2017-02-21 23:59:52 +03:00
printf ( " [ " ) ;
2017-02-10 20:36:11 +03:00
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
}
if ( sep ) {
2017-02-24 02:06:42 +03:00
printf ( " .br \n " ) ;
2017-02-10 20:36:11 +03:00
/* space alignment without short opt */
2017-02-21 23:32:54 +03:00
/* printf(" "); */
2017-02-10 20:36:11 +03:00
}
2017-02-21 23:59:52 +03:00
printf ( " [ COMMON_OPTIONS ] \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " .RE \n " ) ;
printf ( " .br \n " ) ;
}
op_count :
if ( ! cmd - > op_count )
goto done ;
printf ( " .RS 4 \n " ) ;
printf ( " [ " ) ;
if ( cmd - > op_count ) {
for ( op = 0 ; op < cmd - > op_count ; op + + ) {
if ( cmd - > optional_pos_args [ op ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_pos_args [ op ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
}
}
printf ( " ] \n " ) ;
printf ( " .RE \n " ) ;
done :
printf ( " \n " ) ;
}
/*
* common options listed in the usage section .
*
* For commands with only one variant , this is only
* the options which are common to all lvm commands
* ( in lvm_all , see is_lvm_all_opt ) .
*
* For commands with more than one variant , this
* is the set of options common to all variants
* ( in cname - > common_options ) , ( which obviously
* includes the options common to all lvm commands . )
*
* List ordering :
* options with short + long names , alphabetically ,
* then options with only long names , alphabetically
*/
2017-02-21 23:32:54 +03:00
void print_man_usage_common_lvm ( struct command * cmd )
2017-02-10 20:36:11 +03:00
{
struct command_name * cname ;
2017-02-14 19:28:52 +03:00
int i , sep , rp , oo , op , opt_enum ;
2017-02-10 20:36:11 +03:00
if ( ! ( cname = find_command_name ( cmd - > name ) ) )
return ;
2017-02-21 23:32:54 +03:00
printf ( " Common options for lvm: \n " ) ;
printf ( " . \n " ) ;
sep = 0 ;
printf ( " .RS 4 \n " ) ;
/* print those with short opts */
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( ! opt_names [ opt_enum ] . short_opt )
continue ;
if ( ! is_lvm_all_opt ( opt_enum ) )
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-21 23:32:54 +03:00
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt ! = opt_enum )
continue ;
2017-02-21 23:59:52 +03:00
printf ( " [ \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
2017-02-21 23:32:54 +03:00
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-21 23:32:54 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-21 23:32:54 +03:00
sep = 1 ;
break ;
}
}
/* print those without short opts */
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( opt_names [ opt_enum ] . short_opt )
continue ;
if ( ! is_lvm_all_opt ( opt_enum ) )
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-21 23:32:54 +03:00
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt ! = opt_enum )
continue ;
/* space alignment without short opt */
2017-02-21 23:59:52 +03:00
printf ( " [ " ) ;
2017-02-21 23:32:54 +03:00
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-21 23:32:54 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-21 23:32:54 +03:00
sep = 1 ;
break ;
}
}
2017-02-21 23:59:52 +03:00
printf ( " \n .RE \n " ) ;
2017-02-21 23:32:54 +03:00
return ;
}
void print_man_usage_common_cmd ( struct command * cmd )
{
struct command_name * cname ;
int i , sep , rp , oo , op , opt_enum ;
if ( ! ( cname = find_command_name ( cmd - > name ) ) )
return ;
if ( cname - > variants < 2 )
return ;
printf ( " Common options for command: \n " ) ;
printf ( " . \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 0 ;
printf ( " .RS 4 \n " ) ;
/* print those with short opts */
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( ! cname - > common_options [ opt_enum ] )
continue ;
if ( ! opt_names [ opt_enum ] . short_opt )
continue ;
2017-02-21 23:32:54 +03:00
/* common cmd options only used with variants */
if ( cname - > variants < 2 )
continue ;
if ( is_lvm_all_opt ( opt_enum ) )
2017-02-10 20:36:11 +03:00
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt ! = opt_enum )
continue ;
2017-02-21 23:59:52 +03:00
printf ( " [ \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
2017-02-10 20:36:11 +03:00
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
break ;
}
}
/* print those without short opts */
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( ! cname - > common_options [ opt_enum ] )
continue ;
if ( opt_names [ opt_enum ] . short_opt )
continue ;
2017-02-21 23:32:54 +03:00
/* common cmd options only used with variants */
if ( cname - > variants < 2 )
continue ;
if ( is_lvm_all_opt ( opt_enum ) )
2017-02-10 20:36:11 +03:00
continue ;
2017-02-24 02:06:42 +03:00
if ( sep )
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
for ( oo = 0 ; oo < cmd - > oo_count ; oo + + ) {
if ( cmd - > optional_opt_args [ oo ] . opt ! = opt_enum )
continue ;
/* space alignment without short opt */
2017-02-21 23:59:52 +03:00
printf ( " [ " ) ;
2017-02-10 20:36:11 +03:00
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cmd - > name , opt_enum ) ) ;
if ( cmd - > optional_opt_args [ oo ] . def . val_bits ) {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_def_man ( cname , & cmd - > optional_opt_args [ oo ] . def , 1 ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " ] \n " ) ;
printf ( " .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
break ;
}
}
2017-02-21 23:59:52 +03:00
printf ( " \n .RE \n " ) ;
2017-02-21 23:32:54 +03:00
printf ( " .br \n " ) ;
printf ( " \n " ) ;
2017-02-10 20:36:11 +03:00
return ;
}
/*
* Format of description , when different command names have
* different descriptions :
*
* " #cmdname1 "
* " text foo goes here "
* " a second line of text. "
* " #cmdname2 "
* " text bar goes here "
* " another line of text. "
*
* When called for cmdname2 , this function should just print :
*
* " text bar goes here "
* " another line of text. "
*/
static void print_man_option_desc ( struct command_name * cname , int opt_enum )
{
const char * desc = opt_names [ opt_enum ] . desc ;
char buf [ DESC_LINE ] ;
int started_cname = 0 ;
int line_count = 0 ;
int di , bi = 0 ;
if ( desc [ 0 ] ! = ' # ' ) {
printf ( " %s " , desc ) ;
return ;
}
for ( di = 0 ; di < strlen ( desc ) ; di + + ) {
buf [ bi + + ] = desc [ di ] ;
if ( bi = = DESC_LINE ) {
log_error ( " Parsing command defs: print_man_option_desc line too long " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( buf [ bi - 1 ] ! = ' \n ' )
continue ;
if ( buf [ 0 ] ! = ' # ' ) {
if ( started_cname ) {
printf ( " %s " , buf ) ;
line_count + + ;
}
memset ( buf , 0 , sizeof ( buf ) ) ;
bi = 0 ;
continue ;
}
/* Line starting with #cmdname */
/*
* Must be starting a new command name .
* If no lines have been printed , multiple command names
* are using the same text . If lines have been printed ,
* then the start of a new command name means the end
* of text for the current command name .
*/
if ( line_count & & started_cname )
return ;
if ( ! strncmp ( buf + 1 , cname - > name , strlen ( cname - > name ) ) ) {
/* The start of our command name. */
started_cname = 1 ;
memset ( buf , 0 , sizeof ( buf ) ) ;
bi = 0 ;
} else {
/* The start of another command name. */
memset ( buf , 0 , sizeof ( buf ) ) ;
bi = 0 ;
}
}
if ( bi & & started_cname )
printf ( " %s " , buf ) ;
}
/*
2017-02-25 00:11:18 +03:00
* Print a list of all options names for a given command name .
2017-02-10 20:36:11 +03:00
*/
void print_man_all_options_list ( struct command_name * cname )
{
int opt_enum , val_enum ;
int sep = 0 ;
int i ;
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( ! cname - > all_options [ opt_enum ] )
continue ;
if ( sep )
2017-02-24 02:06:42 +03:00
printf ( " .br \n " ) ;
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
2017-02-25 00:11:18 +03:00
if ( opt_names [ opt_enum ] . short_opt ) {
printf ( " \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cname - > name , opt_enum ) ) ;
2017-02-10 20:36:11 +03:00
} else {
2017-02-25 00:11:18 +03:00
/* spaces for alignment without short opt */
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cname - > name , opt_enum ) ) ;
2017-02-10 20:36:11 +03:00
}
val_enum = opt_names [ opt_enum ] . val_enum ;
if ( ! val_names [ val_enum ] . fn ) {
/* takes no arg */
} else if ( ! val_names [ val_enum ] . usage ) {
printf ( " " ) ;
printf ( " \\ fI " ) ;
printf ( " %s " , val_names [ val_enum ] . name ) ;
printf ( " \\ fP " ) ;
} else {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_val_man ( cname , val_names [ val_enum ] . usage ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-24 02:06:42 +03:00
printf ( " \n .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
}
}
/*
* All options used for a given command name , along with descriptions .
*/
void print_man_all_options_desc ( struct command_name * cname )
{
int opt_enum , val_enum ;
int sep = 0 ;
int i ;
for ( i = 0 ; i < ARG_COUNT ; i + + ) {
opt_enum = opt_names_alpha [ i ] - > opt_enum ;
if ( ! cname - > all_options [ opt_enum ] )
continue ;
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-10 20:36:11 +03:00
2017-02-24 02:06:42 +03:00
printf ( " .ad l \n " ) ;
2017-02-10 20:36:11 +03:00
if ( opt_names [ opt_enum ] . short_opt ) {
printf ( " \\ fB-%c \\ fP| \\ fB%s \\ fP " ,
opt_names [ opt_enum ] . short_opt ,
man_long_opt_name ( cname - > name , opt_enum ) ) ;
} else {
printf ( " \\ fB%s \\ fP " , man_long_opt_name ( cname - > name , opt_enum ) ) ;
}
val_enum = opt_names [ opt_enum ] . val_enum ;
if ( ! val_names [ val_enum ] . fn ) {
/* takes no arg */
} else if ( ! val_names [ val_enum ] . usage ) {
printf ( " " ) ;
printf ( " \\ fI " ) ;
printf ( " %s " , val_names [ val_enum ] . name ) ;
printf ( " \\ fP " ) ;
} else {
printf ( " " ) ;
2017-03-02 21:53:01 +03:00
print_val_man ( cname , val_names [ val_enum ] . usage ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-23 01:38:54 +03:00
if ( opt_names [ opt_enum ] . flags & ARG_COUNTABLE )
printf ( " ... " ) ;
2017-02-10 20:36:11 +03:00
if ( opt_names [ opt_enum ] . desc ) {
printf ( " \n " ) ;
printf ( " .br \n " ) ;
print_man_option_desc ( cname , opt_enum ) ;
}
2017-02-24 02:06:42 +03:00
printf ( " .ad b \n " ) ;
2017-02-10 20:36:11 +03:00
sep = 1 ;
}
2017-02-21 00:09:02 +03:00
}
2017-02-10 20:36:11 +03:00
2017-02-21 00:09:02 +03:00
void print_man_all_positions_desc ( struct command_name * cname )
{
struct command * cmd ;
int ci , rp , op ;
int has_vg_val = 0 ;
int has_lv_val = 0 ;
int has_pv_val = 0 ;
int has_tag_val = 0 ;
int has_select_val = 0 ;
int has_lv_type = 0 ;
for ( ci = 0 ; ci < COMMAND_COUNT ; ci + + ) {
cmd = & commands [ ci ] ;
if ( strcmp ( cmd - > name , cname - > name ) )
continue ;
for ( rp = 0 ; rp < cmd - > rp_count ; rp + + ) {
if ( cmd - > required_pos_args [ rp ] . def . val_bits & val_enum_to_bit ( vg_VAL ) )
has_vg_val = 1 ;
if ( cmd - > required_pos_args [ rp ] . def . val_bits & val_enum_to_bit ( lv_VAL ) ) {
has_lv_val = 1 ;
if ( cmd - > required_pos_args [ rp ] . def . lvt_bits )
has_lv_type = 1 ;
}
if ( cmd - > required_pos_args [ rp ] . def . val_bits & val_enum_to_bit ( pv_VAL ) )
has_pv_val = 1 ;
if ( cmd - > required_pos_args [ rp ] . def . val_bits & val_enum_to_bit ( tag_VAL ) )
has_tag_val = 1 ;
if ( cmd - > required_pos_args [ rp ] . def . val_bits & val_enum_to_bit ( select_VAL ) )
has_select_val = 1 ;
}
for ( op = 0 ; op < cmd - > op_count ; op + + ) {
if ( cmd - > optional_pos_args [ op ] . def . val_bits & val_enum_to_bit ( vg_VAL ) )
has_vg_val = 1 ;
if ( cmd - > optional_pos_args [ op ] . def . val_bits & val_enum_to_bit ( lv_VAL ) ) {
has_lv_val = 1 ;
if ( cmd - > optional_pos_args [ op ] . def . lvt_bits )
has_lv_type = 1 ;
}
if ( cmd - > optional_pos_args [ op ] . def . val_bits & val_enum_to_bit ( pv_VAL ) )
has_pv_val = 1 ;
if ( cmd - > optional_pos_args [ op ] . def . val_bits & val_enum_to_bit ( tag_VAL ) )
has_tag_val = 1 ;
if ( cmd - > optional_pos_args [ op ] . def . val_bits & val_enum_to_bit ( select_VAL ) )
has_select_val = 1 ;
}
}
if ( has_vg_val ) {
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ vg_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " Volume Group name. See \\ fBlvm \\ fP(8) for valid names. \n " ) ;
if ( ! strcmp ( cname - > name , " lvcreate " ) )
printf ( " For lvcreate, the required VG positional arg may be \n "
" omitted when the VG name is included in another option, \n "
" e.g. --name VG/LV. \n " ) ;
2017-02-10 20:36:11 +03:00
}
2017-02-21 00:09:02 +03:00
if ( has_lv_val ) {
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ lv_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " Logical Volume name. See \\ fBlvm \\ fP(8) for valid names. \n "
" An LV positional arg generally includes the VG name and LV name, e.g. VG/LV. \n " ) ;
if ( has_lv_type )
printf ( " LV followed by _<type> indicates that an LV of the \n "
" given type is required. (raid represents raid<N> type) \n " ) ;
}
if ( has_pv_val ) {
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ pv_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " Physical Volume name, a device path under /dev. \n "
" For commands managing physical extents, a PV positional arg \n "
" generally accepts a suffix indicating a range of physical extents. \n "
2017-02-28 21:22:12 +03:00
" Start and end range (inclusive): \\ fIPV \\ fP[ \\ fB: \\ fP \\ fIPE \\ fP[ \\ fB- \\ fP \\ fIPE \\ fP]]. \n "
" Start and length range (counting from 0): \\ fIPV \\ fP[ \\ fB: \\ fP \\ fIPE \\ fP[ \\ fB+ \\ fP \\ fIPE \\ fP]]. \n " ) ;
2017-02-21 00:09:02 +03:00
}
if ( has_tag_val ) {
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ tag_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " Tag name. See \\ fBlvm \\ fP(8) for information about tag names and using tags \n "
" in place of a VG, LV or PV. \n " ) ;
}
if ( has_select_val ) {
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ select_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " Select indicates that a required positional parameter can \n "
" be omitted if the \\ fB--select \\ fP option is used. \n "
" No arg appears in this position. \n " ) ;
}
/* Every command uses a string arg somewhere. */
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \\ fI%s \\ fP " , val_names [ string_VAL ] . name ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " See the option description for information about the string content. \n " ) ;
2017-02-24 22:44:05 +03:00
/*
* We could possibly check if the command accepts any option that
* uses Size , and only print this in those cases , but this seems
* so common that we should probably always print it .
*/
2017-02-21 00:09:02 +03:00
2017-02-21 02:10:11 +03:00
printf ( " \n .HP \n " ) ;
2017-02-24 22:44:05 +03:00
printf ( " \\ fISize \\ fP[UNIT] " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \n " ) ;
printf ( " .br \n " ) ;
2017-02-24 22:44:05 +03:00
printf ( " Size is an input number that accepts an optional unit. \n "
" Input units are always treated as base two values, regardless of \n "
2017-02-21 00:09:02 +03:00
" capitalization, e.g. 'k' and 'K' both refer to 1024. \n "
2017-02-24 22:44:05 +03:00
" The default input unit is specified by letter, followed by |UNIT. \n "
" UNIT represents other possible input units: \\ fBbBsSkKmMgGtTpPeE \\ fP. \n "
2017-02-23 23:24:28 +03:00
" (This should not be confused with the output control --units, where \n "
" capital letters mean multiple of 1000.) \n " ) ;
2017-02-21 00:09:02 +03:00
2017-02-25 00:05:17 +03:00
printf ( " .SH ENVIRONMENT VARIABLES " ) ;
2017-02-21 00:09:02 +03:00
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " See \\ fBlvm \\ fP(8) for information about environment variables used by lvm. \n "
" For example, LVM_VG_NAME can generally be substituted for a required VG parameter. \n " ) ;
2017-02-10 20:36:11 +03:00
}
void print_desc_man ( const char * desc )
{
char buf [ DESC_LINE ] = { 0 } ;
int di = 0 ;
int bi = 0 ;
for ( di = 0 ; di < strlen ( desc ) ; di + + ) {
if ( desc [ di ] = = ' \0 ' )
break ;
if ( desc [ di ] = = ' \n ' )
continue ;
if ( ! strncmp ( & desc [ di ] , " DESC: " , 5 ) ) {
if ( bi ) {
printf ( " %s \n " , buf ) ;
printf ( " .br \n " ) ;
memset ( buf , 0 , sizeof ( buf ) ) ;
bi = 0 ;
}
di + = 5 ;
continue ;
}
if ( ! bi & & desc [ di ] = = ' ' )
continue ;
buf [ bi + + ] = desc [ di ] ;
if ( bi = = ( DESC_LINE - 1 ) )
break ;
}
if ( bi ) {
printf ( " %s \n " , buf ) ;
printf ( " .br \n " ) ;
}
}
static char * upper_command_name ( char * str )
{
static char str_upper [ 32 ] ;
int i = 0 ;
while ( * str ) {
str_upper [ i + + ] = toupper ( * str ) ;
str + + ;
}
str_upper [ i ] = ' \0 ' ;
return str_upper ;
}
2017-02-14 01:11:04 +03:00
# define MAX_MAN_DESC (1024 * 1024)
2017-02-10 20:36:11 +03:00
static void include_description_file ( char * name , char * des_file )
{
2017-02-14 01:11:04 +03:00
char buf [ MAX_MAN_DESC ] ;
2017-02-10 20:36:11 +03:00
int fd ;
memset ( buf , 0 , sizeof ( buf ) ) ;
fd = open ( des_file , O_RDONLY ) ;
if ( fd < 0 )
return ;
2017-02-14 19:28:52 +03:00
( void ) read ( fd , buf , sizeof ( buf ) ) ;
2017-02-14 01:11:04 +03:00
buf [ MAX_MAN_DESC - 1 ] = ' \0 ' ;
2017-02-10 20:36:11 +03:00
printf ( " .SH DESCRIPTION \n " ) ;
printf ( " %s \n " , buf ) ;
close ( fd ) ;
}
2017-03-01 02:04:46 +03:00
void print_man ( char * name , char * des_file , int secondary )
2017-02-10 20:36:11 +03:00
{
struct command_name * cname ;
struct command * cmd , * prev_cmd = NULL ;
char * lvmname = name ;
2017-02-14 19:28:52 +03:00
int i ;
2017-02-10 20:36:11 +03:00
2017-02-18 00:33:04 +03:00
if ( ! strncmp ( name , " lvm- " , 4 ) ) {
2017-02-18 21:46:22 +03:00
name [ 3 ] = ' ' ;
2017-02-10 20:36:11 +03:00
name + = 4 ;
2017-02-18 00:33:04 +03:00
}
2017-02-10 20:36:11 +03:00
cname = find_command_name ( name ) ;
2017-02-21 00:09:02 +03:00
printf ( " .TH %s 8 \" LVM TOOLS #VERSION# \" \" Red Hat, Inc. \" \n " ,
2017-02-10 20:36:11 +03:00
upper_command_name ( lvmname ) ) ;
for ( i = 0 ; i < COMMAND_COUNT ; i + + ) {
cmd = & commands [ i ] ;
if ( prev_cmd & & strcmp ( prev_cmd - > name , cmd - > name ) ) {
2017-02-21 23:32:54 +03:00
print_man_usage_common_cmd ( prev_cmd ) ;
print_man_usage_common_lvm ( prev_cmd ) ;
2017-02-10 20:36:11 +03:00
printf ( " \n " ) ;
printf ( " .SH OPTIONS \n " ) ;
printf ( " .br \n " ) ;
print_man_all_options_desc ( cname ) ;
2017-02-21 00:09:02 +03:00
printf ( " .SH VARIABLES \n " ) ;
printf ( " .br \n " ) ;
print_man_all_positions_desc ( cname ) ;
2017-02-10 20:36:11 +03:00
prev_cmd = NULL ;
}
2017-02-17 20:45:13 +03:00
if ( cmd - > cmd_flags & CMD_FLAG_PREVIOUS_SYNTAX )
continue ;
2017-03-01 02:04:46 +03:00
if ( ( cmd - > cmd_flags & CMD_FLAG_SECONDARY_SYNTAX ) & & ! secondary )
2017-02-10 20:36:11 +03:00
continue ;
2017-02-14 01:11:04 +03:00
if ( strcmp ( name , cmd - > name ) )
2017-02-10 20:36:11 +03:00
continue ;
if ( ! prev_cmd | | strcmp ( prev_cmd - > name , cmd - > name ) ) {
printf ( " .SH NAME \n " ) ;
printf ( " . \n " ) ;
if ( cname - > desc )
printf ( " %s \\ - %s \n " , lvmname , cname - > desc ) ;
else
printf ( " %s \n " , lvmname ) ;
printf ( " .P \n " ) ;
printf ( " . \n " ) ;
printf ( " .SH SYNOPSIS \n " ) ;
printf ( " .br \n " ) ;
printf ( " .P \n " ) ;
printf ( " . \n " ) ;
prev_cmd = cmd ;
if ( ! ( cname = find_command_name ( cmd - > name ) ) )
return ;
if ( cname - > variant_has_ro & & cname - > variant_has_rp )
2017-03-02 23:08:59 +03:00
printf ( " \\ fB%s \\ fP \\ fIoption_args \\ fP \\ fIposition_args \\ fP \n " , lvmname ) ;
2017-02-10 20:36:11 +03:00
else if ( cname - > variant_has_ro & & ! cname - > variant_has_rp )
2017-03-02 23:08:59 +03:00
printf ( " \\ fB%s \\ fP \\ fIoption_args \\ fP \n " , lvmname ) ;
2017-02-10 20:36:11 +03:00
else if ( ! cname - > variant_has_ro & & cname - > variant_has_rp )
2017-03-02 23:08:59 +03:00
printf ( " \\ fB%s \\ fP \\ fIposition_args \\ fP \n " , lvmname ) ;
2017-02-10 20:36:11 +03:00
else if ( ! cname - > variant_has_ro & & ! cname - > variant_has_rp )
printf ( " \\ fB%s \\ fP \n " , lvmname ) ;
printf ( " .br \n " ) ;
if ( cname - > variant_has_oo ) {
2017-03-02 23:08:59 +03:00
printf ( " [ \\ fIoption_args \\ fP ] \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " .br \n " ) ;
}
if ( cname - > variant_has_op ) {
2017-03-02 23:08:59 +03:00
printf ( " [ \\ fIposition_args \\ fP ] \n " ) ;
2017-02-10 20:36:11 +03:00
printf ( " .br \n " ) ;
}
printf ( " .P \n " ) ;
printf ( " \n " ) ;
/* listing them all when there's only 1 or 2 is just repetative */
if ( cname - > variants > 2 ) {
printf ( " .P \n " ) ;
print_man_all_options_list ( cname ) ;
printf ( " \n " ) ;
printf ( " .P \n " ) ;
printf ( " \n " ) ;
}
if ( des_file ) {
include_description_file ( lvmname , des_file ) ;
printf ( " .P \n " ) ;
}
printf ( " .SH USAGE \n " ) ;
printf ( " .br \n " ) ;
printf ( " .P \n " ) ;
printf ( " . \n " ) ;
}
if ( cmd - > desc ) {
print_desc_man ( cmd - > desc ) ;
printf ( " .P \n " ) ;
}
print_man_usage ( lvmname , cmd ) ;
if ( i = = ( COMMAND_COUNT - 1 ) ) {
2017-02-21 23:32:54 +03:00
print_man_usage_common_cmd ( cmd ) ;
print_man_usage_common_lvm ( cmd ) ;
2017-02-10 20:36:11 +03:00
printf ( " \n " ) ;
printf ( " .SH OPTIONS \n " ) ;
printf ( " .br \n " ) ;
print_man_all_options_desc ( cname ) ;
2017-02-21 00:09:02 +03:00
printf ( " .SH VARIABLES \n " ) ;
printf ( " .br \n " ) ;
print_man_all_positions_desc ( cname ) ;
2017-03-01 02:04:46 +03:00
} else {
if ( cname - > variants > 2 ) {
printf ( " -- \n " ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
}
2017-02-10 20:36:11 +03:00
}
printf ( " \n " ) ;
continue ;
}
}
2017-03-01 02:04:46 +03:00
void print_man_secondary ( char * name )
{
struct command * cmd ;
char * lvmname = name ;
int header = 0 ;
int i ;
if ( ! strncmp ( name , " lvm- " , 4 ) ) {
name [ 3 ] = ' ' ;
name + = 4 ;
}
for ( i = 0 ; i < COMMAND_COUNT ; i + + ) {
cmd = & commands [ i ] ;
if ( cmd - > cmd_flags & CMD_FLAG_PREVIOUS_SYNTAX )
continue ;
if ( ! ( cmd - > cmd_flags & CMD_FLAG_SECONDARY_SYNTAX ) )
continue ;
if ( strcmp ( name , cmd - > name ) )
continue ;
if ( ! header ) {
printf ( " .SH ADVANCED USAGE \n " ) ;
printf ( " Alternate command forms, advanced command usage, and listing of all valid syntax for completeness. \n " ) ;
printf ( " .P \n " ) ;
header = 1 ;
}
if ( cmd - > desc ) {
print_desc_man ( cmd - > desc ) ;
printf ( " .P \n " ) ;
}
print_man_usage ( lvmname , cmd ) ;
printf ( " -- \n " ) ;
printf ( " \n " ) ;
printf ( " .br \n " ) ;
printf ( " \n " ) ;
}
}
2017-02-10 20:36:11 +03:00
int main ( int argc , char * argv [ ] )
{
2017-03-01 02:04:46 +03:00
char * cmdname = NULL ;
char * desfile = NULL ;
int primary = 0 ;
int secondary = 0 ;
2017-02-10 20:36:11 +03:00
memset ( & commands , 0 , sizeof ( commands ) ) ;
2017-03-01 02:04:46 +03:00
static struct option long_options [ ] = {
{ " primary " , no_argument , 0 , ' p ' } ,
{ " secondary " , no_argument , 0 , ' s ' } ,
{ 0 , 0 , 0 , 0 }
} ;
while ( 1 ) {
int c ;
int option_index = 0 ;
c = getopt_long ( argc , argv , " ps " , long_options , & option_index ) ;
if ( c = = - 1 )
break ;
switch ( c ) {
case ' 0 ' :
break ;
case ' p ' :
primary = 1 ;
break ;
case ' s ' :
secondary = 1 ;
break ;
}
}
if ( ! primary & & ! secondary ) {
log_error ( " Usage: %s --primary|--secondary <command> [/path/to/description-file] " , argv [ 0 ] ) ;
2017-02-10 20:36:11 +03:00
exit ( EXIT_FAILURE ) ;
}
2017-03-01 02:04:46 +03:00
if ( optind < argc )
cmdname = strdup ( argv [ optind + + ] ) ;
if ( optind < argc )
desfile = argv [ optind + + ] ;
2017-02-14 19:16:13 +03:00
define_commands ( NULL ) ;
2017-02-10 20:36:11 +03:00
2017-02-16 18:36:55 +03:00
factor_common_options ( ) ;
2017-03-01 02:04:46 +03:00
if ( primary )
print_man ( cmdname , desfile , secondary ) ;
else if ( secondary )
print_man_secondary ( cmdname ) ;
2017-02-10 20:36:11 +03:00
return 0 ;
}
# endif