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