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