diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/readlink/readlink.1 | 7 | ||||
-rw-r--r-- | usr.bin/readlink/readlink.c | 88 |
2 files changed, 84 insertions, 11 deletions
diff --git a/usr.bin/readlink/readlink.1 b/usr.bin/readlink/readlink.1 index e9176153a47..5bede815c65 100644 --- a/usr.bin/readlink/readlink.1 +++ b/usr.bin/readlink/readlink.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: readlink.1,v 1.2 1997/09/05 20:32:05 kstailey Exp $ +.\" $OpenBSD: readlink.1,v 1.3 1997/09/23 20:13:21 niklas Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -42,7 +42,7 @@ .Nd display target of symbolic link on standard output .Sh SYNOPSIS .Nm readlink -.Op Fl n +.Op Fl fn .Ar file .Sh DESCRIPTION The @@ -55,6 +55,9 @@ code and without printing anything. .Pp The following option is available: .Bl -tag -width flag +.It Fl f +Canonicalize by following every symlink in every component of the given +path recursively. .It Fl n Do not print a trailing newline character. .El diff --git a/usr.bin/readlink/readlink.c b/usr.bin/readlink/readlink.c index f00fd676249..d7baf64fe45 100644 --- a/usr.bin/readlink/readlink.c +++ b/usr.bin/readlink/readlink.c @@ -1,5 +1,5 @@ /* - * $OpenBSD: readlink.c,v 1.9 1997/08/18 20:27:53 kstailey Exp $ + * $OpenBSD: readlink.c,v 1.10 1997/09/23 20:13:21 niklas Exp $ * * Copyright (c) 1997 * Kenneth Stailey (hereinafter referred to as the author) @@ -28,42 +28,112 @@ */ #include <limits.h> +#include <errno.h> #include <stdio.h> +#include <string.h> #include <unistd.h> +void canonicalize __P((const char *, char *)); + int main(argc, argv) -int argc; -char **argv; + int argc; + char **argv; { char buf[PATH_MAX]; - int n, ch, nflag = 0; + int n, ch, nflag = 0, fflag = 0; extern int optind; - while ((ch = getopt(argc, argv, "n")) != -1) + while ((ch = getopt(argc, argv, "fn")) != -1) switch (ch) { + case 'f': + fflag = 1; + break; case 'n': nflag = 1; break; default: (void)fprintf(stderr, - "usage: readlink [-n] symlink\n"); + "usage: readlink [-n] [-f] symlink\n"); exit(1); } argc -= optind; argv += optind; if (argc != 1) { - fprintf(stderr, "usage: readlink [-n] symlink\n"); + fprintf(stderr, "usage: readlink [-n] [-f] symlink\n"); exit(1); } - if ((n = readlink(argv[0], buf, PATH_MAX)) < 0) + n = strlen(argv[0]); + if (n > PATH_MAX - 1) + errx(1, "filename longer than PATH_MAX-1 (%d)\n", + PATH_MAX - 1); + + if (fflag) + canonicalize(argv[0], buf); + else if ((n = readlink(argv[0], buf, PATH_MAX)) < 0) exit(1); - buf[n] = '\0'; printf("%s", buf); if (!nflag) putchar('\n'); exit(0); } + +void +canonicalize(path, newpath) + const char *path; + char *newpath; +{ + int n; + char *p, *np, *lp, c ; + char target[PATH_MAX]; + + strcpy(newpath, path); + for (;;) { + p = np = newpath; + + /* + * If absolute path, skip the root slash now so we won't + * think of this as a NULL component. + */ + if (*p == '/') + p++; + + /* + * loop through all components of the path until a link is + * found then expand it, if no link is found we are ready. + */ + for (; *p; lp = ++p) { + while (*p && *p != '/') + p++; + c = *p; + *p = '\0'; + n = readlink(newpath, target, PATH_MAX); + *p = c; + if (n > 0 || errno != EINVAL) + break; + } + if (!*p && n < 0 && errno == EINVAL) + break; + if (n < 0) + err(1, "%s", newpath); + target[n] = '\0'; +#ifdef DEBUG + fprintf(stderr, "%.*s -> %s : ", p - newpath, newpath, target); +#endif + if (*target == '/') { + bcopy(p, newpath + n, strlen(p) + 1); + bcopy(target, newpath, n); + } else { + bcopy(p, lp + n, strlen(p) + 1); + bcopy(target, lp, n); + } +#ifdef DEBUG + fprintf(stderr, "%s\n", newpath); +#endif + strcpy(target, newpath); + path = target; + } +} |