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-2011 Julian Seward
11 jseward@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 */
scan_colsep(char * colsep,Bool (* func)(const char *))64 static Bool scan_colsep(char *colsep, Bool (*func)(const char *))
65 {
66 char *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 char 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
match_executable(const char * entry)99 static Bool match_executable(const char *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.
ML_(find_executable)132 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