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