Module Name:    src
Committed By:   mlelstv
Date:           Fri Sep 12 07:59:37 UTC 2014

Modified Files:
        src/lib/libutil: getdiskrawname.c

Log Message:
- use a private buffer to resolve symlinks, the previous code was broken
- factored out symlink handling
- handle relative symlinks now
- handle device paths that do not contain a '/'.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/lib/libutil/getdiskrawname.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libutil/getdiskrawname.c
diff -u src/lib/libutil/getdiskrawname.c:1.2 src/lib/libutil/getdiskrawname.c:1.3
--- src/lib/libutil/getdiskrawname.c:1.2	Sun Dec 22 14:31:51 2013
+++ src/lib/libutil/getdiskrawname.c	Fri Sep 12 07:59:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: getdiskrawname.c,v 1.2 2013/12/22 14:31:51 mlelstv Exp $	*/
+/*	$NetBSD: getdiskrawname.c,v 1.3 2014/09/12 07:59:36 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: getdiskrawname.c,v 1.2 2013/12/22 14:31:51 mlelstv Exp $");
+__RCSID("$NetBSD: getdiskrawname.c,v 1.3 2014/09/12 07:59:36 mlelstv Exp $");
 
 #include <sys/stat.h>
 
@@ -37,25 +37,51 @@ __RCSID("$NetBSD: getdiskrawname.c,v 1.2
 #include <string.h>
 #include <errno.h>
 #include <util.h>
+#include <limits.h>
 #include <unistd.h>
 
+static const char *
+resolve_link(char *buf, size_t bufsiz, const char *name)
+{
+	const char *dp;
+	ssize_t nlen, dlen;
+
+	dlen = readlink(name, buf, bufsiz-1);
+	if (dlen == -1)
+		return name;
+
+	buf[dlen] = '\0';
+
+	if (buf[0] != '/') {
+		dp = strrchr(name, '/');
+		if (dp != NULL) {
+			nlen = dp - name + 1;
+			if (nlen + 1 > PATH_MAX)
+				return NULL;
+			if (nlen + dlen + 1 > PATH_MAX)
+				return NULL;
+
+			memmove(buf+nlen, buf, dlen+1);
+			memcpy(buf, name, nlen);
+		}
+	}
+
+	return buf;
+}
+
 const char *
 getdiskrawname(char *buf, size_t bufsiz, const char *name)
 {
-	const char *dp = strrchr(name, '/');
+	const char *dp;
 	struct stat st;
-	ssize_t len;
+	char dest[PATH_MAX];
 
-	if (dp == NULL) {
+	if ((name = resolve_link(dest, sizeof(dest), name)) == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
-	len = readlink(name, buf, bufsiz-1);
-	if (len > 0) {
-		buf[len] = '\0';
-		name = buf;
-	}
+	dp = strrchr(name, '/');
 
 	if (stat(name, &st) == -1)
 		return NULL;
@@ -65,7 +91,10 @@ getdiskrawname(char *buf, size_t bufsiz,
 		return NULL;
 	}
 
-	(void)snprintf(buf, bufsiz, "%.*s/r%s", (int)(dp - name), name, dp + 1);
+	if (dp != NULL)
+		(void)snprintf(buf, bufsiz, "%.*s/r%s", (int)(dp - name), name, dp + 1);
+	else
+		(void)snprintf(buf, bufsiz, "r%s", name);
 
 	return buf;
 }
@@ -75,17 +104,18 @@ getdiskcookedname(char *buf, size_t bufs
 {
 	const char *dp;
 	struct stat st;
-	ssize_t len;
+	char dest[PATH_MAX];
 
-	if ((dp = strrchr(name, '/')) == NULL) {
+	if ((name = resolve_link(dest, sizeof(dest), name)) == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
-	len = readlink(name, buf, bufsiz-1);
-	if (len > 0) {
-		buf[len] = '\0';
-		name = buf;
+	dp = strrchr(name, '/');
+
+	if ((dp != NULL && dp[1] != 'r') || (dp == NULL && name[0] != 'r')) {
+		errno = EINVAL;
+		return NULL;
 	}
 
 	if (stat(name, &st) == -1)
@@ -96,12 +126,10 @@ getdiskcookedname(char *buf, size_t bufs
 		return NULL;
 	}
 
-	if (dp[1] != 'r') {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	(void)snprintf(buf, bufsiz, "%.*s/%s", (int)(dp - name), name, dp + 2);
+	if (dp != NULL)
+		(void)snprintf(buf, bufsiz, "%.*s/%s", (int)(dp - name), name, dp + 2);
+	else
+		(void)snprintf(buf, bufsiz, "%s", name + 1);
 
 	return buf;
 }

Reply via email to