]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/hash.def
Bash-5.2 patch 26: fix typo when specifying readline's custom color prefix
[thirdparty/bash.git] / builtins / hash.def
CommitLineData
726f6388
JA
1This file is hash.def, from which is created hash.c.
2It implements the builtin "hash" in Bash.
3
74091dd4 4Copyright (C) 1987-2021 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
726f6388 12
3185942a
JA
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
726f6388 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES hash.c
22
23$BUILTIN hash
24$FUNCTION hash_builtin
7117c2d2 25$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
3185942a
JA
26Remember or display program locations.
27
28Determine and remember the full pathname of each command NAME. If
29no arguments are given, information about remembered commands is displayed.
30
31Options:
a0c0a00f
CR
32 -d forget the remembered location of each NAME
33 -l display in a format that may be reused as input
ac50fbac 34 -p pathname use PATHNAME as the full pathname of NAME
a0c0a00f
CR
35 -r forget all remembered locations
36 -t print the remembered location of each NAME, preceding
3185942a
JA
37 each location with the corresponding NAME if multiple
38 NAMEs are given
39Arguments:
a0c0a00f 40 NAME Each NAME is searched for in $PATH and added to the list
3185942a
JA
41 of remembered commands.
42
43Exit Status:
44Returns success unless NAME is not found or an invalid option is given.
726f6388
JA
45$END
46
ccc6cda3
JA
47#include <config.h>
48
726f6388
JA
49#include <stdio.h>
50
cce855bc
JA
51#include "../bashtypes.h"
52
ccc6cda3
JA
53#if defined (HAVE_UNISTD_H)
54# include <unistd.h>
55#endif
56
28ef6c31
JA
57#include <errno.h>
58
ccc6cda3 59#include "../bashansi.h"
b80f6443 60#include "../bashintl.h"
726f6388
JA
61
62#include "../shell.h"
63#include "../builtins.h"
d233b485 64#include "../execute_cmd.h"
d166f048 65#include "../flags.h"
cce855bc 66#include "../findcmd.h"
d166f048 67#include "../hashcmd.h"
726f6388 68#include "common.h"
ccc6cda3 69#include "bashgetopt.h"
726f6388
JA
70
71extern int dot_found_in_search;
ccc6cda3 72
8868edaf
CR
73static int add_hashed_command PARAMS((char *, int));
74static int print_hash_info PARAMS((BUCKET_CONTENTS *));
75static int print_portable_hash_info PARAMS((BUCKET_CONTENTS *));
76static int print_hashed_commands PARAMS((int));
77static int list_hashed_filename_targets PARAMS((WORD_LIST *, int));
ccc6cda3 78
726f6388
JA
79/* Print statistics on the current state of hashed commands. If LIST is
80 not empty, then rehash (or hash in the first place) the specified
81 commands. */
ccc6cda3 82int
726f6388
JA
83hash_builtin (list)
84 WORD_LIST *list;
85{
7117c2d2 86 int expunge_hash_table, list_targets, list_portably, delete, opt;
cce855bc 87 char *w, *pathname;
726f6388 88
ccc6cda3 89 if (hashing_enabled == 0)
726f6388 90 {
b80f6443 91 builtin_error (_("hashing disabled"));
726f6388
JA
92 return (EXECUTION_FAILURE);
93 }
94
7117c2d2 95 expunge_hash_table = list_targets = list_portably = delete = 0;
ccc6cda3
JA
96 pathname = (char *)NULL;
97 reset_internal_getopt ();
7117c2d2 98 while ((opt = internal_getopt (list, "dlp:rt")) != -1)
726f6388 99 {
ccc6cda3 100 switch (opt)
726f6388 101 {
7117c2d2
JA
102 case 'd':
103 delete = 1;
104 break;
105 case 'l':
106 list_portably = 1;
726f6388 107 break;
ccc6cda3
JA
108 case 'p':
109 pathname = list_optarg;
110 break;
7117c2d2
JA
111 case 'r':
112 expunge_hash_table = 1;
113 break;
f73dda09
JA
114 case 't':
115 list_targets = 1;
116 break;
a0c0a00f 117 CASE_HELPOPT;
ccc6cda3
JA
118 default:
119 builtin_usage ();
726f6388
JA
120 return (EX_USAGE);
121 }
726f6388 122 }
ccc6cda3 123 list = loptend;
726f6388 124
f73dda09 125 /* hash -t requires at least one argument. */
8868edaf 126 if (list == 0 && (delete || list_targets))
f73dda09 127 {
8868edaf 128 sh_needarg (delete ? "-d" : "-t");
f73dda09
JA
129 return (EXECUTION_FAILURE);
130 }
131
7117c2d2
JA
132 /* We want hash -r to be silent, but hash -- to print hashing info, so
133 we test expunge_hash_table. */
ccc6cda3 134 if (list == 0 && expunge_hash_table == 0)
726f6388 135 {
0628567a 136 opt = print_hashed_commands (list_portably);
8868edaf
CR
137 if (opt == 0 && posixly_correct == 0 &&
138 (list_portably == 0 || shell_compatibility_level <= 50))
0628567a 139 printf (_("%s: hash table empty\n"), this_command_name);
726f6388 140
74091dd4 141 return (sh_chkwrite (EXECUTION_SUCCESS));
726f6388
JA
142 }
143
144 if (expunge_hash_table)
7117c2d2 145 phash_flush ();
726f6388 146
f73dda09
JA
147 /* If someone runs `hash -r -t xyz' he will be disappointed. */
148 if (list_targets)
7117c2d2 149 return (list_hashed_filename_targets (list, list_portably));
f73dda09 150
bb70624e 151#if defined (RESTRICTED_SHELL)
d233b485 152 if (restricted && pathname)
bb70624e 153 {
d233b485
CR
154 if (strchr (pathname, '/'))
155 {
156 sh_restricted (pathname);
157 return (EXECUTION_FAILURE);
158 }
159 /* If we are changing the hash table in a restricted shell, make sure the
160 target pathname can be found using a $PATH search. */
161 w = find_user_command (pathname);
162 if (w == 0 || *w == 0 || executable_file (w) == 0)
163 {
164 sh_notfound (pathname);
165 free (w);
166 return (EXECUTION_FAILURE);
167 }
168 free (w);
bb70624e
JA
169 }
170#endif
171
ccc6cda3 172 for (opt = EXECUTION_SUCCESS; list; list = list->next)
726f6388 173 {
7117c2d2 174 /* Add, remove or rehash the specified commands. */
cce855bc 175 w = list->word->word;
495aee44
CR
176 if (absolute_program (w))
177 continue;
178 else if (pathname)
28ef6c31 179 {
74091dd4 180 if (file_isdir (pathname))
28ef6c31
JA
181 {
182#ifdef EISDIR
183 builtin_error ("%s: %s", pathname, strerror (EISDIR));
184#else
3185942a 185 builtin_error (_("%s: is a directory"), pathname);
28ef6c31
JA
186#endif
187 opt = EXECUTION_FAILURE;
188 }
189 else
7117c2d2 190 phash_insert (w, pathname, 0, 0);
28ef6c31 191 }
95732b49 192 else if (delete)
7117c2d2 193 {
95732b49
JA
194 if (phash_remove (w))
195 {
196 sh_notfound (w);
197 opt = EXECUTION_FAILURE;
198 }
7117c2d2 199 }
cce855bc 200 else if (add_hashed_command (w, 0))
d166f048 201 opt = EXECUTION_FAILURE;
726f6388
JA
202 }
203
204 fflush (stdout);
ccc6cda3 205 return (opt);
726f6388
JA
206}
207
ccc6cda3 208static int
cce855bc
JA
209add_hashed_command (w, quiet)
210 char *w;
ccc6cda3
JA
211 int quiet;
212{
213 int rv;
214 char *full_path;
215
216 rv = 0;
cce855bc 217 if (find_function (w) == 0 && find_shell_builtin (w) == 0)
ccc6cda3 218 {
495aee44 219 phash_remove (w);
cce855bc 220 full_path = find_user_command (w);
ccc6cda3 221 if (full_path && executable_file (full_path))
7117c2d2 222 phash_insert (w, full_path, dot_found_in_search, 0);
ccc6cda3
JA
223 else
224 {
225 if (quiet == 0)
7117c2d2 226 sh_notfound (w);
ccc6cda3
JA
227 rv++;
228 }
7117c2d2 229 FREE (full_path);
ccc6cda3
JA
230 }
231 return (rv);
232}
233
234/* Print information about current hashed info. */
235static int
7117c2d2
JA
236print_hash_info (item)
237 BUCKET_CONTENTS *item;
ccc6cda3 238{
7117c2d2
JA
239 printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
240 return 0;
241}
ccc6cda3 242
7117c2d2
JA
243static int
244print_portable_hash_info (item)
245 BUCKET_CONTENTS *item;
246{
a0c0a00f
CR
247 char *fp, *fn;
248
249 fp = printable_filename (pathdata(item)->path, 1);
250 fn = printable_filename (item->key, 1);
251 printf ("builtin hash -p %s %s\n", fp, fn);
252 if (fp != pathdata(item)->path)
253 free (fp);
254 if (fn != item->key)
255 free (fn);
7117c2d2
JA
256 return 0;
257}
ccc6cda3 258
7117c2d2
JA
259static int
260print_hashed_commands (fmt)
261 int fmt;
262{
263 if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
264 return (0);
ccc6cda3 265
7117c2d2 266 if (fmt == 0)
3185942a 267 printf (_("hits\tcommand\n"));
7117c2d2
JA
268 hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
269 return (1);
ccc6cda3 270}
f73dda09
JA
271
272static int
7117c2d2 273list_hashed_filename_targets (list, fmt)
f73dda09 274 WORD_LIST *list;
7117c2d2 275 int fmt;
f73dda09
JA
276{
277 int all_found, multiple;
278 char *target;
279 WORD_LIST *l;
280
281 all_found = 1;
282 multiple = list->next != 0;
283
284 for (l = list; l; l = l->next)
285 {
7117c2d2 286 target = phash_search (l->word->word);
f73dda09
JA
287 if (target == 0)
288 {
289 all_found = 0;
7117c2d2 290 sh_notfound (l->word->word);
f73dda09
JA
291 continue;
292 }
7117c2d2
JA
293 if (fmt)
294 printf ("builtin hash -p %s %s\n", target, l->word->word);
295 else
296 {
297 if (multiple)
298 printf ("%s\t", l->word->word);
299 printf ("%s\n", target);
300 }
ac50fbac 301 free (target);
f73dda09
JA
302 }
303
304 return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
305}