2 /*--------------------------------------------------------------------*/
3 /*--- Command line handling. m_commandline.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_vki.h"
31 #include "pub_core_libcassert.h"
32 #include "pub_core_libcbase.h"
33 #include "pub_core_libcfile.h"
34 #include "pub_core_libcprint.h"
35 #include "pub_core_libcproc.h"
36 #include "pub_core_mallocfree.h"
37 #include "pub_core_xarray.h"
38 #include "pub_core_clientstate.h"
39 #include "pub_core_commandline.h" /* self */
42 /* Add a string to an expandable array of strings. */
44 static void add_string ( XArray
* /* of HChar* */xa
, HChar
* str
)
46 (void) VG_(addToXA
)( xa
, (void*)(&str
) );
50 /* Read the contents of .valgrindrc in 'dir' into malloc'd memory. */
51 // Note that we deliberately don't free the malloc'd memory. See
52 // comment at call site.
54 static HChar
* read_dot_valgrindrc ( const HChar
* dir
)
56 struct vg_stat stat_buf
;
58 const HChar dot_valgrindrc
[] = ".valgrindrc";
60 vg_assert(dir
!= NULL
);
62 HChar filename
[VG_(strlen
)(dir
) + 1 + VG_(strlen
)(dot_valgrindrc
) + 1];
63 VG_(sprintf
)(filename
, "%s/%s", dir
, dot_valgrindrc
);
65 SysRes fd
= VG_(open
)(filename
, 0, VKI_S_IRUSR
);
66 if ( !sr_isError(fd
) ) {
67 Int res
= VG_(fstat
)( sr_Res(fd
), &stat_buf
);
68 /* Ignore if not owned by the current user, or is not a regular file,
69 or is world writable (CVE-2008-4865). */
71 && stat_buf
.uid
== VG_(geteuid
)()
72 && VKI_S_ISREG(stat_buf
.mode
)
73 && !(stat_buf
.mode
& VKI_S_IWOTH
)) {
74 if ( stat_buf
.size
> 0 ) {
75 f_clo
= VG_(malloc
)("commandline.rdv.1", stat_buf
.size
+1);
76 Int n
= VG_(read
)(sr_Res(fd
), f_clo
, stat_buf
.size
);
78 vg_assert(n
>= 0 && n
<= stat_buf
.size
+1);
83 VG_(message
)(Vg_UserMsg
,
84 "%s was not read as it is either not a regular file,\n"
85 " or is world writeable, or is not owned by the current user.\n",
88 VG_(close
)(sr_Res(fd
));
94 // Add args from a string into VG_(args_for_valgrind), splitting the
95 // string at whitespace and adding each component as a separate arg.
97 static void add_args_from_string ( HChar
* s
)
105 // We have alternating sequences: blanks, non-blanks, blanks...
106 // copy the non-blanks sequences, and add terminating '\0'
107 // deal with " or '-quoted strings properly.
108 while (VG_(isspace
)(*cp
)) cp
++;
111 while ( (quoted
|| !VG_(isspace
)(*cp
)) && *cp
) {
114 } else if (*cp
== '\'' || *cp
== '"') {
121 if (out
< cp
) *out
++ = '\0';
122 if ( *cp
!= 0 ) *cp
++ = '\0'; // terminate if not the last
123 add_string( VG_(args_for_valgrind
), tmp
);
128 /* Split up the args presented by the launcher to m_main.main(), and
129 park them in VG_(args_for_client) and VG_(args_for_valgrind).
131 The resulting arg list is the concatenation of the following:
132 - contents of ~/.valgrindrc
133 - contents of $VALGRIND_OPTS
134 - contents of ./.valgrindrc
135 - args from the command line
138 VG_(args_for_valgrind_noexecpass) is set to be the number of items
139 in the first three categories. They are not passed to child invocations
140 at exec, whereas the last group is.
142 If the last group contains --command-line-only=yes, then the
143 first three groups are left empty.
145 Scheme: first examine the last group (the supplied argc/argv).
146 It should look like this.
148 args-for-v exe_name args-for-c
150 args-for-v are taken until either they don't start with '-' or
153 The exe name and args-for-c are recorded without further ado.
154 Note that args-for-c[0] is the first real arg for the client, not
157 args-for-v are then copied into tmp_xarray.
159 if args-for-v does not include --command-line-only=yes:
160 contents of ~/.valgrindrc, $VALGRIND_OPTS and ./.valgrindrc
161 are copied into VG_(args_for_valgrind).
163 VG_(args_for_valgrind) is made empty.
165 Finally, tmp_xarray is copied onto the end of VG_(args_for_valgrind).
168 void VG_(split_up_argv
)( Int argc
, HChar
** argv
)
172 static Bool already_called
= False
;
174 XArray
* /* of HChar* */ tmp_xarray
;
176 /* This function should be called once, at startup, and then never
178 vg_assert(!already_called
);
179 already_called
= True
;
181 tmp_xarray
= VG_(newXA
)( VG_(malloc
), "commandline.sua.1",
182 VG_(free
), sizeof(HChar
*) );
184 vg_assert( ! VG_(args_for_valgrind
) );
185 VG_(args_for_valgrind
)
186 = VG_(newXA
)( VG_(malloc
), "commandline.sua.2",
187 VG_(free
), sizeof(HChar
*) );
189 vg_assert( ! VG_(args_for_client
) );
191 = VG_(newXA
)( VG_(malloc
), "commandline.sua.3",
192 VG_(free
), sizeof(HChar
*) );
194 /* Collect up the args-for-V. */
195 i
= 1; /* skip the exe (stage2) name. */
196 for (; i
< argc
; i
++) {
198 if (0 == VG_(strcmp
)(argv
[i
], "--")) {
202 if (0 == VG_(strcmp
)(argv
[i
], "--command-line-only=yes"))
204 /* mainly to allow overriding the regtest default */
205 if (0 == VG_(strcmp
)(argv
[i
], "--command-line-only=no")) {
208 if (argv
[i
][0] != '-')
210 add_string( tmp_xarray
, argv
[i
] );
213 /* Should now be looking at the exe name. */
216 VG_(args_the_exename
) = argv
[i
];
220 /* The rest are args for the client. */
221 for (; i
< argc
; i
++) {
223 add_string( VG_(args_for_client
), argv
[i
] );
226 /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
227 ./.valgrindrc into VG_(args_for_valgrind). */
229 // read_dot_valgrindrc() allocates the return value with
230 // VG_(malloc)(). We do not free f1_clo and f2_clo as they get
231 // put into VG_(args_for_valgrind) and so must persist.
232 HChar
* home
= VG_(getenv
)("HOME");
233 HChar
* f1_clo
= home
? read_dot_valgrindrc( home
) : NULL
;
234 HChar
* env_clo
= VG_(strdup
)( "commandline.sua.4",
235 VG_(getenv
)(VALGRIND_OPTS
) );
236 HChar
* f2_clo
= NULL
;
238 // Don't read ./.valgrindrc if "." is the same as "$HOME", else its
239 // contents will be applied twice. (bug #142488)
240 // Also don't try to read it if there is no cwd.
242 const HChar
*cwd
= VG_(get_startup_wd
)();
243 f2_clo
= ( (cwd
== NULL
|| VG_STREQ(home
, cwd
))
244 ? NULL
: read_dot_valgrindrc(".") );
247 if (f1_clo
) add_args_from_string( f1_clo
);
248 if (env_clo
) add_args_from_string( env_clo
);
249 if (f2_clo
) add_args_from_string( f2_clo
);
252 /* .. and record how many extras we got. */
253 VG_(args_for_valgrind_noexecpass
)
254 = VG_(sizeXA
)( VG_(args_for_valgrind
) );
256 /* Finally, copy tmp_xarray onto the end. */
257 for (i
= 0; i
< VG_(sizeXA
)( tmp_xarray
); i
++)
258 add_string( VG_(args_for_valgrind
),
259 * (HChar
**)VG_(indexXA
)( tmp_xarray
, i
) );
261 VG_(deleteXA
)( tmp_xarray
);
264 /*--------------------------------------------------------------------*/
266 /*--------------------------------------------------------------------*/