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