]> git.ipfire.org Git - thirdparty/bash.git/blame - findcmd.c
Bash-4.0 patchlevel 38
[thirdparty/bash.git] / findcmd.c
CommitLineData
cce855bc
JA
1/* findcmd.c -- Functions to search for commands by name. */
2
3185942a 3/* Copyright (C) 1997-2009 Free Software Foundation, Inc.
cce855bc
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
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.
cce855bc 11
3185942a
JA
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.
cce855bc
JA
16
17 You should have received a copy of the GNU General Public License
3185942a
JA
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
cce855bc
JA
20
21#include "config.h"
22
23#include <stdio.h>
f73dda09 24#include "chartypes.h"
cce855bc 25#include "bashtypes.h"
b80f6443 26#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
cce855bc
JA
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
cce855bc
JA
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"
f73dda09 44#include "findcmd.h" /* matching prototypes and declarations */
cce855bc
JA
45
46extern int posixly_correct;
47
48/* Static functions defined and used in this file. */
f73dda09
JA
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 *));
cce855bc
JA
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
cce855bc
JA
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)
f73dda09 80 const char *name;
cce855bc
JA
81{
82 struct stat finfo;
95732b49 83 int r;
cce855bc
JA
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
95732b49
JA
94 r = FS_EXISTS;
95
cce855bc
JA
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. */
95732b49
JA
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;
cce855bc
JA
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
95732b49 110 we can use. The same with whether or not a file is readable. */
cce855bc
JA
111
112 /* Root only requires execute permission for any of owner, group or
95732b49 113 others to be able to exec a file, and can read any file. */
cce855bc
JA
114 if (current_user.euid == (uid_t)0)
115 {
95732b49
JA
116 r |= FS_READABLE;
117 if (finfo.st_mode & S_IXUGO)
118 r |= FS_EXECABLE;
119 return r;
cce855bc
JA
120 }
121
95732b49 122 /* If we are the owner of the file, the owner bits apply. */
b80f6443 123 if (current_user.euid == finfo.st_uid)
95732b49
JA
124 {
125 if (finfo.st_mode & S_IXUSR)
126 r |= FS_EXECABLE;
127 if (finfo.st_mode & S_IRUSR)
128 r |= FS_READABLE;
129 }
cce855bc
JA
130
131 /* If we are in the owning group, the group permissions apply. */
b80f6443 132 else if (group_member (finfo.st_gid))
95732b49
JA
133 {
134 if (finfo.st_mode & S_IXGRP)
135 r |= FS_EXECABLE;
136 if (finfo.st_mode & S_IRGRP)
137 r |= FS_READABLE;
138 }
cce855bc 139
b80f6443
JA
140 /* Else we check whether `others' have permission to execute the file */
141 else
95732b49
JA
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;
cce855bc
JA
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)
f73dda09 159 const char *file;
cce855bc
JA
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)
f73dda09 169 const char *file;
cce855bc
JA
170{
171 return (file_status (file) & FS_DIRECTORY);
172}
173
28ef6c31
JA
174int
175executable_or_directory (file)
f73dda09 176 const char *file;
28ef6c31
JA
177{
178 int s;
179
180 s = file_status (file);
181 return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
182}
183
cce855bc
JA
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)
f73dda09 191 const char *name;
cce855bc
JA
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
95732b49
JA
199 returns the first readable file found; designed to be used to look
200 for shell scripts or files to source. */
cce855bc
JA
201char *
202find_path_file (name)
f73dda09 203 const char *name;
cce855bc 204{
95732b49 205 return (find_user_command_internal (name, FS_READABLE));
cce855bc
JA
206}
207
208static char *
209_find_user_command_internal (name, flags)
f73dda09 210 const char *name;
cce855bc
JA
211 int flags;
212{
213 char *path_list, *cmd;
214 SHELL_VAR *var;
215
7117c2d2 216 /* Search for the value of PATH in both the temporary environments and
cce855bc
JA
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
cce855bc
JA
228 return (cmd);
229}
230
231static char *
232find_user_command_internal (name, flags)
f73dda09 233 const char *name;
cce855bc
JA
234 int flags;
235{
236#ifdef __WIN32__
237 char *res, *dotexe;
238
f73dda09 239 dotexe = (char *)xmalloc (strlen (name) + 5);
cce855bc
JA
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
bb70624e 265 if (path == 0)
cce855bc
JA
266 return (path);
267
bb70624e 268 if (*path == '\0')
cce855bc
JA
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)
f73dda09 282 const char *pathname;
cce855bc
JA
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. */
7117c2d2
JA
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;
cce855bc
JA
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)
7117c2d2 301 hashed_file = phash_search (pathname);
cce855bc
JA
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);
f1be666c 310 if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
cce855bc 311 {
7117c2d2 312 phash_remove (pathname);
cce855bc
JA
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)
28ef6c31 329 {
cce855bc
JA
330 command = find_user_command_in_path (pathname, value_cell (path),
331 FS_EXEC_PREFERRED|FS_NODIRS);
28ef6c31 332 }
cce855bc
JA
333 else
334 command = find_user_command (pathname);
335 if (command && hashing_enabled && temp_path == 0)
7117c2d2 336 phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
cce855bc
JA
337 }
338 return (command);
339}
340
341char *
342user_command_matches (name, flags, state)
f73dda09 343 const char *name;
cce855bc
JA
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;
7117c2d2 360 match_list = strvec_create (match_list_size);
cce855bc
JA
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;
7117c2d2 403 match_list = strvec_resize (match_list, (match_list_size + 1));
cce855bc
JA
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
cce855bc
JA
424static char *
425find_absolute_program (name, flags)
f73dda09 426 const char *name;
cce855bc
JA
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
f73dda09 443 return (NULL);
cce855bc
JA
444}
445
446static char *
447find_in_path_element (name, path, flags, name_len, dotinfop)
f73dda09
JA
448 const char *name;
449 char *path;
cce855bc
JA
450 int flags, name_len;
451 struct stat *dotinfop;
452{
453 int status;
454 char *full_path, *xpath;
455
7117c2d2 456 xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
cce855bc
JA
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
bb70624e 463 full_path = sh_makepath (xpath, name, 0);
cce855bc
JA
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
95732b49
JA
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
cce855bc
JA
485 /* If the file is executable, then it satisfies the cases of
486 EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
95732b49 487 if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) &&
cce855bc
JA
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
95732b49
JA
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))
cce855bc
JA
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)
f73dda09 529 const char *name;
cce855bc
JA
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
28ef6c31
JA
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
cce855bc
JA
596 return (file_to_lose_on);
597}