1/* readlink -- display value of a symbolic link. 2 Copyright (C) 2002-2010 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17/* Written by Dmitry V. Levin */ 18 19#include <config.h> 20#include <stdio.h> 21#include <getopt.h> 22#include <sys/types.h> 23 24#include "system.h" 25#include "canonicalize.h" 26#include "error.h" 27#include "areadlink.h" 28#include "quote.h" 29 30/* The official name of this program (e.g., no `g' prefix). */ 31#define PROGRAM_NAME "readlink" 32 33#define AUTHORS proper_name ("Dmitry V. Levin") 34 35/* If true, do not output the trailing newline. */ 36static bool no_newline; 37 38/* If true, report error messages. */ 39static bool verbose; 40 41static struct option const longopts[] = 42{ 43 {"canonicalize", no_argument, NULL, 'f'}, 44 {"canonicalize-existing", no_argument, NULL, 'e'}, 45 {"canonicalize-missing", no_argument, NULL, 'm'}, 46 {"no-newline", no_argument, NULL, 'n'}, 47 {"quiet", no_argument, NULL, 'q'}, 48 {"silent", no_argument, NULL, 's'}, 49 {"verbose", no_argument, NULL, 'v'}, 50 {GETOPT_HELP_OPTION_DECL}, 51 {GETOPT_VERSION_OPTION_DECL}, 52 {NULL, 0, NULL, 0} 53}; 54 55void 56usage (int status) 57{ 58 if (status != EXIT_SUCCESS) 59 fprintf (stderr, _("Try `%s --help' for more information.\n"), 60 program_name); 61 else 62 { 63 printf (_("Usage: %s [OPTION]... FILE\n"), program_name); 64 fputs (_("Print value of a symbolic link or canonical file name\n\n"), 65 stdout); 66 fputs (_("\ 67 -f, --canonicalize canonicalize by following every symlink in\n\ 68 every component of the given name recursively;\n\ 69 all but the last component must exist\n\ 70 -e, --canonicalize-existing canonicalize by following every symlink in\n\ 71 every component of the given name recursively,\n\ 72 all components must exist\n\ 73"), stdout); 74 fputs (_("\ 75 -m, --canonicalize-missing canonicalize by following every symlink in\n\ 76 every component of the given name recursively,\n\ 77 without requirements on components existence\n\ 78 -n, --no-newline do not output the trailing newline\n\ 79 -q, --quiet,\n\ 80 -s, --silent suppress most error messages\n\ 81 -v, --verbose report error messages\n\ 82"), stdout); 83 fputs (HELP_OPTION_DESCRIPTION, stdout); 84 fputs (VERSION_OPTION_DESCRIPTION, stdout); 85 emit_ancillary_info (); 86 } 87 exit (status); 88} 89 90int 91main (int argc, char **argv) 92{ 93 /* If not -1, use this method to canonicalize. */ 94 int can_mode = -1; 95 96 /* File name to canonicalize. */ 97 const char *fname; 98 99 /* Result of canonicalize. */ 100 char *value; 101 102 int optc; 103 104 initialize_main (&argc, &argv); 105 set_program_name (argv[0]); 106 setlocale (LC_ALL, ""); 107 bindtextdomain (PACKAGE, LOCALEDIR); 108 textdomain (PACKAGE); 109 110 atexit (close_stdout); 111 112 while ((optc = getopt_long (argc, argv, "efmnqsv", longopts, NULL)) != -1) 113 { 114 switch (optc) 115 { 116 case 'e': 117 can_mode = CAN_EXISTING; 118 break; 119 case 'f': 120 can_mode = CAN_ALL_BUT_LAST; 121 break; 122 case 'm': 123 can_mode = CAN_MISSING; 124 break; 125 case 'n': 126 no_newline = true; 127 break; 128 case 'q': 129 case 's': 130 verbose = false; 131 break; 132 case 'v': 133 verbose = true; 134 break; 135 case_GETOPT_HELP_CHAR; 136 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); 137 default: 138 usage (EXIT_FAILURE); 139 } 140 } 141 142 if (optind >= argc) 143 { 144 error (0, 0, _("missing operand")); 145 usage (EXIT_FAILURE); 146 } 147 148 fname = argv[optind++]; 149 150 if (optind < argc) 151 { 152 error (0, 0, _("extra operand %s"), quote (argv[optind])); 153 usage (EXIT_FAILURE); 154 } 155 156 value = (can_mode != -1 157 ? canonicalize_filename_mode (fname, can_mode) 158 : areadlink_with_size (fname, 63)); 159 if (value) 160 { 161 printf ("%s%s", value, (no_newline ? "" : "\n")); 162 free (value); 163 return EXIT_SUCCESS; 164 } 165 166 if (verbose) 167 error (EXIT_FAILURE, errno, "%s", fname); 168 169 return EXIT_FAILURE; 170} 171