1
2 /*--------------------------------------------------------------------*/
3 /*--- Command line handling. m_commandline.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2017 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_libcassert.h"
34 #include "pub_core_libcbase.h"
35 #include "pub_core_libcfile.h"
36 #include "pub_core_libcprint.h"
37 #include "pub_core_libcproc.h"
38 #include "pub_core_mallocfree.h"
39 #include "pub_core_xarray.h"
40 #include "pub_core_clientstate.h"
41 #include "pub_core_commandline.h" /* self */
42
43
44 /* Add a string to an expandable array of strings. */
45
add_string(XArray * xa,HChar * str)46 static void add_string ( XArray* /* of HChar* */xa, HChar* str )
47 {
48 (void) VG_(addToXA)( xa, (void*)(&str) );
49 }
50
51
52 /* Read the contents of .valgrindrc in 'dir' into malloc'd memory. */
53 // Note that we deliberately don't free the malloc'd memory. See
54 // comment at call site.
55
read_dot_valgrindrc(const HChar * dir)56 static HChar* read_dot_valgrindrc ( const HChar* dir )
57 {
58 struct vg_stat stat_buf;
59 HChar* f_clo = NULL;
60 const HChar dot_valgrindrc[] = ".valgrindrc";
61
62 vg_assert(dir != NULL);
63
64 HChar filename[VG_(strlen)(dir) + 1 + VG_(strlen)(dot_valgrindrc) + 1];
65 VG_(sprintf)(filename, "%s/%s", dir, dot_valgrindrc);
66
67 SysRes fd = VG_(open)(filename, 0, VKI_S_IRUSR);
68 if ( !sr_isError(fd) ) {
69 Int res = VG_(fstat)( sr_Res(fd), &stat_buf );
70 /* Ignore if not owned by the current user, or is not a regular file,
71 or is world writeable (CVE-2008-4865). */
72 if (res == 0
73 && stat_buf.uid == VG_(geteuid)()
74 && VKI_S_ISREG(stat_buf.mode)
75 && !(stat_buf.mode & VKI_S_IWOTH)) {
76 if ( stat_buf.size > 0 ) {
77 f_clo = VG_(malloc)("commandline.rdv.1", stat_buf.size+1);
78 Int n = VG_(read)(sr_Res(fd), f_clo, stat_buf.size);
79 if (n == -1) n = 0;
80 vg_assert(n >= 0 && n <= stat_buf.size+1);
81 f_clo[n] = '\0';
82 }
83 }
84 else
85 VG_(message)(Vg_UserMsg,
86 "%s was not read as it is either not a regular file,\n"
87 " or is world writeable, or is not owned by the current user.\n",
88 filename);
89
90 VG_(close)(sr_Res(fd));
91 }
92 return f_clo;
93 }
94
95
96 // Add args from a string into VG_(args_for_valgrind), splitting the
97 // string at whitespace and adding each component as a separate arg.
98
add_args_from_string(HChar * s)99 static void add_args_from_string ( HChar* s )
100 {
101 HChar* tmp;
102 HChar* cp = s;
103 vg_assert(cp);
104 while (True) {
105 // We have alternating sequences: blanks, non-blanks, blanks...
106 // copy the non-blanks sequences, and add terminating '\0'
107 while (VG_(isspace)(*cp)) cp++;
108 if (*cp == 0) break;
109 tmp = cp;
110 while ( !VG_(isspace)(*cp) && *cp != 0 ) cp++;
111 if ( *cp != 0 ) *cp++ = '\0'; // terminate if not the last
112 add_string( VG_(args_for_valgrind), tmp );
113 }
114 }
115
116
117 /* Split up the args presented by the launcher to m_main.main(), and
118 park them in VG_(args_for_client) and VG_(args_for_valgrind).
119
120 The resulting arg list is the concatenation of the following:
121 - contents of ~/.valgrindrc
122 - contents of $VALGRIND_OPTS
123 - contents of ./.valgrindrc
124 - args from the command line
125 in the stated order.
126
127 VG_(args_for_valgrind_noexecpass) is set to be the number of items
128 in the first three categories. They are not passed to child invocations
129 at exec, whereas the last group is.
130
131 If the last group contains --command-line-only=yes, then the
132 first three groups are left empty.
133
134 Scheme: first examine the last group (the supplied argc/argv).
135 It should look like this.
136
137 args-for-v exe_name args-for-c
138
139 args-for-v are taken until either they don't start with '-' or
140 a "--" is seen.
141
142 The exe name and args-for-c are recorded without further ado.
143 Note that args-for-c[0] is the first real arg for the client, not
144 its executable name.
145
146 args-for-v are then copied into tmp_xarray.
147
148 if args-for-v does not include --command-line-only=yes:
149 contents of ~/.valgrindrc, $VALGRIND_OPTS and ./.valgrindrc
150 are copied into VG_(args_for_valgrind).
151 else
152 VG_(args_for_valgrind) is made empty.
153
154 Finally, tmp_xarray is copied onto the end of VG_(args_for_valgrind).
155 */
156
VG_(split_up_argv)157 void VG_(split_up_argv)( Int argc, HChar** argv )
158 {
159 Int i;
160 Bool augment = True;
161 static Bool already_called = False;
162
163 XArray* /* of HChar* */ tmp_xarray;
164
165 /* This function should be called once, at startup, and then never
166 again. */
167 vg_assert(!already_called);
168 already_called = True;
169
170 tmp_xarray = VG_(newXA)( VG_(malloc), "commandline.sua.1",
171 VG_(free), sizeof(HChar*) );
172
173 vg_assert( ! VG_(args_for_valgrind) );
174 VG_(args_for_valgrind)
175 = VG_(newXA)( VG_(malloc), "commandline.sua.2",
176 VG_(free), sizeof(HChar*) );
177
178 vg_assert( ! VG_(args_for_client) );
179 VG_(args_for_client)
180 = VG_(newXA)( VG_(malloc), "commandline.sua.3",
181 VG_(free), sizeof(HChar*) );
182
183 /* Collect up the args-for-V. */
184 i = 1; /* skip the exe (stage2) name. */
185 for (; i < argc; i++) {
186 vg_assert(argv[i]);
187 if (0 == VG_(strcmp)(argv[i], "--")) {
188 i++;
189 break;
190 }
191 if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
192 augment = False;
193 if (argv[i][0] != '-')
194 break;
195 add_string( tmp_xarray, argv[i] );
196 }
197
198 /* Should now be looking at the exe name. */
199 if (i < argc) {
200 vg_assert(argv[i]);
201 VG_(args_the_exename) = argv[i];
202 i++;
203 }
204
205 /* The rest are args for the client. */
206 for (; i < argc; i++) {
207 vg_assert(argv[i]);
208 add_string( VG_(args_for_client), argv[i] );
209 }
210
211 /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
212 ./.valgrindrc into VG_(args_for_valgrind). */
213 if (augment) {
214 // read_dot_valgrindrc() allocates the return value with
215 // VG_(malloc)(). We do not free f1_clo and f2_clo as they get
216 // put into VG_(args_for_valgrind) and so must persist.
217 HChar* home = VG_(getenv)("HOME");
218 HChar* f1_clo = home ? read_dot_valgrindrc( home ) : NULL;
219 HChar* env_clo = VG_(strdup)( "commandline.sua.4",
220 VG_(getenv)(VALGRIND_OPTS) );
221 HChar* f2_clo = NULL;
222
223 // Don't read ./.valgrindrc if "." is the same as "$HOME", else its
224 // contents will be applied twice. (bug #142488)
225 // Also don't try to read it if there is no cwd.
226 if (home) {
227 const HChar *cwd = VG_(get_startup_wd)();
228 f2_clo = ( (cwd == NULL || VG_STREQ(home, cwd))
229 ? NULL : read_dot_valgrindrc(".") );
230 }
231
232 if (f1_clo) add_args_from_string( f1_clo );
233 if (env_clo) add_args_from_string( env_clo );
234 if (f2_clo) add_args_from_string( f2_clo );
235 }
236
237 /* .. and record how many extras we got. */
238 VG_(args_for_valgrind_noexecpass)
239 = VG_(sizeXA)( VG_(args_for_valgrind) );
240
241 /* Finally, copy tmp_xarray onto the end. */
242 for (i = 0; i < VG_(sizeXA)( tmp_xarray ); i++)
243 add_string( VG_(args_for_valgrind),
244 * (HChar**)VG_(indexXA)( tmp_xarray, i ) );
245
246 VG_(deleteXA)( tmp_xarray );
247 }
248
249 /*--------------------------------------------------------------------*/
250 /*--- end ---*/
251 /*--------------------------------------------------------------------*/
252