2 /*--------------------------------------------------------------------*/
3 /*--- Startup: search PATH for an executable initimg-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, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 The GNU General Public License is contained in the file COPYING.
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 */
40 #include "priv_initimg_pathscan.h"
43 /*====================================================================*/
44 /*=== Find executable ===*/
45 /*====================================================================*/
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.
52 This routine will return True if (*func) returns True and False if
53 it reaches the end of the list without that happening.
55 static Bool
scan_colsep(HChar
*colsep
, Bool (*func
)(const HChar
*))
69 if (*cp
== ':' || *cp
== '\0') {
87 static const HChar
*executable_name_in
;
88 static HChar
*executable_name_out
;
90 static Bool
match_executable(const HChar
*entry
)
92 /* empty ENTRY element means '.' */
96 HChar buf
[VG_(strlen
)(entry
) + 1 + VG_(strlen
)(executable_name_in
) + 1];
98 VG_(sprintf
)(buf
, "%s/%s", entry
, executable_name_in
);
100 // Don't match directories
101 if (VG_(is_dir
)(buf
))
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
)
114 executable_name_out
= VG_(strdup
)("match_executable", buf
);
115 return False
; // Keep looking
117 return False
; // Keep looking
121 // Returns NULL if it wasn't found.
122 const HChar
* ML_(find_executable
) ( const HChar
* exec
)
124 vg_assert(NULL
!= exec
);
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:
130 // valgrind: ./foo: is a directory
134 // No '/' - we need to search the path
135 HChar
* path
= VG_(getenv
)("PATH");
137 VG_(free
)(executable_name_out
);
139 executable_name_in
= exec
;
140 executable_name_out
= NULL
;
141 scan_colsep(path
, match_executable
);
143 return executable_name_out
;
146 /*--------------------------------------------------------------------*/
148 /*--------------------------------------------------------------------*/