summaryrefslogtreecommitdiffstats
path: root/usr.bin/readlink
diff options
context:
space:
mode:
authorniklas <niklas@openbsd.org>1997-09-23 20:13:21 +0000
committerniklas <niklas@openbsd.org>1997-09-23 20:13:21 +0000
commitbf4941a2e6ff37b34e2b9b6faa669f8233d81b24 (patch)
tree689821f50295998cc711aa09943da9468b77b51f /usr.bin/readlink
parentMake disksubr byte order independent. This code is now so generic that it (diff)
downloadwireguard-openbsd-bf4941a2e6ff37b34e2b9b6faa669f8233d81b24.tar.xz
wireguard-openbsd-bf4941a2e6ff37b34e2b9b6faa669f8233d81b24.zip
Add -f option to follow all symlinks recursively in a pathname
Diffstat (limited to 'usr.bin/readlink')
-rw-r--r--usr.bin/readlink/readlink.17
-rw-r--r--usr.bin/readlink/readlink.c88
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;
+ }
+}