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; }