| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | /* hashcmd.c - functions for managing a hash table mapping command names to
 | 
					
						
							|  |  |  | 	       full pathnames. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* Copyright (C) 1997-2009 Free Software Foundation, Inc.
 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    Bash is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |    it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |    the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |    (at your option) any later version. | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    Bash is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |    GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bashtypes.h"
 | 
					
						
							|  |  |  | #include "posixstat.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (HAVE_UNISTD_H)
 | 
					
						
							|  |  |  | #  include <unistd.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bashansi.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "shell.h"
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include "findcmd.h"
 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | #include "hashcmd.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern int hashing_enabled; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static void phash_freedata __P((PTR_T)); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | phash_create () | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if (hashed_filenames == 0) | 
					
						
							|  |  |  |     hashed_filenames = hash_create (FILENAME_HASH_BUCKETS); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | phash_freedata (data) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      PTR_T data; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   free (((PATH_DATA *)data)->path); | 
					
						
							|  |  |  |   free (data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | phash_flush () | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (hashed_filenames) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     hash_flush (hashed_filenames, phash_freedata); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Remove FILENAME from the table of hashed commands. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | int | 
					
						
							|  |  |  | phash_remove (filename) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      const char *filename; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   register BUCKET_CONTENTS *item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (hashing_enabled == 0 || hashed_filenames == 0) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   item = hash_remove (filename, hashed_filenames, 0); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   if (item) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (item->data) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	phash_freedata (item->data); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |       free (item->key); | 
					
						
							|  |  |  |       free (item); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       return 0; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   return 1; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | /* Place FILENAME (key) and FULL_PATH (data->path) into the
 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |    hash table.  CHECK_DOT if non-null is for future calls to | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |    phash_search (); it means that this file was found | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |    in a directory in $PATH that is not an absolute pathname. | 
					
						
							|  |  |  |    FOUND is the initial value for times_found. */ | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | phash_insert (filename, full_path, check_dot, found) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      char *filename, *full_path; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |      int check_dot, found; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   register BUCKET_CONTENTS *item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (hashing_enabled == 0) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if (hashed_filenames == 0) | 
					
						
							|  |  |  |     phash_create (); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   item = hash_insert (filename, hashed_filenames, 0); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   if (item->data) | 
					
						
							|  |  |  |     free (pathdata(item)->path); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       item->key = savestring (filename); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       item->data = xmalloc (sizeof (PATH_DATA)); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   pathdata(item)->path = savestring (full_path); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   pathdata(item)->flags = 0; | 
					
						
							|  |  |  |   if (check_dot) | 
					
						
							|  |  |  |     pathdata(item)->flags |= HASH_CHKDOT; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   if (*full_path != '/') | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |     pathdata(item)->flags |= HASH_RELPATH; | 
					
						
							|  |  |  |   item->times_found = found; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return the full pathname that FILENAME hashes to.  If FILENAME
 | 
					
						
							|  |  |  |    is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check | 
					
						
							|  |  |  |    ./FILENAME and return that if it is executable.  This always | 
					
						
							|  |  |  |    returns a newly-allocated string; the caller is responsible | 
					
						
							|  |  |  |    for freeing it. */ | 
					
						
							|  |  |  | char * | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | phash_search (filename) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      const char *filename; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   register BUCKET_CONTENTS *item; | 
					
						
							|  |  |  |   char *path, *dotted_filename, *tail; | 
					
						
							|  |  |  |   int same; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (hashing_enabled == 0 || hashed_filenames == 0) | 
					
						
							|  |  |  |     return ((char *)NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   item = hash_search (filename, hashed_filenames, 0); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (item == NULL) | 
					
						
							|  |  |  |     return ((char *)NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If this filename is hashed, but `.' comes before it in the path,
 | 
					
						
							|  |  |  |      see if ./filename is executable.  If the hashed value is not an | 
					
						
							|  |  |  |      absolute pathname, see if ./`hashed-value' exists. */ | 
					
						
							|  |  |  |   path = pathdata(item)->path; | 
					
						
							|  |  |  |   if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH)) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       tail = (pathdata(item)->flags & HASH_RELPATH) ? path : (char *)filename;	/* XXX - fix const later */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |       /* If the pathname does not start with a `./', add a `./' to it. */ | 
					
						
							|  |  |  |       if (tail[0] != '.' || tail[1] != '/') | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	  dotted_filename = (char *)xmalloc (3 + strlen (tail)); | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	  dotted_filename[0] = '.'; dotted_filename[1] = '/'; | 
					
						
							|  |  |  | 	  strcpy (dotted_filename + 2, tail); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	dotted_filename = savestring (tail); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (executable_file (dotted_filename)) | 
					
						
							|  |  |  | 	return (dotted_filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       free (dotted_filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  |       if (pathdata(item)->flags & HASH_RELPATH) | 
					
						
							|  |  |  | 	return ((char *)NULL); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Watch out.  If this file was hashed to "./filename", and
 | 
					
						
							|  |  |  | 	 "./filename" is not executable, then return NULL. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Since we already know "./filename" is not executable, what
 | 
					
						
							|  |  |  | 	 we're really interested in is whether or not the `path' | 
					
						
							|  |  |  | 	 portion of the hashed filename is equivalent to the current | 
					
						
							|  |  |  | 	 directory, but only if it starts with a `.'.  (This catches | 
					
						
							|  |  |  | 	 ./. and so on.)  same_file () tests general Unix file | 
					
						
							|  |  |  | 	 equivalence -- same device and inode. */ | 
					
						
							|  |  |  |       if (*path == '.') | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  same = 0; | 
					
						
							|  |  |  | 	  tail = (char *)strrchr (path, '/'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if (tail) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      *tail = '\0'; | 
					
						
							|  |  |  | 	      same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL); | 
					
						
							|  |  |  | 	      *tail = '/'; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  return same ? (char *)NULL : savestring (path); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return (savestring (path)); | 
					
						
							|  |  |  | } |