]> git.ipfire.org Git - thirdparty/bash.git/blob - examples/loadables/realpath.c
ef836713827ee0787a809e21f44aa1f9889a40a3
[thirdparty/bash.git] / examples / loadables / realpath.c
1 /*
2 * realpath -- canonicalize pathnames, resolving symlinks
3 *
4 * usage: realpath [-cqsv] [-a name] pathname [pathname...]
5 *
6 * options: -a name assign each canonicalized pathname to indexed array
7 * variable NAME
8 * -c check whether or not each resolved path exists
9 * -q no output, exit status determines whether path is valid
10 * -s strip . and .. from the pathname only, no symlink resolution
11 * -v produce verbose output
12 *
13 *
14 * exit status: 0 if all pathnames resolved
15 * 1 if any of the pathname arguments could not be resolved
16 *
17 *
18 * Bash loadable builtin version
19 *
20 * Chet Ramey
21 * chet@po.cwru.edu
22 */
23
24 /*
25 Copyright (C) 1999-2009,2021,2022 Free Software Foundation, Inc.
26
27 This file is part of GNU Bash.
28 Bash is free software: you can redistribute it and/or modify
29 it under the terms of the GNU General Public License as published by
30 the Free Software Foundation, either version 3 of the License, or
31 (at your option) any later version.
32
33 Bash is distributed in the hope that it will be useful,
34 but WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 GNU General Public License for more details.
37
38 You should have received a copy of the GNU General Public License
39 along with Bash. If not, see <http://www.gnu.org/licenses/>.
40 */
41
42 #include "config.h"
43
44 #include <sys/types.h>
45 #include <sys/stat.h>
46
47 #include <stdio.h>
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #include "bashansi.h"
52 #include <maxpath.h>
53 #include <errno.h>
54
55 #include "builtins.h"
56 #include "shell.h"
57 #include "bashgetopt.h"
58 #include "common.h"
59
60 #ifndef errno
61 extern int errno;
62 #endif
63
64 extern char *sh_realpath();
65
66 int
67 realpath_builtin(WORD_LIST *list)
68 {
69 int opt, cflag, vflag, qflag, sflag, aflag, es;
70 char *r, realbuf[PATH_MAX], *p, *newpath;
71 struct stat sb;
72 #if defined (ARRAY_VARS)
73 arrayind_t ind;
74 char *aname;
75 SHELL_VAR *v;
76 #endif
77
78 if (list == 0) {
79 builtin_usage();
80 return (EX_USAGE);
81 }
82
83 vflag = cflag = qflag = aflag = sflag = 0;
84 #if defined (ARRAY_VARS)
85 aname = NULL;
86 v = NULL;
87 ind = 0;
88 #endif
89 reset_internal_getopt();
90 while ((opt = internal_getopt (list, "a:cqsv")) != -1) {
91 switch (opt) {
92 #if defined (ARRAY_VARS)
93 case 'a':
94 aflag = 1;
95 aname = list_optarg;
96 break;
97 #endif
98 case 'c':
99 cflag = 1;
100 break;
101 case 'q':
102 qflag = 1;
103 break;
104 case 's':
105 sflag = 1;
106 break;
107 case 'v':
108 vflag = 1;
109 break;
110 CASE_HELPOPT;
111 default:
112 builtin_usage();
113 return (EX_USAGE);
114 }
115 }
116
117 list = loptend;
118
119 if (list == 0) {
120 builtin_usage();
121 return (EX_USAGE);
122 }
123
124 #if defined (ARRAY_VARS)
125 if (aflag && legal_identifier (aname) == 0) {
126 sh_invalidid(aname);
127 return (EXECUTION_FAILURE);
128 }
129 if (aname && builtin_unbind_variable (aname) == -2)
130 return (EXECUTION_FAILURE);
131 if (aname) {
132 v = find_or_make_array_variable (aname, 1);
133 if (v == 0 || readonly_p (v) || noassign_p (v)) {
134 if (v && readonly_p (v))
135 err_readonly (aname);
136 return (EXECUTION_FAILURE);
137 } else if (array_p (v) == 0) {
138 builtin_error ("%s: not an indexed array", aname);
139 return (EXECUTION_FAILURE);
140 }
141 if (invisible_p (v))
142 VUNSETATTR (v, att_invisible);
143 array_flush (array_cell (v));
144 }
145 #endif
146
147 for (es = EXECUTION_SUCCESS; list; list = list->next) {
148 p = list->word->word;
149 if (sflag) {
150 /* sh_canonpath doesn't convert to absolute pathnames */
151 newpath = make_absolute(p, get_string_value("PWD"));
152 r = sh_canonpath(newpath, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
153 free(newpath);
154 } else
155 r = sh_realpath(p, realbuf);
156 if (r == 0) {
157 es = EXECUTION_FAILURE;
158 if (qflag == 0)
159 builtin_error("%s: cannot resolve: %s", p, strerror(errno));
160 continue;
161 }
162 if (cflag && (stat(r, &sb) < 0)) {
163 es = EXECUTION_FAILURE;
164 if (qflag == 0)
165 builtin_error("%s: %s", p, strerror(errno));
166 continue;
167 }
168 if (aflag) {
169 bind_array_element (v, ind, r, 0);
170 ind++;
171 }
172 if (qflag == 0) {
173 if (vflag)
174 printf ("%s -> ", p);
175 printf("%s\n", r);
176 }
177 if (sflag)
178 free (r);
179 }
180 return es;
181 }
182
183 char *realpath_doc[] = {
184 "Display pathname in canonical form.",
185 "",
186 "Display the canonicalized version of each PATHNAME argument, resolving",
187 "symbolic links.",
188 "The -a option stores each canonicalized PATHNAME argument into the indexed",
189 "array VARNAME.",
190 "The -c option checks whether or not each resolved name exists.",
191 "The -q option produces no output; the exit status determines the",
192 "validity of each PATHNAME, but any array assignment is still performed.",
193 "If the -s option is supplied, canonicalize . and .. pathname components",
194 "without resolving symbolic links.",
195 "The -v option produces verbose output.",
196 "The exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
197 (char *)NULL
198 };
199
200 struct builtin realpath_struct = {
201 "realpath", /* builtin name */
202 realpath_builtin, /* function implementing the builtin */
203 BUILTIN_ENABLED, /* initial flags for builtin */
204 realpath_doc, /* array of long documentation strings */
205 "realpath [-a varname] [-cqsv] pathname [pathname...]", /* usage synopsis */
206 0 /* reserved for internal use */
207 };