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