1 /* findcmd.c -- Functions to search for commands by name. */
3 /* Copyright (C) 1997-2009 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
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.
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.
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/>.
24 #include "chartypes.h"
25 #include "bashtypes.h"
26 #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
27 # include <sys/file.h>
30 #include "posixstat.h"
32 #if defined (HAVE_UNISTD_H)
45 #include "findcmd.h" /* matching prototypes and declarations */
51 extern int posixly_correct;
53 /* Static functions defined and used in this file. */
54 static char *_find_user_command_internal __P((const char *, int));
55 static char *find_user_command_internal __P((const char *, int));
56 static char *find_user_command_in_path __P((const char *, char *, int));
57 static char *find_in_path_element __P((const char *, char *, int, int, struct stat *));
58 static char *find_absolute_program __P((const char *, int));
60 static char *get_next_path_element __P((char *, int *));
62 /* The file name which we would try to execute, except that it isn't
63 possible to execute it. This is the first file that matches the
64 name that we are looking for while we are searching $PATH for a
65 suitable one to execute. If we cannot find a suitable executable
66 file, then we use this one. */
67 static char *file_to_lose_on;
69 /* Non-zero if we should stat every command found in the hash table to
70 make sure it still exists. */
71 int check_hashed_filenames;
73 /* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command ()
74 encounters a `.' as the directory pathname while scanning the
75 list of possible pathnames; i.e., if `.' comes before the directory
76 containing the file of interest. */
77 int dot_found_in_search = 0;
79 /* Return some flags based on information about this file.
80 The EXISTS bit is non-zero if the file is found.
81 The EXECABLE bit is non-zero the file is executble.
82 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);
101 #if defined (HAVE_EACCESS)
102 /* Use eaccess(2) if we have it to take things like ACLs and other
103 file access mechanisms into account. eaccess uses the effective
104 user and group IDs, not the real ones. We could use sh_eaccess,
105 but we don't want any special treatment for /dev/fd. */
106 if (eaccess (name, X_OK) == 0)
108 if (eaccess (name, R_OK) == 0)
113 /* We have to use access(2) to determine access because AFS does not
114 support Unix file system semantics. This may produce wrong
115 answers for non-AFS files when ruid != euid. I hate AFS. */
116 if (access (name, X_OK) == 0)
118 if (access (name, R_OK) == 0)
122 #else /* !HAVE_EACCESS && !AFS */
124 /* Find out if the file is actually executable. By definition, the
125 only other criteria is that the file has an execute bit set that
126 we can use. The same with whether or not a file is readable. */
128 /* Root only requires execute permission for any of owner, group or
129 others to be able to exec a file, and can read any file. */
130 if (current_user.euid == (uid_t)0)
133 if (finfo.st_mode & S_IXUGO)
138 /* If we are the owner of the file, the owner bits apply. */
139 if (current_user.euid == finfo.st_uid)
141 if (finfo.st_mode & S_IXUSR)
143 if (finfo.st_mode & S_IRUSR)
147 /* If we are in the owning group, the group permissions apply. */
148 else if (group_member (finfo.st_gid))
150 if (finfo.st_mode & S_IXGRP)
152 if (finfo.st_mode & S_IRGRP)
156 /* Else we check whether `others' have permission to execute the file */
159 if (finfo.st_mode & S_IXOTH)
161 if (finfo.st_mode & S_IROTH)
169 /* Return non-zero if FILE exists and is executable.
170 Note that this function is the definition of what an
171 executable file is; do not change this unless YOU know
172 what an executable file is. */
174 executable_file (file)
179 s = file_status (file);
181 if (s & FS_DIRECTORY)
182 errno = EISDIR; /* let's see if we can improve error messages */
184 return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
191 return (file_status (file) & FS_DIRECTORY);
195 executable_or_directory (file)
200 s = file_status (file);
201 return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
204 /* Locate the executable file referenced by NAME, searching along
205 the contents of the shell PATH variable. Return a new string
206 which is the full pathname to the file, or NULL if the file
207 couldn't be found. If a file is found that isn't executable,
208 and that is the only match, then return that. */
210 find_user_command (name)
213 return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
216 /* Locate the file referenced by NAME, searching along the contents
217 of the shell PATH variable. Return a new string which is the full
218 pathname to the file, or NULL if the file couldn't be found. This
219 returns the first readable file found; designed to be used to look
220 for shell scripts or files to source. */
222 find_path_file (name)
225 return (find_user_command_internal (name, FS_READABLE));
229 _find_user_command_internal (name, flags)
233 char *path_list, *cmd;
236 /* Search for the value of PATH in both the temporary environments and
237 in the regular list of variables. */
238 if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
239 path_list = value_cell (var);
241 path_list = (char *)NULL;
243 if (path_list == 0 || *path_list == '\0')
244 return (savestring (name));
246 cmd = find_user_command_in_path (name, path_list, flags);
252 find_user_command_internal (name, flags)
259 dotexe = (char *)xmalloc (strlen (name) + 5);
260 strcpy (dotexe, name);
261 strcat (dotexe, ".exe");
262 res = _find_user_command_internal (dotexe, flags);
265 res = _find_user_command_internal (name, flags);
268 return (_find_user_command_internal (name, flags));
272 /* Return the next element from PATH_LIST, a colon separated list of
273 paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
274 the index is modified by this function.
275 Return the next element of PATH_LIST or NULL if there are no more. */
277 get_next_path_element (path_list, path_index_pointer)
279 int *path_index_pointer;
283 path = extract_colon_unit (path_list, path_index_pointer);
291 path = savestring (".");
297 /* Look for PATHNAME in $PATH. Returns either the hashed command
298 corresponding to PATHNAME or the first instance of PATHNAME found
299 in $PATH. Returns a newly-allocated string. */
301 search_for_command (pathname)
302 const char *pathname;
304 char *hashed_file, *command;
308 hashed_file = command = (char *)NULL;
310 /* If PATH is in the temporary environment for this command, don't use the
311 hash table to search for the full pathname. */
312 path = find_variable_internal ("PATH", 1);
313 temp_path = path && tempvar_p (path);
314 if (temp_path == 0 && path)
315 path = (SHELL_VAR *)NULL;
317 /* Don't waste time trying to find hashed data for a pathname
318 that is already completely specified or if we're using a command-
319 specific value for PATH. */
320 if (path == 0 && absolute_program (pathname) == 0)
321 hashed_file = phash_search (pathname);
323 /* If a command found in the hash table no longer exists, we need to
324 look for it in $PATH. Thank you Posix.2. This forces us to stat
325 every command found in the hash table. */
327 if (hashed_file && (posixly_correct || check_hashed_filenames))
329 st = file_status (hashed_file);
330 if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
332 phash_remove (pathname);
334 hashed_file = (char *)NULL;
339 command = hashed_file;
340 else if (absolute_program (pathname))
341 /* A command containing a slash is not looked up in PATH or saved in
343 command = savestring (pathname);
346 /* If $PATH is in the temporary environment, we've already retrieved
347 it, so don't bother trying again. */
350 command = find_user_command_in_path (pathname, value_cell (path),
351 FS_EXEC_PREFERRED|FS_NODIRS);
354 command = find_user_command (pathname);
355 if (command && hashing_enabled && temp_path == 0)
356 phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
362 user_command_matches (name, flags, state)
367 int path_index, name_len;
368 char *path_list, *path_element, *match;
370 static char **match_list = NULL;
371 static int match_list_size = 0;
372 static int match_index = 0;
376 /* Create the list of matches. */
380 match_list = strvec_create (match_list_size);
383 /* Clear out the old match list. */
384 for (i = 0; i < match_list_size; i++)
387 /* We haven't found any files yet. */
390 if (absolute_program (name))
392 match_list[0] = find_absolute_program (name, flags);
393 match_list[1] = (char *)NULL;
394 path_list = (char *)NULL;
398 name_len = strlen (name);
399 file_to_lose_on = (char *)NULL;
400 dot_found_in_search = 0;
401 stat (".", &dotinfo);
402 path_list = get_string_value ("PATH");
406 while (path_list && path_list[path_index])
408 path_element = get_next_path_element (path_list, &path_index);
410 if (path_element == 0)
413 match = find_in_path_element (name, path_element, flags, name_len, &dotinfo);
420 if (match_index + 1 == match_list_size)
422 match_list_size += 10;
423 match_list = strvec_resize (match_list, (match_list_size + 1));
426 match_list[match_index++] = match;
427 match_list[match_index] = (char *)NULL;
428 FREE (file_to_lose_on);
429 file_to_lose_on = (char *)NULL;
432 /* We haven't returned any strings yet. */
436 match = match_list[match_index];
445 find_absolute_program (name, flags)
451 st = file_status (name);
453 /* If the file doesn't exist, quit now. */
454 if ((st & FS_EXISTS) == 0)
455 return ((char *)NULL);
457 /* If we only care about whether the file exists or not, return
458 this filename. Otherwise, maybe we care about whether this
459 file is executable. If it is, and that is what we want, return it. */
460 if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE)))
461 return (savestring (name));
467 find_in_path_element (name, path, flags, name_len, dotinfop)
471 struct stat *dotinfop;
474 char *full_path, *xpath;
476 xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
478 /* Remember the location of "." in the path, in all its forms
479 (as long as they begin with a `.', e.g. `./.') */
480 if (dot_found_in_search == 0 && *xpath == '.')
481 dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
483 full_path = sh_makepath (xpath, name, 0);
485 status = file_status (full_path);
490 if ((status & FS_EXISTS) == 0)
493 return ((char *)NULL);
496 /* The file exists. If the caller simply wants the first file, here it is. */
497 if (flags & FS_EXISTS)
500 /* If we have a readable file, and the caller wants a readable file, this
502 if ((flags & FS_READABLE) && (status & FS_READABLE))
505 /* If the file is executable, then it satisfies the cases of
506 EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
507 if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) &&
508 (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
510 FREE (file_to_lose_on);
511 file_to_lose_on = (char *)NULL;
515 /* The file is not executable, but it does exist. If we prefer
516 an executable, then remember this one if it is the first one
518 if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0)
519 file_to_lose_on = savestring (full_path);
521 /* If we want only executable files, or we don't want directories and
522 this file is a directory, or we want a readable file and this file
523 isn't readable, fail. */
524 if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) ||
525 ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) ||
526 ((flags & FS_READABLE) && (status & FS_READABLE) == 0))
529 return ((char *)NULL);
535 /* This does the dirty work for find_user_command_internal () and
536 user_command_matches ().
537 NAME is the name of the file to search for.
538 PATH_LIST is a colon separated list of directories to search.
539 FLAGS contains bit fields which control the files which are eligible.
541 FS_EXEC_ONLY: The file must be an executable to be found.
542 FS_EXEC_PREFERRED: If we can't find an executable, then the
543 the first file matching NAME will do.
544 FS_EXISTS: The first file found will do.
545 FS_NODIRS: Don't find any directories.
548 find_user_command_in_path (name, path_list, flags)
553 char *full_path, *path;
554 int path_index, name_len;
557 /* We haven't started looking, so we certainly haven't seen
558 a `.' as the directory path yet. */
559 dot_found_in_search = 0;
561 if (absolute_program (name))
563 full_path = find_absolute_program (name, flags);
567 if (path_list == 0 || *path_list == '\0')
568 return (savestring (name)); /* XXX */
570 file_to_lose_on = (char *)NULL;
571 name_len = strlen (name);
572 stat (".", &dotinfo);
575 while (path_list[path_index])
577 /* Allow the user to interrupt out of a lengthy path search. */
580 path = get_next_path_element (path_list, &path_index);
584 /* Side effects: sets dot_found_in_search, possibly sets
586 full_path = find_in_path_element (name, path, flags, name_len, &dotinfo);
589 /* This should really be in find_in_path_element, but there isn't the
590 right combination of flags. */
591 if (full_path && is_directory (full_path))
599 FREE (file_to_lose_on);
604 /* We didn't find exactly what the user was looking for. Return
605 the contents of FILE_TO_LOSE_ON which is NULL when the search
606 required an executable, or non-NULL if a file was found and the
607 search would accept a non-executable as a last resort. If the
608 caller specified FS_NODIRS, and file_to_lose_on is a directory,
610 if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on))
612 free (file_to_lose_on);
613 file_to_lose_on = (char *)NULL;
616 return (file_to_lose_on);