Imported from ../bash-2.02.tar.gz.
[platform/upstream/bash.git] / findcmd.c
1 /* findcmd.c -- Functions to search for commands by name. */
2
3 /* Copyright (C) 1997 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 1, or (at your option)
10    any later version.
11
12    Bash is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash; see the file COPYING.  If not, write to the
19    Free Software Foundation Inc.,
20    59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include "bashtypes.h"
27 #ifndef _MINIX
28 #  include <sys/file.h>
29 #endif
30 #include "filecntl.h"
31 #include "posixstat.h"
32
33 #if defined (HAVE_UNISTD_H)
34 #  include <unistd.h>
35 #endif
36
37 #if defined (HAVE_LIMITS_H)
38 #  include <limits.h>
39 #endif
40
41 #include "bashansi.h"
42
43 #include "memalloc.h"
44 #include "shell.h"
45 #include "flags.h"
46 #include "hashlib.h"
47 #include "pathexp.h"
48 #include "hashcmd.h"
49
50 extern int posixly_correct;
51
52 /* Static functions defined and used in this file. */
53 static char *find_user_command_internal (), *find_user_command_in_path ();
54 static char *find_in_path_element (), *find_absolute_program ();
55
56 /* The file name which we would try to execute, except that it isn't
57    possible to execute it.  This is the first file that matches the
58    name that we are looking for while we are searching $PATH for a
59    suitable one to execute.  If we cannot find a suitable executable
60    file, then we use this one. */
61 static char *file_to_lose_on;
62
63 /* Non-zero if we should stat every command found in the hash table to
64    make sure it still exists. */
65 int check_hashed_filenames;
66
67 /* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command ()
68    encounters a `.' as the directory pathname while scanning the
69    list of possible pathnames; i.e., if `.' comes before the directory
70    containing the file of interest. */
71 int dot_found_in_search = 0;
72
73 #define u_mode_bits(x) (((x) & 0000700) >> 6)
74 #define g_mode_bits(x) (((x) & 0000070) >> 3)
75 #define o_mode_bits(x) (((x) & 0000007) >> 0)
76 #define X_BIT(x) ((x) & 1)
77
78 /* Return some flags based on information about this file.
79    The EXISTS bit is non-zero if the file is found.
80    The EXECABLE bit is non-zero the file is executble.
81    Zero is returned if the file is not found. */
82 int
83 file_status (name)
84      char *name;
85 {
86   struct stat finfo;
87
88   /* Determine whether this file exists or not. */
89   if (stat (name, &finfo) < 0)
90     return (0);
91
92   /* If the file is a directory, then it is not "executable" in the
93      sense of the shell. */
94   if (S_ISDIR (finfo.st_mode))
95     return (FS_EXISTS|FS_DIRECTORY);
96
97 #if defined (AFS)
98   /* We have to use access(2) to determine access because AFS does not
99      support Unix file system semantics.  This may produce wrong
100      answers for non-AFS files when ruid != euid.  I hate AFS. */
101   if (access (name, X_OK) == 0)
102     return (FS_EXISTS | FS_EXECABLE);
103   else
104     return (FS_EXISTS);
105 #else /* !AFS */
106
107   /* Find out if the file is actually executable.  By definition, the
108      only other criteria is that the file has an execute bit set that
109      we can use. */
110
111   /* Root only requires execute permission for any of owner, group or
112      others to be able to exec a file. */
113   if (current_user.euid == (uid_t)0)
114     {
115       int bits;
116
117       bits = (u_mode_bits (finfo.st_mode) |
118               g_mode_bits (finfo.st_mode) |
119               o_mode_bits (finfo.st_mode));
120
121       if (X_BIT (bits))
122         return (FS_EXISTS | FS_EXECABLE);
123     }
124
125   /* If we are the owner of the file, the owner execute bit applies. */
126   if (current_user.euid == finfo.st_uid && X_BIT (u_mode_bits (finfo.st_mode)))
127     return (FS_EXISTS | FS_EXECABLE);
128
129   /* If we are in the owning group, the group permissions apply. */
130   if (group_member (finfo.st_gid) && X_BIT (g_mode_bits (finfo.st_mode)))
131     return (FS_EXISTS | FS_EXECABLE);
132
133   /* If `others' have execute permission to the file, then so do we,
134      since we are also `others'. */
135   if (X_BIT (o_mode_bits (finfo.st_mode)))
136     return (FS_EXISTS | FS_EXECABLE);
137
138   return (FS_EXISTS);
139 #endif /* !AFS */
140 }
141
142 /* Return non-zero if FILE exists and is executable.
143    Note that this function is the definition of what an
144    executable file is; do not change this unless YOU know
145    what an executable file is. */
146 int
147 executable_file (file)
148      char *file;
149 {
150   int s;
151
152   s = file_status (file);
153   return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
154 }
155
156 int
157 is_directory (file)
158      char *file;
159 {
160   return (file_status (file) & FS_DIRECTORY);
161 }
162
163 /* Locate the executable file referenced by NAME, searching along
164    the contents of the shell PATH variable.  Return a new string
165    which is the full pathname to the file, or NULL if the file
166    couldn't be found.  If a file is found that isn't executable,
167    and that is the only match, then return that. */
168 char *
169 find_user_command (name)
170      char *name;
171 {
172   return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
173 }
174
175 /* Locate the file referenced by NAME, searching along the contents
176    of the shell PATH variable.  Return a new string which is the full
177    pathname to the file, or NULL if the file couldn't be found.  This
178    returns the first file found. */
179 char *
180 find_path_file (name)
181      char *name;
182 {
183   return (find_user_command_internal (name, FS_EXISTS));
184 }
185
186 static char *
187 _find_user_command_internal (name, flags)
188      char *name;
189      int flags;
190 {
191   char *path_list, *cmd;
192   SHELL_VAR *var;
193
194   /* Search for the value of PATH in both the temporary environment, and
195      in the regular list of variables. */
196   if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
197     path_list = value_cell (var);
198   else
199     path_list = (char *)NULL;
200
201   if (path_list == 0 || *path_list == '\0')
202     return (savestring (name));
203
204   cmd = find_user_command_in_path (name, path_list, flags);
205
206   if (var && tempvar_p (var))
207     dispose_variable (var);
208
209   return (cmd);
210 }
211
212 static char *
213 find_user_command_internal (name, flags)
214      char *name;
215      int flags;
216 {
217 #ifdef __WIN32__
218   char *res, *dotexe;
219
220   dotexe = xmalloc (strlen (name) + 5);
221   strcpy (dotexe, name);
222   strcat (dotexe, ".exe");
223   res = _find_user_command_internal (dotexe, flags);
224   free (dotexe);
225   if (res == 0)
226     res = _find_user_command_internal (name, flags);
227   return res;
228 #else
229   return (_find_user_command_internal (name, flags));
230 #endif
231 }
232
233 /* Return the next element from PATH_LIST, a colon separated list of
234    paths.  PATH_INDEX_POINTER is the address of an index into PATH_LIST;
235    the index is modified by this function.
236    Return the next element of PATH_LIST or NULL if there are no more. */
237 static char *
238 get_next_path_element (path_list, path_index_pointer)
239      char *path_list;
240      int *path_index_pointer;
241 {
242   char *path;
243
244   path = extract_colon_unit (path_list, path_index_pointer);
245
246   if (!path)
247     return (path);
248
249   if (!*path)
250     {
251       free (path);
252       path = savestring (".");
253     }
254
255   return (path);
256 }
257
258 /* Look for PATHNAME in $PATH.  Returns either the hashed command
259    corresponding to PATHNAME or the first instance of PATHNAME found
260    in $PATH.  Returns a newly-allocated string. */
261 char *
262 search_for_command (pathname)
263      char *pathname;
264 {
265   char *hashed_file, *command;
266   int temp_path, st;
267   SHELL_VAR *path;
268
269   hashed_file = command = (char *)NULL;
270
271   /* If PATH is in the temporary environment for this command, don't use the
272      hash table to search for the full pathname. */
273   path = find_tempenv_variable ("PATH");
274   temp_path = path != 0;
275
276   /* Don't waste time trying to find hashed data for a pathname
277      that is already completely specified or if we're using a command-
278      specific value for PATH. */
279   if (path == 0 && absolute_program (pathname) == 0)
280     hashed_file = find_hashed_filename (pathname);
281
282   /* If a command found in the hash table no longer exists, we need to
283      look for it in $PATH.  Thank you Posix.2.  This forces us to stat
284      every command found in the hash table. */
285
286   if (hashed_file && (posixly_correct || check_hashed_filenames))
287     {
288       st = file_status (hashed_file);
289       if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0)
290         {
291           remove_hashed_filename (pathname);
292           free (hashed_file);
293           hashed_file = (char *)NULL;
294         }
295     }
296
297   if (hashed_file)
298     command = hashed_file;
299   else if (absolute_program (pathname))
300     /* A command containing a slash is not looked up in PATH or saved in
301        the hash table. */
302     command = savestring (pathname);
303   else
304     {
305       /* If $PATH is in the temporary environment, we've already retrieved
306          it, so don't bother trying again. */
307       if (temp_path)
308         {
309           command = find_user_command_in_path (pathname, value_cell (path),
310                                                FS_EXEC_PREFERRED|FS_NODIRS);
311           if (tempvar_p (path))
312             dispose_variable (path);
313         }
314       else
315         command = find_user_command (pathname);
316       if (command && hashing_enabled && temp_path == 0)
317         remember_filename (pathname, command, dot_found_in_search, 1);
318     }
319   return (command);
320 }
321
322 char *
323 user_command_matches (name, flags, state)
324      char *name;
325      int flags, state;
326 {
327   register int i;
328   int  path_index, name_len;
329   char *path_list, *path_element, *match;
330   struct stat dotinfo;
331   static char **match_list = NULL;
332   static int match_list_size = 0;
333   static int match_index = 0;
334
335   if (state == 0)
336     {
337       /* Create the list of matches. */
338       if (match_list == 0)
339         {
340           match_list_size = 5;
341           match_list = (char **)xmalloc (match_list_size * sizeof(char *));
342         }
343
344       /* Clear out the old match list. */
345       for (i = 0; i < match_list_size; i++)
346         match_list[i] = 0;
347
348       /* We haven't found any files yet. */
349       match_index = 0;
350
351       if (absolute_program (name))
352         {
353           match_list[0] = find_absolute_program (name, flags);
354           match_list[1] = (char *)NULL;
355           path_list = (char *)NULL;
356         }
357       else
358         {
359           name_len = strlen (name);
360           file_to_lose_on = (char *)NULL;
361           dot_found_in_search = 0;
362           stat (".", &dotinfo);
363           path_list = get_string_value ("PATH");
364           path_index = 0;
365         }
366
367       while (path_list && path_list[path_index])
368         {
369           path_element = get_next_path_element (path_list, &path_index);
370
371           if (path_element == 0)
372             break;
373
374           match = find_in_path_element (name, path_element, flags, name_len, &dotinfo);
375
376           free (path_element);
377
378           if (match == 0)
379             continue;
380
381           if (match_index + 1 == match_list_size)
382             {
383               match_list_size += 10;
384               match_list = (char **)xrealloc (match_list, (match_list_size + 1) * sizeof (char *));
385             }
386
387           match_list[match_index++] = match;
388           match_list[match_index] = (char *)NULL;
389           FREE (file_to_lose_on);
390           file_to_lose_on = (char *)NULL;
391         }
392
393       /* We haven't returned any strings yet. */
394       match_index = 0;
395     }
396
397   match = match_list[match_index];
398
399   if (match)
400     match_index++;
401
402   return (match);
403 }
404
405 /* Turn PATH, a directory, and NAME, a filename, into a full pathname.
406    This allocates new memory and returns it. */
407 static char *
408 make_full_pathname (path, name, name_len)
409      char *path, *name;
410      int name_len;
411 {
412   char *full_path;
413   int path_len;
414
415   path_len = strlen (path);
416   full_path = xmalloc (2 + path_len + name_len);
417   strcpy (full_path, path);
418   full_path[path_len] = '/';
419   strcpy (full_path + path_len + 1, name);
420   return (full_path);
421 }
422
423 static char *
424 find_absolute_program (name, flags)
425      char *name;
426      int flags;
427 {
428   int st;
429
430   st = file_status (name);
431
432   /* If the file doesn't exist, quit now. */
433   if ((st & FS_EXISTS) == 0)
434     return ((char *)NULL);
435
436   /* If we only care about whether the file exists or not, return
437      this filename.  Otherwise, maybe we care about whether this
438      file is executable.  If it is, and that is what we want, return it. */
439   if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE)))
440     return (savestring (name));
441
442   return ((char *)NULL);
443 }
444
445 static char *
446 find_in_path_element (name, path, flags, name_len, dotinfop)
447      char *name, *path;
448      int flags, name_len;
449      struct stat *dotinfop;
450 {
451   int status;
452   char *full_path, *xpath;
453
454   xpath = (*path == '~') ? bash_tilde_expand (path) : path;
455
456   /* Remember the location of "." in the path, in all its forms
457      (as long as they begin with a `.', e.g. `./.') */
458   if (dot_found_in_search == 0 && *xpath == '.')
459     dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
460
461   full_path = make_full_pathname (xpath, name, name_len);
462
463   status = file_status (full_path);
464
465   if (xpath != path)
466     free (xpath);
467
468   if ((status & FS_EXISTS) == 0)
469     {
470       free (full_path);
471       return ((char *)NULL);
472     }
473
474   /* The file exists.  If the caller simply wants the first file, here it is. */
475   if (flags & FS_EXISTS)
476     return (full_path);
477
478   /* If the file is executable, then it satisfies the cases of
479       EXEC_ONLY and EXEC_PREFERRED.  Return this file unconditionally. */
480   if ((status & FS_EXECABLE) &&
481       (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
482     {
483       FREE (file_to_lose_on);
484       file_to_lose_on = (char *)NULL;
485       return (full_path);
486     }
487
488   /* The file is not executable, but it does exist.  If we prefer
489      an executable, then remember this one if it is the first one
490      we have found. */
491   if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0)
492     file_to_lose_on = savestring (full_path);
493
494   /* If we want only executable files, or we don't want directories and
495      this file is a directory, fail. */
496   if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) ||
497       ((flags & FS_NODIRS) && (status & FS_DIRECTORY)))
498     {
499       free (full_path);
500       return ((char *)NULL);
501     }
502   else
503     return (full_path);
504 }
505
506 /* This does the dirty work for find_user_command_internal () and
507    user_command_matches ().
508    NAME is the name of the file to search for.
509    PATH_LIST is a colon separated list of directories to search.
510    FLAGS contains bit fields which control the files which are eligible.
511    Some values are:
512       FS_EXEC_ONLY:             The file must be an executable to be found.
513       FS_EXEC_PREFERRED:        If we can't find an executable, then the
514                                 the first file matching NAME will do.
515       FS_EXISTS:                The first file found will do.
516       FS_NODIRS:                Don't find any directories.
517 */
518 static char *
519 find_user_command_in_path (name, path_list, flags)
520      char *name;
521      char *path_list;
522      int flags;
523 {
524   char *full_path, *path;
525   int path_index, name_len;
526   struct stat dotinfo;
527
528   /* We haven't started looking, so we certainly haven't seen
529      a `.' as the directory path yet. */
530   dot_found_in_search = 0;
531
532   if (absolute_program (name))
533     {
534       full_path = find_absolute_program (name, flags);
535       return (full_path);
536     }
537
538   if (path_list == 0 || *path_list == '\0')
539     return (savestring (name));         /* XXX */
540
541   file_to_lose_on = (char *)NULL;
542   name_len = strlen (name);
543   stat (".", &dotinfo);
544   path_index = 0;
545
546   while (path_list[path_index])
547     {
548       /* Allow the user to interrupt out of a lengthy path search. */
549       QUIT;
550
551       path = get_next_path_element (path_list, &path_index);
552       if (path == 0)
553         break;
554
555       /* Side effects: sets dot_found_in_search, possibly sets
556          file_to_lose_on. */
557       full_path = find_in_path_element (name, path, flags, name_len, &dotinfo);
558       free (path);
559
560       /* This should really be in find_in_path_element, but there isn't the
561          right combination of flags. */
562       if (full_path && is_directory (full_path))
563         {
564           free (full_path);
565           continue;
566         }
567
568       if (full_path)
569         {
570           FREE (file_to_lose_on);
571           return (full_path);
572         }
573     }
574
575   /* We didn't find exactly what the user was looking for.  Return
576      the contents of FILE_TO_LOSE_ON which is NULL when the search
577      required an executable, or non-NULL if a file was found and the
578      search would accept a non-executable as a last resort. */
579   return (file_to_lose_on);
580 }