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)
44 #include "findcmd.h" /* matching prototypes and declarations */
46 extern int posixly_correct
;
48 /* Static functions defined and used in this file. */
49 static char *_find_user_command_internal
__P((const char *, int));
50 static char *find_user_command_internal
__P((const char *, int));
51 static char *find_user_command_in_path
__P((const char *, char *, int));
52 static char *find_in_path_element
__P((const char *, char *, int, int, struct stat
*));
53 static char *find_absolute_program
__P((const char *, int));
55 static char *get_next_path_element
__P((char *, int *));
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. */
62 static char *file_to_lose_on
;
64 /* Non-zero if we should stat every command found in the hash table to
65 make sure it still exists. */
66 int check_hashed_filenames
;
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. */
72 int dot_found_in_search
= 0;
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. */
85 /* Determine whether this file exists or not. */
86 if (stat (name
, &finfo
) < 0)
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
);
96 #if defined (HAVE_EACCESS)
97 /* Use eaccess(2) if we have it to take things like ACLs and other
98 file access mechanisms into account. eaccess uses the effective
99 user and group IDs, not the real ones. We could use sh_eaccess,
100 but we don't want any special treatment for /dev/fd. */
101 if (eaccess (name
, X_OK
) == 0)
103 if (eaccess (name
, R_OK
) == 0)
108 /* We have to use access(2) to determine access because AFS does not
109 support Unix file system semantics. This may produce wrong
110 answers for non-AFS files when ruid != euid. I hate AFS. */
111 if (access (name
, X_OK
) == 0)
113 if (access (name
, R_OK
) == 0)
117 #else /* !HAVE_EACCESS && !AFS */
119 /* Find out if the file is actually executable. By definition, the
120 only other criteria is that the file has an execute bit set that
121 we can use. The same with whether or not a file is readable. */
123 /* Root only requires execute permission for any of owner, group or
124 others to be able to exec a file, and can read any file. */
125 if (current_user
.euid
== (uid_t
)0)
128 if (finfo
.st_mode
& S_IXUGO
)
133 /* If we are the owner of the file, the owner bits apply. */
134 if (current_user
.euid
== finfo
.st_uid
)
136 if (finfo
.st_mode
& S_IXUSR
)
138 if (finfo
.st_mode
& S_IRUSR
)
142 /* If we are in the owning group, the group permissions apply. */
143 else if (group_member (finfo
.st_gid
))
145 if (finfo
.st_mode
& S_IXGRP
)
147 if (finfo
.st_mode
& S_IRGRP
)
151 /* Else we check whether `others' have permission to execute the file */
154 if (finfo
.st_mode
& S_IXOTH
)
156 if (finfo
.st_mode
& S_IROTH
)
164 /* Return non-zero if FILE exists and is executable.
165 Note that this function is the definition of what an
166 executable file is; do not change this unless YOU know
167 what an executable file is. */
169 executable_file (file
)
174 s
= file_status (file
);
175 return ((s
& FS_EXECABLE
) && ((s
& FS_DIRECTORY
) == 0));
182 return (file_status (file
) & FS_DIRECTORY
);
186 executable_or_directory (file
)
191 s
= file_status (file
);
192 return ((s
& FS_EXECABLE
) || (s
& FS_DIRECTORY
));
195 /* Locate the executable file referenced by NAME, searching along
196 the contents of the shell PATH variable. Return a new string
197 which is the full pathname to the file, or NULL if the file
198 couldn't be found. If a file is found that isn't executable,
199 and that is the only match, then return that. */
201 find_user_command (name
)
204 return (find_user_command_internal (name
, FS_EXEC_PREFERRED
|FS_NODIRS
));
207 /* Locate the file referenced by NAME, searching along the contents
208 of the shell PATH variable. Return a new string which is the full
209 pathname to the file, or NULL if the file couldn't be found. This
210 returns the first readable file found; designed to be used to look
211 for shell scripts or files to source. */
213 find_path_file (name
)
216 return (find_user_command_internal (name
, FS_READABLE
));
220 _find_user_command_internal (name
, flags
)
224 char *path_list
, *cmd
;
227 /* Search for the value of PATH in both the temporary environments and
228 in the regular list of variables. */
229 if (var
= find_variable_internal ("PATH", 1)) /* XXX could be array? */
230 path_list
= value_cell (var
);
232 path_list
= (char *)NULL
;
234 if (path_list
== 0 || *path_list
== '\0')
235 return (savestring (name
));
237 cmd
= find_user_command_in_path (name
, path_list
, flags
);
243 find_user_command_internal (name
, flags
)
250 dotexe
= (char *)xmalloc (strlen (name
) + 5);
251 strcpy (dotexe
, name
);
252 strcat (dotexe
, ".exe");
253 res
= _find_user_command_internal (dotexe
, flags
);
256 res
= _find_user_command_internal (name
, flags
);
259 return (_find_user_command_internal (name
, flags
));
263 /* Return the next element from PATH_LIST, a colon separated list of
264 paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
265 the index is modified by this function.
266 Return the next element of PATH_LIST or NULL if there are no more. */
268 get_next_path_element (path_list
, path_index_pointer
)
270 int *path_index_pointer
;
274 path
= extract_colon_unit (path_list
, path_index_pointer
);
282 path
= savestring (".");
288 /* Look for PATHNAME in $PATH. Returns either the hashed command
289 corresponding to PATHNAME or the first instance of PATHNAME found
290 in $PATH. Returns a newly-allocated string. */
292 search_for_command (pathname
)
293 const char *pathname
;
295 char *hashed_file
, *command
;
299 hashed_file
= command
= (char *)NULL
;
301 /* If PATH is in the temporary environment for this command, don't use the
302 hash table to search for the full pathname. */
303 path
= find_variable_internal ("PATH", 1);
304 temp_path
= path
&& tempvar_p (path
);
305 if (temp_path
== 0 && path
)
306 path
= (SHELL_VAR
*)NULL
;
308 /* Don't waste time trying to find hashed data for a pathname
309 that is already completely specified or if we're using a command-
310 specific value for PATH. */
311 if (path
== 0 && absolute_program (pathname
) == 0)
312 hashed_file
= phash_search (pathname
);
314 /* If a command found in the hash table no longer exists, we need to
315 look for it in $PATH. Thank you Posix.2. This forces us to stat
316 every command found in the hash table. */
318 if (hashed_file
&& (posixly_correct
|| check_hashed_filenames
))
320 st
= file_status (hashed_file
);
321 if ((st
& (FS_EXISTS
|FS_EXECABLE
)) != (FS_EXISTS
|FS_EXECABLE
))
323 phash_remove (pathname
);
325 hashed_file
= (char *)NULL
;
330 command
= hashed_file
;
331 else if (absolute_program (pathname
))
332 /* A command containing a slash is not looked up in PATH or saved in
334 command
= savestring (pathname
);
337 /* If $PATH is in the temporary environment, we've already retrieved
338 it, so don't bother trying again. */
341 command
= find_user_command_in_path (pathname
, value_cell (path
),
342 FS_EXEC_PREFERRED
|FS_NODIRS
);
345 command
= find_user_command (pathname
);
346 if (command
&& hashing_enabled
&& temp_path
== 0)
347 phash_insert ((char *)pathname
, command
, dot_found_in_search
, 1); /* XXX fix const later */
353 user_command_matches (name
, flags
, state
)
358 int path_index
, name_len
;
359 char *path_list
, *path_element
, *match
;
361 static char **match_list
= NULL
;
362 static int match_list_size
= 0;
363 static int match_index
= 0;
367 /* Create the list of matches. */
371 match_list
= strvec_create (match_list_size
);
374 /* Clear out the old match list. */
375 for (i
= 0; i
< match_list_size
; i
++)
378 /* We haven't found any files yet. */
381 if (absolute_program (name
))
383 match_list
[0] = find_absolute_program (name
, flags
);
384 match_list
[1] = (char *)NULL
;
385 path_list
= (char *)NULL
;
389 name_len
= strlen (name
);
390 file_to_lose_on
= (char *)NULL
;
391 dot_found_in_search
= 0;
392 stat (".", &dotinfo
);
393 path_list
= get_string_value ("PATH");
397 while (path_list
&& path_list
[path_index
])
399 path_element
= get_next_path_element (path_list
, &path_index
);
401 if (path_element
== 0)
404 match
= find_in_path_element (name
, path_element
, flags
, name_len
, &dotinfo
);
411 if (match_index
+ 1 == match_list_size
)
413 match_list_size
+= 10;
414 match_list
= strvec_resize (match_list
, (match_list_size
+ 1));
417 match_list
[match_index
++] = match
;
418 match_list
[match_index
] = (char *)NULL
;
419 FREE (file_to_lose_on
);
420 file_to_lose_on
= (char *)NULL
;
423 /* We haven't returned any strings yet. */
427 match
= match_list
[match_index
];
436 find_absolute_program (name
, flags
)
442 st
= file_status (name
);
444 /* If the file doesn't exist, quit now. */
445 if ((st
& FS_EXISTS
) == 0)
446 return ((char *)NULL
);
448 /* If we only care about whether the file exists or not, return
449 this filename. Otherwise, maybe we care about whether this
450 file is executable. If it is, and that is what we want, return it. */
451 if ((flags
& FS_EXISTS
) || ((flags
& FS_EXEC_ONLY
) && (st
& FS_EXECABLE
)))
452 return (savestring (name
));
458 find_in_path_element (name
, path
, flags
, name_len
, dotinfop
)
462 struct stat
*dotinfop
;
465 char *full_path
, *xpath
;
467 xpath
= (*path
== '~') ? bash_tilde_expand (path
, 0) : path
;
469 /* Remember the location of "." in the path, in all its forms
470 (as long as they begin with a `.', e.g. `./.') */
471 if (dot_found_in_search
== 0 && *xpath
== '.')
472 dot_found_in_search
= same_file (".", xpath
, dotinfop
, (struct stat
*)NULL
);
474 full_path
= sh_makepath (xpath
, name
, 0);
476 status
= file_status (full_path
);
481 if ((status
& FS_EXISTS
) == 0)
484 return ((char *)NULL
);
487 /* The file exists. If the caller simply wants the first file, here it is. */
488 if (flags
& FS_EXISTS
)
491 /* If we have a readable file, and the caller wants a readable file, this
493 if ((flags
& FS_READABLE
) && (status
& FS_READABLE
))
496 /* If the file is executable, then it satisfies the cases of
497 EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
498 if ((status
& FS_EXECABLE
) && (flags
& (FS_EXEC_ONLY
|FS_EXEC_PREFERRED
)) &&
499 (((flags
& FS_NODIRS
) == 0) || ((status
& FS_DIRECTORY
) == 0)))
501 FREE (file_to_lose_on
);
502 file_to_lose_on
= (char *)NULL
;
506 /* The file is not executable, but it does exist. If we prefer
507 an executable, then remember this one if it is the first one
509 if ((flags
& FS_EXEC_PREFERRED
) && file_to_lose_on
== 0)
510 file_to_lose_on
= savestring (full_path
);
512 /* If we want only executable files, or we don't want directories and
513 this file is a directory, or we want a readable file and this file
514 isn't readable, fail. */
515 if ((flags
& (FS_EXEC_ONLY
|FS_EXEC_PREFERRED
)) ||
516 ((flags
& FS_NODIRS
) && (status
& FS_DIRECTORY
)) ||
517 ((flags
& FS_READABLE
) && (status
& FS_READABLE
) == 0))
520 return ((char *)NULL
);
526 /* This does the dirty work for find_user_command_internal () and
527 user_command_matches ().
528 NAME is the name of the file to search for.
529 PATH_LIST is a colon separated list of directories to search.
530 FLAGS contains bit fields which control the files which are eligible.
532 FS_EXEC_ONLY: The file must be an executable to be found.
533 FS_EXEC_PREFERRED: If we can't find an executable, then the
534 the first file matching NAME will do.
535 FS_EXISTS: The first file found will do.
536 FS_NODIRS: Don't find any directories.
539 find_user_command_in_path (name
, path_list
, flags
)
544 char *full_path
, *path
;
545 int path_index
, name_len
;
548 /* We haven't started looking, so we certainly haven't seen
549 a `.' as the directory path yet. */
550 dot_found_in_search
= 0;
552 if (absolute_program (name
))
554 full_path
= find_absolute_program (name
, flags
);
558 if (path_list
== 0 || *path_list
== '\0')
559 return (savestring (name
)); /* XXX */
561 file_to_lose_on
= (char *)NULL
;
562 name_len
= strlen (name
);
563 stat (".", &dotinfo
);
566 while (path_list
[path_index
])
568 /* Allow the user to interrupt out of a lengthy path search. */
571 path
= get_next_path_element (path_list
, &path_index
);
575 /* Side effects: sets dot_found_in_search, possibly sets
577 full_path
= find_in_path_element (name
, path
, flags
, name_len
, &dotinfo
);
580 /* This should really be in find_in_path_element, but there isn't the
581 right combination of flags. */
582 if (full_path
&& is_directory (full_path
))
590 FREE (file_to_lose_on
);
595 /* We didn't find exactly what the user was looking for. Return
596 the contents of FILE_TO_LOSE_ON which is NULL when the search
597 required an executable, or non-NULL if a file was found and the
598 search would accept a non-executable as a last resort. If the
599 caller specified FS_NODIRS, and file_to_lose_on is a directory,
601 if (file_to_lose_on
&& (flags
& FS_NODIRS
) && is_directory (file_to_lose_on
))
603 free (file_to_lose_on
);
604 file_to_lose_on
= (char *)NULL
;
607 return (file_to_lose_on
);