1 /* findcmd.c -- Functions to search for commands by name. */
3 /* Copyright (C) 1997 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
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)
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.
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. */
25 #include "chartypes.h"
26 #include "bashtypes.h"
27 #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
28 # include <sys/file.h>
31 #include "posixstat.h"
33 #if defined (HAVE_UNISTD_H)
45 #include "findcmd.h" /* matching prototypes and declarations */
47 extern int posixly_correct;
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));
56 static char *get_next_path_element __P((char *, int *));
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;
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;
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;
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)
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. */
90 /* Determine whether this file exists or not. */
91 if (stat (name, &finfo) < 0)
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);
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);
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
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)
116 bits = (u_mode_bits (finfo.st_mode) |
117 g_mode_bits (finfo.st_mode) |
118 o_mode_bits (finfo.st_mode));
120 return ((X_BIT (bits)) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
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);
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);
131 /* Else we check whether `others' have permission to execute the file */
133 return ((X_BIT (o_mode_bits (finfo.st_mode))) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
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. */
142 executable_file (file)
147 s = file_status (file);
148 return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
155 return (file_status (file) & FS_DIRECTORY);
159 executable_or_directory (file)
164 s = file_status (file);
165 return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
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. */
174 find_user_command (name)
177 return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
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. */
185 find_path_file (name)
188 return (find_user_command_internal (name, FS_EXISTS));
192 _find_user_command_internal (name, flags)
196 char *path_list, *cmd;
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);
204 path_list = (char *)NULL;
206 if (path_list == 0 || *path_list == '\0')
207 return (savestring (name));
209 cmd = find_user_command_in_path (name, path_list, flags);
215 find_user_command_internal (name, flags)
222 dotexe = (char *)xmalloc (strlen (name) + 5);
223 strcpy (dotexe, name);
224 strcat (dotexe, ".exe");
225 res = _find_user_command_internal (dotexe, flags);
228 res = _find_user_command_internal (name, flags);
231 return (_find_user_command_internal (name, flags));
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. */
240 get_next_path_element (path_list, path_index_pointer)
242 int *path_index_pointer;
246 path = extract_colon_unit (path_list, path_index_pointer);
254 path = savestring (".");
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. */
264 search_for_command (pathname)
265 const char *pathname;
267 char *hashed_file, *command;
271 hashed_file = command = (char *)NULL;
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;
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);
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. */
290 if (hashed_file && (posixly_correct || check_hashed_filenames))
292 st = file_status (hashed_file);
293 if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0)
295 phash_remove (pathname);
297 hashed_file = (char *)NULL;
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
306 command = savestring (pathname);
309 /* If $PATH is in the temporary environment, we've already retrieved
310 it, so don't bother trying again. */
313 command = find_user_command_in_path (pathname, value_cell (path),
314 FS_EXEC_PREFERRED|FS_NODIRS);
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 */
325 user_command_matches (name, flags, state)
330 int path_index, name_len;
331 char *path_list, *path_element, *match;
333 static char **match_list = NULL;
334 static int match_list_size = 0;
335 static int match_index = 0;
339 /* Create the list of matches. */
343 match_list = strvec_create (match_list_size);
346 /* Clear out the old match list. */
347 for (i = 0; i < match_list_size; i++)
350 /* We haven't found any files yet. */
353 if (absolute_program (name))
355 match_list[0] = find_absolute_program (name, flags);
356 match_list[1] = (char *)NULL;
357 path_list = (char *)NULL;
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");
369 while (path_list && path_list[path_index])
371 path_element = get_next_path_element (path_list, &path_index);
373 if (path_element == 0)
376 match = find_in_path_element (name, path_element, flags, name_len, &dotinfo);
383 if (match_index + 1 == match_list_size)
385 match_list_size += 10;
386 match_list = strvec_resize (match_list, (match_list_size + 1));
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;
395 /* We haven't returned any strings yet. */
399 match = match_list[match_index];
408 find_absolute_program (name, flags)
414 st = file_status (name);
416 /* If the file doesn't exist, quit now. */
417 if ((st & FS_EXISTS) == 0)
418 return ((char *)NULL);
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));
430 find_in_path_element (name, path, flags, name_len, dotinfop)
434 struct stat *dotinfop;
437 char *full_path, *xpath;
439 xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
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);
446 full_path = sh_makepath (xpath, name, 0);
448 status = file_status (full_path);
453 if ((status & FS_EXISTS) == 0)
456 return ((char *)NULL);
459 /* The file exists. If the caller simply wants the first file, here it is. */
460 if (flags & FS_EXISTS)
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)))
468 FREE (file_to_lose_on);
469 file_to_lose_on = (char *)NULL;
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
476 if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0)
477 file_to_lose_on = savestring (full_path);
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)))
485 return ((char *)NULL);
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.
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.
504 find_user_command_in_path (name, path_list, flags)
509 char *full_path, *path;
510 int path_index, name_len;
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;
517 if (absolute_program (name))
519 full_path = find_absolute_program (name, flags);
523 if (path_list == 0 || *path_list == '\0')
524 return (savestring (name)); /* XXX */
526 file_to_lose_on = (char *)NULL;
527 name_len = strlen (name);
528 stat (".", &dotinfo);
531 while (path_list[path_index])
533 /* Allow the user to interrupt out of a lengthy path search. */
536 path = get_next_path_element (path_list, &path_index);
540 /* Side effects: sets dot_found_in_search, possibly sets
542 full_path = find_in_path_element (name, path, flags, name_len, &dotinfo);
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))
555 FREE (file_to_lose_on);
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,
566 if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on))
568 free (file_to_lose_on);
569 file_to_lose_on = (char *)NULL;
572 return (file_to_lose_on);