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