mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			19 Commits
		
	
	
		
			v2_03_36
			...
			dev-dct-cm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c3ce2456b7 | ||
|  | 7ccbe49876 | ||
|  | 295bf7baaa | ||
|  | fe1d4e6a08 | ||
|  | 2023297736 | ||
|  | c0a356561a | ||
|  | 4df2157c72 | ||
|  | 08cf602be1 | ||
|  | 072ef008ea | ||
|  | 5b5e37791c | ||
|  | e916797ec2 | ||
|  | 51205a1bc0 | ||
|  | a7840b31a1 | ||
|  | 4f60bcd9f2 | ||
|  | 6c119560ab | ||
|  | 2cf8f93fe6 | ||
|  | d658ddfc70 | ||
|  | 268374c235 | ||
|  | 45e23131b8 | 
| @@ -88,11 +88,19 @@ struct cmd_context { | ||||
| 	 * Command line and arguments. | ||||
| 	 */ | ||||
| 	const char *cmd_line; | ||||
| 	const char *name; /* needed before cmd->command is set */ | ||||
| 	struct command *command; | ||||
| 	char **argv; | ||||
| 	struct arg_values *arg_values; | ||||
| 	struct arg_values *opt_arg_values; | ||||
| 	struct dm_list arg_value_groups; | ||||
|  | ||||
| 	/* | ||||
| 	 * Position args remaining after command name | ||||
| 	 * and --options are removed from original argc/argv. | ||||
| 	 */ | ||||
| 	int position_argc; | ||||
| 	char **position_argv; | ||||
|  | ||||
| 	/* | ||||
| 	 * Format handlers. | ||||
| 	 */ | ||||
|   | ||||
| @@ -319,7 +319,6 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem, | ||||
| { | ||||
| 	int top_level = 0; | ||||
| 	unsigned snap_count; | ||||
| 	struct lv_segment *seg; | ||||
|  | ||||
| 	/* non-top-level LVs */ | ||||
| 	if (lv_is_thin_pool_metadata(lv)) { | ||||
| @@ -353,7 +352,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem, | ||||
| 			    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN])) | ||||
| 				goto_bad; | ||||
| 		} | ||||
| 		if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv)) | ||||
| 		if (lv_is_thin_snapshot(lv)) | ||||
| 			if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) || | ||||
| 			    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT])) | ||||
| 				goto_bad; | ||||
|   | ||||
| @@ -1066,9 +1066,16 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l | ||||
| * Useful functions for managing snapshots. | ||||
| */ | ||||
| int lv_is_origin(const struct logical_volume *lv); | ||||
| #define lv_is_thick_origin lv_is_origin | ||||
|  | ||||
| int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count); | ||||
| int lv_is_cache_origin(const struct logical_volume *lv); | ||||
| int lv_is_thin_snapshot(const struct logical_volume *lv); | ||||
|  | ||||
| int lv_is_cow(const struct logical_volume *lv); | ||||
| #define lv_is_thick_snapshot lv_is_cow | ||||
|  | ||||
| int lv_is_cache_origin(const struct logical_volume *lv); | ||||
|  | ||||
| int lv_is_merging_cow(const struct logical_volume *cow); | ||||
| uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size); | ||||
| int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size); | ||||
|   | ||||
| @@ -748,6 +748,19 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count) | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int lv_is_thin_snapshot(const struct logical_volume *lv) | ||||
| { | ||||
| 	struct lv_segment *seg; | ||||
|  | ||||
| 	if (!lv_is_thin_volume(lv)) | ||||
| 		return 0; | ||||
|  | ||||
| 	if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv)) | ||||
| 		return 1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Explict check of new thin pool for usability | ||||
|  * | ||||
|   | ||||
| @@ -140,6 +140,13 @@ Makefile: Makefile.in | ||||
| 	  *) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_PROFILE_DIR#+$(DEFAULT_PROFILE_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;s+#DEFAULT_PID_DIR#+@DEFAULT_PID_DIR@+;s+#SYSTEMD_GENERATOR_DIR#+$(SYSTEMD_GENERATOR_DIR)+;s+#DEFAULT_MANGLING#+$(DEFAULT_MANGLING)+;" $< > $@ ;; \ | ||||
| 	esac | ||||
|  | ||||
| ccmd: ../tools/create-commands.c | ||||
| 	$(CC) ../tools/create-commands.c -o ccmd | ||||
|  | ||||
| generate: ccmd | ||||
| 	./ccmd --output man -s 0 -p 1 -c lvcreate ../tools/command-lines.in > lvcreate.8.a | ||||
| 	cat lvcreate.8.a lvcreate.8.b > lvcreate.8.in | ||||
|  | ||||
| install_man5: $(MAN5) | ||||
| 	$(INSTALL) -d $(MAN5DIR) | ||||
| 	$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/ | ||||
|   | ||||
| @@ -85,12 +85,9 @@ offset=$(( offset + 2 )) | ||||
| # update in case  mirror ever gets faster and allows parallel read | ||||
| aux delay_dev "$dev2" 0 2000 ${offset}:1 | ||||
| lvcreate -aey -l5 -Zn -Wn --type mirror --regionsize 16K -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE" | ||||
| # FIXME: add a new explicit option to define the polling behavior | ||||
| # done here with 'lvconvert vg/lv'.  That option can specify | ||||
| # that the command succeeds even if the LV doesn't need polling. | ||||
| should not lvconvert -m-1 $vg/$lv1 "$dev1" | ||||
| aux enable_dev "$dev2" | ||||
| should lvconvert $vg/$lv1 # wait | ||||
| lvconvert --startpoll $vg/$lv1 || true # wait | ||||
| lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed... | ||||
|  | ||||
| aux wait_for_sync $vg $lv1 | ||||
| @@ -116,7 +113,7 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4" | ||||
| # Next convert should fail b/c we can't have 2 at once | ||||
| should not lvconvert -m+1 $vg/$lv1 "$dev5" | ||||
| aux enable_dev "$dev4" | ||||
| should lvconvert $vg/$lv1 # wait | ||||
| lvconvert --startpoll $vg/$lv1 || true # wait | ||||
| lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed | ||||
|  | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| @@ -159,7 +156,7 @@ lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE | ||||
| lvchange -an $vg/$lv1 | ||||
| lvconvert -m+1 $vg/$lv1 "$dev4" | ||||
| lvchange -aey $vg/$lv1 | ||||
| should lvconvert $vg/$lv1 # wait | ||||
| lvconvert --startpoll $vg/$lv1 || true # wait | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| check mirror_no_temporaries $vg $lv1 | ||||
| lvremove -ff $vg | ||||
| @@ -171,7 +168,7 @@ lvremove -ff $vg | ||||
| lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE" | ||||
| LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4" | ||||
| lvconvert -m-1 $vg/$lv1 "$dev4" | ||||
| should lvconvert $vg/$lv1 # wait | ||||
| lvconvert --startpoll $vg/$lv1 || true # wait | ||||
|  | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| check mirror_no_temporaries $vg $lv1 | ||||
| @@ -182,7 +179,7 @@ lvremove -ff $vg | ||||
| lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE" | ||||
| LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5" | ||||
| lvconvert -m-1 $vg/$lv1 "$dev4" | ||||
| should lvconvert $vg/$lv1 # wait | ||||
| lvconvert --startpoll $vg/$lv1 || true # wait | ||||
|  | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| check mirror_no_temporaries $vg $lv1 | ||||
| @@ -195,9 +192,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4" | ||||
| # FIXME: Extra wait here for mirror upconvert synchronization | ||||
| # otherwise we may fail her on parallel upconvert and downconvert | ||||
| # lvconvert-mirror-updown.sh tests this errornous case separately | ||||
| should lvconvert $vg/$lv1 | ||||
| lvconvert --startpoll $vg/$lv1 || true | ||||
| lvconvert -m-1 $vg/$lv1 "$dev2" | ||||
| should lvconvert $vg/$lv1 | ||||
| lvconvert --startpoll $vg/$lv1 || true | ||||
|  | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| check mirror_no_temporaries $vg $lv1 | ||||
| @@ -210,9 +207,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4" | ||||
| # FIXME: Extra wait here for mirror upconvert synchronization | ||||
| # otherwise we may fail her on parallel upconvert and downconvert | ||||
| # lvconvert-mirror-updown.sh tests this errornous case separately | ||||
| should lvconvert $vg/$lv1 | ||||
| lvconvert --startpoll $vg/$lv1 || true | ||||
| lvconvert -m-1 $vg/$lv1 "$dev2" | ||||
| should lvconvert $vg/$lv1 | ||||
| lvconvert --startpoll $vg/$lv1 || true | ||||
|  | ||||
| check mirror $vg $lv1 "$dev3" | ||||
| check mirror_no_temporaries $vg $lv1 | ||||
|   | ||||
| @@ -30,8 +30,8 @@ aux wait_for_sync $vg $lv2 | ||||
| lvchange -an $vg/$lv1 | ||||
|  | ||||
| # conversion fails for internal volumes | ||||
| invalid lvconvert --thinpool $vg/${lv1}_rimage_0 | ||||
| invalid lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0 | ||||
| not lvconvert --thinpool $vg/${lv1}_rimage_0 | ||||
| not lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0 | ||||
|  | ||||
| lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
|  | ||||
|   | ||||
| @@ -58,13 +58,13 @@ lvchange -an $vg/$lv1 | ||||
| # conversion fails for mirror segment type | ||||
| fail lvconvert --thinpool $vg/$lv1 | ||||
| # cannot use same LV | ||||
| invalid lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2 | ||||
| not lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2 | ||||
|  | ||||
| prepare_lvs | ||||
|  | ||||
| # conversion fails for internal volumes | ||||
| # can't use --readahead with --poolmetadata | ||||
| invalid lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512 | ||||
| not lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512 | ||||
| lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
|  | ||||
| prepare_lvs | ||||
| @@ -81,9 +81,9 @@ grep "Pool zeroing and large" err | ||||
| UUID=$(get lv_field $vg/$lv2 uuid) | ||||
| # Fail is pool is active | ||||
| # TODO  maybe detect inactive pool and deactivate | ||||
| fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2 | ||||
| fail lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1 | ||||
| lvchange -an $vg | ||||
| lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2 | ||||
| lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1 | ||||
| check lv_field $vg/${lv1}_tmeta uuid "$UUID" | ||||
| lvremove -f $vg | ||||
|  | ||||
| @@ -96,20 +96,20 @@ lvcreate -L1M -n $lv3 $vg | ||||
| # chunk size is bigger then size of thin pool data | ||||
| fail lvconvert --yes -c 1G --thinpool $vg/$lv3 | ||||
| # stripes can't be used with poolmetadata | ||||
| invalid lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| not lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| # too small metadata (<2M) | ||||
| fail lvconvert --yes -c 64 --thinpool $vg/$lv1 --poolmetadata $vg/$lv3 | ||||
| # too small chunk size fails | ||||
| invalid lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| not lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| # too big chunk size fails | ||||
| invalid lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| not lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| # negative chunk size fails | ||||
| invalid lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| not lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| # non multiple of 64KiB fails | ||||
| invalid lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
| not lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 | ||||
|  | ||||
| # cannot use same LV for pool and convertion | ||||
| invalid lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3 | ||||
| not lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3 | ||||
|  | ||||
| # Warning about smaller then suggested | ||||
| lvconvert --yes -c 256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err | ||||
| @@ -129,7 +129,7 @@ if test "$TSIZE" = 64T; then | ||||
| lvcreate -L24T -n $lv1 $vg | ||||
| # Warning about bigger then needed (24T data and 16G -> 128K chunk) | ||||
| lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err | ||||
| grep "WARNING: Chunk size is too small" err | ||||
| grep "too small" err | ||||
| lvremove -f $vg | ||||
| fi | ||||
|  | ||||
|   | ||||
| @@ -56,7 +56,7 @@ fail lvcreate -l 1 --cachepool pool8 $vg | ||||
|  | ||||
| # no size specified | ||||
| invalid lvcreate --cachepool pool $vg 2>&1 | tee err | ||||
| grep "specify either size or extents" err | ||||
| # grep "specify either size or extents" err | ||||
|  | ||||
| # Check nothing has been created yet | ||||
| check vg_field $vg lv_count 0 | ||||
|   | ||||
| @@ -54,7 +54,7 @@ mkdir test_mnt | ||||
|  | ||||
| setup_merge_ $vg1 $lv1 | ||||
| mount "$(lvdev_ $vg1 $lv1)" test_mnt | ||||
| lvconvert --merge $vg1/$(snap_lv_name_ $lv1) | ||||
| lvconvert --mergesnapshot $vg1/$(snap_lv_name_ $lv1) | ||||
| umount test_mnt | ||||
| vgchange -an $vg1 | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,7 @@ snap_and_merge() { | ||||
| 	SLEEP_PID=$! | ||||
|  | ||||
| 	# initiate background merge | ||||
| 	lvconvert -b --merge $vg/$lv2 | ||||
| 	lvconvert -b --mergesnapshot $vg/$lv2 | ||||
|  | ||||
| 	lvs -a -o+lv_merging,lv_merge_failed $vg | ||||
| 	kill $SLEEP_PID | ||||
|   | ||||
| @@ -51,15 +51,15 @@ mkdir test_mnt | ||||
| # test full merge of a single LV | ||||
| setup_merge_ $vg $lv1 | ||||
|  | ||||
| # make sure lvconvert --merge requires explicit LV listing | ||||
| not lvconvert --merge | ||||
| lvconvert --merge $vg/$(snap_lv_name_ $lv1) | ||||
| # make sure lvconvert --mergesnapshot requires explicit LV listing | ||||
| not lvconvert --mergesnapshot | ||||
| lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1) | ||||
| lvremove -f $vg/$lv1 | ||||
|  | ||||
|  | ||||
| # test that an actively merging snapshot may not be removed | ||||
| setup_merge_ $vg $lv1 | ||||
| lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1) | ||||
| lvconvert -i+100 --mergesnapshot --background $vg/$(snap_lv_name_ $lv1) | ||||
| not lvremove -f $vg/$(snap_lv_name_ $lv1) | ||||
| lvremove -f $vg/$lv1 | ||||
|  | ||||
| @@ -67,7 +67,7 @@ lvremove -f $vg/$lv1 | ||||
| # "onactivate merge" test | ||||
| setup_merge_ $vg $lv1 | ||||
| mount "$(lvdev_ $vg $lv1)" test_mnt | ||||
| lvconvert --merge $vg/$(snap_lv_name_ $lv1) | ||||
| lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1) | ||||
| # -- refresh LV while FS is still mounted (merge must not start), | ||||
| #    verify 'snapshot-origin' target is still being used | ||||
| lvchange --refresh $vg/$lv1 | ||||
| @@ -88,7 +88,7 @@ lvremove -f $vg/$lv1 | ||||
| #    to make sure preload of origin's metadata is _not_ performed | ||||
| setup_merge_ $vg $lv1 | ||||
| mount "$(lvdev_ $vg $lv1)" test_mnt | ||||
| lvconvert --merge $vg/$(snap_lv_name_ $lv1) | ||||
| lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1) | ||||
| # -- refresh LV while FS is still mounted (merge must not start), | ||||
| #    verify 'snapshot-origin' target is still being used | ||||
| lvchange --refresh $vg/$lv1 | ||||
| @@ -99,7 +99,7 @@ lvremove -f $vg/$lv1 | ||||
|  | ||||
| # test multiple snapshot merge; tests copy out that is driven by merge | ||||
| setup_merge_ $vg $lv1 1 | ||||
| lvconvert --merge $vg/$(snap_lv_name_ $lv1) | ||||
| lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1) | ||||
| lvremove -f $vg/$lv1 | ||||
|  | ||||
|  | ||||
| @@ -108,7 +108,7 @@ setup_merge_ $vg $lv1 | ||||
| setup_merge_ $vg $lv2 | ||||
| lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1) | ||||
| lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2) | ||||
| lvconvert --merge @this_is_a_test | ||||
| lvconvert --mergesnapshot @this_is_a_test | ||||
| lvs $vg | tee out | ||||
| not grep $(snap_lv_name_ $lv1) out | ||||
| not grep $(snap_lv_name_ $lv2) out | ||||
|   | ||||
| @@ -44,7 +44,7 @@ touch mntsnap/test_snap | ||||
|  | ||||
| lvs -o+tags,thin_id $vg | ||||
|  | ||||
| lvconvert --merge $vg/snap | ||||
| lvconvert --mergethin $vg/snap | ||||
|  | ||||
| umount mnt | ||||
|  | ||||
| @@ -102,12 +102,12 @@ lvcreate -s -n snap $vg/$lv1 | ||||
| lvcreate -s -L10 -n oldsnapof_${lv1} $vg/$lv1 | ||||
| not lvconvert --merge $vg/snap | ||||
| $MKFS "$DM_DEV_DIR/$vg/oldsnapof_${lv1}" | ||||
| lvconvert --merge $vg/oldsnapof_${lv1} | ||||
| lvconvert --mergesnapshot $vg/oldsnapof_${lv1} | ||||
| fsck -n "$DM_DEV_DIR/$vg/$lv1" | ||||
| check lv_not_exists $vg oldsnapof_${lv1} | ||||
| # Add old snapshot to thin snapshot | ||||
| lvcreate -s -L10 -n oldsnapof_snap $vg/snap | ||||
| lvconvert --merge $vg/snap | ||||
| lvconvert --mergethin $vg/snap | ||||
| lvremove -f $vg/oldsnapof_snap | ||||
|  | ||||
| vgremove -ff $vg | ||||
|   | ||||
| @@ -34,7 +34,7 @@ mount "$DM_DEV_DIR/$vg/$lv1" mnt | ||||
| lvcreate -s -n snap $vg/$lv1 | ||||
| check lv_field $vg/snap thin_id "3" | ||||
|  | ||||
| lvconvert --merge $vg/snap | ||||
| lvconvert --mergethin $vg/snap | ||||
|  | ||||
| umount mnt | ||||
| vgchange -an $vg | ||||
|   | ||||
| @@ -23,7 +23,6 @@ lvcreate -l 1 -n lv1 $vg "$dev1" | ||||
| invalid vgextend | ||||
| # --metadatacopies => use --pvmetadatacopies | ||||
| invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out | ||||
| grep -- "use --pvmetadatacopies" out | ||||
|  | ||||
| # VG name should exist | ||||
| fail vgextend --restoremissing $vg-invalid "$dev1" | ||||
|   | ||||
| @@ -76,6 +76,7 @@ SOURCES2 =\ | ||||
|  | ||||
| TARGETS =\ | ||||
| 	.commands \ | ||||
| 	command-lines.h \ | ||||
| 	liblvm2cmd.a \ | ||||
| 	lvm | ||||
|  | ||||
| @@ -99,7 +100,8 @@ LIB_VERSION = $(LIB_VERSION_LVM) | ||||
| CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \ | ||||
| 	liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \ | ||||
| 	liblvm2cmd-static.a dmsetup.static lvm.static \ | ||||
| 	$(LDDEPS) .exported_symbols_generated | ||||
| 	$(LDDEPS) .exported_symbols_generated \ | ||||
| 	ccmd command-lines.h command-lines-count.h | ||||
|  | ||||
| ifeq ("@CMDLIB@", "yes") | ||||
| 	TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) | ||||
| @@ -171,6 +173,13 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX) | ||||
| 	$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \ | ||||
| 		egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands | ||||
|  | ||||
| ccmd: create-commands.c | ||||
| 	$(CC) create-commands.c -o ccmd | ||||
|  | ||||
| command-lines.h: ccmd | ||||
| 	./ccmd --output struct command-lines.in > command-lines.h | ||||
| 	./ccmd --output count command-lines.in > command-lines-count.h | ||||
|  | ||||
| ifneq ("$(CFLOW_CMD)", "") | ||||
| CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) | ||||
| -include $(top_builddir)/libdm/libdevmapper.cflow | ||||
|   | ||||
							
								
								
									
										412
									
								
								tools/args.h
									
									
									
									
									
								
							
							
						
						
									
										412
									
								
								tools/args.h
									
									
									
									
									
								
							| @@ -17,215 +17,221 @@ | ||||
|  * Put all long args that don't have a corresponding short option first. | ||||
|  */ | ||||
| /* *INDENT-OFF* */ | ||||
| arg(abort_ARG, '\0', "abort", NULL, 0, 0) | ||||
| arg(activationmode_ARG, '\0', "activationmode", string_arg, 0, 0) | ||||
| arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE, 0) | ||||
| arg(aligned_ARG, '\0', "aligned", NULL, 0, 0) | ||||
| arg(alloc_ARG, '\0', "alloc", alloc_arg, 0, 0) | ||||
| arg(atomic_ARG, '\0', "atomic", NULL, 0, 0) | ||||
| arg(atversion_ARG, '\0', "atversion", string_arg, 0, 0) | ||||
| arg(binary_ARG, '\0', "binary", NULL, 0, 0) | ||||
| arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", size_mb_arg, 0, 0) | ||||
| arg(cache_long_ARG, '\0', "cache", NULL, 0, 0) | ||||
| arg(cachemode_ARG, '\0', "cachemode", cachemode_arg, 0, 0) | ||||
| arg(cachepool_ARG, '\0', "cachepool", string_arg, 0, 0) | ||||
| arg(commandprofile_ARG, '\0', "commandprofile", string_arg, 0, 0) | ||||
| arg(config_ARG, '\0', "config", string_arg, 0, 0) | ||||
| arg(configreport_ARG, '\0', "configreport", string_arg, ARG_GROUPABLE, 1) | ||||
| arg(configtype_ARG, '\0', "type", string_arg, 0, 0) | ||||
| arg(corelog_ARG, '\0', "corelog", NULL, 0, 0) | ||||
| arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0, 0) | ||||
| arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0, 0) | ||||
| arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE, 0) | ||||
| arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0, 0) | ||||
| arg(discards_ARG, '\0', "discards", discards_arg, 0, 0) | ||||
| arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0, 0) | ||||
| arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0, 0) | ||||
| arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE, 0) | ||||
| arg(foreign_ARG, '\0', "foreign", NULL, 0, 0) | ||||
| arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", NULL, 0, 0) | ||||
| arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0, 0) | ||||
| arg(ignorelocal_ARG, '\0', "ignorelocal", NULL, 0, 0) | ||||
| arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0, 0) | ||||
| arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0, 0) | ||||
| arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0, 0) | ||||
| arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0, 0) | ||||
| arg(labelsector_ARG, '\0', "labelsector", int_arg, 0, 0) | ||||
| arg(lockopt_ARG, '\0', "lockopt", string_arg, 0, 0) | ||||
| arg(lockstart_ARG, '\0', "lockstart", NULL, 0, 0) | ||||
| arg(lockstop_ARG, '\0', "lockstop", NULL, 0, 0) | ||||
| arg(locktype_ARG, '\0', "locktype", locktype_arg, 0, 0) | ||||
| arg(logonly_ARG, '\0', "logonly", NULL, 0, 0) | ||||
| arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0, 0) | ||||
| arg(merge_ARG, '\0', "merge", NULL, 0, 0) | ||||
| arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0, 0) | ||||
| arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0, 0) | ||||
| arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0, 0) | ||||
| arg(metadataprofile_ARG, '\0', "metadataprofile", string_arg, 0, 0) | ||||
| arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0, 0) | ||||
| arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE, 0) | ||||
| arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0, 0) | ||||
| arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_arg, 0, 0) | ||||
| arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0, 0) | ||||
| arg(mknodes_ARG, '\0', "mknodes", NULL, 0, 0) | ||||
| arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0, 0) | ||||
| arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0, 0) | ||||
| arg(noheadings_ARG, '\0', "noheadings", NULL, 0, 0) | ||||
| arg(nohistory_ARG, '\0', "nohistory", NULL, 0, 0) | ||||
| arg(nolocking_ARG, '\0', "nolocking", NULL, 0, 0) | ||||
| arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0, 0) | ||||
| arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0, 0) | ||||
| arg(nosync_ARG, '\0', "nosync", NULL, 0, 0) | ||||
| arg(notifydbus_ARG, '\0', "notifydbus", NULL, 0, 0) | ||||
| arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0, 0) | ||||
| arg(originname_ARG, '\0', "originname", string_arg, 0, 0) | ||||
| arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0, 0) | ||||
| arg(poll_ARG, '\0', "poll", yes_no_arg, 0, 0) | ||||
| arg(polloperation_ARG, '\0', "polloperation", string_arg, 0, 0) | ||||
| arg(pooldatasize_ARG, '\0', "pooldatasize", size_mb_arg, 0, 0) | ||||
| arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0, 0) | ||||
| arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0) | ||||
| arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0) | ||||
| arg(profile_ARG, '\0', "profile", string_arg, 0, 0) | ||||
| arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0) | ||||
| arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0) | ||||
| arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0) | ||||
| arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0) | ||||
| arg(raidwritebehind_ARG, '\0', "raidwritebehind", int_arg, 0, 0) | ||||
| arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(readonly_ARG, '\0', "readonly", NULL, 0, 0) | ||||
| arg(refresh_ARG, '\0', "refresh", NULL, 0, 0) | ||||
| arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0) | ||||
| arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(repair_ARG, '\0', "repair", NULL, 0, 0) | ||||
| arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0) | ||||
| arg(restorefile_ARG, '\0', "restorefile", string_arg, 0, 0) | ||||
| arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0, 0) | ||||
| arg(resync_ARG, '\0', "resync", NULL, 0, 0) | ||||
| arg(rows_ARG, '\0', "rows", NULL, 0, 0) | ||||
| arg(segments_ARG, '\0', "segments", NULL, 0, 0) | ||||
| arg(separator_ARG, '\0', "separator", string_arg, 0, 0) | ||||
| arg(shared_ARG, '\0', "shared", NULL, 0, 0) | ||||
| arg(sinceversion_ARG, '\0', "sinceversion", string_arg, 0, 0) | ||||
| arg(split_ARG, '\0', "split", NULL, 0, 0) | ||||
| arg(splitcache_ARG, '\0', "splitcache", NULL, 0, 0) | ||||
| arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0, 0) | ||||
| arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0, 0) | ||||
| arg(showdeprecated_ARG, '\0', "showdeprecated", NULL, 0, 0) | ||||
| arg(showunsupported_ARG, '\0', "showunsupported", NULL, 0, 0) | ||||
| arg(stripes_long_ARG, '\0', "stripes", int_arg, 0, 0) | ||||
| arg(syncaction_ARG, '\0', "syncaction", string_arg, 0, 0)	/* FIXME Use custom validation fn */ | ||||
| arg(sysinit_ARG, '\0', "sysinit", NULL, 0, 0) | ||||
| arg(systemid_ARG, '\0', "systemid", string_arg, 0, 0) | ||||
| arg(thinpool_ARG, '\0', "thinpool", string_arg, 0, 0) | ||||
| arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0, 0) | ||||
| arg(trustcache_ARG, '\0', "trustcache", NULL, 0, 0) | ||||
| arg(type_ARG, '\0', "type", segtype_arg, 0, 0) | ||||
| arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0, 0) | ||||
| arg(uncache_ARG, '\0', "uncache", NULL, 0, 0) | ||||
| arg(cachepolicy_ARG, '\0', "cachepolicy", string_arg, 0, 0) | ||||
| arg(cachesettings_ARG, '\0', "cachesettings", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(unconfigured_ARG, '\0', "unconfigured", NULL, 0, 0) | ||||
| arg(units_ARG, '\0', "units", string_arg, 0, 0) | ||||
| arg(unquoted_ARG, '\0', "unquoted", NULL, 0, 0) | ||||
| arg(usepolicies_ARG, '\0', "usepolicies", NULL, 0, 0) | ||||
| arg(validate_ARG, '\0', "validate", NULL, 0, 0) | ||||
| arg(version_ARG, '\0', "version", NULL, 0, 0) | ||||
| arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0, 0) | ||||
| arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0, 0) | ||||
| arg(withsummary_ARG, '\0', "withsummary", NULL, 0, 0) | ||||
| arg(withcomments_ARG, '\0', "withcomments", NULL, 0, 0) | ||||
| arg(withspaces_ARG, '\0', "withspaces", NULL, 0, 0) | ||||
| arg(withversions_ARG, '\0', "withversions", NULL, 0, 0) | ||||
| arg(writebehind_ARG, '\0', "writebehind", int_arg, 0, 0) | ||||
| arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(ARG_UNUSED, '-', "", 0, 0, 0)  /* place holder for unused 0 value */ | ||||
|  | ||||
| arg(abort_ARG, '\0', "abort", 0, 0, 0) | ||||
| arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0) | ||||
| arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0) | ||||
| arg(aligned_ARG, '\0', "aligned", 0, 0, 0) | ||||
| arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0) | ||||
| arg(atomic_ARG, '\0', "atomic", 0, 0, 0) | ||||
| arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0) | ||||
| arg(binary_ARG, '\0', "binary", 0, 0, 0) | ||||
| arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0) | ||||
| arg(cache_long_ARG, '\0', "cache", 0, 0, 0) | ||||
| arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0) | ||||
| arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0) | ||||
| arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0) | ||||
| arg(config_ARG, '\0', "config", string_VAL, 0, 0) | ||||
| arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1) | ||||
| arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0) | ||||
| arg(corelog_ARG, '\0', "corelog", 0, 0, 0) | ||||
| arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0) | ||||
| arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0) | ||||
| arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0) | ||||
| arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0) | ||||
| arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0) | ||||
| arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0) | ||||
| arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0) | ||||
| arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0) | ||||
| arg(foreign_ARG, '\0', "foreign", 0, 0, 0) | ||||
| arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0) | ||||
| arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0) | ||||
| arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0) | ||||
| arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0) | ||||
| arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0) | ||||
| arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0) | ||||
| arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0) | ||||
| arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0) | ||||
| arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0) | ||||
| arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0) | ||||
| arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0) | ||||
| arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0) | ||||
| arg(logonly_ARG, '\0', "logonly", 0, 0, 0) | ||||
| arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0) | ||||
| arg(merge_ARG, '\0', "merge", 0, 0, 0) | ||||
| arg(mergemirrors_ARG, '\0', "mergemirrors", 0, 0, 0) | ||||
| arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0) | ||||
| arg(mergethin_ARG, '\0', "mergethin", 0, 0, 0) | ||||
| arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0) | ||||
| arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0) | ||||
| arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0) | ||||
| arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0) | ||||
| arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0) | ||||
| arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0) | ||||
| arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0) | ||||
| arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0) | ||||
| arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0) | ||||
| arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0) | ||||
| arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0) | ||||
| arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0) | ||||
| arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0) | ||||
| arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0) | ||||
| arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0) | ||||
| arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0) | ||||
| arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0) | ||||
| arg(nosync_ARG, '\0', "nosync", 0, 0, 0) | ||||
| arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0) | ||||
| arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0) | ||||
| arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0) | ||||
| arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0) | ||||
| arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0) | ||||
| arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0) | ||||
| arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0) | ||||
| arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0) | ||||
| arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0) | ||||
| arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0) | ||||
| arg(profile_ARG, '\0', "profile", string_VAL, 0, 0) | ||||
| arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0) | ||||
| arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0) | ||||
| arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0) | ||||
| arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0) | ||||
| arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0) | ||||
| arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0) | ||||
| arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0) | ||||
| arg(readonly_ARG, '\0', "readonly", 0, 0, 0) | ||||
| arg(refresh_ARG, '\0', "refresh", 0, 0, 0) | ||||
| arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0) | ||||
| arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0) | ||||
| arg(repair_ARG, '\0', "repair", 0, 0, 0) | ||||
| arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0) | ||||
| arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0) | ||||
| arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0) | ||||
| arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0) | ||||
| arg(resync_ARG, '\0', "resync", 0, 0, 0) | ||||
| arg(rows_ARG, '\0', "rows", 0, 0, 0) | ||||
| arg(segments_ARG, '\0', "segments", 0, 0, 0) | ||||
| arg(separator_ARG, '\0', "separator", string_VAL, 0, 0) | ||||
| arg(shared_ARG, '\0', "shared", 0, 0, 0) | ||||
| arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0) | ||||
| arg(split_ARG, '\0', "split", 0, 0, 0) | ||||
| arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0) | ||||
| arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0) | ||||
| arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0) | ||||
| arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0) | ||||
| arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0) | ||||
| arg(startpoll_ARG, '\0', "startpoll", 0, 0, 0) | ||||
| arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0) | ||||
| arg(swapmetadata_ARG, '\0', "swapmetadata", 0, 0, 0) | ||||
| arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0) | ||||
| arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0) | ||||
| arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0) | ||||
| arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0) | ||||
| arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0) | ||||
| arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0) | ||||
| arg(type_ARG, '\0', "type", segtype_VAL, 0, 0) | ||||
| arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0) | ||||
| arg(uncache_ARG, '\0', "uncache", 0, 0, 0) | ||||
| arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0) | ||||
| arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0) | ||||
| arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0) | ||||
| arg(units_ARG, '\0', "units", units_VAL, 0, 0) | ||||
| arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0) | ||||
| arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0) | ||||
| arg(validate_ARG, '\0', "validate", 0, 0, 0) | ||||
| arg(version_ARG, '\0', "version", 0, 0, 0) | ||||
| arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0) | ||||
| arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0) | ||||
| arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0) | ||||
| arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0) | ||||
| arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0) | ||||
| arg(withversions_ARG, '\0', "withversions", 0, 0, 0) | ||||
| arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0) | ||||
| arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0) | ||||
|  | ||||
| /* Allow some variations */ | ||||
| arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0, 0) | ||||
| arg(available_ARG, '\0', "available", activation_arg, 0, 0) | ||||
| arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0, 0) | ||||
| arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0) | ||||
| arg(available_ARG, '\0', "available", activation_VAL, 0, 0) | ||||
| arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0) | ||||
|  | ||||
| /* | ||||
|  * ... and now the short args. | ||||
|  */ | ||||
| arg(activate_ARG, 'a', "activate", activation_arg, 0, 0) | ||||
| arg(all_ARG, 'a', "all", NULL, 0, 0) | ||||
| arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0, 0) | ||||
| arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0, 0) | ||||
| arg(background_ARG, 'b', "background", NULL, 0, 0) | ||||
| arg(backgroundfork_ARG, 'b', "background", NULL, 0, 0) | ||||
| arg(basevgname_ARG, 'n', "basevgname", string_arg, 0, 0) | ||||
| arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0, 0) | ||||
| arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0, 0) | ||||
| arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0, 0) | ||||
| arg(colon_ARG, 'c', "colon", NULL, 0, 0) | ||||
| arg(columns_ARG, 'C', "columns", NULL, 0, 0) | ||||
| arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0, 0) | ||||
| arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE, 0) | ||||
| arg(exported_ARG, 'e', "exported", NULL, 0, 0) | ||||
| arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0, 0) | ||||
| arg(file_ARG, 'f', "file", string_arg, 0, 0) | ||||
| arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE, 0) | ||||
| arg(full_ARG, 'f', "full", NULL, 0, 0) | ||||
| arg(help_ARG, 'h', "help", NULL, 0, 0) | ||||
| arg(cache_ARG, 'H', "cache", NULL, 0, 0) | ||||
| arg(history_ARG, 'H', "history", NULL, 0, 0) | ||||
| arg(help2_ARG, '?', "", NULL, 0, 0) | ||||
| arg(import_ARG, 'i', "import", NULL, 0, 0) | ||||
| arg(interval_ARG, 'i', "interval", int_arg, 0, 0) | ||||
| arg(iop_version_ARG, 'i', "iop_version", NULL, 0, 0) | ||||
| arg(stripes_ARG, 'i', "stripes", int_arg, 0, 0) | ||||
| arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0, 0) | ||||
| arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0, 0) | ||||
| arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0, 0) | ||||
| arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0, 0) | ||||
| arg(list_ARG, 'l', "list", NULL, 0, 0) | ||||
| arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0, 0) | ||||
| arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0, 0) | ||||
| arg(size_ARG, 'L', "size", size_mb_arg, 0, 0) | ||||
| arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0, 0) | ||||
| arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE, 0) | ||||
| arg(setactivationskip_ARG, 'k', "setactivationskip", yes_no_arg, 0, 0) | ||||
| arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", NULL, 0, 0) | ||||
| arg(maps_ARG, 'm', "maps", NULL, 0, 0) | ||||
| arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0, 0) | ||||
| arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0, 0) | ||||
| arg(name_ARG, 'n', "name", string_arg, 0, 0) | ||||
| arg(nofsck_ARG, 'n', "nofsck", NULL, 0, 0) | ||||
| arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0, 0) | ||||
| arg(oldpath_ARG, 'n', "oldpath", NULL, 0, 0) | ||||
| arg(options_ARG, 'o', "options", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(sort_ARG, 'O', "sort", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0, 0) | ||||
| arg(permission_ARG, 'p', "permission", permission_arg, 0, 0) | ||||
| arg(partial_ARG, 'P', "partial", NULL, 0, 0) | ||||
| arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0, 0) | ||||
| arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE, 0) | ||||
| arg(readahead_ARG, 'r', "readahead", readahead_arg, 0, 0) | ||||
| arg(resizefs_ARG, 'r', "resizefs", NULL, 0, 0) | ||||
| arg(reset_ARG, 'R', "reset", NULL, 0, 0) | ||||
| arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0, 0) | ||||
| arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0, 0) | ||||
| arg(snapshot_ARG, 's', "snapshot", NULL, 0, 0) | ||||
| arg(short_ARG, 's', "short", NULL, 0, 0) | ||||
| arg(stdin_ARG, 's', "stdin", NULL, 0, 0) | ||||
| arg(select_ARG, 'S', "select", string_arg, ARG_GROUPABLE, 0) | ||||
| arg(test_ARG, 't', "test", NULL, 0, 0) | ||||
| arg(thin_ARG, 'T', "thin", NULL, 0, 0) | ||||
| arg(uuid_ARG, 'u', "uuid", NULL, 0, 0) | ||||
| arg(uuidstr_ARG, 'u', "uuid", string_arg, 0, 0) | ||||
| arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0, 0) | ||||
| arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE, 0) | ||||
| arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0, 0) | ||||
| arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0, 0) | ||||
| arg(wipesignatures_ARG, 'W', "wipesignatures", yes_no_arg, 0, 0) | ||||
| arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0, 0) | ||||
| arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0, 0) | ||||
| arg(yes_ARG, 'y', "yes", NULL, 0, 0) | ||||
| arg(zero_ARG, 'Z', "zero", yes_no_arg, 0, 0) | ||||
| arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0) | ||||
| arg(all_ARG, 'a', "all", 0, 0, 0) | ||||
| arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0) | ||||
| arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0) | ||||
| arg(background_ARG, 'b', "background", 0, 0, 0) | ||||
| arg(backgroundfork_ARG, 'b', "background", 0, 0, 0) | ||||
| arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0) | ||||
| arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0) | ||||
| arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0) | ||||
| arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0) | ||||
| arg(colon_ARG, 'c', "colon", 0, 0, 0) | ||||
| arg(columns_ARG, 'C', "columns", 0, 0, 0) | ||||
| arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0) | ||||
| arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0) | ||||
| arg(exported_ARG, 'e', "exported", 0, 0, 0) | ||||
| arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0) | ||||
| arg(file_ARG, 'f', "file", string_VAL, 0, 0) | ||||
| arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0) | ||||
| arg(full_ARG, 'f', "full", 0, 0, 0) | ||||
| arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0) | ||||
| arg(cache_ARG, 'H', "cache", 0, 0, 0) | ||||
| arg(history_ARG, 'H', "history", 0, 0, 0) | ||||
| arg(help2_ARG, '?', "", 0, 0, 0) | ||||
| arg(import_ARG, 'i', "import", 0, 0, 0) | ||||
| arg(interval_ARG, 'i', "interval", number_VAL, 0, 0) | ||||
| arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0) | ||||
| arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0) | ||||
| arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0) | ||||
| arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0) | ||||
| arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0) | ||||
| arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0) | ||||
| arg(list_ARG, 'l', "list", 0, 0, 0) | ||||
| arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0) | ||||
| arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0) | ||||
| arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0) | ||||
| arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0) | ||||
| arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0) | ||||
| arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0) | ||||
| arg(maps_ARG, 'm', "maps", 0, 0, 0) | ||||
| arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0) | ||||
| arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0) | ||||
| arg(name_ARG, 'n', "name", string_VAL, 0, 0) | ||||
| arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0) | ||||
| arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0) | ||||
| arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0) | ||||
| arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0) | ||||
| arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0) | ||||
| arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0) | ||||
| arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0) | ||||
| arg(partial_ARG, 'P', "partial", 0, 0, 0) | ||||
| arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0) | ||||
| arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0) | ||||
| arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0) | ||||
| arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0) | ||||
| arg(reset_ARG, 'R', "reset", 0, 0, 0) | ||||
| arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0) | ||||
| arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0) | ||||
| arg(snapshot_ARG, 's', "snapshot", 0, 0, 0) | ||||
| arg(short_ARG, 's', "short", 0, 0, 0) | ||||
| arg(stdin_ARG, 's', "stdin", 0, 0, 0) | ||||
| arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0) | ||||
| arg(test_ARG, 't', "test", 0, 0, 0) | ||||
| arg(thin_ARG, 'T', "thin", 0, 0, 0) | ||||
| arg(uuid_ARG, 'u', "uuid", 0, 0, 0) | ||||
| arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0) | ||||
| arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0) | ||||
| arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0) | ||||
| arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0) | ||||
| arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0) | ||||
| arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0) | ||||
| arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0) | ||||
| arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0) | ||||
| arg(yes_ARG, 'y', "yes", 0, 0, 0) | ||||
| arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0) | ||||
|  | ||||
| /* this should always be last */ | ||||
| arg(ARG_COUNT, '-', "", NULL, 0, 0) | ||||
| arg(ARG_COUNT, '-', "", 0, 0, 0) | ||||
| /* *INDENT-ON* */ | ||||
|   | ||||
							
								
								
									
										1622
									
								
								tools/command-lines.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1622
									
								
								tools/command-lines.in
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										201
									
								
								tools/command.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								tools/command.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| /* | ||||
|  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   | ||||
|  * Copyright (C) 2004-2015 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef _LVM_COMMAND_H | ||||
| #define _LVM_COMMAND_H | ||||
|  | ||||
| struct cmd_context; | ||||
|  | ||||
| /* old per-command-name function */ | ||||
| typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| /* new per-command-line-id functions */ | ||||
| typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| struct command_function { | ||||
| 	int command_line_enum; | ||||
| 	command_line_fn fn; | ||||
| }; | ||||
|  | ||||
| struct command_name { | ||||
| 	const char *name; | ||||
| 	const char *desc; /* general command description from commands.h */ | ||||
| 	unsigned int flags; | ||||
|  | ||||
| 	/* union of {required,optional}_opt_args for all commands with this name */ | ||||
| 	int valid_args[ARG_COUNT]; | ||||
| 	int num_args; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Command defintion | ||||
|  * | ||||
|  * A command is defined in terms of a command name, | ||||
|  * required options (+args), optional options (+args), | ||||
|  * required positional args, optional positional args. | ||||
|  * | ||||
|  * A positional arg always has non-zero pos_arg.def.types. | ||||
|  * The first positional arg has pos_arg.pos of 1. | ||||
|  */ | ||||
|  | ||||
| /* arg_def flags */ | ||||
| #define ARG_DEF_FLAG_NEW                1 << 0 | ||||
| #define ARG_DEF_FLAG_MAY_REPEAT         1 << 1 | ||||
|  | ||||
| static inline int val_bit_is_set(uint64_t val_bits, int val_enum) | ||||
| { | ||||
| 	return (val_bits & (1 << val_enum)) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| static inline uint64_t val_enum_to_bit(int val_enum) | ||||
| { | ||||
| 	return (1ULL << val_enum); | ||||
| } | ||||
|  | ||||
| static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum) | ||||
| { | ||||
| 	return (lvp_bits & (1 << lvp_enum)) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| static inline uint64_t lvp_enum_to_bit(int lvp_enum) | ||||
| { | ||||
| 	return (1ULL << lvp_enum); | ||||
| } | ||||
|  | ||||
| static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum) | ||||
| { | ||||
| 	return (lvt_bits & (1 << lvt_enum)) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| static inline uint64_t lvt_enum_to_bit(int lvt_enum) | ||||
| { | ||||
| 	return (1ULL << lvt_enum); | ||||
| } | ||||
|  | ||||
| /* Description a value that follows an option or exists in a position. */ | ||||
|  | ||||
| struct arg_def { | ||||
| 	uint64_t val_bits;   /* bits of x_VAL, can be multiple for pos_arg */ | ||||
| 	uint64_t lvt_bits;   /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */ | ||||
| 	uint64_t num;        /* a literal number for conststr_VAL */ | ||||
| 	const char *str;     /* a literal string for constnum_VAL */ | ||||
| 	uint32_t flags;      /* ARG_DEF_FLAG_ */ | ||||
| }; | ||||
|  | ||||
| /* Description of an option and the value that follows it. */ | ||||
|  | ||||
| struct opt_arg { | ||||
| 	int opt;             /* option, e.g. foo_ARG */ | ||||
| 	struct arg_def def;  /* defines accepted values */ | ||||
| }; | ||||
|  | ||||
| /* Description of a position and the value that exists there. */ | ||||
|  | ||||
| struct pos_arg { | ||||
| 	int pos;             /* position, e.g. first is 1 */ | ||||
| 	struct arg_def def;  /* defines accepted values */ | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Commands using a given command definition must follow a set | ||||
|  * of rules.  If a given command+LV matches the conditions in | ||||
|  * opts/lvt_bits/lvp_bits, then the checks are applied. | ||||
|  * If one condition is not met, the checks are not applied. | ||||
|  * If no conditions are set, the checks are always applied. | ||||
|  */ | ||||
|  | ||||
| #define RULE_INVALID 1 | ||||
| #define RULE_REQUIRE 2 | ||||
|  | ||||
| struct cmd_rule { | ||||
| 	int *opts;			/* if any option in this list is set, the check may apply */ | ||||
| 	uint64_t lvt_bits;		/* if LV has one of these types (lvt_enum_to_bit), the check may apply */ | ||||
| 	uint64_t lvp_bits;		/* if LV has all of these properties (lvp_enum_to_bit), the check may apply */ | ||||
|  | ||||
| 	int *check_opts;		/* used options must [not] be in this list */ | ||||
| 	uint64_t check_lvt_bits;	/* LV must [not] have one of these type */ | ||||
| 	uint64_t check_lvp_bits;	/* LV must [not] have all of these properties */ | ||||
|  | ||||
| 	uint32_t rule;			/* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */ | ||||
| 	int opts_count;			/* entries in opts[] */ | ||||
| 	int check_opts_count;		/* entries in check_opts[] */ | ||||
|  | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * CMD_RO_ARGS needs to accomodate a list of options, | ||||
|  * of which one is required after which the rest are | ||||
|  * optional. | ||||
|  */ | ||||
| #define CMD_RO_ARGS 64          /* required opt args */ | ||||
| #define CMD_OO_ARGS 150         /* optional opt args */ | ||||
| #define CMD_RP_ARGS 8           /* required positional args */ | ||||
| #define CMD_OP_ARGS 8           /* optional positional args */ | ||||
| #define CMD_MAX_RULES 32        /* max number of rules per command def */ | ||||
|  | ||||
| /* | ||||
|  * one or more from required_opt_args is required, | ||||
|  * then the rest are optional. | ||||
|  */ | ||||
| #define CMD_FLAG_ONE_REQUIRED_OPT   1 | ||||
| #define CMD_FLAG_SECONDARY_SYNTAX   2 | ||||
|  | ||||
| /* a register of the lvm commands */ | ||||
| struct command { | ||||
| 	const char *name; | ||||
| 	const char *desc; /* specific command description from command-lines.h */ | ||||
| 	const char *usage; /* excludes common options like --help, --debug */ | ||||
| 	const char *usage_common; /* includes commmon options like --help, --debug */ | ||||
| 	const char *command_line_id; | ||||
| 	int command_line_enum; /* <command_line_id>_CMD */ | ||||
|  | ||||
| 	struct command_name *cname; | ||||
|  | ||||
| 	command_fn fn;                      /* old style */ | ||||
| 	struct command_function *functions; /* new style */ | ||||
|  | ||||
| 	unsigned int flags; /* copied from command_name.flags from commands.h */ | ||||
|  | ||||
| 	unsigned int cmd_flags; /* CMD_FLAG_ */ | ||||
|  | ||||
| 	/* definitions of opt/pos args */ | ||||
|  | ||||
| 	/* required args following an --opt */ | ||||
| 	struct opt_arg required_opt_args[CMD_RO_ARGS]; | ||||
|  | ||||
| 	/* optional args following an --opt */ | ||||
| 	struct opt_arg optional_opt_args[CMD_OO_ARGS]; | ||||
|  | ||||
| 	/* required positional args */ | ||||
| 	struct pos_arg required_pos_args[CMD_RP_ARGS]; | ||||
|  | ||||
| 	/* optional positional args */ | ||||
| 	struct pos_arg optional_pos_args[CMD_OP_ARGS]; | ||||
|  | ||||
| 	struct cmd_rule rules[CMD_MAX_RULES]; | ||||
|  | ||||
| 	int ro_count; | ||||
| 	int oo_count; | ||||
| 	int rp_count; | ||||
| 	int op_count; | ||||
|  | ||||
| 	/* used for processing current position */ | ||||
| 	int pos_count; | ||||
|  | ||||
| 	int rule_count; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										1428
									
								
								tools/commands.h
									
									
									
									
									
								
							
							
						
						
									
										1428
									
								
								tools/commands.h
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2898
									
								
								tools/create-commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2898
									
								
								tools/create-commands.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										56
									
								
								tools/lv_props.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tools/lv_props.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
|  | ||||
| /* | ||||
|  * NULL in the last arg can be replaced with actual | ||||
|  * calls to the lv_is_prop() function when those | ||||
|  * become functions (are #define now), take uniform | ||||
|  * args (e.g. some take cmd others don't), and are | ||||
|  * exposed in tools.h | ||||
|  * | ||||
|  * Until then, the lv_is_prop() functions are | ||||
|  * called indirectly through _lv_is_prop(). | ||||
|  */ | ||||
|  | ||||
| lvp(LVP_NONE, "", NULL) /* enum value 0 means none */ | ||||
| lvp(is_locked_LVP, "lv_is_locked", NULL) | ||||
| lvp(is_partial_LVP, "lv_is_partial", NULL) | ||||
| lvp(is_virtual_LVP, "lv_is_virtual", NULL) | ||||
| lvp(is_merging_LVP, "lv_is_merging", NULL) | ||||
| lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL) | ||||
| lvp(is_converting_LVP, "lv_is_converting", NULL) | ||||
| lvp(is_external_origin_LVP, "lv_is_external_origin", NULL) | ||||
| lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL) | ||||
| lvp(is_not_synced_LVP, "lv_is_not_synced", NULL) | ||||
| lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL) | ||||
| lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL) | ||||
| lvp(is_pvmove_LVP, "lv_is_pvmove", NULL) | ||||
| lvp(is_removed_LVP, "lv_is_removed", NULL) | ||||
| lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL) | ||||
|  | ||||
| /* kinds of sub LV */ | ||||
| lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL) | ||||
| lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL) | ||||
| lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL) | ||||
| lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL) | ||||
| lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL) | ||||
| lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL) | ||||
| lvp(is_raid_image_LVP, "lv_is_raid_image", NULL) | ||||
| lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL) | ||||
|  | ||||
| /* | ||||
|  * is_thick_origin should be used instead of is_origin | ||||
|  * is_thick_snapshot is generally used as LV_snapshot from lv_types.h | ||||
|  */ | ||||
| lvp(is_origin_LVP, "lv_is_origin", NULL) | ||||
| lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL) | ||||
| lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL) | ||||
| lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL) | ||||
| lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL) | ||||
|  | ||||
| lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL) | ||||
| lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL) | ||||
| lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL) | ||||
| lvp(is_visible_LVP, "lv_is_visible", NULL) | ||||
| lvp(is_historical_LVP, "lv_is_historical", NULL) | ||||
| lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL) | ||||
| lvp(LVP_COUNT, "", NULL) | ||||
|  | ||||
							
								
								
									
										34
									
								
								tools/lv_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tools/lv_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * LV types used in command definitions.  The type strings are used | ||||
|  * as LV suffixes, e.g. LV_type or LV_type1_type2. | ||||
|  * | ||||
|  * The final NULL arg can be replaced with lv_is_type() functions | ||||
|  * if the current lv_is_type #defines become functions and are | ||||
|  * moved to tools.h | ||||
|  * | ||||
|  * Until then, the lv_is_type() functions are called indirectly | ||||
|  * through _lv_is_type(). | ||||
|  */ | ||||
|  | ||||
| lvt(LVT_NONE, "", NULL) | ||||
| lvt(linear_LVT, "linear", NULL) | ||||
| lvt(striped_LVT, "striped", NULL) | ||||
| lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */ | ||||
| lvt(thin_LVT, "thin", NULL) | ||||
| lvt(thinpool_LVT, "thinpool", NULL) | ||||
| lvt(cache_LVT, "cache", NULL) | ||||
| lvt(cachepool_LVT, "cachepool", NULL) | ||||
| lvt(mirror_LVT, "mirror", NULL) | ||||
| lvt(raid_LVT, "raid", NULL) | ||||
| lvt(raid0_LVT, "raid0", NULL) | ||||
| lvt(raid1_LVT, "raid1", NULL) | ||||
| lvt(raid4_LVT, "raid4", NULL) | ||||
| lvt(raid5_LVT, "raid5", NULL) | ||||
| lvt(raid6_LVT, "raid6", NULL) | ||||
| lvt(raid10_LVT, "raid10", NULL) | ||||
| lvt(error_LVT, "error", NULL) | ||||
| lvt(zero_LVT, "zero", NULL) | ||||
| lvt(LVT_COUNT, "", NULL) | ||||
|  | ||||
							
								
								
									
										922
									
								
								tools/lvchange.c
									
									
									
									
									
								
							
							
						
						
									
										922
									
								
								tools/lvchange.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3410
									
								
								tools/lvconvert.c
									
									
									
									
									
								
							
							
						
						
									
										3410
									
								
								tools/lvconvert.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -58,5 +58,5 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv) | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &_lvdisplay_single); | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &_lvdisplay_single); | ||||
| } | ||||
|   | ||||
							
								
								
									
										32
									
								
								tools/lvm.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								tools/lvm.c
									
									
									
									
									
								
							| @@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state) | ||||
| 		len = strlen(text); | ||||
| 	} | ||||
|  | ||||
| 	while (i < _cmdline->num_commands) | ||||
| 		if (!strncmp(text, _cmdline->commands[i++].name, len)) | ||||
| 			return strdup(_cmdline->commands[i - 1].name); | ||||
| 	while (i < _cmdline->num_command_names) | ||||
| 		if (!strncmp(text, _cmdline->command_names[i++].name, len)) | ||||
| 			return strdup(_cmdline->command_names[i - 1].name); | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
| @@ -57,7 +57,7 @@ static char *_list_args(const char *text, int state) | ||||
| { | ||||
| 	static int match_no = 0; | ||||
| 	static size_t len = 0; | ||||
| 	static struct command *com; | ||||
| 	static struct command_name *cname; | ||||
|  | ||||
| 	/* Initialise if this is a new completion attempt */ | ||||
| 	if (!state) { | ||||
| @@ -65,40 +65,40 @@ static char *_list_args(const char *text, int state) | ||||
| 		int j; | ||||
|  | ||||
| 		match_no = 0; | ||||
| 		com = NULL; | ||||
| 		cname = NULL; | ||||
| 		len = strlen(text); | ||||
|  | ||||
| 		/* Find start of first word in line buffer */ | ||||
| 		while (isspace(*s)) | ||||
| 			s++; | ||||
|  | ||||
| 		/* Look for word in list of commands */ | ||||
| 		for (j = 0; j < _cmdline->num_commands; j++) { | ||||
| 		/* Look for word in list of command names */ | ||||
| 		for (j = 0; j < _cmdline->num_command_names; j++) { | ||||
| 			const char *p; | ||||
| 			char *q = s; | ||||
|  | ||||
| 			p = _cmdline->commands[j].name; | ||||
| 			p = _cmdline->command_names[j].name; | ||||
| 			while (*p == *q) { | ||||
| 				p++; | ||||
| 				q++; | ||||
| 			} | ||||
| 			if ((!*p) && *q == ' ') { | ||||
| 				com = _cmdline->commands + j; | ||||
| 				cname = _cmdline->command_names + j; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!com) | ||||
| 	if (!cname) | ||||
| 		return NULL; | ||||
|  | ||||
| 	/* Short form arguments */ | ||||
| 	if (len < 3) { | ||||
| 		while (match_no < com->num_args) { | ||||
| 		while (match_no < cname->num_args) { | ||||
| 			char s[3]; | ||||
| 			char c; | ||||
| 			if (!(c = (_cmdline->arg_props + | ||||
| 				   com->valid_args[match_no++])->short_arg)) | ||||
| 				   cname->valid_args[match_no++])->short_arg)) | ||||
| 				continue; | ||||
|  | ||||
| 			sprintf(s, "-%c", c); | ||||
| @@ -108,13 +108,13 @@ static char *_list_args(const char *text, int state) | ||||
| 	} | ||||
|  | ||||
| 	/* Long form arguments */ | ||||
| 	if (match_no < com->num_args) | ||||
| 		match_no = com->num_args; | ||||
| 	if (match_no < cname->num_args) | ||||
| 		match_no = cname->num_args; | ||||
|  | ||||
| 	while (match_no - com->num_args < com->num_args) { | ||||
| 	while (match_no - cname->num_args < cname->num_args) { | ||||
| 		const char *l; | ||||
| 		l = (_cmdline->arg_props + | ||||
| 		     com->valid_args[match_no++ - com->num_args])->long_arg; | ||||
| 		     cname->valid_args[match_no++ - cname->num_args])->long_arg; | ||||
| 		if (*(l + 2) && !strncmp(text, l, len)) | ||||
| 			return strdup(l); | ||||
| 	} | ||||
|   | ||||
| @@ -19,10 +19,11 @@ | ||||
| struct cmd_context; | ||||
|  | ||||
| struct cmdline_context { | ||||
|         struct arg_props *arg_props; | ||||
|         struct command *commands; | ||||
|         int num_commands; | ||||
|         int commands_size; | ||||
| 	struct arg_props *arg_props; | ||||
| 	struct command *commands; | ||||
| 	int num_commands; | ||||
| 	struct command_name *command_names; | ||||
| 	int num_command_names; | ||||
| }; | ||||
|  | ||||
| int lvm2_main(int argc, char **argv); | ||||
|   | ||||
| @@ -30,12 +30,12 @@ void *cmdlib_lvm2_init(unsigned static_compile) | ||||
| { | ||||
| 	struct cmd_context *cmd; | ||||
|  | ||||
| 	lvm_register_commands(); | ||||
|  | ||||
| 	init_is_static(static_compile); | ||||
| 	if (!(cmd = init_lvm(1, 1))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	lvm_register_commands(); | ||||
|  | ||||
| 	return (void *) cmd; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										1470
									
								
								tools/lvmcmdline.c
									
									
									
									
									
								
							
							
						
						
									
										1470
									
								
								tools/lvmcmdline.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -27,5 +27,5 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv) | ||||
| 	cmd->include_historical_lvs = 1; | ||||
|  | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL, | ||||
| 			       &lvremove_single); | ||||
| 			       NULL, &lvremove_single); | ||||
| } | ||||
|   | ||||
| @@ -119,5 +119,5 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv) | ||||
| 		 */ | ||||
| 	} | ||||
|  | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &lvscan_single); | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &lvscan_single); | ||||
| } | ||||
|   | ||||
| @@ -517,14 +517,14 @@ static int _report_all_in_vg(struct cmd_context *cmd, struct processing_handle * | ||||
| 			r = _vgs_single(cmd, vg->name, vg, handle); | ||||
| 			break; | ||||
| 		case LVS: | ||||
| 			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, | ||||
| 			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL, | ||||
| 						  do_lv_info && !do_lv_seg_status ? &_lvs_with_info_single : | ||||
| 						  !do_lv_info && do_lv_seg_status ? &_lvs_with_status_single : | ||||
| 						  do_lv_info && do_lv_seg_status ? &_lvs_with_info_and_status_single : | ||||
| 										   &_lvs_single); | ||||
| 			break; | ||||
| 		case SEGS: | ||||
| 			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, | ||||
| 			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL, | ||||
| 						  do_lv_info && !do_lv_seg_status ? &_lvsegs_with_info_single : | ||||
| 						  !do_lv_info && do_lv_seg_status ? &_lvsegs_with_status_single : | ||||
| 						  do_lv_info && do_lv_seg_status ? &_lvsegs_with_info_and_status_single : | ||||
| @@ -1099,7 +1099,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle, | ||||
| 			if (args->full_report_vg) | ||||
| 				r = _report_all_in_vg(cmd, handle, args->full_report_vg, LVS, lv_info_needed, lv_segment_status_needed); | ||||
| 			else | ||||
| 				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, | ||||
| 				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL, | ||||
| 						    lv_info_needed && !lv_segment_status_needed ? &_lvs_with_info_single : | ||||
| 						    !lv_info_needed && lv_segment_status_needed ? &_lvs_with_status_single : | ||||
| 						    lv_info_needed && lv_segment_status_needed ? &_lvs_with_info_and_status_single : | ||||
| @@ -1133,7 +1133,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle, | ||||
| 			if (args->full_report_vg) | ||||
| 				r = _report_all_in_vg(cmd, handle, args->full_report_vg, SEGS, lv_info_needed, lv_segment_status_needed); | ||||
| 			else | ||||
| 				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, | ||||
| 				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL, | ||||
| 						    lv_info_needed && !lv_segment_status_needed ? &_lvsegs_with_info_single : | ||||
| 						    !lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_status_single : | ||||
| 						    lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_info_and_status_single : | ||||
|   | ||||
							
								
								
									
										798
									
								
								tools/toollib.c
									
									
									
									
									
								
							
							
						
						
									
										798
									
								
								tools/toollib.c
									
									
									
									
									
								
							| @@ -801,10 +801,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd, | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, metadatacopies_ARG)) | ||||
| 		vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, | ||||
| 							DEFAULT_VGMETADATACOPIES); | ||||
| 	else if (arg_is_set(cmd, vgmetadatacopies_ARG)) | ||||
| 	if (arg_is_set(cmd, vgmetadatacopies_ARG)) | ||||
| 		vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG, | ||||
| 							DEFAULT_VGMETADATACOPIES); | ||||
| 	else | ||||
| @@ -2329,10 +2326,606 @@ static struct lv_segment _historical_lv_segment = { | ||||
| 	.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list), | ||||
| }; | ||||
|  | ||||
| int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count, | ||||
| 		       int *match_count, int *unmatch_count) | ||||
| { | ||||
| 	int match = 0; | ||||
| 	int unmatch = 0; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		if (arg_is_set(cmd, opts[i])) | ||||
| 			match++; | ||||
| 		else | ||||
| 			unmatch++; | ||||
| 	} | ||||
|  | ||||
| 	if (match_count) | ||||
| 		*match_count = match; | ||||
| 	if (unmatch_count) | ||||
| 		*unmatch_count = unmatch; | ||||
|  | ||||
| 	return match ? 1 : 0; | ||||
| } | ||||
|        | ||||
| void opt_array_to_str(struct cmd_context *cmd, int *opts, int count, | ||||
| 		      char *buf, int len) | ||||
| { | ||||
| 	int pos = 0; | ||||
| 	int ret; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		ret = snprintf(buf + pos, len - pos, "%s ", arg_long_option_name(opts[i])); | ||||
| 		if (ret >= len - pos) | ||||
| 			break; | ||||
| 		pos += ret; | ||||
| 	} | ||||
|  | ||||
| 	buf[len - 1] = '\0'; | ||||
| } | ||||
|  | ||||
| static void lvp_bits_to_str(uint64_t bits, char *buf, int len) | ||||
| { | ||||
| 	struct lv_props *prop; | ||||
| 	int lvp_enum; | ||||
| 	int pos = 0; | ||||
| 	int ret; | ||||
|  | ||||
| 	for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) { | ||||
| 		if (!(prop = get_lv_prop(lvp_enum))) | ||||
| 			continue; | ||||
|  | ||||
| 		if (lvp_bit_is_set(bits, lvp_enum)) { | ||||
| 			ret = snprintf(buf + pos, len - pos, "%s ", prop->name); | ||||
| 			if (ret >= len - pos) | ||||
| 				break; | ||||
| 			pos += ret; | ||||
| 		} | ||||
| 	} | ||||
| 	buf[len - 1] = '\0'; | ||||
| } | ||||
|  | ||||
| static void lvt_bits_to_str(uint64_t bits, char *buf, int len) | ||||
| { | ||||
| 	struct lv_types *type; | ||||
| 	int lvt_enum; | ||||
| 	int pos = 0; | ||||
| 	int ret; | ||||
|  | ||||
| 	for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) { | ||||
| 		if (!(type = get_lv_type(lvt_enum))) | ||||
| 			continue; | ||||
|  | ||||
| 		if (lvt_bit_is_set(bits, lvt_enum)) { | ||||
| 			ret = snprintf(buf + pos, len - pos, "%s ", type->name); | ||||
| 			if (ret >= len - pos) | ||||
| 				break; | ||||
| 			pos += ret; | ||||
| 		} | ||||
| 	} | ||||
| 	buf[len - 1] = '\0'; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This is the lv_prop function pointer used for lv_is_foo() #defines. | ||||
|  * Alternatively, lv_is_foo() could all be turned into functions. | ||||
|  */ | ||||
|  | ||||
| static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum) | ||||
| { | ||||
| 	switch (lvp_enum) { | ||||
| 	case is_locked_LVP: | ||||
| 		return lv_is_locked(lv); | ||||
| 	case is_partial_LVP: | ||||
| 		return lv_is_partial(lv); | ||||
| 	case is_virtual_LVP: | ||||
| 		return lv_is_virtual(lv); | ||||
| 	case is_merging_LVP: | ||||
| 		return lv_is_merging(lv); | ||||
| 	case is_merging_origin_LVP: | ||||
| 		return lv_is_merging_origin(lv); | ||||
| 	case is_converting_LVP: | ||||
| 		return lv_is_converting(lv); | ||||
| 	case is_external_origin_LVP: | ||||
| 		return lv_is_external_origin(lv); | ||||
| 	case is_virtual_origin_LVP: | ||||
| 		return lv_is_virtual_origin(lv); | ||||
| 	case is_not_synced_LVP: | ||||
| 		return lv_is_not_synced(lv); | ||||
| 	case is_pending_delete_LVP: | ||||
| 		return lv_is_pending_delete(lv); | ||||
| 	case is_error_when_full_LVP: | ||||
| 		return lv_is_error_when_full(lv); | ||||
| 	case is_pvmove_LVP: | ||||
| 		return lv_is_pvmove(lv); | ||||
| 	case is_removed_LVP: | ||||
| 		return lv_is_removed(lv); | ||||
| 	case is_vg_writable_LVP: | ||||
| 		return (lv->vg->status & LVM_WRITE) ? 1 : 0; | ||||
| 	case is_thinpool_data_LVP: | ||||
| 		return lv_is_thin_pool_data(lv); | ||||
| 	case is_thinpool_metadata_LVP: | ||||
| 		return lv_is_thin_pool_metadata(lv); | ||||
| 	case is_cachepool_data_LVP: | ||||
| 		return lv_is_cache_pool_data(lv); | ||||
| 	case is_cachepool_metadata_LVP: | ||||
| 		return lv_is_cache_pool_metadata(lv); | ||||
| 	case is_mirror_image_LVP: | ||||
| 		return lv_is_mirror_image(lv); | ||||
| 	case is_mirror_log_LVP: | ||||
| 		return lv_is_mirror_log(lv); | ||||
| 	case is_raid_image_LVP: | ||||
| 		return lv_is_raid_image(lv); | ||||
| 	case is_raid_metadata_LVP: | ||||
| 		return lv_is_raid_metadata(lv); | ||||
| 	case is_origin_LVP: /* use lv_is_thick_origin */ | ||||
| 		return lv_is_origin(lv); | ||||
| 	case is_thick_origin_LVP: | ||||
| 		return lv_is_thick_origin(lv); | ||||
| 	case is_thick_snapshot_LVP: | ||||
| 		return lv_is_thick_snapshot(lv); | ||||
| 	case is_thin_origin_LVP: | ||||
| 		return lv_is_thin_origin(lv, NULL); | ||||
| 	case is_thin_snapshot_LVP: | ||||
| 		return lv_is_thin_snapshot(lv); | ||||
| 	case is_cache_origin_LVP: | ||||
| 		return lv_is_cache_origin(lv); | ||||
| 	case is_merging_cow_LVP: | ||||
| 		return lv_is_merging_cow(lv); | ||||
| 	case is_cow_covering_origin_LVP: | ||||
| 		return lv_is_cow_covering_origin(lv); | ||||
| 	case is_visible_LVP: | ||||
| 		return lv_is_visible(lv); | ||||
| 	case is_historical_LVP: | ||||
| 		return lv_is_historical(lv); | ||||
| 	case is_raid_with_tracking_LVP: | ||||
| 		return lv_is_raid_with_tracking(lv); | ||||
| 	default: | ||||
| 		log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Check if an LV matches a given LV type enum. | ||||
|  */ | ||||
|  | ||||
| static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum) | ||||
| { | ||||
| 	struct lv_segment *seg = first_seg(lv); | ||||
|  | ||||
| 	switch (lvt_enum) { | ||||
| 	case striped_LVT: | ||||
| 		return seg_is_striped(seg) && !lv_is_cow(lv); | ||||
| 	case linear_LVT: | ||||
| 		return seg_is_linear(seg) && !lv_is_cow(lv); | ||||
| 	case snapshot_LVT: | ||||
| 		return lv_is_cow(lv); | ||||
| 	case thin_LVT: | ||||
| 		return lv_is_thin_volume(lv); | ||||
| 	case thinpool_LVT: | ||||
| 		return lv_is_thin_pool(lv); | ||||
| 	case cache_LVT: | ||||
| 		return lv_is_cache(lv); | ||||
| 	case cachepool_LVT: | ||||
| 		return lv_is_cache_pool(lv); | ||||
| 	case mirror_LVT: | ||||
| 		return lv_is_mirror(lv); | ||||
| 	case raid_LVT: | ||||
| 		return lv_is_raid(lv); | ||||
| 	case raid0_LVT: | ||||
| 		return seg_is_raid0(seg); | ||||
| 	case raid1_LVT: | ||||
| 		return seg_is_raid1(seg); | ||||
| 	case raid4_LVT: | ||||
| 		return seg_is_raid4(seg); | ||||
| #if 0 | ||||
| 	case raid5_LVT: | ||||
| 		return seg_is_raid5(seg); | ||||
| 	case raid6_LVT: | ||||
| 		return seg_is_raid6(seg); | ||||
| #endif | ||||
| 	case raid10_LVT: | ||||
| 		return seg_is_raid10(seg); | ||||
| 	case error_LVT: | ||||
| 		return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR); | ||||
| 	case zero_LVT: | ||||
| 		return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO); | ||||
| 	default: | ||||
| 		log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int get_lvt_enum(struct logical_volume *lv) | ||||
| { | ||||
| 	struct lv_segment *seg = first_seg(lv); | ||||
|  | ||||
| 	/* | ||||
| 	 * The order these are checked is important, because a snapshot LV has | ||||
| 	 * a linear seg type. | ||||
| 	 */ | ||||
|  | ||||
| 	if (lv_is_cow(lv)) | ||||
| 		return snapshot_LVT; | ||||
| 	if (seg_is_linear(seg)) | ||||
| 		return linear_LVT; | ||||
| 	if (seg_is_striped(seg)) | ||||
| 		return striped_LVT; | ||||
| 	if (lv_is_thin_volume(lv)) | ||||
| 		return thin_LVT; | ||||
| 	if (lv_is_thin_pool(lv)) | ||||
| 		return thinpool_LVT; | ||||
| 	if (lv_is_cache(lv)) | ||||
| 		return cache_LVT; | ||||
| 	if (lv_is_cache_pool(lv)) | ||||
| 		return cachepool_LVT; | ||||
| 	if (lv_is_mirror(lv)) | ||||
| 		return mirror_LVT; | ||||
| 	if (lv_is_raid(lv)) | ||||
| 		return raid_LVT; | ||||
| 	if (seg_is_raid0(seg)) | ||||
| 		return raid0_LVT; | ||||
| 	if (seg_is_raid1(seg)) | ||||
| 		return raid1_LVT; | ||||
| 	if (seg_is_raid4(seg)) | ||||
| 		return raid4_LVT; | ||||
| #if 0 | ||||
| 	if (seg_is_raid5(seg)) | ||||
| 		return raid5_LVT; | ||||
| 	if (seg_is_raid6(seg)) | ||||
| 		return raid6_LVT; | ||||
| #endif | ||||
| 	if (seg_is_raid10(seg)) | ||||
| 		return raid10_LVT; | ||||
|  | ||||
| 	if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR)) | ||||
| 		return error_LVT; | ||||
| 	if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO)) | ||||
| 		return zero_LVT; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Call lv_is_<type> for each <type>_LVT bit set in lvt_bits. | ||||
|  * If lv matches one of the specified lv types, then return 1. | ||||
|  */ | ||||
|  | ||||
| static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits, | ||||
| 			   uint64_t *match_bits, uint64_t *unmatch_bits) | ||||
| { | ||||
| 	struct lv_types *type; | ||||
| 	int lvt_enum; | ||||
| 	int found_a_match = 0; | ||||
| 	int match; | ||||
|  | ||||
| 	if (match_bits) | ||||
| 		*match_bits = 0; | ||||
| 	if (unmatch_bits) | ||||
| 		*unmatch_bits = 0; | ||||
|  | ||||
| 	for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) { | ||||
| 		if (!lvt_bit_is_set(lvt_bits, lvt_enum)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!(type = get_lv_type(lvt_enum))) | ||||
| 			continue; | ||||
|  | ||||
| 		/* | ||||
| 		 * All types are currently handled by _lv_is_type() | ||||
| 		 * because lv_is_type() are #defines and not exposed | ||||
| 		 * in tools.h | ||||
| 		 */ | ||||
|  | ||||
| 		if (!type->fn) | ||||
| 			match = _lv_is_type(cmd, lv, lvt_enum); | ||||
| 		else | ||||
| 			match = type->fn(cmd, lv); | ||||
|  | ||||
| 		if (match) | ||||
| 			found_a_match = 1; | ||||
|  | ||||
| 		if (match_bits && match) | ||||
| 			*match_bits |= lvt_enum_to_bit(lvt_enum); | ||||
|  | ||||
| 		if (unmatch_bits && !match) | ||||
| 			*unmatch_bits |= lvt_enum_to_bit(lvt_enum); | ||||
| 	} | ||||
|  | ||||
| 	return found_a_match; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits. | ||||
|  * If lv matches all of the specified lv properties, then return 1. | ||||
|  */ | ||||
|  | ||||
| static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits, | ||||
| 			   uint64_t *match_bits, uint64_t *unmatch_bits) | ||||
| { | ||||
| 	struct lv_props *prop; | ||||
| 	int lvp_enum; | ||||
| 	int found_a_mismatch = 0; | ||||
| 	int match; | ||||
|  | ||||
| 	if (match_bits) | ||||
| 		*match_bits = 0; | ||||
| 	if (unmatch_bits) | ||||
| 		*unmatch_bits = 0; | ||||
|  | ||||
| 	for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) { | ||||
| 		if (!lvp_bit_is_set(lvp_bits, lvp_enum)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!(prop = get_lv_prop(lvp_enum))) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!prop->fn) | ||||
| 			match = _lv_is_prop(cmd, lv, lvp_enum); | ||||
| 		else | ||||
| 			match = prop->fn(cmd, lv); | ||||
|  | ||||
| 		if (!match) | ||||
| 			found_a_mismatch = 1; | ||||
|  | ||||
| 		if (match_bits && match) | ||||
| 			*match_bits |= lvp_enum_to_bit(lvp_enum); | ||||
|  | ||||
| 		if (unmatch_bits && !match) | ||||
| 			*unmatch_bits |= lvp_enum_to_bit(lvp_enum); | ||||
| 	} | ||||
|  | ||||
| 	return !found_a_mismatch; | ||||
| } | ||||
|  | ||||
| static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv, int pos) | ||||
| { | ||||
| 	int ret = 1; | ||||
|  | ||||
| 	if (!pos) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!cmd->command->required_pos_args[pos-1].def.lvt_bits) | ||||
| 		return 1; | ||||
|  | ||||
| 	if (!val_bit_is_set(cmd->command->required_pos_args[pos-1].def.val_bits, lv_VAL)) { | ||||
| 		log_error(INTERNAL_ERROR "Command (%s %d) arg position %d does not permit an LV (%llx)", | ||||
| 			  cmd->command->command_line_id, cmd->command->command_line_enum, | ||||
| 			  pos, (unsigned long long)cmd->command->required_pos_args[pos-1].def.val_bits); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[pos-1].def.lvt_bits, NULL, NULL); | ||||
| 	if (!ret) { | ||||
| 		int lvt_enum = get_lvt_enum(lv); | ||||
| 		struct lv_types *type = get_lv_type(lvt_enum); | ||||
| 		log_warn("Operation on LV %s which has invalid type %s.", | ||||
| 			 display_lvname(lv), type ? type->name : "unknown"); | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Check if LV passes each rule specified in command definition. */ | ||||
|  | ||||
| static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv) | ||||
| { | ||||
| 	char buf[64]; | ||||
| 	struct cmd_rule *rule; | ||||
| 	struct lv_types *lvtype = NULL; | ||||
| 	uint64_t lv_props_match_bits, lv_props_unmatch_bits; | ||||
| 	uint64_t lv_types_match_bits, lv_types_unmatch_bits; | ||||
| 	int opts_match_count, opts_unmatch_count; | ||||
| 	int lvt_enum; | ||||
| 	int ret = 1; | ||||
| 	int i; | ||||
|  | ||||
| 	lvt_enum = get_lvt_enum(lv); | ||||
| 	if (lvt_enum) | ||||
| 		lvtype = get_lv_type(lvt_enum); | ||||
|  | ||||
| 	for (i = 0; i < cmd->command->rule_count; i++) { | ||||
| 		rule = &cmd->command->rules[i]; | ||||
|  | ||||
| 		/* | ||||
| 		 * RULE: <conditions> INVALID|REQUIRE <checks> | ||||
| 		 * | ||||
| 		 * If all the conditions apply to the command+LV, then | ||||
| 		 * the checks are performed.  If all conditions are zero | ||||
| 		 * (!opts_count, !lvt_bits, !lvp_bits), then the check | ||||
| 		 * is always performed. | ||||
| 		 * | ||||
| 		 * Conditions: | ||||
| 		 * | ||||
| 		 * 1. options (opts): if any of the specified options are set, | ||||
| 		 *    then the checks may apply. | ||||
| 		 * | ||||
| 		 * 2. LV types (lvt_bits): if any of the specified LV types | ||||
| 		 *    match the LV, then the checks may apply. | ||||
| 		 * | ||||
| 		 * 3. LV properties (lvp_bits): if all of the specified | ||||
| 		 *    LV properties match the LV, then the checks may apply. | ||||
| 		 * | ||||
| 		 * If conditions 1, 2, 3 all pass, then the checks apply. | ||||
| 		 * | ||||
| 		 * Checks: | ||||
| 		 * | ||||
| 		 * 1. options (check_opts): | ||||
| 		 *    INVALID: if any of the specified options are set, | ||||
| 		 *    then the command fails. | ||||
| 		 *    REQUIRE: if any of the specified options are not set, | ||||
| 		 *    then the command fails. | ||||
| 		 * | ||||
| 		 * 2. LV types (check_lvt_bits): | ||||
| 		 *    INVALID: if any of the specified LV types match the LV, | ||||
| 		 *    then the command fails. | ||||
| 		 *    REQUIRE: if none of the specified LV types match the LV, | ||||
| 		 *    then the command fails. | ||||
| 		 * | ||||
| 		 * 3. LV properties (check_lvp_bits): | ||||
| 		 *    INVALID: if any of the specified LV properties match | ||||
| 		 *    the LV, then the command fails. | ||||
| 		 *    REQUIRE: if any of the specified LV properties do not match | ||||
| 		 *    the LV, then the command fails. | ||||
| 		 */ | ||||
|  | ||||
| 		if (rule->opts_count && !opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL)) | ||||
| 			continue; | ||||
|  | ||||
| 		/* If LV matches one type in lvt_bits, this returns 1. */ | ||||
| 		if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL)) | ||||
| 			continue; | ||||
|  | ||||
| 		/* If LV matches all properties in lvp_bits, this returns 1. */ | ||||
| 		if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL)) | ||||
| 			continue; | ||||
|  | ||||
| 		/* | ||||
| 		 * Check the options, LV types, LV properties. | ||||
| 		 */ | ||||
|  | ||||
| 		if (rule->check_opts) | ||||
| 			opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count, | ||||
| 					   &opts_match_count, &opts_unmatch_count); | ||||
|  | ||||
| 		if (rule->check_lvt_bits) | ||||
| 			_lv_types_match(cmd, lv, rule->check_lvt_bits, | ||||
| 					&lv_types_match_bits, &lv_types_unmatch_bits); | ||||
|  | ||||
| 		if (rule->check_lvp_bits) | ||||
| 			_lv_props_match(cmd, lv, rule->check_lvp_bits, | ||||
| 					&lv_props_match_bits, &lv_props_unmatch_bits); | ||||
| 		 | ||||
| 		/* | ||||
| 		 * Evaluate if the check results pass based on the rule. | ||||
| 		 * The options are checked again here because the previous | ||||
| 		 * option validation (during command matching) does not cover | ||||
| 		 * cases where the option is combined with conditions of LV types | ||||
| 		 * or properties. | ||||
| 		 */ | ||||
|  | ||||
| 		/* Fail if any invalid options are set. */ | ||||
|  | ||||
| 		if (rule->check_opts && (rule->rule == RULE_INVALID) && opts_match_count) { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| 			opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf)); | ||||
| 			log_warn("An invalid option is set: %s", buf); | ||||
| 			ret = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* Fail if any required options are not set. */ | ||||
|  | ||||
| 		if (rule->check_opts && (rule->rule == RULE_REQUIRE) && opts_unmatch_count)  { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| 			opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf)); | ||||
| 			log_warn("A required option is not set: %s", buf); | ||||
| 			ret = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* Fail if the LV matches any of the invalid LV types. */ | ||||
|  | ||||
| 		if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) { | ||||
| 			log_warn("Command on LV %s with invalid type: %s", | ||||
| 				 display_lvname(lv), lvtype ? lvtype->name : "unknown"); | ||||
| 			ret = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* Fail if the LV does not match any of the required LV types. */ | ||||
|  | ||||
| 		if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| 			lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf)); | ||||
| 			log_warn("Command on LV %s with type %s does not match required type: %s", | ||||
| 				 display_lvname(lv), lvtype ? lvtype->name : "unknown", buf); | ||||
| 			ret = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* Fail if the LV matches any of the invalid LV properties. */ | ||||
|  | ||||
| 		if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| 			lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf)); | ||||
| 			log_warn("Command on LV %s with invalid properties: %s", | ||||
| 				 display_lvname(lv), buf); | ||||
| 			ret = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* Fail if the LV does not match any of the required LV properties. */ | ||||
|  | ||||
| 		if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| 			lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf)); | ||||
| 			log_warn("Command on LV %s requires properties: %s", | ||||
| 				 display_lvname(lv), buf); | ||||
| 			ret = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Return which arg position the given LV is at, | ||||
|  * where 1 represents the first position arg. | ||||
|  * When the first position arg is repeatable, | ||||
|  * return 1 for all. | ||||
|  * | ||||
|  * Return 0 when the command has no required | ||||
|  * position args. (optional position args are | ||||
|  * not considered.) | ||||
|  */ | ||||
|  | ||||
| static int _find_lv_arg_position(struct cmd_context *cmd, struct logical_volume *lv) | ||||
| { | ||||
| 	const char *sep, *lvname; | ||||
| 	int i; | ||||
|  | ||||
| 	if (cmd->command->rp_count == 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (cmd->command->rp_count == 1) | ||||
| 		return 1; | ||||
|  | ||||
| 	for (i = 0; i < cmd->position_argc; i++) { | ||||
| 		if (i == cmd->command->rp_count) | ||||
| 			break; | ||||
|  | ||||
| 		if (!val_bit_is_set(cmd->command->required_pos_args[i].def.val_bits, lv_VAL)) | ||||
| 			continue; | ||||
|  | ||||
| 		if ((sep = strstr(cmd->position_argv[i], "/"))) | ||||
| 			lvname = sep + 1; | ||||
| 		else | ||||
| 			lvname = cmd->position_argv[i]; | ||||
|  | ||||
| 		if (!strcmp(lvname, lv->name)) | ||||
| 			return i + 1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * If the last position arg is an LV and this | ||||
| 	 * arg is beyond that position, then the last | ||||
| 	 * LV position arg is repeatable, so return | ||||
| 	 * that position. | ||||
| 	 */ | ||||
| 	if (i == cmd->command->rp_count) { | ||||
| 		int last_pos = cmd->command->rp_count; | ||||
| 		if (val_bit_is_set(cmd->command->required_pos_args[last_pos-1].def.val_bits, lv_VAL)) | ||||
| 			return last_pos; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 			  struct dm_list *arg_lvnames, const struct dm_list *tags_in, | ||||
| 			  int stop_on_error, | ||||
| 			  struct processing_handle *handle, | ||||
| 			  check_single_lv_fn_t check_single_lv, | ||||
| 			  process_single_lv_fn_t process_single_lv) | ||||
| { | ||||
| 	log_report_t saved_log_report_state = log_get_report_state(); | ||||
| @@ -2342,14 +2935,17 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 	int ret = 0; | ||||
| 	int whole_selected = 0; | ||||
| 	int handle_supplied = handle != NULL; | ||||
| 	int lv_is_named_arg; | ||||
| 	unsigned process_lv; | ||||
| 	unsigned process_all = 0; | ||||
| 	unsigned tags_supplied = 0; | ||||
| 	unsigned lvargs_supplied = 0; | ||||
| 	int lv_arg_pos; | ||||
| 	struct lv_list *lvl; | ||||
| 	struct dm_str_list *sl; | ||||
| 	struct dm_list final_lvs; | ||||
| 	struct lv_list *final_lvl; | ||||
| 	struct dm_list found_arg_lvnames; | ||||
| 	struct glv_list *glvl, *tglvl; | ||||
| 	int do_report_ret_code = 1; | ||||
|  | ||||
| @@ -2360,6 +2956,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		stack; | ||||
|  | ||||
| 	dm_list_init(&final_lvs); | ||||
| 	dm_list_init(&found_arg_lvnames); | ||||
|  | ||||
| 	if (!vg_check_status(vg, EXPORTED_VG)) { | ||||
| 		ret_max = ECMD_FAILED; | ||||
| @@ -2453,6 +3050,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) { | ||||
| 			/* Remove LV from list of unprocessed LV names */ | ||||
| 			str_list_del(arg_lvnames, lvl->lv->name); | ||||
| 			str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name); | ||||
| 			process_lv = 1; | ||||
| 		} | ||||
|  | ||||
| @@ -2500,6 +3098,43 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 		if (lv_is_removed(lvl->lv)) | ||||
| 			continue; | ||||
|  | ||||
| 		lv_is_named_arg = str_list_match_item(&found_arg_lvnames, lvl->lv->name); | ||||
|  | ||||
| 		lv_arg_pos = _find_lv_arg_position(cmd, lvl->lv); | ||||
|  | ||||
| 		/* | ||||
| 		 * The command definition may include restrictions on the | ||||
| 		 * types and properties of LVs that can be processed. | ||||
| 		 */ | ||||
|  | ||||
| 		if (!_check_lv_types(cmd, lvl->lv, lv_arg_pos)) { | ||||
| 			/* FIXME: include this result in report log? */ | ||||
| 			if (lv_is_named_arg) { | ||||
| 				log_error("Operation not permitted (%s %d) on LV %s.", | ||||
| 					  cmd->command->command_line_id, cmd->command->command_line_enum, | ||||
| 					  display_lvname(lvl->lv)); | ||||
| 				ret_max = ECMD_FAILED; | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!_check_lv_rules(cmd, lvl->lv)) { | ||||
| 			/* FIXME: include this result in report log? */ | ||||
| 			if (lv_is_named_arg) { | ||||
| 				log_error("Operation not permitted (%s %d) on LV %s.", | ||||
| 					  cmd->command->command_line_id, cmd->command->command_line_enum, | ||||
| 					  display_lvname(lvl->lv)); | ||||
| 				ret_max = ECMD_FAILED; | ||||
| 			}  | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (check_single_lv && !check_single_lv(cmd, lvl->lv, handle, lv_is_named_arg)) { | ||||
| 			if (lv_is_named_arg) | ||||
| 				ret_max = ECMD_FAILED; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name); | ||||
|  | ||||
| 		ret = process_single_lv(cmd, lvl->lv, handle); | ||||
| @@ -2730,12 +3365,150 @@ static int _get_arg_lvnames(struct cmd_context *cmd, | ||||
| 	return ret_max; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * This is a non-standard way of finding vgname/lvname to process.  It exists | ||||
|  * because an earlier form of lvconvert did not follow the standard form, and | ||||
|  * came up with its own inconsistent approach. | ||||
|  * | ||||
|  * In this case, when the position arg is a single name, it is treated as an LV | ||||
|  * name (not a VG name).  This leaves the VG unknown.  So, other option values | ||||
|  * must be searched for a VG name.  If one of those option values contains a | ||||
|  * vgname/lvname value, then the VG name is extracted and used for the LV | ||||
|  * position arg. | ||||
|  * | ||||
|  * Other option values that are searched for a VG name are: | ||||
|  * --thinpool, --cachepool. | ||||
|  * | ||||
|  *  . command vg/lv1 | ||||
|  *  . add vg to arg_vgnames | ||||
|  *  . add vg/lv1 to arg_lvnames | ||||
|  * | ||||
|  *  command lv1 | ||||
|  *  . error: no vg name | ||||
|  * | ||||
|  *  command --option vg/lv1 vg/lv2 | ||||
|  *  . verify both vg names match | ||||
|  *  . add vg to arg_vgnames | ||||
|  *  . add vg/lv2 to arg_lvnames | ||||
|  * | ||||
|  *  command --option lv1 lv2 | ||||
|  *  . error: no vg name | ||||
|  * | ||||
|  *  command --option vg/lv1 lv2 | ||||
|  *  . add vg to arg_vgnames | ||||
|  *  . add vg/lv2 to arg_lvnames | ||||
|  * | ||||
|  *  command --option lv1 vg/lv2 | ||||
|  *  . add vg to arg_vgnames | ||||
|  *  . add vg/lv2 to arg_lvnames | ||||
|  */ | ||||
|  | ||||
| static int _get_arg_lvnames_using_options(struct cmd_context *cmd, | ||||
| 			    		  int argc, char **argv, | ||||
| 					  struct dm_list *arg_vgnames, | ||||
| 					  struct dm_list *arg_lvnames) | ||||
| { | ||||
| 	const char *pos_name = NULL; | ||||
| 	const char *arg_name = NULL; | ||||
| 	const char *pos_vgname = NULL; | ||||
| 	const char *opt_vgname = NULL; | ||||
| 	const char *pos_lvname = NULL; | ||||
| 	const char *use_vgname = NULL; | ||||
| 	char *tmp_name; | ||||
| 	char *split; | ||||
| 	char *vglv; | ||||
| 	size_t vglv_sz; | ||||
|  | ||||
| 	if (argc != 1) { | ||||
| 		log_error("One LV position arg is required."); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	if (!(pos_name = dm_pool_strdup(cmd->mem, argv[0]))) { | ||||
| 		log_error("string alloc failed."); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	if ((split = strchr(pos_name, '/'))) { | ||||
| 		pos_vgname = pos_name; | ||||
| 		pos_lvname = split + 1; | ||||
| 		*split = '\0'; | ||||
| 	} else { | ||||
| 		pos_lvname = pos_name; | ||||
| 		pos_vgname = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, thinpool_ARG)) | ||||
| 		arg_name = arg_str_value(cmd, thinpool_ARG, NULL); | ||||
| 	else if (arg_is_set(cmd, cachepool_ARG)) | ||||
| 		arg_name = arg_str_value(cmd, cachepool_ARG, NULL); | ||||
|  | ||||
| 	if (!pos_vgname && !arg_name) { | ||||
| 		log_error("Cannot find VG name for LV %s.", pos_lvname); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_name && (split = strchr(arg_name, '/'))) { | ||||
| 		/* combined VG/LV */ | ||||
|  | ||||
| 		if (!(tmp_name = dm_pool_strdup(cmd->mem, arg_name))) { | ||||
| 			log_error("string alloc failed."); | ||||
| 			return ECMD_FAILED; | ||||
| 		} | ||||
|  | ||||
| 		if (!(split = strchr(tmp_name, '/'))) | ||||
| 			return ECMD_FAILED; | ||||
|  | ||||
| 		opt_vgname = tmp_name; | ||||
| 		/* Don't care about opt lvname. */ | ||||
| 		/* opt_lvname = split + 1; */ | ||||
| 		*split = '\0'; | ||||
| 	} else { | ||||
| 		/* Don't care about opt lvname. */ | ||||
| 		/* opt_lvname = arg_name; */ | ||||
| 		opt_vgname = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (!pos_vgname && !opt_vgname) { | ||||
| 		log_error("Cannot find VG name for LV %s.", pos_lvname); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	if (pos_vgname && opt_vgname && strcmp(pos_vgname, opt_vgname)) { | ||||
| 		log_error("VG name mismatch from position arg (%s) and option arg (%s).", | ||||
| 			  pos_vgname, opt_vgname); | ||||
| 		return ECMD_FAILED;  | ||||
| 	} | ||||
|  | ||||
| 	use_vgname = pos_vgname ? pos_vgname : opt_vgname; | ||||
|  | ||||
| 	if (!str_list_add(cmd->mem, arg_vgnames, dm_pool_strdup(cmd->mem, use_vgname))) { | ||||
| 		log_error("strlist allocation failed."); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	vglv_sz = strlen(use_vgname) + strlen(pos_lvname) + 2; | ||||
|  | ||||
| 	if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) || | ||||
| 	    dm_snprintf(vglv, vglv_sz, "%s/%s", use_vgname, pos_lvname) < 0) { | ||||
| 		log_error("vg/lv string alloc failed."); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
| 	if (!str_list_add(cmd->mem, arg_lvnames, vglv)) { | ||||
| 		log_error("strlist allocation failed."); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| 	return ECMD_PROCESSED; | ||||
| } | ||||
|  | ||||
| static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags, | ||||
| 				     struct dm_list *vgnameids_to_process, | ||||
| 				     struct dm_list *arg_vgnames, | ||||
| 				     struct dm_list *arg_lvnames, | ||||
| 				     struct dm_list *arg_tags, | ||||
| 				     struct processing_handle *handle, | ||||
| 				     check_single_lv_fn_t check_single_lv, | ||||
| 				     process_single_lv_fn_t process_single_lv) | ||||
| { | ||||
| 	log_report_t saved_log_report_state = log_get_report_state(); | ||||
| @@ -2828,7 +3601,7 @@ static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flag | ||||
| 			goto endvg; | ||||
|  | ||||
| 		ret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg, 0, | ||||
| 					    handle, process_single_lv); | ||||
| 					    handle, check_single_lv, process_single_lv); | ||||
| 		if (ret != ECMD_PROCESSED) | ||||
| 			stack; | ||||
| 		report_log_ret_code(ret); | ||||
| @@ -2859,6 +3632,7 @@ int process_each_lv(struct cmd_context *cmd, | ||||
| 		    const char *one_vgname, const char *one_lvname, | ||||
| 		    uint32_t read_flags, | ||||
| 		    struct processing_handle *handle, | ||||
| 		    check_single_lv_fn_t check_single_lv, | ||||
| 		    process_single_lv_fn_t process_single_lv) | ||||
| { | ||||
| 	log_report_t saved_log_report_state = log_get_report_state(); | ||||
| @@ -2887,7 +3661,12 @@ int process_each_lv(struct cmd_context *cmd, | ||||
| 	/* | ||||
| 	 * Find any LVs, VGs or tags explicitly provided on the command line. | ||||
| 	 */ | ||||
| 	if ((ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags) != ECMD_PROCESSED)) { | ||||
| 	if (cmd->command->flags & GET_VGNAME_FROM_OPTIONS) | ||||
| 		ret = _get_arg_lvnames_using_options(cmd, argc, argv, &arg_vgnames, &arg_lvnames); | ||||
| 	else | ||||
| 		ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags); | ||||
|  | ||||
| 	if (ret != ECMD_PROCESSED) { | ||||
| 		ret_max = ret; | ||||
| 		goto_out; | ||||
| 	} | ||||
| @@ -2974,7 +3753,7 @@ int process_each_lv(struct cmd_context *cmd, | ||||
| 		_choose_vgs_to_process(cmd, &arg_vgnames, &vgnameids_on_system, &vgnameids_to_process); | ||||
|  | ||||
| 	ret = _process_lv_vgnameid_list(cmd, read_flags, &vgnameids_to_process, &arg_vgnames, &arg_lvnames, | ||||
| 					&arg_tags, handle, process_single_lv); | ||||
| 					&arg_tags, handle, check_single_lv, process_single_lv); | ||||
|  | ||||
| 	if (ret > ret_max) | ||||
| 		ret_max = ret; | ||||
| @@ -3936,11 +4715,6 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p | ||||
| 	if (pp->pva.pvmetadatacopies < 0) | ||||
| 		pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL); | ||||
|  | ||||
| 	if (pp->pva.pvmetadatacopies > 2) { | ||||
| 		log_error("Metadatacopies may only be 0, 1 or 2"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size); | ||||
|  | ||||
| 	return 1; | ||||
|   | ||||
| @@ -98,6 +98,18 @@ typedef int (*process_single_pvseg_fn_t) (struct cmd_context * cmd, | ||||
| 					  struct pv_segment * pvseg, | ||||
| 					  struct processing_handle *handle); | ||||
|  | ||||
| /* | ||||
|  * Called prior to process_single_lv() to decide if the LV should be | ||||
|  * processed.  If this returns 0, the LV is not processed. | ||||
|  * | ||||
|  * This can evaluate the combination of command definition and | ||||
|  * the LV object to decide if the combination is allowed. | ||||
|  */ | ||||
| typedef int (*check_single_lv_fn_t) (struct cmd_context *cmd, | ||||
| 				     struct logical_volume *lv, | ||||
| 				     struct processing_handle *handle, | ||||
| 				     int lv_is_named_arg); | ||||
|  | ||||
| int process_each_vg(struct cmd_context *cmd, | ||||
| 	            int argc, char **argv, | ||||
| 		    const char *one_vgname, | ||||
| @@ -125,6 +137,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd, | ||||
| int process_each_lv(struct cmd_context *cmd, int argc, char **argv, | ||||
| 		    const char *one_vgname, const char *one_lvname, | ||||
| 		    uint32_t flags, struct processing_handle *handle, | ||||
| 		    check_single_lv_fn_t check_single_lv, | ||||
| 		    process_single_lv_fn_t process_single_lv); | ||||
|  | ||||
|  | ||||
| @@ -141,6 +154,7 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, | ||||
| 			  struct dm_list *arg_lvnames, const struct dm_list *tagsl, | ||||
| 			  int stop_on_error, struct processing_handle *handle, | ||||
| 			  check_single_lv_fn_t check_single_lv, | ||||
| 			  process_single_lv_fn_t process_single_lv); | ||||
|  | ||||
| struct processing_handle *init_processing_handle(struct cmd_context *cmd, struct processing_handle *parent_handle); | ||||
| @@ -159,6 +173,12 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name); | ||||
| const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name, | ||||
| 			 unsigned *dev_dir_found); | ||||
|  | ||||
| int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count, | ||||
| 		       int *match_count, int *unmatch_count); | ||||
|  | ||||
| void opt_array_to_str(struct cmd_context *cmd, int *opts, int count, | ||||
| 		      char *buf, int len); | ||||
|  | ||||
| int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp); | ||||
| int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp); | ||||
|  | ||||
| @@ -220,4 +240,6 @@ int validate_restricted_lvname_param(struct cmd_context *cmd, const char **vg_na | ||||
| int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, | ||||
|                     struct processing_handle *handle __attribute__((unused))); | ||||
|  | ||||
| int get_lvt_enum(struct logical_volume *lv); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										121
									
								
								tools/tools.h
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								tools/tools.h
									
									
									
									
									
								
							| @@ -50,20 +50,41 @@ | ||||
| #define CMD_LEN 256 | ||||
| #define MAX_ARGS 64 | ||||
|  | ||||
| /* command functions */ | ||||
| typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv); | ||||
| /* define the enums for the values accepted by command line --options, foo_VAL */ | ||||
| enum { | ||||
| #define val(a, b, c, d) a , | ||||
| #include "vals.h" | ||||
| #undef val | ||||
| }; | ||||
|  | ||||
| #define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv); | ||||
| #include "commands.h" | ||||
| #undef xx | ||||
|  | ||||
| /* define the enums for the command line switches */ | ||||
| /* define the enums for the command line --options, foo_ARG */ | ||||
| enum { | ||||
| #define arg(a, b, c, d, e, f) a , | ||||
| #include "args.h" | ||||
| #undef arg | ||||
| }; | ||||
|  | ||||
| /* command functions */ | ||||
| #define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv); | ||||
| #include "commands.h" | ||||
| #undef xx | ||||
|  | ||||
| /* define enums for LV properties, foo_LVP */ | ||||
| enum { | ||||
| #define lvp(a, b, c) a , | ||||
| #include "lv_props.h" | ||||
| #undef lvp | ||||
| }; | ||||
|  | ||||
| /* define enums for LV types, foo_LVT */ | ||||
| enum { | ||||
| #define lvt(a, b, c) a , | ||||
| #include "lv_types.h" | ||||
| #undef lvt | ||||
| }; | ||||
|  | ||||
| #include "command.h" | ||||
|  | ||||
| #define ARG_COUNTABLE 0x00000001	/* E.g. -vvvv */ | ||||
| #define ARG_GROUPABLE 0x00000002	/* E.g. --addtag */ | ||||
|  | ||||
| @@ -79,13 +100,13 @@ struct arg_values { | ||||
| /*	void *ptr; // Currently not used. */ | ||||
| }; | ||||
|  | ||||
| /* a global table of possible arguments */ | ||||
| /* a global table of possible --option's */ | ||||
| struct arg_props { | ||||
| 	int arg_enum; /* foo_ARG from args.h */ | ||||
| 	const char short_arg; | ||||
| 	char _padding[7]; | ||||
| 	const char *long_arg; | ||||
|  | ||||
| 	int (*fn) (struct cmd_context *cmd, struct arg_values *av); | ||||
| 	int val_enum; /* foo_VAL from vals.h */ | ||||
| 	uint32_t flags; | ||||
| 	uint32_t prio; | ||||
| }; | ||||
| @@ -96,6 +117,29 @@ struct arg_value_group_list { | ||||
| 	uint32_t prio; | ||||
| }; | ||||
|  | ||||
| /* a global table of possible --option values */ | ||||
| struct val_props { | ||||
| 	int val_enum; /* foo_VAL from vals.h */ | ||||
| 	int (*fn) (struct cmd_context *cmd, struct arg_values *av); | ||||
| 	const char *name; | ||||
| 	const char *usage; | ||||
| }; | ||||
|  | ||||
| /* a global table of possible LV properties */ | ||||
| struct lv_props { | ||||
| 	int lvp_enum; /* is_foo_LVP from lv_props.h */ | ||||
| 	const char *name; /* "lv_is_foo" used in command-lines.in */ | ||||
| 	int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */ | ||||
| }; | ||||
|  | ||||
| /* a global table of possible LV types */ | ||||
| /* (as exposed externally in command line interface, not exactly as internal segtype is used) */ | ||||
| struct lv_types { | ||||
| 	int lvt_enum; /* is_foo_LVT from lv_types.h */ | ||||
| 	const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */ | ||||
| 	int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */ | ||||
| }; | ||||
|  | ||||
| #define CACHE_VGMETADATA	0x00000001 | ||||
| #define PERMITTED_READ_ONLY 	0x00000002 | ||||
| /* Process all VGs if none specified on the command line. */ | ||||
| @@ -118,19 +162,8 @@ struct arg_value_group_list { | ||||
| #define ENABLE_DUPLICATE_DEVS    0x00000400 | ||||
| /* Command does not accept tags as args. */ | ||||
| #define DISALLOW_TAG_ARGS        0x00000800 | ||||
|   | ||||
| /* a register of the lvm commands */ | ||||
| struct command { | ||||
| 	const char *name; | ||||
| 	const char *desc; | ||||
| 	const char *usage; | ||||
| 	command_fn fn; | ||||
|  | ||||
| 	unsigned flags; | ||||
|  | ||||
| 	int num_args; | ||||
| 	int *valid_args; | ||||
| }; | ||||
| /* Command may need to find VG name in an option value. */ | ||||
| #define GET_VGNAME_FROM_OPTIONS  0x00001000 | ||||
|  | ||||
| void usage(const char *name); | ||||
|  | ||||
| @@ -157,7 +190,15 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av); | ||||
| int alloc_arg(struct cmd_context *cmd, struct arg_values *av); | ||||
| int locktype_arg(struct cmd_context *cmd, struct arg_values *av); | ||||
| int readahead_arg(struct cmd_context *cmd, struct arg_values *av); | ||||
| int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
| int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); | ||||
|  | ||||
| /* we use the enums to access the switches */ | ||||
| unsigned arg_count(const struct cmd_context *cmd, int a); | ||||
| @@ -199,4 +240,38 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, | ||||
|  | ||||
| int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg); | ||||
|  | ||||
| struct lv_props *get_lv_prop(int lvp_enum); | ||||
| struct lv_types *get_lv_type(int lvt_enum); | ||||
| struct command *get_command(int cmd_enum); | ||||
|  | ||||
| int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_merge_thin_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
| int lvconvert_split_cachepool_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										136
									
								
								tools/vals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								tools/vals.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
|  | ||||
| /* | ||||
|  * Define value types which describe values accepted | ||||
|  * by the --option's in args.h, and can also describe | ||||
|  * the values accepted as positional args. | ||||
|  * | ||||
|  * Previously, accepted values were only "described" | ||||
|  * by identifying the parsing function to use. | ||||
|  * | ||||
|  * Some standard val types are used by many options, | ||||
|  * e.g. many options (aa_ARG, bb_ARG, cc_ARG) all | ||||
|  * accept a number_VAL. | ||||
|  * | ||||
|  * Other special val types are used by only one option, | ||||
|  * e.g. only mirrorlog_ARG accepts a mirrorlog_VAL. | ||||
|  * This typically means that there are some specific | ||||
|  * words that are recognized after the option. | ||||
|  * | ||||
|  * Some options currently take a standard val type, | ||||
|  * (esp string_VAL), but they could be given their | ||||
|  * own custom val type.  The advantage of using a | ||||
|  * custom val type is the possibility of validating | ||||
|  * the value when parsing it with a custom parsing | ||||
|  * function, and the possibility of displaying the | ||||
|  * actual accepted values in the command usage. | ||||
|  * Without a custom val type, the code must do ad hoc | ||||
|  * validation of the string values, and the usage | ||||
|  * output for the option will only say "String" | ||||
|  * rather than giving the accepted string values. | ||||
|  * Even without a custom parsing function, there is | ||||
|  * reason to define a custom x_VAL enum so that a | ||||
|  * more descriptive usage string can be specified | ||||
|  * as opposed to just "String". | ||||
|  * | ||||
|  * Most of the val types defined here are used after | ||||
|  * --option's, and are referenced in foo_ARG entries | ||||
|  * in args.h.  But, some val types are only used to | ||||
|  * represent positional values in command definitions, | ||||
|  * e.g. vg_VAL. | ||||
|  * | ||||
|  * val(a, b, c, d) | ||||
|  * | ||||
|  * a:  foo_VAL enums | ||||
|  * b:  the function to parse and set the value | ||||
|  * c:  the name used to reference this value in command defs | ||||
|  * d:  what to display in usage output for this value | ||||
|  * | ||||
|  * command defintions will use --option NAME, where NAME | ||||
|  * is shown in val() field c.  NAME will be translated to | ||||
|  * foo_VAL enum in field a, which is used in commands[] | ||||
|  * structs. | ||||
|  * | ||||
|  * option definitions (arg.h) will reference foo_VAL enum | ||||
|  * in field a. | ||||
|  * | ||||
|  * FIXME: for specialized val types, the set of recognized | ||||
|  * words is not defined or stored in a consistent way, | ||||
|  * but is just whatever the parsing function happens to look | ||||
|  * for, so adding a new accepted value for the val type is | ||||
|  * generally making the parsing function recognize a new | ||||
|  * word, and making the implementation code also recognize | ||||
|  * that word to do something different.  This new word should | ||||
|  * then also be added to the usage string for the val type here. | ||||
|  * It would be nice if the accepted values could be defined in a | ||||
|  * more consistent way, and perhaps in a single place, perhaps in | ||||
|  * struct val_props. | ||||
|  * | ||||
|  * The usage text for an option is not always the full | ||||
|  * set of words accepted for an option, but may be a | ||||
|  * subset.  i.e. an outdated word that no longer does | ||||
|  * anything may not be shown, but may still be recognized | ||||
|  * and ignored, or an option that shouldn't be used in | ||||
|  * general isn't shown to avoid suggesting it. | ||||
|  * e.g. for --activate we show the most common "y|n|ay" | ||||
|  * without showing the lvmlockd variations "ey|sy" which | ||||
|  * are not applicable in general. | ||||
|  * | ||||
|  * FIXME: are there some specialized or irrelevant | ||||
|  * options included in the usage text below that should | ||||
|  * be removed?  Should "lvm1" be removed? | ||||
|  * | ||||
|  * For Number args that take optional units, a full usage | ||||
|  * could be "Number[bBsSkKmMgGtTpPeE]" (with implied |), | ||||
|  * but repeating this full specification produces cluttered | ||||
|  * output, and doesn't indicate which unit is the default. | ||||
|  * "Number[units]" would be cleaner, as would a subset of | ||||
|  * common units, e.g. "Number[kmg...]", but neither helps | ||||
|  * with default.  "Number[k|unit]" and "Number[m|unit]" show | ||||
|  * the default, and "unit" indicates that other units | ||||
|  * are possible without listing them all.  This also | ||||
|  * suggests using the preferred lower case letters, because | ||||
|  * --size and other option args treat upper/lower letters | ||||
|  * the same, all as 1024 SI base.  For this reason, we | ||||
|  * should avoid suggesting the upper case letters. | ||||
|  */ | ||||
|  | ||||
| val(none_VAL, NULL, "None", "ERR")             /* unused, for enum value 0 */ | ||||
| val(conststr_VAL, NULL, "ConstString", "ERR")  /* used only for command defs */ | ||||
| val(constnum_VAL, NULL, "ConstNumber", "ERR")  /* used only for command defs */ | ||||
| val(bool_VAL, yes_no_arg, "Bool", "y|n") | ||||
| val(number_VAL, int_arg, "Number", NULL) | ||||
| val(string_VAL, string_arg, "String", NULL) | ||||
| val(vg_VAL, string_arg, "VG", NULL) | ||||
| val(lv_VAL, string_arg, "LV", NULL) | ||||
| val(pv_VAL, string_arg, "PV", NULL) | ||||
| val(tag_VAL, tag_arg, "Tag", NULL) | ||||
| val(select_VAL, NULL, "Select", NULL)       /* used only for command defs */ | ||||
| val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete") | ||||
| val(activation_VAL, activation_arg, "Active", "y|n|ay") | ||||
| val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback") | ||||
| val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore") | ||||
| val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk") | ||||
| val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]") | ||||
| val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]") | ||||
| val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number") | ||||
| val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%VG|%PVS|%FREE]") | ||||
| val(permission_VAL, permission_arg, "Permission", "rw|r") | ||||
| val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1") | ||||
| val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE") | ||||
| val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool") | ||||
| val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit") | ||||
| val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none") | ||||
| val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors") | ||||
| val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number") | ||||
| val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2") | ||||
| val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused") | ||||
| val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin") | ||||
| val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]") | ||||
| val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair") | ||||
| val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json") | ||||
| val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg") | ||||
| val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata") | ||||
|  | ||||
| /* this should always be last */ | ||||
| val(VAL_COUNT, NULL, NULL, NULL) | ||||
|  | ||||
| @@ -482,6 +482,9 @@ static int _vgchange_metadata_copies(struct cmd_context *cmd, | ||||
| { | ||||
| 	uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES); | ||||
|  | ||||
| 	log_warn("vgchange_metadata_copies new %u vg_mda_copies %u D %u", | ||||
| 		 mda_copies, vg_mda_copies(vg), DEFAULT_VGMETADATACOPIES); | ||||
|  | ||||
| 	if (mda_copies == vg_mda_copies(vg)) { | ||||
| 		if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED) | ||||
| 			log_warn("Number of metadata copies for VG %s is already unmanaged.", | ||||
|   | ||||
| @@ -157,24 +157,12 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv) | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, metadatacopies_ARG)) { | ||||
| 		log_error("Invalid option --metadatacopies, " | ||||
| 			  "use --pvmetadatacopies instead."); | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
| 	if (!(cmd->fmt->features & FMT_MDAS) && | ||||
| 	    (arg_is_set(cmd, pvmetadatacopies_ARG) || | ||||
| 	     arg_is_set(cmd, metadatasize_ARG))) { | ||||
| 	    arg_is_set(cmd, pvmetadatacopies_ARG)) { | ||||
| 		log_error("Metadata parameters only apply to text format"); | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, pvmetadatacopies_ARG) && | ||||
| 	    arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) { | ||||
| 		log_error("Metadatacopies may only be 0, 1 or 2"); | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	if (!(cmd->fmt->features & FMT_BAS) && | ||||
| 		arg_is_set(cmd, bootloaderareasize_ARG)) { | ||||
| 		log_error("Bootloader area parameters only apply to text format"); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name, | ||||
| 		vgdisplay_extents(vg); | ||||
|  | ||||
| 		process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, NULL, | ||||
| 				      (process_single_lv_fn_t)lvdisplay_full); | ||||
| 				      NULL, (process_single_lv_fn_t)lvdisplay_full); | ||||
|  | ||||
| 		log_print("--- Physical volumes ---"); | ||||
| 		process_each_pv_in_vg(cmd, vg, NULL, | ||||
|   | ||||
| @@ -136,12 +136,6 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, metadatacopies_ARG)) { | ||||
| 		log_error("Invalid option --metadatacopies, " | ||||
| 			  "use --pvmetadatacopies instead."); | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	} | ||||
|  | ||||
| 	vg_name = skip_dev_dir(cmd, argv[0], NULL); | ||||
| 	argc--; | ||||
| 	argv++; | ||||
|   | ||||
| @@ -33,5 +33,5 @@ int vgmknodes(struct cmd_context *cmd, int argc, char **argv) | ||||
| 	if (!lv_mknodes(cmd, NULL)) | ||||
| 		return_ECMD_FAILED; | ||||
|  | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, &_vgmknodes_single); | ||||
| 	return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, NULL, &_vgmknodes_single); | ||||
| } | ||||
|   | ||||
| @@ -62,7 +62,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name, | ||||
| 		} | ||||
|  | ||||
| 		if ((ret = process_each_lv_in_vg(cmd, vg, NULL, NULL, 1, &void_handle, | ||||
| 						 (process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) { | ||||
| 						 NULL, (process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) { | ||||
| 			stack; | ||||
| 			return ret; | ||||
| 		} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user