diff options
| author | mlelstv <mlelstv@NetBSD.org> | 2014-09-12 07:59:36 +0000 |
|---|---|---|
| committer | mlelstv <mlelstv@NetBSD.org> | 2014-09-12 07:59:36 +0000 |
| commit | 7ea191e42eb36928d5f6d702fefdaf5a97643ce3 (patch) | |
| tree | 90c16bb4c25c8c5fabc86e08b20103fcb1b662a7 /lib/libutil | |
| parent | a743bc13d6ba077a292bfd809b539e3dd523d71e (diff) | |
- 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 '/'.
Diffstat (limited to 'lib/libutil')
| -rw-r--r-- | lib/libutil/getdiskrawname.c | 74 |
1 files changed, 51 insertions, 23 deletions
diff --git a/lib/libutil/getdiskrawname.c b/lib/libutil/getdiskrawname.c index ed1c21a40dc..d3089d52aa2 100644 --- a/lib/libutil/getdiskrawname.c +++ b/lib/libutil/getdiskrawname.c @@ -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 2013/12/22 14:31:51 mlelstv Exp $"); #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, const char *name) 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 bufsiz, const char *name) { 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 bufsiz, const char *name) 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; } |
