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-2013 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_initimg.h" /* self */ 48 49 #include "priv_initimg_pathscan.h" 50 51 52 /*====================================================================*/ 53 /*=== Find executable ===*/ 54 /*====================================================================*/ 55 56 /* Scan a colon-separated list, and call a function on each element. 57 The string must be mutable, because we insert a temporary '\0', but 58 the string will end up unmodified. (*func) should return True if it 59 doesn't need to see any more. 60 61 This routine will return True if (*func) returns True and False if 62 it reaches the end of the list without that happening. 63 */ 64 static Bool scan_colsep(HChar *colsep, Bool (*func)(const HChar *)) 65 { 66 HChar *cp, *entry; 67 int end; 68 69 if (colsep == NULL || 70 *colsep == '\0') 71 return False; 72 73 entry = cp = colsep; 74 75 do { 76 end = (*cp == '\0'); 77 78 if (*cp == ':' || *cp == '\0') { 79 HChar save = *cp; 80 81 *cp = '\0'; 82 if ((*func)(entry)) { 83 *cp = save; 84 return True; 85 } 86 *cp = save; 87 entry = cp+1; 88 } 89 cp++; 90 } while(!end); 91 92 return False; 93 } 94 95 /* Need a static copy because can't use dynamic mem allocation yet */ 96 static HChar executable_name_in [VKI_PATH_MAX]; 97 static HChar executable_name_out[VKI_PATH_MAX]; 98 99 static Bool match_executable(const HChar *entry) 100 { 101 HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3]; 102 103 /* empty PATH element means '.' */ 104 if (*entry == '\0') 105 entry = "."; 106 107 VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in); 108 109 // Don't match directories 110 if (VG_(is_dir)(buf)) 111 return False; 112 113 // If we match an executable, we choose that immediately. If we find a 114 // matching non-executable we remember it but keep looking for an 115 // matching executable later in the path. 116 if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) { 117 VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 ); 118 executable_name_out[VKI_PATH_MAX-1] = 0; 119 return True; // Stop looking 120 } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0 121 && VG_STREQ(executable_name_out, "")) 122 { 123 VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 ); 124 executable_name_out[VKI_PATH_MAX-1] = 0; 125 return False; // Keep looking 126 } else { 127 return False; // Keep looking 128 } 129 } 130 131 // Returns NULL if it wasn't found. 132 const HChar* ML_(find_executable) ( const HChar* exec ) 133 { 134 vg_assert(NULL != exec); 135 if (VG_(strchr)(exec, '/')) { 136 // Has a '/' - use the name as is 137 VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 ); 138 } else { 139 // No '/' - we need to search the path 140 HChar* path; 141 VG_(strncpy)( executable_name_in, exec, VKI_PATH_MAX-1 ); 142 VG_(memset) ( executable_name_out, 0, VKI_PATH_MAX ); 143 path = VG_(getenv)("PATH"); 144 scan_colsep(path, match_executable); 145 } 146 return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out; 147 } 148 149 /*--------------------------------------------------------------------*/ 150 /*--- end ---*/ 151 /*--------------------------------------------------------------------*/ 152