---
readlink.1 | 53 ++++++++------
readlink.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 210 insertions(+), 78 deletions(-)
diff --git a/readlink.1 b/readlink.1
index 43ac58a..e279753 100644
--- a/readlink.1
+++ b/readlink.1
_AT_@ -1,33 +1,46 @@
-.Dd 2015-10-08
+.Dd 2015-11-14
.Dt READLINK 1
.Os sbase
.Sh NAME
.Nm readlink
-.Nd print symbolic link target or canonical file name
+.Nd Print resolved symbolic links or canonical paths
.Sh SYNOPSIS
.Nm
-.Op Fl e | Fl f | Fl m
-.Op Fl n
-.Ar path
+.Op Fl f | m
+.Op Fl n | z
+.Op Fl q
+.Ar file
+.Op file ...
.Sh DESCRIPTION
.Nm
-writes the target of
-.Ar path ,
-if it is a symbolic link, to stdout.
-If not,
-.Nm
-exits with a non-zero return value.
+prints the target of a symbolic link (default) or canonical path for each given
+.Ar file
+(
+.Fl f
+or
+.Fl m
+)
.Sh OPTIONS
.Bl -tag -width Ds
-.It Fl e | Fl f | Fl m
-Canonicalize
-.Ar name ,
-which needn't be a symlink,
-by recursively following every symlink in its path components.
-All | All but the last | No path components must exist.
-.It Fl n
-Do not print the terminating newline.
+.It Fl f
+All but the last path components must exist.
+.Fl f
+is identical to
+.Xr realpath 1
+default behavior.
+.It Fl m
+None of the path components must exist.
+.It Fl n | Fl z
+Newline | NUL is printed after each resolved path.
+.It Fl q
+Suppress error messages. Exit status will indicate if errors were encountered.
.El
+.Sh EXIT STATUS
+.Bl -tag -width Ds
+.It 0
+All paths were successfully resolved.
+.It 1
+An error was encountered resolving at least one of the given paths.
.Sh SEE ALSO
-.Xr readlink 2 ,
+.Xr readlink 3
.Xr realpath 3
diff --git a/readlink.c b/readlink.c
index 8d2a98d..b231467 100644
--- a/readlink.c
+++ b/readlink.c
_AT_@ -1,92 +1,211 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
-
-#include <libgen.h>
-#include <unistd.h>
-#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "util.h"
+static int efmflag = 0;
+static int nflag = 0;
+static int qflag = 0;
+static int zflag = 0;
+
static void
usage(void)
{
- eprintf("usage: %s [-e | -f | -m] [-n] path\n", argv0);
+ eprintf("usage: %s [-f | -m] [-z | -n] [q] file [file ...]\n", argv0);
+}
+
+char *
+realpathm(const char * path, char * resolvedpath) {
+ const char *p = path;
+ char buf1[PATH_MAX] = {0}, buf2[PATH_MAX] = {0},
+ *a = buf1, *b = buf2, *ret = resolvedpath;
+ int i = 0, m = 0;
+
+ if (!*p) {
+ errno = ENOENT;
+ ret = NULL;
+ goto badpath;
+ }
+
+ if (strnlen(path, PATH_MAX) == PATH_MAX) {
+ errno = ENAMETOOLONG;
+ ret = NULL;
+ goto badpath;
+ }
+
+ if (*p == '/') {
+ p++;
+ } else {
+ if (!realpath(".", a)) {
+ ret = NULL;
+ goto badpath;
+ }
+ }
+ strcat(a, "/");
+
+ while (*p) {
+ i = strlen(a);
+ while (*p && *p != '/') {
+ if (i >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ ret = NULL;
+ goto badpath;
+ }
+ a[i++] = *p++;
+ }
+ a[i] = '\0';
+ if (*p)
+ ++p;
+ if (i > 2 && !strcmp(&a[i-3], "/..")) {
+ if (m)
+ --m;
+ if (i == 3) {
+ strcpy(a, "/");
+ i = 1;
+ }
+ else {
+ i -= 3;
+ while (i > 0 && a[--i] != '/') ;
+ a[i] = '\0';
+ }
+ } else if (i > 1 && !strcmp(&a[i-2], "/.")) {
+ if (i == 2) {
+ strcpy(a, "/");
+ i = 1;
+ } else {
+ i -= 2;
+ a[i] = '\0';
+ }
+ } else if (a[i] == '/') {
+ if (i > 1)
+ a[--i] = '\0';
+ } else if (m) {
+ ++m;
+ } else if (!realpath(a, b)) {
+ if (errno == ENOENT) {
+ ++m;
+ } else {
+ ret = NULL;
+ goto badpath;
+ }
+ } else if (a == buf1) {
+ a = buf2;
+ b = buf1;
+ } else {
+ a = buf1;
+ b = buf2;
+ }
+ if (a[i-1] != '/' && strlcat(a, "/", PATH_MAX) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ ret = NULL;
+ goto badpath;
+ }
+ }
+ i = strlen(a)-1;
+ if (a[i] == '/')
+ a[i] = '\0';
+ if (!ret)
+ ret = emalloc(PATH_MAX);
+ estrlcpy(ret, a, PATH_MAX);
+
+badpath:
+ return ret;
}
int
main(int argc, char *argv[])
{
- struct stat st;
- ssize_t n;
- int nflag = 0, mefflag = 0;
- char buf1[PATH_MAX], buf2[PATH_MAX], arg[PATH_MAX],
- *p, *slash, *prefix, *lp, *b = buf1;
+ int i, n, e = 0, ret = 0;
+ char rp[PATH_MAX], tmp[PATH_MAX], le, *p;
+ struct stat s;
ARGBEGIN {
- case 'm':
case 'e':
case 'f':
- mefflag = ARGC();
+ case 'm':
+ efmflag = ARGC();
break;
case 'n':
nflag = 1;
break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
default:
usage();
} ARGEND
- if (argc != 1)
+ if (!argc)
usage();
- if (strlen(argv[0]) >= PATH_MAX)
- eprintf("path too long\n");
-
- switch (mefflag) {
- case 'm':
- slash = strchr(argv[0], '/');
- prefix = (slash == argv[0]) ? "/" : (!slash) ? "./" : "";
-
- estrlcpy(arg, prefix, sizeof(arg));
- estrlcat(arg, argv[0], sizeof(arg));
-
- for (lp = "", p = arg + (argv[0][0] == '/'); *p; p++) {
- if (*p != '/')
- continue;
- *p = '\0';
- if (!realpath(arg, b)) {
- *p = '/';
- goto mdone;
+ if (zflag)
+ le = '\0';
+ else if (!nflag)
+ le = '\n';
+ for (i = 0; i < argc; i++) {
+ switch (efmflag) {
+ case 'e':
+ if (!realpath(argv[i], rp)) {
+ if (!qflag)
+ weprintf("realpath '%s':", argv[i]);
+ e = 1;
}
- b = (b == buf1) ? buf2 : buf1;
- lp = p;
- *p = '/';
+ break;
+ case 'm':
+ if (!realpathm(argv[i], rp)) {
+ if (!qflag)
+ weprintf("realpathm '%s':", argv[i]);
+ e = 1;
+ }
+ break;
+ case 'f':
+ if (!realpathm(argv[i], rp)) {
+ if (!qflag)
+ weprintf("realpathm '%s':", argv[i]);
+ e = 1;
+ } else {
+ p = strrchr(rp, '/');
+ if (p == rp)
+ p = NULL;
+ }
+ if (p) {
+ *p = '\0';
+ if (stat(rp, &s) < 0) {
+ if (!qflag)
+ weprintf("stat '%s':", rp);
+ e = 1;
+ break;
+ } else {
+ *p = '/';
+ }
+ }
+ break;
+ default:
+ if ((n = readlink(argv[i], rp, PATH_MAX-1)) < 0) {
+ if (!qflag)
+ weprintf("readlink '%s':", argv[i]);
+ e = 1;
+ } else {
+ rp[n] = '\0';
+ }
+ break;
}
- if (!realpath(arg, b)) {
-mdone:
- b = (b == buf1) ? buf2 : buf1;
- estrlcat(b, lp, sizeof(arg));
+ if (e) {
+ ret = 1;
+ e = 0;
+ } else {
+ fputs(rp, stdout);
+ putchar(le);
}
- break;
- case 'e':
- if (stat(argv[0], &st) < 0)
- eprintf("stat %s:", argv[0]);
- if (!realpath(argv[0], b))
- eprintf("realpath %s:", argv[0]);
- break;
- case 'f':
- if (!realpath(argv[0], b))
- eprintf("realpath %s:", argv[0]);
- break;
- default:
- if ((n = readlink(argv[0], b, PATH_MAX - 1)) < 0)
- eprintf("readlink %s:", argv[0]);
- b[n] = '\0';
}
- fputs(b, stdout);
- if (!nflag)
- putchar('\n');
-
- return fshut(stdout, "<stdout>");
+ return ret;
}
--
2.3.6
--NyChO5MpGs3JHJbz--
Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Wed Nov 18 2015 - 05:12:09 CET