m_commandline.c revision b32f58018498ea2225959b0ba11c18f0c433deef
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-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_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
46static 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
56static 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
95static 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
153void 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