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-2017 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    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 
     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 
    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