]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/hash.def
Bash-5.3 distribution sources and documentation
[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
b8c60bc9 4Copyright (C) 1987-2024 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 70
b8c60bc9
CR
71static int add_hashed_command (char *, int);
72static int print_hash_info (BUCKET_CONTENTS *);
73static int print_portable_hash_info (BUCKET_CONTENTS *);
74static int print_hashed_commands (int);
75static int list_hashed_filename_targets (WORD_LIST *, int);
ccc6cda3 76
726f6388
JA
77/* Print statistics on the current state of hashed commands. If LIST is
78 not empty, then rehash (or hash in the first place) the specified
79 commands. */
ccc6cda3 80int
b8c60bc9 81hash_builtin (WORD_LIST *list)
726f6388 82{
7117c2d2 83 int expunge_hash_table, list_targets, list_portably, delete, opt;
cce855bc 84 char *w, *pathname;
726f6388 85
ccc6cda3 86 if (hashing_enabled == 0)
726f6388 87 {
b80f6443 88 builtin_error (_("hashing disabled"));
726f6388
JA
89 return (EXECUTION_FAILURE);
90 }
91
7117c2d2 92 expunge_hash_table = list_targets = list_portably = delete = 0;
ccc6cda3
JA
93 pathname = (char *)NULL;
94 reset_internal_getopt ();
7117c2d2 95 while ((opt = internal_getopt (list, "dlp:rt")) != -1)
726f6388 96 {
ccc6cda3 97 switch (opt)
726f6388 98 {
7117c2d2
JA
99 case 'd':
100 delete = 1;
101 break;
102 case 'l':
103 list_portably = 1;
726f6388 104 break;
ccc6cda3
JA
105 case 'p':
106 pathname = list_optarg;
107 break;
7117c2d2
JA
108 case 'r':
109 expunge_hash_table = 1;
110 break;
f73dda09
JA
111 case 't':
112 list_targets = 1;
113 break;
a0c0a00f 114 CASE_HELPOPT;
ccc6cda3
JA
115 default:
116 builtin_usage ();
726f6388
JA
117 return (EX_USAGE);
118 }
726f6388 119 }
ccc6cda3 120 list = loptend;
726f6388 121
f73dda09 122 /* hash -t requires at least one argument. */
8868edaf 123 if (list == 0 && (delete || list_targets))
f73dda09 124 {
8868edaf 125 sh_needarg (delete ? "-d" : "-t");
b8c60bc9
CR
126 return (sh_chkwrite (EXECUTION_FAILURE));
127 }
128
129 /* It's an error to specify a pathname to hash to, but no name to hash. */
130 if (pathname && list == 0)
131 {
132 builtin_usage ();
133 return (EX_USAGE);
f73dda09
JA
134 }
135
7117c2d2
JA
136 /* We want hash -r to be silent, but hash -- to print hashing info, so
137 we test expunge_hash_table. */
b8c60bc9 138
ccc6cda3 139 if (list == 0 && expunge_hash_table == 0)
726f6388 140 {
0628567a 141 opt = print_hashed_commands (list_portably);
8868edaf
CR
142 if (opt == 0 && posixly_correct == 0 &&
143 (list_portably == 0 || shell_compatibility_level <= 50))
0628567a 144 printf (_("%s: hash table empty\n"), this_command_name);
726f6388 145
74091dd4 146 return (sh_chkwrite (EXECUTION_SUCCESS));
726f6388
JA
147 }
148
149 if (expunge_hash_table)
7117c2d2 150 phash_flush ();
726f6388 151
f73dda09
JA
152 /* If someone runs `hash -r -t xyz' he will be disappointed. */
153 if (list_targets)
7117c2d2 154 return (list_hashed_filename_targets (list, list_portably));
b8c60bc9 155
bb70624e 156#if defined (RESTRICTED_SHELL)
d233b485 157 if (restricted && pathname)
bb70624e 158 {
b8c60bc9 159 if (absolute_program (pathname))
d233b485
CR
160 {
161 sh_restricted (pathname);
162 return (EXECUTION_FAILURE);
163 }
164 /* If we are changing the hash table in a restricted shell, make sure the
165 target pathname can be found using a $PATH search. */
166 w = find_user_command (pathname);
167 if (w == 0 || *w == 0 || executable_file (w) == 0)
168 {
169 sh_notfound (pathname);
170 free (w);
171 return (EXECUTION_FAILURE);
172 }
173 free (w);
bb70624e
JA
174 }
175#endif
176
ccc6cda3 177 for (opt = EXECUTION_SUCCESS; list; list = list->next)
726f6388 178 {
7117c2d2 179 /* Add, remove or rehash the specified commands. */
cce855bc 180 w = list->word->word;
495aee44
CR
181 if (absolute_program (w))
182 continue;
183 else if (pathname)
28ef6c31 184 {
74091dd4 185 if (file_isdir (pathname))
28ef6c31
JA
186 {
187#ifdef EISDIR
188 builtin_error ("%s: %s", pathname, strerror (EISDIR));
189#else
3185942a 190 builtin_error (_("%s: is a directory"), pathname);
28ef6c31
JA
191#endif
192 opt = EXECUTION_FAILURE;
193 }
194 else
7117c2d2 195 phash_insert (w, pathname, 0, 0);
28ef6c31 196 }
95732b49 197 else if (delete)
7117c2d2 198 {
95732b49
JA
199 if (phash_remove (w))
200 {
201 sh_notfound (w);
202 opt = EXECUTION_FAILURE;
203 }
7117c2d2 204 }
cce855bc 205 else if (add_hashed_command (w, 0))
d166f048 206 opt = EXECUTION_FAILURE;
726f6388
JA
207 }
208
209 fflush (stdout);
ccc6cda3 210 return (opt);
726f6388
JA
211}
212
ccc6cda3 213static int
b8c60bc9 214add_hashed_command (char *w, int quiet)
ccc6cda3
JA
215{
216 int rv;
217 char *full_path;
218
219 rv = 0;
cce855bc 220 if (find_function (w) == 0 && find_shell_builtin (w) == 0)
ccc6cda3 221 {
495aee44 222 phash_remove (w);
cce855bc 223 full_path = find_user_command (w);
ccc6cda3 224 if (full_path && executable_file (full_path))
7117c2d2 225 phash_insert (w, full_path, dot_found_in_search, 0);
ccc6cda3
JA
226 else
227 {
228 if (quiet == 0)
7117c2d2 229 sh_notfound (w);
ccc6cda3
JA
230 rv++;
231 }
7117c2d2 232 FREE (full_path);
ccc6cda3
JA
233 }
234 return (rv);
235}
236
237/* Print information about current hashed info. */
238static int
b8c60bc9 239print_hash_info (BUCKET_CONTENTS *item)
ccc6cda3 240{
7117c2d2
JA
241 printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
242 return 0;
243}
ccc6cda3 244
7117c2d2 245static int
b8c60bc9 246print_portable_hash_info (BUCKET_CONTENTS *item)
7117c2d2 247{
a0c0a00f
CR
248 char *fp, *fn;
249
250 fp = printable_filename (pathdata(item)->path, 1);
251 fn = printable_filename (item->key, 1);
252 printf ("builtin hash -p %s %s\n", fp, fn);
253 if (fp != pathdata(item)->path)
254 free (fp);
255 if (fn != item->key)
256 free (fn);
7117c2d2
JA
257 return 0;
258}
ccc6cda3 259
7117c2d2 260static int
b8c60bc9 261print_hashed_commands (int fmt)
7117c2d2
JA
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
b8c60bc9 273list_hashed_filename_targets (WORD_LIST *list, int fmt)
f73dda09
JA
274{
275 int all_found, multiple;
276 char *target;
277 WORD_LIST *l;
278
279 all_found = 1;
280 multiple = list->next != 0;
281
282 for (l = list; l; l = l->next)
283 {
7117c2d2 284 target = phash_search (l->word->word);
f73dda09
JA
285 if (target == 0)
286 {
287 all_found = 0;
7117c2d2 288 sh_notfound (l->word->word);
f73dda09
JA
289 continue;
290 }
7117c2d2
JA
291 if (fmt)
292 printf ("builtin hash -p %s %s\n", target, l->word->word);
293 else
294 {
295 if (multiple)
296 printf ("%s\t", l->word->word);
297 printf ("%s\n", target);
298 }
ac50fbac 299 free (target);
f73dda09
JA
300 }
301
b8c60bc9 302 return (sh_chkwrite (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE));
f73dda09 303}