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