]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is hash.def, from which is created hash.c. |
2 | It implements the builtin "hash" in Bash. | |
3 | ||
ac50fbac | 4 | Copyright (C) 1987-2013 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
8 | Bash is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation, either version 3 of the License, or | |
11 | (at your option) any later version. | |
726f6388 | 12 | |
3185942a JA |
13 | Bash is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
726f6388 | 17 | |
3185942a JA |
18 | You should have received a copy of the GNU General Public License |
19 | along 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 |
26 | Remember or display program locations. |
27 | ||
28 | Determine and remember the full pathname of each command NAME. If | |
29 | no arguments are given, information about remembered commands is displayed. | |
30 | ||
31 | Options: | |
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 |
3185942a JA |
35 | -r forget all remembered locations |
36 | -t print the remembered location of each NAME, preceding | |
37 | each location with the corresponding NAME if multiple | |
38 | NAMEs are given | |
39 | Arguments: | |
40 | NAME Each NAME is searched for in $PATH and added to the list | |
41 | of remembered commands. | |
42 | ||
43 | Exit Status: | |
44 | Returns 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" | |
d166f048 | 64 | #include "../flags.h" |
cce855bc | 65 | #include "../findcmd.h" |
d166f048 | 66 | #include "../hashcmd.h" |
726f6388 | 67 | #include "common.h" |
ccc6cda3 | 68 | #include "bashgetopt.h" |
726f6388 | 69 | |
0628567a | 70 | extern int posixly_correct; |
726f6388 | 71 | extern int dot_found_in_search; |
ccc6cda3 JA |
72 | extern char *this_command_name; |
73 | ||
f73dda09 | 74 | static int add_hashed_command __P((char *, int)); |
7117c2d2 JA |
75 | static int print_hash_info __P((BUCKET_CONTENTS *)); |
76 | static int print_portable_hash_info __P((BUCKET_CONTENTS *)); | |
77 | static int print_hashed_commands __P((int)); | |
78 | static int list_hashed_filename_targets __P((WORD_LIST *, int)); | |
ccc6cda3 | 79 | |
726f6388 JA |
80 | /* Print statistics on the current state of hashed commands. If LIST is |
81 | not empty, then rehash (or hash in the first place) the specified | |
82 | commands. */ | |
ccc6cda3 | 83 | int |
726f6388 JA |
84 | hash_builtin (list) |
85 | WORD_LIST *list; | |
86 | { | |
7117c2d2 | 87 | int expunge_hash_table, list_targets, list_portably, delete, opt; |
cce855bc | 88 | char *w, *pathname; |
726f6388 | 89 | |
ccc6cda3 | 90 | if (hashing_enabled == 0) |
726f6388 | 91 | { |
b80f6443 | 92 | builtin_error (_("hashing disabled")); |
726f6388 JA |
93 | return (EXECUTION_FAILURE); |
94 | } | |
95 | ||
7117c2d2 | 96 | expunge_hash_table = list_targets = list_portably = delete = 0; |
ccc6cda3 JA |
97 | pathname = (char *)NULL; |
98 | reset_internal_getopt (); | |
7117c2d2 | 99 | while ((opt = internal_getopt (list, "dlp:rt")) != -1) |
726f6388 | 100 | { |
ccc6cda3 | 101 | switch (opt) |
726f6388 | 102 | { |
7117c2d2 JA |
103 | case 'd': |
104 | delete = 1; | |
105 | break; | |
106 | case 'l': | |
107 | list_portably = 1; | |
726f6388 | 108 | break; |
ccc6cda3 JA |
109 | case 'p': |
110 | pathname = list_optarg; | |
111 | break; | |
7117c2d2 JA |
112 | case 'r': |
113 | expunge_hash_table = 1; | |
114 | break; | |
f73dda09 JA |
115 | case 't': |
116 | list_targets = 1; | |
117 | break; | |
ccc6cda3 JA |
118 | default: |
119 | builtin_usage (); | |
726f6388 JA |
120 | return (EX_USAGE); |
121 | } | |
726f6388 | 122 | } |
ccc6cda3 | 123 | list = loptend; |
726f6388 | 124 | |
f73dda09 JA |
125 | /* hash -t requires at least one argument. */ |
126 | if (list == 0 && list_targets) | |
127 | { | |
7117c2d2 | 128 | sh_needarg ("-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 JA |
136 | opt = print_hashed_commands (list_portably); |
137 | if (opt == 0 && posixly_correct == 0) | |
138 | printf (_("%s: hash table empty\n"), this_command_name); | |
726f6388 JA |
139 | |
140 | return (EXECUTION_SUCCESS); | |
141 | } | |
142 | ||
143 | if (expunge_hash_table) | |
7117c2d2 | 144 | phash_flush (); |
726f6388 | 145 | |
f73dda09 JA |
146 | /* If someone runs `hash -r -t xyz' he will be disappointed. */ |
147 | if (list_targets) | |
7117c2d2 | 148 | return (list_hashed_filename_targets (list, list_portably)); |
f73dda09 | 149 | |
bb70624e JA |
150 | #if defined (RESTRICTED_SHELL) |
151 | if (restricted && pathname && strchr (pathname, '/')) | |
152 | { | |
7117c2d2 | 153 | sh_restricted (pathname); |
bb70624e JA |
154 | return (EXECUTION_FAILURE); |
155 | } | |
156 | #endif | |
157 | ||
ccc6cda3 | 158 | for (opt = EXECUTION_SUCCESS; list; list = list->next) |
726f6388 | 159 | { |
7117c2d2 | 160 | /* Add, remove or rehash the specified commands. */ |
cce855bc | 161 | w = list->word->word; |
495aee44 CR |
162 | if (absolute_program (w)) |
163 | continue; | |
164 | else if (pathname) | |
28ef6c31 JA |
165 | { |
166 | if (is_directory (pathname)) | |
167 | { | |
168 | #ifdef EISDIR | |
169 | builtin_error ("%s: %s", pathname, strerror (EISDIR)); | |
170 | #else | |
3185942a | 171 | builtin_error (_("%s: is a directory"), pathname); |
28ef6c31 JA |
172 | #endif |
173 | opt = EXECUTION_FAILURE; | |
174 | } | |
175 | else | |
7117c2d2 | 176 | phash_insert (w, pathname, 0, 0); |
28ef6c31 | 177 | } |
95732b49 | 178 | else if (delete) |
7117c2d2 | 179 | { |
95732b49 JA |
180 | if (phash_remove (w)) |
181 | { | |
182 | sh_notfound (w); | |
183 | opt = EXECUTION_FAILURE; | |
184 | } | |
7117c2d2 | 185 | } |
cce855bc | 186 | else if (add_hashed_command (w, 0)) |
d166f048 | 187 | opt = EXECUTION_FAILURE; |
726f6388 JA |
188 | } |
189 | ||
190 | fflush (stdout); | |
ccc6cda3 | 191 | return (opt); |
726f6388 JA |
192 | } |
193 | ||
ccc6cda3 | 194 | static int |
cce855bc JA |
195 | add_hashed_command (w, quiet) |
196 | char *w; | |
ccc6cda3 JA |
197 | int quiet; |
198 | { | |
199 | int rv; | |
200 | char *full_path; | |
201 | ||
202 | rv = 0; | |
cce855bc | 203 | if (find_function (w) == 0 && find_shell_builtin (w) == 0) |
ccc6cda3 | 204 | { |
495aee44 | 205 | phash_remove (w); |
cce855bc | 206 | full_path = find_user_command (w); |
ccc6cda3 | 207 | if (full_path && executable_file (full_path)) |
7117c2d2 | 208 | phash_insert (w, full_path, dot_found_in_search, 0); |
ccc6cda3 JA |
209 | else |
210 | { | |
211 | if (quiet == 0) | |
7117c2d2 | 212 | sh_notfound (w); |
ccc6cda3 JA |
213 | rv++; |
214 | } | |
7117c2d2 | 215 | FREE (full_path); |
ccc6cda3 JA |
216 | } |
217 | return (rv); | |
218 | } | |
219 | ||
220 | /* Print information about current hashed info. */ | |
221 | static int | |
7117c2d2 JA |
222 | print_hash_info (item) |
223 | BUCKET_CONTENTS *item; | |
ccc6cda3 | 224 | { |
7117c2d2 JA |
225 | printf ("%4d\t%s\n", item->times_found, pathdata(item)->path); |
226 | return 0; | |
227 | } | |
ccc6cda3 | 228 | |
7117c2d2 JA |
229 | static int |
230 | print_portable_hash_info (item) | |
231 | BUCKET_CONTENTS *item; | |
232 | { | |
233 | printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key); | |
234 | return 0; | |
235 | } | |
ccc6cda3 | 236 | |
7117c2d2 JA |
237 | static int |
238 | print_hashed_commands (fmt) | |
239 | int fmt; | |
240 | { | |
241 | if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0) | |
242 | return (0); | |
ccc6cda3 | 243 | |
7117c2d2 | 244 | if (fmt == 0) |
3185942a | 245 | printf (_("hits\tcommand\n")); |
7117c2d2 JA |
246 | hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info); |
247 | return (1); | |
ccc6cda3 | 248 | } |
f73dda09 JA |
249 | |
250 | static int | |
7117c2d2 | 251 | list_hashed_filename_targets (list, fmt) |
f73dda09 | 252 | WORD_LIST *list; |
7117c2d2 | 253 | int fmt; |
f73dda09 JA |
254 | { |
255 | int all_found, multiple; | |
256 | char *target; | |
257 | WORD_LIST *l; | |
258 | ||
259 | all_found = 1; | |
260 | multiple = list->next != 0; | |
261 | ||
262 | for (l = list; l; l = l->next) | |
263 | { | |
7117c2d2 | 264 | target = phash_search (l->word->word); |
f73dda09 JA |
265 | if (target == 0) |
266 | { | |
267 | all_found = 0; | |
7117c2d2 | 268 | sh_notfound (l->word->word); |
f73dda09 JA |
269 | continue; |
270 | } | |
7117c2d2 JA |
271 | if (fmt) |
272 | printf ("builtin hash -p %s %s\n", target, l->word->word); | |
273 | else | |
274 | { | |
275 | if (multiple) | |
276 | printf ("%s\t", l->word->word); | |
277 | printf ("%s\n", target); | |
278 | } | |
ac50fbac | 279 | free (target); |
f73dda09 JA |
280 | } |
281 | ||
282 | return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE); | |
283 | } |