• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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