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