1/* vi: set sw=4 ts=4: */
2/*
3 * Mini readlink implementation for busybox
4 *
5 * Copyright (C) 2000,2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
8 */
9#include "libbb.h"
10
11/*
12 * # readlink --version
13 * readlink (GNU coreutils) 6.10
14 * # readlink --help
15 *   -f, --canonicalize
16 *      canonicalize by following every symlink in
17 *      every component of the given name recursively;
18 *      all but the last component must exist
19 *   -e, --canonicalize-existing
20 *      canonicalize by following every symlink in
21 *      every component of the given name recursively,
22 *      all components must exist
23 *   -m, --canonicalize-missing
24 *      canonicalize by following every symlink in
25 *      every component of the given name recursively,
26 *      without requirements on components existence
27 *   -n, --no-newline              do not output the trailing newline
28 *   -q, --quiet, -s, --silent     suppress most error messages
29 *   -v, --verbose                 report error messages
30 *
31 * bbox supports: -f -n -v (fully), -q -s (accepts but ignores)
32 */
33
34int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
35int readlink_main(int argc UNUSED_PARAM, char **argv)
36{
37	char *buf;
38	char *fname;
39	char pathbuf[PATH_MAX];
40
41	IF_FEATURE_READLINK_FOLLOW(
42		unsigned opt;
43		/* We need exactly one non-option argument.  */
44		opt_complementary = "=1";
45		opt = getopt32(argv, "fnvsq");
46		fname = argv[optind];
47	)
48	IF_NOT_FEATURE_READLINK_FOLLOW(
49		const unsigned opt = 0;
50		if (argc != 2) bb_show_usage();
51		fname = argv[1];
52	)
53
54	/* compat: coreutils readlink reports errors silently via exit code */
55	if (!(opt & 4)) /* not -v */
56		logmode = LOGMODE_NONE;
57
58	if (opt & 1) { /* -f */
59		buf = realpath(fname, pathbuf);
60	} else {
61		buf = xmalloc_readlink_or_warn(fname);
62	}
63
64	if (!buf)
65		return EXIT_FAILURE;
66	printf((opt & 2) ? "%s" : "%s\n", buf);
67
68	if (ENABLE_FEATURE_CLEAN_UP && !opt)
69		free(buf);
70
71	fflush_stdout_and_exit(EXIT_SUCCESS);
72}
73