| /* vi: set sw=4 ts=4: */ | |
| /* | |
| * Mini readlink implementation for busybox | |
| * | |
| * Copyright (C) 2000,2001 Matt Kraai <kraai@alumni.carnegiemellon.edu> | |
| * | |
| * Licensed under GPLv2 or later, see file LICENSE in this source tree. | |
| */ | |
| //config:config READLINK | |
| //config: bool "readlink (4 kb)" | |
| //config: default y | |
| //config: help | |
| //config: This program reads a symbolic link and returns the name | |
| //config: of the file it points to | |
| //config: | |
| //config:config FEATURE_READLINK_FOLLOW | |
| //config: bool "Enable canonicalization by following all symlinks (-f)" | |
| //config: default y | |
| //config: depends on READLINK | |
| //config: help | |
| //config: Enable the readlink option (-f). | |
| //applet:IF_READLINK(APPLET_NOFORK(readlink, readlink, BB_DIR_USR_BIN, BB_SUID_DROP, readlink)) | |
| //kbuild:lib-$(CONFIG_READLINK) += readlink.o | |
| //usage:#define readlink_trivial_usage | |
| //usage: IF_FEATURE_READLINK_FOLLOW("[-fnv] ") "FILE" | |
| //usage:#define readlink_full_usage "\n\n" | |
| //usage: "Display the value of a symlink" | |
| //usage: IF_FEATURE_READLINK_FOLLOW( "\n" | |
| //usage: "\n -f Canonicalize by following all symlinks" | |
| //usage: "\n -n Don't add newline" | |
| //usage: "\n -v Verbose" | |
| //usage: ) | |
| #include "libbb.h" | |
| /* | |
| * # readlink --version | |
| * readlink (GNU coreutils) 6.10 | |
| * # readlink --help | |
| * -f, --canonicalize | |
| * canonicalize by following every symlink in | |
| * every component of the given name recursively; | |
| * all but the last component must exist | |
| * -e, --canonicalize-existing | |
| * canonicalize by following every symlink in | |
| * every component of the given name recursively, | |
| * all components must exist | |
| * -m, --canonicalize-missing | |
| * canonicalize by following every symlink in | |
| * every component of the given name recursively, | |
| * without requirements on components existence | |
| * -n, --no-newline do not output the trailing newline | |
| * -q, --quiet, -s, --silent suppress most error messages | |
| * -v, --verbose report error messages | |
| * | |
| * bbox supports: -f (partially) -n -v (fully), -q -s (accepts but ignores) | |
| * Note: we export the -f flag, but our -f behaves like coreutils' -e. | |
| * Unfortunately, there isn't a C lib function we can leverage to get this | |
| * behavior which means we'd have to implement the full stack ourselves :(. | |
| */ | |
| int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int readlink_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| char *buf; | |
| char *fname; | |
| IF_FEATURE_READLINK_FOLLOW( | |
| unsigned opt; | |
| /* We need exactly one non-option argument. */ | |
| opt = getopt32(argv, "^" "fnvsq" "\0" "=1"); | |
| fname = argv[optind]; | |
| ) | |
| IF_NOT_FEATURE_READLINK_FOLLOW( | |
| const unsigned opt = 0; | |
| if (argc != 2) bb_show_usage(); | |
| fname = argv[1]; | |
| ) | |
| /* compat: coreutils readlink reports errors silently via exit code */ | |
| if (!(opt & 4)) /* not -v */ | |
| logmode = LOGMODE_NONE; | |
| /* NOFORK: only one alloc is allowed; must free */ | |
| if (opt & 1) { /* -f */ | |
| buf = xmalloc_realpath_coreutils(fname); | |
| } else { | |
| buf = xmalloc_readlink_or_warn(fname); | |
| } | |
| if (!buf) | |
| return EXIT_FAILURE; | |
| printf((opt & 2) ? "%s" : "%s\n", buf); | |
| free(buf); | |
| fflush_stdout_and_exit(EXIT_SUCCESS); | |
| } |