1 2 /*--------------------------------------------------------------------*/ 3 /*--- Startup: search PATH for an executable initimg-pathscan.c ---*/ 4 /*--------------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2007 Julian Seward 11 jseward (at) acm.org 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26 02111-1307, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 #include "pub_core_basics.h" 32 #include "pub_core_vki.h" 33 #include "pub_core_debuglog.h" 34 #include "pub_core_libcbase.h" 35 #include "pub_core_libcassert.h" 36 #include "pub_core_libcfile.h" 37 #include "pub_core_libcproc.h" 38 #include "pub_core_libcprint.h" 39 #include "pub_core_xarray.h" 40 #include "pub_core_clientstate.h" 41 #include "pub_core_aspacemgr.h" 42 #include "pub_core_mallocfree.h" 43 #include "pub_core_machine.h" 44 #include "pub_core_ume.h" 45 #include "pub_core_options.h" 46 #include "pub_core_tooliface.h" /* VG_TRACK */ 47 #include "pub_core_threadstate.h" /* ThreadArchState */ 48 #include "pub_core_initimg.h" /* self */ 49 50 #include "priv_initimg_pathscan.h" 51 52 53 /*====================================================================*/ 54 /*=== Find executable ===*/ 55 /*====================================================================*/ 56 57 /* Scan a colon-separated list, and call a function on each element. 58 The string must be mutable, because we insert a temporary '\0', but 59 the string will end up unmodified. (*func) should return True if it 60 doesn't need to see any more. 61 62 This routine will return True if (*func) returns True and False if 63 it reaches the end of the list without that happening. 64 */ 65 static Bool scan_colsep(char *colsep, Bool (*func)(const char *)) 66 { 67 char *cp, *entry; 68 int end; 69 70 if (colsep == NULL || 71 *colsep == '\0') 72 return False; 73 74 entry = cp = colsep; 75 76 do { 77 end = (*cp == '\0'); 78 79 if (*cp == ':' || *cp == '\0') { 80 char save = *cp; 81 82 *cp = '\0'; 83 if ((*func)(entry)) { 84 *cp = save; 85 return True; 86 } 87 *cp = save; 88 entry = cp+1; 89 } 90 cp++; 91 } while(!end); 92 93 return False; 94 } 95 96 /* Need a static copy because can't use dynamic mem allocation yet */ 97 static HChar executable_name_in [VKI_PATH_MAX]; 98 static HChar executable_name_out[VKI_PATH_MAX]; 99 100 static Bool match_executable(const char *entry) 101 { 102 HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3]; 103 104 /* empty PATH element means '.' */ 105 if (*entry == '\0') 106 entry = "."; 107 108 VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in); 109 110 // Don't match directories 111 if (VG_(is_dir)(buf)) 112 return False; 113 114 // If we match an executable, we choose that immediately. If we find a 115 // matching non-executable we remember it but keep looking for an 116 // matching executable later in the path. 117 if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) { 118 VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 ); 119 executable_name_out[VKI_PATH_MAX-1] = 0; 120 return True; // Stop looking 121 } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0 122 && VG_STREQ(executable_name_out, "")) 123 { 124 VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 ); 125 executable_name_out[VKI_PATH_MAX-1] = 0; 126 return False; // Keep looking 127 } else { 128 return False; // Keep looking 129 } 130 } 131 132 // Returns NULL if it wasn't found. 133 HChar* ML_(find_executable) ( const HChar* exec ) 134 { 135 vg_assert(NULL != exec); 136 if (VG_(strchr)(exec, '/')) { 137 // Has a '/' - use the name as is 138 VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 ); 139 } else { 140 // No '/' - we need to search the path 141 HChar* path; 142 VG_(strncpy)( executable_name_in, exec, VKI_PATH_MAX-1 ); 143 VG_(memset) ( executable_name_out, 0, VKI_PATH_MAX ); 144 path = VG_(getenv)("PATH"); 145 scan_colsep(path, match_executable); 146 } 147 return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out; 148 } 149 150 /*--------------------------------------------------------------------*/ 151 /*--- end ---*/ 152 /*--------------------------------------------------------------------*/ 153