Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/realpath Make realpath(1) compat with the planned (n...
details: https://anonhg.NetBSD.org/src/rev/da562c4e7aac
branches: trunk
changeset: 368601:da562c4e7aac
user: kre <kre%NetBSD.org@localhost>
date: Thu Jul 21 09:47:31 2022 +0000
description:
Make realpath(1) compat with the planned (not yet approved) specification
for POSIX.8 (its next version). (Should the requirements change, the code
here can be updated).
This adds two new options. -e and -E
-e just tells realpath to do what it has done since it was imported here.
-E makes realpath more compatible with the coreutils version, and allows
the final component of the path to not exist (the final component after
all symlinks have been expanded, not of the arg on the command line - though
that one not existing is one case of the more general spec.).
POSIX is not going to specify which of those is the default - instead is
planning to require users to always explicitly specify one.
The default (now) here is -E. This makes us more compat with coreutils.
realpath was added in the first place because it is (apparently) used in
real world scripts - the more we can support, the better.
Note that in all cases where realpath -e succeeds, realpath -E will succeed
as well. This means that any uses of "realpath file" that have been
working in HEAD will still work. Some cases that would have failed
will work (by default) now.
diffstat:
usr.bin/realpath/realpath.1 | 65 +++++++++++++-
usr.bin/realpath/realpath.c | 192 +++++++++++++++++++++++++++++++++++++++----
2 files changed, 232 insertions(+), 25 deletions(-)
diffs (truncated from 351 to 300 lines):
diff -r e9108f910875 -r da562c4e7aac usr.bin/realpath/realpath.1
--- a/usr.bin/realpath/realpath.1 Thu Jul 21 09:19:53 2022 +0000
+++ b/usr.bin/realpath/realpath.1 Thu Jul 21 09:47:31 2022 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: realpath.1,v 1.1 2020/02/02 21:49:44 kamil Exp $
+.\" $NetBSD: realpath.1,v 1.2 2022/07/21 09:47:31 kre Exp $
.\"-
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -34,15 +34,15 @@
.\" From: src/bin/pwd/pwd.1,v 1.11 2000/11/20 11:39:39 ru Exp
.\" $FreeBSD: head/bin/realpath/realpath.1 314436 2017-02-28 23:42:47Z imp $
.\"
-.Dd February 2, 2020
+.Dd July 21, 2022
.Dt REALPATH 1
.Os
.Sh NAME
.Nm realpath
-.Nd return resolved physical path
+.Nd return resolved canonical path
.Sh SYNOPSIS
.Nm
-.Op Fl q
+.Op Fl eEq
.Op Ar path ...
.Sh DESCRIPTION
The
@@ -55,27 +55,78 @@
.Pa /./
and
.Pa /../
-in
-.Ar path .
+in each
+.Ar path ,
+and writes the result of each to standard output
+followed by a newline.
If
.Ar path
is absent, the current working directory
.Pq Sq Pa .\&
is assumed.
.Pp
+With the
+.Fl E
+option
+(the default)
+it is not an error for the final component
+of the resolved pathname to reference a file
+which does not exist.
+.Pp
+The
+.Fl e
+option reverses the effect of
+.Fl E ,
+requiring the
+.Ar path
+to resolve to an existing pathname.
+.Pp
If
.Fl q
is specified, warnings will not be printed when
.Xr realpath 3
fails.
+Messages about other errors, such as bad usage, are still printed.
+.Pp
+On error, nothing is written
+to standard output for that
+.Ar path .
+If
+.Fl q
+was not given a diagnostic is written to standard error.
.Sh EXIT STATUS
.Ex -std
+Any failure to resolve a
+.Ar path
+is an error for this purpose,
+the
+.Fl q
+option is irrelevant.
.Sh SEE ALSO
+.Xr readlink 1
.Xr realpath 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to comply with the forthcoming
+edition of the POSIX standard.
+To be fully POSIX compliant, applications must use
+either the
+.Fl e
+or
+.Fl E
+option, as which of those (if in fact either, and
+not some other behaviour) applies in their absence
+is unspecified.
+The standard requires support for only a single, mandatory,
+.Ar path
+argument.
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 4.3
and was imported into
-.Nx 10 .
+.Nx 10 ,
+but modified to be slightly more compatible with the coreutils version,
+and the proposed POSIX standard requirements.
diff -r e9108f910875 -r da562c4e7aac usr.bin/realpath/realpath.c
--- a/usr.bin/realpath/realpath.c Thu Jul 21 09:19:53 2022 +0000
+++ b/usr.bin/realpath/realpath.c Thu Jul 21 09:47:31 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: realpath.c,v 1.1 2020/02/02 21:49:44 kamil Exp $ */
+/* $NetBSD: realpath.c,v 1.2 2022/07/21 09:47:31 kre Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -35,34 +35,49 @@
#if 0
__FBSDID("$FreeBSD: head/bin/realpath/realpath.c 326025 2017-11-20 19:49:47Z pfg $");
#else
-__RCSID("$NetBSD: realpath.c,v 1.1 2020/02/02 21:49:44 kamil Exp $");
+__RCSID("$NetBSD: realpath.c,v 1.2 2022/07/21 09:47:31 kre Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
+#include <sys/stat.h>
#include <err.h>
+#include <errno.h>
#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+static bool process(char *path);
static void usage(void) __dead;
+static const char options[] = "Eeq";
+
+char dot[] = ".";
+
+bool eflag = false; /* default to -E mode */
+bool qflag = false;
+
int
main(int argc, char *argv[])
{
- char buf[PATH_MAX];
- char *p;
- const char *path;
- int ch, qflag, rval;
+ char *path;
+ int ch, rval;
setprogname(argv[0]);
- qflag = 0;
- while ((ch = getopt(argc, argv, "q")) != -1) {
+ while ((ch = getopt(argc, argv, options)) != -1) {
switch (ch) {
+ case 'e':
+ eflag = true;
+ break;
+ case 'E':
+ eflag = false;
+ break;
case 'q':
- qflag = 1;
+ qflag = true;
break;
case '?':
default:
@@ -71,23 +86,164 @@
}
argc -= optind;
argv += optind;
- path = *argv != NULL ? *argv++ : ".";
- rval = 0;
+
+ path = *argv != NULL ? *argv++ : dot;
+ rval = 0;
do {
- if ((p = realpath(path, buf)) == NULL) {
+ if (path[0] == '\0') {
+ /* ignore -q for this one */
+ warnx("Invalid path ''");
+ rval = 1;
+ continue;
+ }
+ if (!process(path))
+ rval = 1;;
+ } while ((path = *argv++) != NULL);
+ exit(rval);
+}
+
+static bool
+process(char *path)
+{
+ char buf[PATH_MAX];
+ char buf2[sizeof buf];
+ char lbuf[PATH_MAX];
+ char *pp, *p, *q, *r, *s;
+ struct stat sb;
+ bool dir_reqd = false;
+
+ if ((p = realpath(path, buf)) != NULL) {
+ (void)printf("%s\n", p);
+ return true;
+ }
+
+ if (eflag || errno != ENOENT) {
+ if (!qflag)
+ warn("%s", path);
+ return false;
+ }
+
+ p = strrchr(path, '/');
+ while (p != NULL && p > &path[1] && p[1] == '\0') {
+ dir_reqd = true;
+ *p = '\0';
+ p = strrchr(path, '/');
+ }
+
+ if (p == NULL) {
+ p = realpath(".", buf);
+ if ((size_t)snprintf(buf2, sizeof buf2, "%s/%s", buf, path)
+ >= sizeof buf2) {
+ if (!qflag)
+ warnx("%s/%s: path too long", p, path);
+ return false;
+ }
+ path = buf2;
+ p = strrchr(path, '/');
+ if (p == NULL)
+ abort();
+ }
+
+ *p = '\0';
+ pp = ++p;
+
+ q = path; r = buf; s = buf2;
+ while (realpath(*q ? q : "/", r) != NULL) {
+ ssize_t llen;
+
+ if (strcmp(r, "/") == 0 || strcmp(r, "//") == 0)
+ r++;
+ if ((size_t)snprintf(s, sizeof buf, "%s/%s", r, pp)
+ >= sizeof buf)
+ return false;
+
+ if (lstat(s, &sb) == -1 || !S_ISLNK(sb.st_mode)) {
+ (void)printf("%s\n", s);
+ return true;
+ }
+
+ q = strchr(r, '\0');
+ if (q >= &r[sizeof buf - 3]) {
+ *p = '/';
+ if (!qflag)
+ warnx("Expanded path for %s too long\n", path);
+ return false;
+ }
+
+ if ((llen = readlink(s, lbuf, sizeof lbuf - 2)) == -1) {
+ *p = '/';
if (!qflag)
warn("%s", path);
- rval = 1;
- } else
- (void)printf("%s\n", p);
- } while ((path = *argv++) != NULL);
- exit(rval);
+ return false;
+ }
+ lbuf[llen] = '\0';
+
+ if (lbuf[0] == '/') {
+ q = lbuf;
+ if (dir_reqd) {
+ lbuf[llen++] = '/';
+ lbuf[llen] = '\0';
+ }
+ } else {
+ if (q != buf2) {
+ q = buf2;
+ r = buf;
+ } else {
+ q = buf;
+ r = buf2;
+ }
+
+ if ((size_t)snprintf(q, sizeof buf, "%s/%s%s", r, lbuf,
+ (dir_reqd ? "/" : "")) >= sizeof buf) {
+ *p = '/';
+ if (!qflag)
Home |
Main Index |
Thread Index |
Old Index