commit: 71488732777247defa6ec1654ab50d56124bb0db
parent 6640362d9df83900ffc23d7d966daaa611ad9fa5
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Wed, 24 Apr 2024 20:20:49 +0200
cmd/readlink: new
Diffstat:
3 files changed, 161 insertions(+), 0 deletions(-)
diff --git a/cmd/readlink.1 b/cmd/readlink.1
@@ -0,0 +1,56 @@
+.\" utils-std: Collection of commonly available Unix tools
+.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+.\" SPDX-License-Identifier: MPL-2.0
+.Dd 2024-04-24
+.Dt READLINK 1
+.Os
+.Sh NAME
+.Nm readlink
+.Nd print content of a symbolic link
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Ar path
+.Sh DESCRIPTION
+Note: For canonicalization of a path, see the
+.Xr realpath 1
+utility instead.
+.Pp
+The
+.Nm
+utility reads the symbolic link of
+.Ar path
+and prints it.
+.Pp
+If
+.Ar path
+is not a symbolic link,
+.Nm
+errors out.
+.Sh OPTIONS
+.Bl -tag -width ee
+.It Fl n
+Do not print a trailing newline.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Assign
+.Pa //example.org/
+to
+.Pa foobar
+and read it:
+.Bd -literal
+$ ln -s //example.org/ foobar
+$ readlink foobar
+//example.org/
+.Ed
+.Sh SEE ALSO
+.Xr ln 1 ,
+.Xr readlink 3
+.Sh STANDARDS
+.Nm
+should be compliant with
+IEEE P1003.1-202x/D4 (“POSIX.1”).
+.Sh AUTHORS
+.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/readlink.c b/cmd/readlink.c
@@ -0,0 +1,68 @@
+// utils-std: Collection of commonly available Unix tools
+// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <errno.h>
+#include <limits.h> // PATH_MAX
+#include <stdbool.h>
+#include <stdio.h> // fprintf
+#include <string.h> // strerror
+#include <unistd.h> // getopt
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: readlink [-n] file\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ bool newline = true;
+
+ int c = -1;
+ while((c = getopt(argc, argv, ":n")) != -1)
+ {
+ switch(c)
+ {
+ case 'n':
+ newline = false;
+ break;
+ case ':':
+ fprintf(stderr, "readlink: Error: Missing operand for option: '-%c'\n", optopt);
+ usage();
+ return 1;
+ case '?':
+ fprintf(stderr, "readlink: Error: Unrecognised option: '-%c'\n", optopt);
+ usage();
+ return 1;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if(argc != 1)
+ {
+ fprintf(stderr, "readlink: Expected one file as argument, got %d\n", argc);
+ usage();
+ return 1;
+ }
+
+ char buf[PATH_MAX] = "";
+ if(readlink(argv[0], buf, sizeof(buf) - 1) < 0)
+ {
+ fprintf(stderr,
+ "readlink: Error: Failed reading symbolic link of '%s': %s\n",
+ argv[0],
+ strerror(errno));
+ return 1;
+ }
+
+ printf("%s", buf);
+ if(newline) printf("\n");
+
+ return 0;
+}
diff --git a/test-cmd/readlink.t b/test-cmd/readlink.t
@@ -0,0 +1,37 @@
+#!/usr/bin/env cram
+# SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+# SPDX-License-Identifier: MPL-2.0
+
+ $ export PATH="$TESTDIR/../cmd:$PATH"
+
+ $ test "$(command -v readlink)" = "$TESTDIR/../cmd/readlink"
+
+ $ ln -s //example.org/ foobar
+ $ readlink foobar
+ //example.org/
+ $ readlink -n foobar
+ //example.org/ (no-eol)
+
+ $ readlink
+ readlink: Expected one file as argument, got 0
+ Usage: readlink [-n] file
+ [1]
+ $ readlink foo bar
+ readlink: Expected one file as argument, got 2
+ Usage: readlink [-n] file
+ [1]
+
+ $ test ! -f enoent
+ $ readlink enoent
+ readlink: Error: Failed reading symbolic link of 'enoent': No such file or directory
+ [1]
+
+ $ touch regular
+ $ readlink regular
+ readlink: Error: Failed reading symbolic link of 'regular': Invalid argument
+ [1]
+
+ $ mkdir dir
+ $ readlink dir
+ readlink: Error: Failed reading symbolic link of 'dir': Invalid argument
+ [1]