-> 3.17.0 final.
[valgrind.git] / coregrind / m_pathscan.c
blob02b371486e77e8086f988a63ed2d7ab264a3d3a5
2 /*--------------------------------------------------------------------*/
3 /*--- search PATH for an executable m_pathscan.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2000-2017 Julian Seward
11 jseward@acm.org
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 #include "pub_core_basics.h"
30 #include "pub_core_libcbase.h"
31 #include "pub_core_libcassert.h"
32 #include "pub_core_libcfile.h"
33 #include "pub_core_libcproc.h"
34 #include "pub_core_libcprint.h"
35 #include "pub_core_mallocfree.h"
36 #include "pub_core_pathscan.h" /* self */
39 /*====================================================================*/
40 /*=== Find executable ===*/
41 /*====================================================================*/
43 /* Scan a colon-separated list, and call a function on each element.
44 The string must be mutable, because we insert a temporary '\0', but
45 the string will end up unmodified. (*func) should return True if it
46 doesn't need to see any more.
48 This routine will return True if (*func) returns True and False if
49 it reaches the end of the list without that happening.
51 static Bool scan_colsep(HChar *colsep, Bool (*func)(const HChar *))
53 HChar *cp, *entry;
54 int end;
56 if (colsep == NULL ||
57 *colsep == '\0')
58 return False;
60 entry = cp = colsep;
62 do {
63 end = (*cp == '\0');
65 if (*cp == ':' || *cp == '\0') {
66 HChar save = *cp;
68 *cp = '\0';
69 if ((*func)(entry)) {
70 *cp = save;
71 return True;
73 *cp = save;
74 entry = cp+1;
76 cp++;
77 } while(!end);
79 return False;
83 static const HChar *executable_name_in;
84 static HChar *executable_name_out;
86 static Bool match_executable(const HChar *entry)
88 /* empty ENTRY element means '.' */
89 if (*entry == '\0')
90 entry = ".";
92 HChar buf[VG_(strlen)(entry) + 1 + VG_(strlen)(executable_name_in) + 1];
94 VG_(sprintf)(buf, "%s/%s", entry, executable_name_in);
96 // Don't match directories
97 if (VG_(is_dir)(buf))
98 return False;
100 // If we match an executable, we choose that immediately. If we find a
101 // matching non-executable we remember it but keep looking for an
102 // matching executable later in the path.
103 if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) {
104 VG_(free)(executable_name_out);
105 executable_name_out = VG_(strdup)("match_executable", buf);
106 return True; // Stop looking
107 } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0
108 && executable_name_out == NULL)
110 executable_name_out = VG_(strdup)("match_executable", buf);
111 return False; // Keep looking
112 } else {
113 return False; // Keep looking
117 // Returns NULL if it wasn't found.
118 const HChar* VG_(find_executable) ( const HChar* exec )
120 vg_assert(NULL != exec);
122 if (VG_(strchr)(exec, '/')) {
123 // Has a '/' - use the name as is even if exec is a directory.
124 // The reason is that we get a better error message this way:
125 // valgrind ./foo
126 // valgrind: ./foo: is a directory
127 return exec;
130 // No '/' - we need to search the path
131 HChar* path = VG_(getenv)("PATH");
133 VG_(free)(executable_name_out);
135 executable_name_in = exec;
136 executable_name_out = NULL;
137 scan_colsep(path, match_executable);
139 return executable_name_out;
142 /*--------------------------------------------------------------------*/
143 /*--- end ---*/
144 /*--------------------------------------------------------------------*/