6724ad178829aa3de1ec2a63291002d472d09cdc
[platform/upstream/bash.git] / builtins / hash.def
1 This file is hash.def, from which is created hash.c.
2 It implements the builtin "hash" in Bash.
3
4 Copyright (C) 1987-2010 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
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.
12
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.
17
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/>.
20
21 $PRODUCES hash.c
22
23 $BUILTIN hash
24 $FUNCTION hash_builtin
25 $SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
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
34   -p pathname   use PATHNAME is the full pathname of NAME
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.
45 $END
46
47 #include <config.h>
48
49 #include <stdio.h>
50
51 #include "../bashtypes.h"
52
53 #if defined (HAVE_UNISTD_H)
54 #  include <unistd.h>
55 #endif
56
57 #include <errno.h>
58
59 #include "../bashansi.h"
60 #include "../bashintl.h"
61
62 #include "../shell.h"
63 #include "../builtins.h"
64 #include "../flags.h"
65 #include "../findcmd.h"
66 #include "../hashcmd.h"
67 #include "common.h"
68 #include "bashgetopt.h"
69
70 extern int posixly_correct;
71 extern int dot_found_in_search;
72 extern char *this_command_name;
73
74 static int add_hashed_command __P((char *, int));
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));
79
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. */
83 int
84 hash_builtin (list)
85      WORD_LIST *list;
86 {
87   int expunge_hash_table, list_targets, list_portably, delete, opt;
88   char *w, *pathname;
89
90   if (hashing_enabled == 0)
91     {
92       builtin_error (_("hashing disabled"));
93       return (EXECUTION_FAILURE);
94     }
95
96   expunge_hash_table = list_targets = list_portably = delete = 0;
97   pathname = (char *)NULL;
98   reset_internal_getopt ();
99   while ((opt = internal_getopt (list, "dlp:rt")) != -1)
100     {
101       switch (opt)
102         {
103         case 'd':
104           delete = 1;
105           break;
106         case 'l':
107           list_portably = 1;
108           break;
109         case 'p':
110           pathname = list_optarg;
111           break;
112         case 'r':
113           expunge_hash_table = 1;
114           break;
115         case 't':
116           list_targets = 1;
117           break;
118         default:
119           builtin_usage ();
120           return (EX_USAGE);
121         }
122     }
123   list = loptend;
124
125   /* hash -t requires at least one argument. */
126   if (list == 0 && list_targets)
127     {
128       sh_needarg ("-t");
129       return (EXECUTION_FAILURE);
130     }
131
132   /* We want hash -r to be silent, but hash -- to print hashing info, so
133      we test expunge_hash_table. */
134   if (list == 0 && expunge_hash_table == 0)
135     {
136       opt = print_hashed_commands (list_portably);
137       if (opt == 0 && posixly_correct == 0)
138         printf (_("%s: hash table empty\n"), this_command_name);
139
140       return (EXECUTION_SUCCESS);
141     }
142
143   if (expunge_hash_table)
144     phash_flush ();
145
146   /* If someone runs `hash -r -t xyz' he will be disappointed. */
147   if (list_targets)
148     return (list_hashed_filename_targets (list, list_portably));
149       
150 #if defined (RESTRICTED_SHELL)
151   if (restricted && pathname && strchr (pathname, '/'))
152     {
153       sh_restricted (pathname);
154       return (EXECUTION_FAILURE);
155     }
156 #endif
157
158   for (opt = EXECUTION_SUCCESS; list; list = list->next)
159     {
160       /* Add, remove or rehash the specified commands. */
161       w = list->word->word;
162       if (absolute_program (w))
163         continue;
164       else if (pathname)
165         {
166           if (is_directory (pathname))
167             {
168 #ifdef EISDIR
169               builtin_error ("%s: %s", pathname, strerror (EISDIR));
170 #else
171               builtin_error (_("%s: is a directory"), pathname);
172 #endif
173               opt = EXECUTION_FAILURE;
174             }
175           else
176             phash_insert (w, pathname, 0, 0);
177         }
178       else if (delete)
179         {
180           if (phash_remove (w))
181             {
182               sh_notfound (w);
183               opt = EXECUTION_FAILURE;
184             }
185         }
186       else if (add_hashed_command (w, 0))
187         opt = EXECUTION_FAILURE;
188     }
189
190   fflush (stdout);
191   return (opt);
192 }
193
194 static int
195 add_hashed_command (w, quiet)
196      char *w;
197      int quiet;
198 {
199   int rv;
200   char *full_path;
201
202   rv = 0;
203   if (find_function (w) == 0 && find_shell_builtin (w) == 0)
204     {
205       phash_remove (w);
206       full_path = find_user_command (w);
207       if (full_path && executable_file (full_path))
208         phash_insert (w, full_path, dot_found_in_search, 0);
209       else
210         {
211           if (quiet == 0)
212             sh_notfound (w);
213           rv++;
214         }
215       FREE (full_path);
216     }
217   return (rv);
218 }
219
220 /* Print information about current hashed info. */
221 static int
222 print_hash_info (item)
223      BUCKET_CONTENTS *item;
224 {
225   printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
226   return 0;
227 }
228
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 }
236
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);
243
244   if (fmt == 0)
245     printf (_("hits\tcommand\n"));
246   hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
247   return (1);
248 }
249
250 static int
251 list_hashed_filename_targets (list, fmt)
252      WORD_LIST *list;
253      int fmt;
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     {
264       target = phash_search (l->word->word);
265       if (target == 0)
266         {
267           all_found = 0;
268           sh_notfound (l->word->word);
269           continue;
270         }
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         }
279     }
280
281   return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
282 }