public inbox for lvm2-cvs@sourceware.org
help / color / mirror / Atom feed
From: prajnoha@sourceware.org
To: lvm-devel@redhat.com, lvm2-cvs@sourceware.org
Subject: LVM2 ./WHATS_NEW_DM libdm/libdevmapper.h libdm ...
Date: Wed, 15 Feb 2012 11:27:00 -0000	[thread overview]
Message-ID: <20120215112703.11213.qmail@sourceware.org> (raw)

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	prajnoha@sourceware.org	2012-02-15 11:27:02

Modified files:
	.              : WHATS_NEW_DM 
	libdm          : libdevmapper.h libdm-common.c libdm-common.h 
	libdm/ioctl    : libdm-iface.c libdm-targets.h 

Log message:
	Mangle device name on dm_task_set_name/newname call if necessary.
	
	If dm_task_set_name/newname is called, the name provided will be
	automatically translated to correct encoded form with the hex enconding
	so any character not on udev whitelist will be mangled with \xNN
	format where NN is hex value of the character used.
	
	By default, the name mangling mode used is the one set during
	configure with the '--with-default-name-mangling' option.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW_DM.diff?cvsroot=lvm2&r1=1.558&r2=1.559
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/libdevmapper.h.diff?cvsroot=lvm2&r1=1.179&r2=1.180
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/libdm-common.c.diff?cvsroot=lvm2&r1=1.138&r2=1.139
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/libdm-common.h.diff?cvsroot=lvm2&r1=1.10&r2=1.11
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/ioctl/libdm-iface.c.diff?cvsroot=lvm2&r1=1.134&r2=1.135
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/ioctl/libdm-targets.h.diff?cvsroot=lvm2&r1=1.33&r2=1.34

--- LVM2/WHATS_NEW_DM	2012/02/15 11:17:57	1.558
+++ LVM2/WHATS_NEW_DM	2012/02/15 11:27:01	1.559
@@ -1,5 +1,7 @@
 Version 1.02.71 - 
 ====================================
+  Mangle device name on dm_task_set_name/newname call if necessary.
+  Add dm_set/get_name_mangling_mode to set/get name mangling in libdevmapper.
   Add configure --with-default-name-mangling.
   Test for parsed words in _umount() dmeventd snapshot plugin.
   Fix memory leak in fail path of parse_loop_device_name() in dmsetup.
--- LVM2/libdm/libdevmapper.h	2012/02/15 11:17:58	1.179
+++ LVM2/libdm/libdevmapper.h	2012/02/15 11:27:01	1.180
@@ -287,6 +287,12 @@
 } dm_string_mangling_t;
 
 /*
+ * Set/get mangling mode used for device-mapper names.
+ */
+int dm_set_name_mangling_mode(dm_string_mangling_t name_mangling);
+dm_string_mangling_t dm_get_name_mangling_mode(void);
+
+/*
  * Configure the device-mapper directory
  */
 int dm_set_dev_dir(const char *dir);
--- LVM2/libdm/libdm-common.c	2012/02/13 14:39:24	1.138
+++ LVM2/libdm/libdm-common.c	2012/02/15 11:27:02	1.139
@@ -66,6 +66,7 @@
 
 static int _verbose = 0;
 static int _suspended_dev_counter = 0;
+static int _name_mangling_mode = DEFAULT_DM_NAME_MANGLING;
 
 #ifdef HAVE_SELINUX_LABEL_H
 static struct selabel_handle *_selabel_handle = NULL;
@@ -201,6 +202,18 @@
 	return _suspended_dev_counter;
 }
 
+int dm_set_name_mangling_mode(dm_string_mangling_t name_mangling_mode)
+{
+	_name_mangling_mode = name_mangling_mode;
+
+	return 1;
+}
+
+dm_string_mangling_t dm_get_name_mangling_mode(void)
+{
+	return _name_mangling_mode;
+}
+
 struct dm_task *dm_task_create(int type)
 {
 	struct dm_task *dmt = dm_zalloc(sizeof(*dmt));
@@ -238,18 +251,18 @@
 /*
  * Find the name associated with a given device number by scanning _dm_dir.
  */
-static char *_find_dm_name_of_device(dev_t st_rdev)
+static int _find_dm_name_of_device(dev_t st_rdev, char *buf, size_t buf_len)
 {
 	const char *name;
 	char path[PATH_MAX];
 	struct dirent *dirent;
 	DIR *d;
-	struct stat buf;
-	char *new_name = NULL;
+	struct stat st;
+	int r = 0;
 
 	if (!(d = opendir(_dm_dir))) {
 		log_sys_error("opendir", _dm_dir);
-		return NULL;
+		return 0;
 	}
 
 	while ((dirent = readdir(d))) {
@@ -264,13 +277,12 @@
 			continue;
 		}
 
-		if (stat(path, &buf))
+		if (stat(path, &st))
 			continue;
 
-		if (buf.st_rdev == st_rdev) {
-			if (!(new_name = dm_strdup(name)))
-				log_error("dm_task_set_name: strdup(%s) failed",
-					  name);
+		if (st.st_rdev == st_rdev) {
+			strncpy(buf, name, buf_len);
+			r = 1;
 			break;
 		}
 	}
@@ -278,72 +290,212 @@
 	if (closedir(d))
 		log_sys_error("closedir", _dm_dir);
 
-	return new_name;
+	return r;
 }
 
-int dm_task_set_name(struct dm_task *dmt, const char *name)
+static int _is_whitelisted_char(char c)
 {
-	char *pos;
-	char *new_name = NULL;
-	char path[PATH_MAX];
-	struct stat st1, st2;
-
-	dm_free(dmt->dev_name);
-	dmt->dev_name = NULL;
-
 	/*
-	 * Path supplied for existing device?
+	 * Actually, DM supports any character in a device name.
+	 * This whitelist is just for proper integration with udev.
 	 */
-	if ((pos = strrchr(name, '/'))) {
-		if (dmt->type == DM_DEVICE_CREATE) {
-			log_error("Name \"%s\" invalid. It contains \"/\".", name);
-			return 0;
-		}
+        if ((c >= '0' && c <= '9') ||
+            (c >= 'A' && c <= 'Z') ||
+            (c >= 'a' && c <= 'z') ||
+            strchr("#+-.:=@_", c) != NULL)
+                return 1;
 
-		if (stat(name, &st1)) {
-			log_error("Device %s not found", name);
-			return 0;
-		}
+        return 0;
+}
 
-		/*
-		 * If supplied path points to same device as last component
-		 * under /dev/mapper, use that name directly.  Otherwise call
-		 * _find_dm_name_of_device() to scan _dm_dir for a match.
-		 */
-		if (dm_snprintf(path, sizeof(path), "%s/%s", _dm_dir,
-				pos + 1) == -1) {
-			log_error("Couldn't create path for %s", pos + 1);
-			return 0;
+/*
+ * Mangle all characters in the input string which are not on a whitelist
+ * with '\xNN' format where NN is the hex value of the character.
+ */
+int mangle_name(const char *str, size_t len, char *buf,
+		size_t buf_len, dm_string_mangling_t mode)
+{
+	int need_mangling = -1; /* -1 don't know yet, 0 no, 1 yes */
+	size_t i, j;
+
+	if (!str || !buf)
+		return -1;
+
+	/* Is there anything to do at all? */
+	if (!*str || !len || mode == DM_STRING_MANGLING_NONE)
+		return 0;
+
+	if (buf_len < DM_NAME_LEN) {
+		log_error(INTERNAL_ERROR "mangle_name: supplied buffer too small");
+		return -1;
+	}
+
+	for (i = 0, j = 0; str[i]; i++) {
+		if (mode == DM_STRING_MANGLING_AUTO) {
+			/*
+			 * Detect already mangled part of the string and keep it.
+			 * Return error on mixture of mangled/not mangled!
+			 */
+			if (str[i] == '\\' && str[i+1] == 'x') {
+				if ((len - i < 4) || (need_mangling == 1))
+					goto bad1;
+				if (buf_len - j < 4)
+					goto bad2;
+
+				memcpy(&buf[j], &str[i], 4);
+				i+=3; j+=4;
+
+				need_mangling = 0;
+				continue;
+			}
 		}
 
-		if (!stat(path, &st2) && (st1.st_rdev == st2.st_rdev))
-			name = pos + 1;
-		else if ((new_name = _find_dm_name_of_device(st1.st_rdev)))
-			name = new_name;
-		else {
-			log_error("Device %s not found", name);
-			return 0;
+		if (_is_whitelisted_char(str[i])) {
+			/* whitelisted, keep it. */
+			if (buf_len - j < 1)
+				goto bad2;
+			buf[j] = str[i];
+			j++;
+		} else {
+			/*
+			 * Not on a whitelist, mangle it.
+			 * Return error on mixture of mangled/not mangled
+			 * unless a DM_STRING_MANGLING_HEX is used!.
+			 */
+			if ((mode != DM_STRING_MANGLING_HEX) && (need_mangling == 0))
+				goto bad1;
+			if (buf_len - j < 4)
+				goto bad2;
+
+			sprintf(&buf[j], "\\x%02x", (unsigned char) str[i]);
+			j+=4;
+
+			need_mangling = 1;
 		}
 	}
 
+	if (buf_len - j < 1)
+		goto bad2;
+	buf[j] = '\0';
+
+	/* All chars in the string whitelisted? */
+	if (need_mangling == -1)
+		need_mangling = 0;
+
+	return need_mangling;
+
+bad1:
+	log_error("The name \"%s\" contains mixed mangled and unmangled "
+		  "characters or it's already mangled improperly.", str);
+	return -1;
+bad2:
+	log_error("Mangled form of the name too long for \"%s\".", str);
+	return -1;
+}
+
+static int _dm_task_set_name(struct dm_task *dmt, const char *name,
+			     dm_string_mangling_t mangling_mode)
+{
+	char mangled_name[DM_NAME_LEN];
+	int r;
+
+	dm_free(dmt->dev_name);
+	dmt->dev_name = NULL;
+	dm_free(dmt->mangled_dev_name);
+	dmt->mangled_dev_name = NULL;
+
 	if (strlen(name) >= DM_NAME_LEN) {
-		log_error("Name \"%s\" too long", name);
-		dm_free(new_name);
+		log_error("Name \"%s\" too long.", name);
+		return 0;
+	}
+
+	if ((r = mangle_name(name, strlen(name), mangled_name,
+			     sizeof(mangled_name), mangling_mode)) < 0) {
+		log_error("Failed to mangle device name \"%s\".", name);
 		return 0;
 	}
 
-	if (new_name)
-		dmt->dev_name = new_name;
-	else if (!(dmt->dev_name = dm_strdup(name))) {
-		log_error("dm_task_set_name: strdup(%s) failed", name);
+	/* Store mangled_dev_name only if it differs from dev_name! */
+	if (r) {
+		log_debug("Device name mangled [%s]: %s --> %s",
+			  mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+			  name, mangled_name);
+		if (!(dmt->mangled_dev_name = dm_strdup(mangled_name))) {
+			log_error("_dm_task_set_name: dm_strdup(%s) failed", mangled_name);
+			return 0;
+		}
+	}
+
+	if (!(dmt->dev_name = dm_strdup(name))) {
+		log_error("_dm_task_set_name: strdup(%s) failed", name);
 		return 0;
 	}
 
 	return 1;
 }
 
+static int _dm_task_set_name_from_path(struct dm_task *dmt, const char *path,
+				       const char *name)
+{
+	char buf[PATH_MAX];
+	struct stat st1, st2;
+	const char *final_name;
+
+	if (dmt->type == DM_DEVICE_CREATE) {
+		log_error("Name \"%s\" invalid. It contains \"/\".", path);
+		return 0;
+	}
+
+	if (stat(path, &st1)) {
+		log_error("Device %s not found", path);
+		return 0;
+	}
+
+	/*
+	 * If supplied path points to same device as last component
+	 * under /dev/mapper, use that name directly.  Otherwise call
+	 * _find_dm_name_of_device() to scan _dm_dir for a match.
+	 */
+	if (dm_snprintf(buf, sizeof(buf), "%s/%s", _dm_dir, name) == -1) {
+		log_error("Couldn't create path for %s", name);
+		return 0;
+	}
+
+	if (!stat(path, &st2) && (st1.st_rdev == st2.st_rdev))
+		final_name = name;
+	else if (_find_dm_name_of_device(st1.st_rdev, buf, sizeof(buf)))
+		final_name = buf;
+	else {
+		log_error("Device %s not found", name);
+		return 0;
+	}
+
+	/* This is an already existing path - do not mangle! */
+	return _dm_task_set_name(dmt, final_name, DM_STRING_MANGLING_NONE);
+}
+
+int dm_task_set_name(struct dm_task *dmt, const char *name)
+{
+	char *pos;
+
+	/* Path supplied for existing device? */
+	if ((pos = strrchr(name, '/')))
+		return _dm_task_set_name_from_path(dmt, name, pos + 1);
+
+	return _dm_task_set_name(dmt, name, dm_get_name_mangling_mode());
+}
+
+const char *dm_task_get_name(const struct dm_task *dmt)
+{
+	return (dmt->dmi.v4->name);
+}
+
 int dm_task_set_newname(struct dm_task *dmt, const char *newname)
 {
+	dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
+	char mangled_name[DM_NAME_LEN];
+	int r;
+
 	if (strchr(newname, '/')) {
 		log_error("Name \"%s\" invalid. It contains \"/\".", newname);
 		return 0;
@@ -354,10 +506,24 @@
 		return 0;
 	}
 
+	if ((r = mangle_name(newname, strlen(newname), mangled_name,
+			     sizeof(mangled_name), mangling_mode)) < 0) {
+		log_error("Failed to mangle new device name \"%s\"", newname);
+		return 0;
+	}
+
+	if (r) {
+		log_debug("New device name mangled [%s]: %s --> %s",
+			  mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+			  newname, mangled_name);
+		newname = mangled_name;
+	}
+
 	if (!(dmt->newname = dm_strdup(newname))) {
 		log_error("dm_task_set_newname: strdup(%s) failed", newname);
 		return 0;
 	}
+
 	dmt->new_uuid = 0;
 
 	return 1;
--- LVM2/libdm/libdm-common.h	2012/01/09 12:26:15	1.10
+++ LVM2/libdm/libdm-common.h	2012/02/15 11:27:02	1.11
@@ -18,6 +18,9 @@
 
 #include "libdevmapper.h"
 
+int mangle_name(const char *str, size_t len, char *buf,
+		size_t buf_len, dm_string_mangling_t mode);
+
 struct target *create_target(uint64_t start,
 			     uint64_t len,
 			     const char *type, const char *params);
--- LVM2/libdm/ioctl/libdm-iface.c	2012/02/08 12:59:20	1.134
+++ LVM2/libdm/ioctl/libdm-iface.c	2012/02/15 11:27:02	1.135
@@ -450,6 +450,7 @@
 
 	_dm_zfree_dmi(dmt->dmi.v4);
 	dm_free(dmt->dev_name);
+	dm_free(dmt->mangled_dev_name);
 	dm_free(dmt->newname);
 	dm_free(dmt->message);
 	dm_free(dmt->geometry);
@@ -674,11 +675,6 @@
 				       MINOR(dmt->dmi.v4->dev), read_ahead);
 }
 
-const char *dm_task_get_name(const struct dm_task *dmt)
-{
-	return (dmt->dmi.v4->name);
-}
-
 const char *dm_task_get_uuid(const struct dm_task *dmt)
 {
 	return (dmt->dmi.v4->uuid);
--- LVM2/libdm/ioctl/libdm-targets.h	2011/10/19 16:36:02	1.33
+++ LVM2/libdm/ioctl/libdm-targets.h	2012/02/15 11:27:02	1.34
@@ -33,6 +33,7 @@
 struct dm_task {
 	int type;
 	char *dev_name;
+	char *mangled_dev_name;
 
 	struct target *head, *tail;
 


             reply	other threads:[~2012-02-15 11:27 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-02-15 11:27 prajnoha [this message]
  -- strict thread matches above, loose matches on Subject: below --
2012-03-02 17:31 zkabelac
2012-02-23 22:45 zkabelac
2012-02-15 12:23 prajnoha
2012-02-15 11:39 prajnoha
2012-01-11 12:34 prajnoha
2011-12-21 12:47 zkabelac
2011-09-29  8:53 zkabelac
2011-09-22 17:36 prajnoha
2011-09-22 17:23 prajnoha
2011-09-22 17:17 prajnoha
2011-09-22 17:09 prajnoha
2011-08-19 16:26 agk
2011-03-10 12:48 zkabelac
2011-02-18 14:38 zkabelac
2011-02-04 16:08 mbroz
2011-01-04 14:43 prajnoha
2010-10-25 13:13 zkabelac
2010-10-15  1:10 agk
2010-04-28 13:37 prajnoha
2009-11-13 12:43 prajnoha
2009-10-22 12:55 prajnoha
2009-06-03 11:40 agk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120215112703.11213.qmail@sourceware.org \
    --to=prajnoha@sourceware.org \
    --cc=lvm-devel@redhat.com \
    --cc=lvm2-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).