[lvm-devel] master - lvm2app: Add VG/LV name validation

tasleson tasleson at fedoraproject.org
Tue Nov 19 20:56:41 UTC 2013


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0dd247502ace2dd20763d1b664edc280a255de06
Commit:        0dd247502ace2dd20763d1b664edc280a255de06
Parent:        e54e70dc66a8be0dbc61e1dbc65310d86d35b086
Author:        Tony Asleson <tasleson at redhat.com>
AuthorDate:    Thu Sep 26 11:37:40 2013 -0500
Committer:     Tony Asleson <tasleson at redhat.com>
CommitterDate: Tue Nov 19 14:40:39 2013 -0600

lvm2app: Add VG/LV name validation

C library portion for
https://bugzilla.redhat.com/show_bug.cgi?id=883689

Signed-off-by: Tony Asleson <tasleson at redhat.com>
---
 lib/display/display.c            |   29 ++++++++++++++++++++++++++++
 lib/display/display.h            |    3 ++
 lib/metadata/metadata-exported.h |    1 +
 lib/metadata/metadata.c          |   12 ++++++----
 lib/misc/lvm-string.c            |   39 +++++++++++++++++++++++++------------
 lib/misc/lvm-string.h            |    8 ++++++-
 liblvm/lvm2app.h                 |   32 +++++++++++++++++++++++++++++++
 liblvm/lvm_base.c                |    1 +
 liblvm/lvm_vg.c                  |   30 +++++++++++++++++++++++++++++
 9 files changed, 136 insertions(+), 19 deletions(-)

diff --git a/lib/display/display.c b/lib/display/display.c
index be56f12..2fd37a2 100644
--- a/lib/display/display.c
+++ b/lib/display/display.c
@@ -915,6 +915,35 @@ void display_segtypes(const struct cmd_context *cmd)
 	}
 }
 
+void display_name_error(name_error_t name_error)
+{
+	if (name_error != NAME_VALID) {
+		switch(name_error) {
+		case NAME_INVALID_EMPTY:
+			log_error("Name is zero length");
+			break;
+		case NAME_INVALID_HYPEN:
+			log_error("Name cannot start with hyphen");
+			break;
+		case NAME_INVALID_DOTS:
+			log_error("Name starts with . or .. and has no "
+						"following character(s)");
+			break;
+		case NAME_INVALID_CHARSET:
+			log_error("Name contains invalid character, valid set includes: "
+					"[a-zA-Z0-9.-_+]");
+			break;
+		case NAME_INVALID_LENGTH:
+			/* Report that name length -1 to accommodate nul*/
+			log_error("Name length exceeds maximum limit of %d", (NAME_LEN -1));
+			break;
+		default:
+			log_error("Unknown error %d on name validation", name_error);
+			break;
+		}
+	}
+}
+
 /*
  * Prompt for y or n from stdin.
  * Defaults to 'no' in silent mode.
diff --git a/lib/display/display.h b/lib/display/display.h
index 8462901..077fff4 100644
--- a/lib/display/display.h
+++ b/lib/display/display.h
@@ -18,6 +18,7 @@
 
 #include "metadata-exported.h"
 #include "locking.h"
+#include "lvm-string.h"
 
 #include <stdint.h>
 
@@ -53,6 +54,8 @@ void vgdisplay_short(const struct volume_group *vg);
 void display_formats(const struct cmd_context *cmd);
 void display_segtypes(const struct cmd_context *cmd);
 
+void display_name_error(name_error_t name_error);
+
 /*
  * Allocation policy display conversion routines.
  */
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 7429241..ed1ec8d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -581,6 +581,7 @@ int pv_analyze(struct cmd_context *cmd, const char *pv_name,
 /* FIXME: move internal to library */
 uint32_t pv_list_extents_free(const struct dm_list *pvh);
 
+int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name);
 int vg_validate(struct volume_group *vg);
 struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name);
 int vg_remove_mdas(struct volume_group *vg);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index d80958d..53d7e5e 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -435,13 +435,15 @@ int move_pvs_used_by_lv(struct volume_group *vg_from,
 	return 1;
 }
 
-static int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
+int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
 {
 	static char vg_path[PATH_MAX];
+	name_error_t name_error;
 
-	if (!validate_name(vg_name)) {
-		log_error("New volume group name \"%s\" is invalid.",
-			  vg_name);
+	name_error = validate_name_detailed(vg_name);
+	if (NAME_VALID != name_error) {
+		display_name_error(name_error);
+		log_error("New volume group name \"%s\" is invalid.", vg_name);
 		return 0;
 	}
 
@@ -4574,7 +4576,7 @@ void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored)
 	else
 		return;	/* No change */
 
-	log_debug_metadata("%s ignored flag for mda %s at offset %" PRIu64 ".", 
+	log_debug_metadata("%s ignored flag for mda %s at offset %" PRIu64 ".",
 			   mda_ignored ? "Setting" : "Clearing",
 			   mda->ops->mda_metadata_locn_name ? mda->ops->mda_metadata_locn_name(locn) : "",
 			   mda->ops->mda_metadata_locn_offset ? mda->ops->mda_metadata_locn_offset(locn) : UINT64_C(0));
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 8aa1f6c..380fe81 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -63,35 +63,40 @@ int validate_tag(const char *n)
 	return 1;
 }
 
-/*
- * Device layer names are all of the form <vg>-<lv>-<layer>, any
- * other hyphens that appear in these names are quoted with yet
- * another hyphen.  The top layer of any device has no layer
- * name.  eg, vg0-lvol0.
- */
-int validate_name(const char *n)
+static int _validate_name(const char *n)
 {
 	register char c;
 	register int len = 0;
 
 	if (!n || !*n)
-		return 0;
+		return -1;
 
 	/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
 	if (*n == '-')
-		return 0;
+		return -2;
 
 	if ((*n == '.') && (!n[1] || (n[1] == '.' && !n[2]))) /* ".", ".." */
-		return 0;
+		return -3;
 
 	while ((len++, c = *n++))
 		if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
-			return 0;
+			return -4;
 
 	if (len > NAME_LEN)
-		return 0;
+		return -5;
 
-	return 1;
+	return 0;
+}
+
+/*
+ * Device layer names are all of the form <vg>-<lv>-<layer>, any
+ * other hyphens that appear in these names are quoted with yet
+ * another hyphen.  The top layer of any device has no layer
+ * name.  eg, vg0-lvol0.
+ */
+int validate_name(const char *n)
+{
+	return (_validate_name(n) < 0 ? 0 : 1);
 }
 
 int apply_lvname_restrictions(const char *name)
@@ -136,6 +141,14 @@ int apply_lvname_restrictions(const char *name)
 	return 1;
 }
 
+/*
+ * Validates name and returns an emunerated reason for name validataion failure.
+ */
+name_error_t validate_name_detailed(const char *name)
+{
+	return _validate_name(name);
+}
+
 int is_reserved_lvname(const char *name)
 {
 	int rc, old_suppress;
diff --git a/lib/misc/lvm-string.h b/lib/misc/lvm-string.h
index 6be048d..13aacf8 100644
--- a/lib/misc/lvm-string.h
+++ b/lib/misc/lvm-string.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
@@ -24,6 +24,11 @@
 
 struct pool;
 
+typedef enum name_error { NAME_VALID = 0, NAME_INVALID_EMPTY = -1,
+					NAME_INVALID_HYPEN = -2, NAME_INVALID_DOTS = -3,
+					NAME_INVALID_CHARSET = -4, NAME_INVALID_LENGTH = -5}
+					name_error_t;
+
 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
   __attribute__ ((format(printf, 3, 4)));
 
@@ -31,6 +36,7 @@ char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
 		    const char *layer);
 
 int validate_name(const char *n);
+name_error_t validate_name_detailed(const char *n);
 int validate_tag(const char *n);
 
 int apply_lvname_restrictions(const char *name);
diff --git a/liblvm/lvm2app.h b/liblvm/lvm2app.h
index afc6793..0940b6f 100644
--- a/liblvm/lvm2app.h
+++ b/liblvm/lvm2app.h
@@ -510,6 +510,21 @@ vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode,
 		  uint32_t flags);
 
 /**
+ * Validate a name to be used for new VG construction.
+ *
+ * This function checks that the name has no invalid characters,
+ * the length doesn't exceed maximum and that the VG name isn't already in use
+ * and that the name adheres to any other limitations.
+ *
+ * \param libh
+ * Valid library handle
+ *
+ * \param name
+ * Name to validate for new VG create.
+ */
+int lvm_vg_name_validate(lvm_t libh, const char *vg_name);
+
+/**
  * Create a VG with default parameters.
  *
  * \memberof lvm_t
@@ -1554,6 +1569,23 @@ int lvm_lv_resize(const lv_t lv, uint64_t new_size);
 lv_t lvm_lv_snapshot(const lv_t lv, const char *snap_name, uint64_t max_snap_size);
 
 /**
+ * Validate a name to be used for LV creation.
+ *
+ * Validates that the name does not contain any invalid characters, max length
+ * and that the LV name doesn't already exist for this VG.
+ *
+ * Note: You can have the same LV name in different VGs, thus the reason this
+ * function requires that you specify a VG to check against.
+ *
+ * \param lv
+ * Volume group handle.
+ *
+ * \param name
+ * Name to validate
+ */
+int lvm_lv_name_validate(const vg_t vg, const char *lv_name);
+
+/**
  * Thin provisioning discard policies
  */
 typedef enum {
diff --git a/liblvm/lvm_base.c b/liblvm/lvm_base.c
index b7603e3..139cc97 100644
--- a/liblvm/lvm_base.c
+++ b/liblvm/lvm_base.c
@@ -18,6 +18,7 @@
 #include "lvm-version.h"
 #include "metadata-exported.h"
 #include "lvm2app.h"
+#include "lvm-string.h"
 
 const char *lvm_library_get_version(void)
 {
diff --git a/liblvm/lvm_vg.c b/liblvm/lvm_vg.c
index 214f459..d3c8ae2 100644
--- a/liblvm/lvm_vg.c
+++ b/liblvm/lvm_vg.c
@@ -21,6 +21,7 @@
 #include "lvmetad.h"
 #include "lvm_misc.h"
 #include "lvm2app.h"
+#include "display.h"
 
 int lvm_vg_add_tag(vg_t vg, const char *tag)
 {
@@ -385,3 +386,32 @@ int lvm_scan(lvm_t libh)
 		return -1;
 	return 0;
 }
+
+int lvm_lv_name_validate(const vg_t vg, const char *name)
+{
+	name_error_t name_error;
+
+	name_error = validate_name_detailed(name);
+
+	if (NAME_VALID == name_error) {
+		if (apply_lvname_restrictions(name)) {
+			if (!find_lv_in_vg(vg, name)) {
+				return 0;
+			} else {
+				log_errno(EINVAL, "LV name exists in VG");
+			}
+		}
+	} else {
+		display_name_error(name_error);
+	}
+	return -1;
+}
+
+int lvm_vg_name_validate(lvm_t libh, const char *name)
+{
+	struct cmd_context *cmd = (struct cmd_context *)libh;
+
+	if (validate_new_vg_name(cmd, name))
+		return 0;
+	return -1;
+}




More information about the lvm-devel mailing list