2 /*--------------------------------------------------------------------*/
3 /*--- search PATH for an executable m_pathscan.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2017 Julian Seward
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
*))
65 if (*cp
== ':' || *cp
== '\0') {
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 '.' */
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
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
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:
126 // valgrind: ./foo: is a directory
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 /*--------------------------------------------------------------------*/
144 /*--------------------------------------------------------------------*/