blob: 1b223b3c52254fedd1a49821a4316310c2e6791e
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 GPLv2 or later, see file LICENSE in this source tree. |
8 | */ |
9 | //config:config READLINK |
10 | //config: bool "readlink" |
11 | //config: default y |
12 | //config: help |
13 | //config: This program reads a symbolic link and returns the name |
14 | //config: of the file it points to |
15 | //config: |
16 | //config:config FEATURE_READLINK_FOLLOW |
17 | //config: bool "Enable canonicalization by following all symlinks (-f)" |
18 | //config: default y |
19 | //config: depends on READLINK |
20 | //config: help |
21 | //config: Enable the readlink option (-f). |
22 | |
23 | //applet:IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) |
24 | |
25 | //kbuild:lib-$(CONFIG_READLINK) += readlink.o |
26 | |
27 | //usage:#define readlink_trivial_usage |
28 | //usage: IF_FEATURE_READLINK_FOLLOW("[-fnv] ") "FILE" |
29 | //usage:#define readlink_full_usage "\n\n" |
30 | //usage: "Display the value of a symlink" |
31 | //usage: IF_FEATURE_READLINK_FOLLOW( "\n" |
32 | //usage: "\n -f Canonicalize by following all symlinks" |
33 | //usage: "\n -n Don't add newline" |
34 | //usage: "\n -v Verbose" |
35 | //usage: ) |
36 | |
37 | #include "libbb.h" |
38 | |
39 | /* |
40 | * # readlink --version |
41 | * readlink (GNU coreutils) 6.10 |
42 | * # readlink --help |
43 | * -f, --canonicalize |
44 | * canonicalize by following every symlink in |
45 | * every component of the given name recursively; |
46 | * all but the last component must exist |
47 | * -e, --canonicalize-existing |
48 | * canonicalize by following every symlink in |
49 | * every component of the given name recursively, |
50 | * all components must exist |
51 | * -m, --canonicalize-missing |
52 | * canonicalize by following every symlink in |
53 | * every component of the given name recursively, |
54 | * without requirements on components existence |
55 | * -n, --no-newline do not output the trailing newline |
56 | * -q, --quiet, -s, --silent suppress most error messages |
57 | * -v, --verbose report error messages |
58 | * |
59 | * bbox supports: -f (partially) -n -v (fully), -q -s (accepts but ignores) |
60 | * Note: we export the -f flag, but our -f behaves like coreutils' -e. |
61 | * Unfortunately, there isn't a C lib function we can leverage to get this |
62 | * behavior which means we'd have to implement the full stack ourselves :(. |
63 | */ |
64 | |
65 | int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
66 | int readlink_main(int argc UNUSED_PARAM, char **argv) |
67 | { |
68 | char *buf; |
69 | char *fname; |
70 | |
71 | IF_FEATURE_READLINK_FOLLOW( |
72 | unsigned opt; |
73 | /* We need exactly one non-option argument. */ |
74 | opt_complementary = "=1"; |
75 | opt = getopt32(argv, "fnvsq"); |
76 | fname = argv[optind]; |
77 | ) |
78 | IF_NOT_FEATURE_READLINK_FOLLOW( |
79 | const unsigned opt = 0; |
80 | if (argc != 2) bb_show_usage(); |
81 | fname = argv[1]; |
82 | ) |
83 | |
84 | /* compat: coreutils readlink reports errors silently via exit code */ |
85 | if (!(opt & 4)) /* not -v */ |
86 | logmode = LOGMODE_NONE; |
87 | |
88 | if (opt & 1) { /* -f */ |
89 | buf = xmalloc_realpath(fname); |
90 | } else { |
91 | buf = xmalloc_readlink_or_warn(fname); |
92 | } |
93 | |
94 | if (!buf) |
95 | return EXIT_FAILURE; |
96 | printf((opt & 2) ? "%s" : "%s\n", buf); |
97 | |
98 | if (ENABLE_FEATURE_CLEAN_UP) |
99 | free(buf); |
100 | |
101 | fflush_stdout_and_exit(EXIT_SUCCESS); |
102 | } |
103 |