LCOV - code coverage report
Current view: top level - mnt/wasteland/wcohen/systemtap_write/systemtap - util.cxx (source / functions) Hit Total Coverage
Test: stap.info Lines: 373 505 73.9 %
Date: 2013-03-08 Functions: 39 45 86.7 %
Branches: 446 1062 42.0 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) Andrew Tridgell 2002 (original file)
       2                 :            : // Copyright (C) 2006-2011 Red Hat Inc. (systemtap changes)
       3                 :            : //
       4                 :            : // This program is free software; you can redistribute it and/or
       5                 :            : // modify it under the terms of the GNU General Public License as
       6                 :            : // published by the Free Software Foundation; either version 2 of the
       7                 :            : // License, or (at your option) any later version.
       8                 :            : //
       9                 :            : // This program is distributed in the hope that it will be useful, but
      10                 :            : // WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
      12                 :            : // General Public License for more details.
      13                 :            : //
      14                 :            : // You should have received a copy of the GNU General Public License
      15                 :            : // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16                 :            : 
      17                 :            : #include "util.h"
      18                 :            : #include "stap-probe.h"
      19                 :            : #include <stdexcept>
      20                 :            : #include <cerrno>
      21                 :            : #include <map>
      22                 :            : #include <set>
      23                 :            : #include <string>
      24                 :            : #include <fstream>
      25                 :            : #include <cassert>
      26                 :            : #include <ext/stdio_filebuf.h>
      27                 :            : 
      28                 :            : extern "C" {
      29                 :            : #include <elf.h>
      30                 :            : #include <fcntl.h>
      31                 :            : #include <grp.h>
      32                 :            : #include <pwd.h>
      33                 :            : #include <spawn.h>
      34                 :            : #include <stdio.h>
      35                 :            : #include <stdlib.h>
      36                 :            : #include <sys/stat.h>
      37                 :            : #include <sys/types.h>
      38                 :            : #include <sys/wait.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <regex.h>
      41                 :            : #include <stdarg.h>
      42                 :            : #ifndef SINGLE_THREADED
      43                 :            : #include <pthread.h>
      44                 :            : #endif
      45                 :            : }
      46                 :            : 
      47                 :            : using namespace std;
      48                 :            : using namespace __gnu_cxx;
      49                 :            : 
      50                 :            : 
      51                 :            : // Return current users home directory or die.
      52                 :            : const char *
      53                 :         70 : get_home_directory(void)
      54                 :            : {
      55                 :         70 :   const char *p = getenv("HOME");
      56         [ +  - ]:         70 :   if (p)
      57                 :         70 :     return p;
      58                 :            : 
      59                 :          0 :   struct passwd *pwd = getpwuid(getuid());
      60         [ #  # ]:          0 :   if (pwd)
      61                 :          0 :     return pwd->pw_dir;
      62                 :            : 
      63                 :          0 :   cerr << _("Unable to determine home directory") << endl;
      64                 :         70 :   return "/";
      65                 :            : }
      66                 :            : 
      67                 :            : 
      68                 :            : // Get the size of a file in bytes
      69                 :            : size_t
      70                 :       4185 : get_file_size(const string &path)
      71                 :            : {
      72                 :            :   struct stat file_info;
      73                 :            : 
      74 [ +  - ][ +  + ]:       4185 :   if (stat(path.c_str(), &file_info) == 0)
      75                 :       4150 :     return file_info.st_size;
      76                 :            :   else
      77                 :       4185 :     return 0;
      78                 :            : }
      79                 :            : 
      80                 :            : // Get the size of a file in bytes
      81                 :            : size_t
      82                 :        988 : get_file_size(int fd)
      83                 :            : {
      84                 :            :   struct stat file_info;
      85                 :            : 
      86         [ +  - ]:        988 :   if (fstat(fd, &file_info) == 0)
      87                 :        988 :     return file_info.st_size;
      88                 :            :   else
      89                 :        988 :     return 0;
      90                 :            : }
      91                 :            : 
      92                 :            : // Check that a file is present
      93                 :            : bool
      94                 :       5281 : file_exists (const string &path)
      95                 :            : {
      96                 :            :   struct stat file_info;
      97                 :            : 
      98 [ +  - ][ +  + ]:       5281 :   if (stat(path.c_str(), &file_info) == 0)
      99                 :       4349 :     return true;
     100                 :            : 
     101                 :       5281 :   return false;
     102                 :            : }
     103                 :            : 
     104                 :            : // Copy a file.  The copy is done via a temporary file and atomic
     105                 :            : // rename.
     106                 :            : bool
     107                 :       2856 : copy_file(const string& src, const string& dest, bool verbose)
     108                 :            : {
     109                 :            :   int fd1, fd2;
     110                 :            :   char buf[10240];
     111                 :            :   int n;
     112         [ +  - ]:       2856 :   string tmp;
     113                 :            :   char *tmp_name;
     114                 :            :   mode_t mask;
     115                 :            : 
     116         [ +  + ]:       2856 :   if (verbose)
     117 [ +  - ][ +  - ]:         48 :     clog << _F("Copying %s to %s", src.c_str(), dest.c_str()) << endl;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     118                 :            : 
     119                 :            :   // Open the src file.
     120 [ +  - ][ +  - ]:       2856 :   fd1 = open(src.c_str(), O_RDONLY);
     121         [ -  + ]:       2856 :   if (fd1 == -1)
     122                 :          0 :     goto error;
     123                 :            : 
     124                 :            :   // Open the temporary output file.
     125 [ +  - ][ +  - ]:       2856 :   tmp = dest + string(".XXXXXX");
         [ +  - ][ +  - ]
                 [ +  - ]
     126         [ +  - ]:       2856 :   tmp_name = (char *)tmp.c_str();
     127         [ +  - ]:       2856 :   fd2 = mkstemp(tmp_name);
     128         [ -  + ]:       2856 :   if (fd2 == -1)
     129                 :            :     {
     130         [ #  # ]:          0 :       close(fd1);
     131                 :          0 :       goto error;
     132                 :            :     }
     133                 :            : 
     134                 :            :   // Copy the src file to the temporary output file.
     135 [ +  - ][ +  + ]:      98724 :   while ((n = read(fd1, buf, sizeof(buf))) > 0)
     136                 :            :     {
     137 [ +  - ][ -  + ]:      95868 :       if (write(fd2, buf, n) != n)
     138                 :            :         {
     139         [ #  # ]:          0 :           close(fd2);
     140         [ #  # ]:          0 :           close(fd1);
     141                 :          0 :           unlink(tmp_name);
     142                 :          0 :           goto error;
     143                 :            :         }
     144                 :            :     }
     145         [ +  - ]:       2856 :   close(fd1);
     146                 :            : 
     147                 :            :   // Set the permissions on the temporary output file.
     148                 :       2856 :   mask = umask(0);
     149                 :       2856 :   fchmod(fd2, 0666 & ~mask);
     150                 :       2856 :   umask(mask);
     151                 :            : 
     152                 :            :   // Close the temporary output file.  The close can fail on NFS if
     153                 :            :   // out of space.
     154 [ +  - ][ -  + ]:       2856 :   if (close(fd2) == -1)
     155                 :            :     {
     156                 :          0 :       unlink(tmp_name);
     157                 :          0 :       goto error;
     158                 :            :     }
     159                 :            : 
     160                 :            :   // Rename the temporary output file to the destination file.
     161         [ +  - ]:       2856 :   unlink(dest.c_str());
     162 [ +  - ][ -  + ]:       2856 :   if (rename(tmp_name, dest.c_str()) == -1)
     163                 :            :     {
     164                 :          0 :       unlink(tmp_name);
     165                 :          0 :       goto error;
     166                 :            :     }
     167                 :            : 
     168                 :       2856 :   return true;
     169                 :            : 
     170                 :            : error:
     171 [ #  # ][ #  # ]:          0 :   cerr << _F("Copy failed (\"%s\" to \"%s\"): %s", src.c_str(),
         [ #  # ][ #  # ]
                 [ #  # ]
     172         [ #  # ]:          0 :              dest.c_str(), strerror(errno)) << endl;
     173         [ +  - ]:       2856 :   return false;
     174                 :            : }
     175                 :            : 
     176                 :            : 
     177                 :            : // Make sure a directory exists.
     178                 :            : int
     179                 :      15172 : create_dir(const char *dir, int mode)
     180                 :            : {
     181                 :            :   struct stat st;
     182         [ +  + ]:      15172 :   if (stat(dir, &st) == 0)
     183                 :            :     {
     184         [ +  + ]:      15078 :       if (S_ISDIR(st.st_mode))
     185                 :      15076 :         return 0;
     186                 :          2 :       errno = ENOTDIR;
     187                 :          2 :       return 1;
     188                 :            :     }
     189                 :            : 
     190                 :            :   // Create the directory. We must create each component
     191                 :            :   // of the path ourselves.
     192         [ +  - ]:         94 :   vector<string> components;
     193 [ +  - ][ +  - ]:         94 :   tokenize (dir, components, "/");
         [ +  - ][ +  - ]
                 [ +  - ]
     194         [ +  - ]:         94 :   string path;
     195         [ +  - ]:         94 :   if (*dir == '/')
     196                 :            :     {
     197                 :            :       // Absolute path
     198         [ +  - ]:         94 :       path = "/";
     199                 :            :     }
     200                 :         94 :   unsigned limit = components.size ();
     201         [ -  + ]:         94 :   assert (limit != 0);
     202         [ +  + ]:        607 :   for (unsigned ix = 0; ix < limit; ++ix)
     203                 :            :     {
     204 [ +  - ][ +  - ]:        513 :       path += components[ix] + '/';
                 [ +  - ]
     205 [ +  - ][ +  + ]:        513 :       if (mkdir(path.c_str (), mode) != 0 && errno != EEXIST)
         [ -  + ][ -  + ]
     206                 :          0 :         return 1;
     207                 :            :     }
     208                 :            : 
     209 [ +  - ][ +  - ]:      15172 :   return 0;
     210                 :            : }
     211                 :            : 
     212                 :            : // Remove a file or directory
     213                 :            : int
     214                 :          2 : remove_file_or_dir (const char *name)
     215                 :            : {
     216                 :            :   int rc;
     217                 :            :   struct stat st;
     218                 :            : 
     219         [ +  - ]:          2 :   if ((rc = stat(name, &st)) != 0)
     220                 :            :     {
     221         [ +  - ]:          2 :       if (errno == ENOENT)
     222                 :          2 :         return 0;
     223                 :          0 :       return 1;
     224                 :            :     }
     225                 :            : 
     226         [ #  # ]:          0 :   if (remove (name) != 0)
     227                 :          0 :     return 1;
     228                 :            : 
     229                 :          2 :   return 0;
     230                 :            : }
     231                 :            : 
     232                 :            : /* Obtain the gid of the given group. */
     233                 :          0 : gid_t get_gid (const char *group_name)
     234                 :            : {
     235                 :            :   struct group *stgr;
     236                 :            :   /* If we couldn't find the group, return an invalid number. */
     237                 :          0 :   stgr = getgrnam(group_name);
     238         [ #  # ]:          0 :   if (stgr == NULL)
     239                 :          0 :     return (gid_t)-1;
     240                 :          0 :   return stgr->gr_gid;
     241                 :            : }
     242                 :            : 
     243                 :            : // Determine whether the current user is in the given group
     244                 :            : // by gid.
     245                 :            : bool
     246                 :          0 : in_group_id (gid_t target_gid)
     247                 :            : {
     248                 :            :   // According to the getgroups() man page, getgroups() may not
     249                 :            :   // return the effective gid, so try to match it first. */
     250         [ #  # ]:          0 :   if (target_gid == getegid())
     251                 :          0 :     return true;
     252                 :            : 
     253                 :            :   // Get the list of the user's groups.
     254                 :          0 :   int ngids = getgroups(0, 0); // Returns the number to allocate.
     255         [ #  # ]:          0 :   if (ngids > 0) {
     256                 :          0 :     gid_t gidlist[ngids];
     257                 :          0 :     ngids = getgroups(ngids, gidlist);
     258 [ #  # ][ #  # ]:          0 :     for (int i = 0; i < ngids; i++) {
     259                 :            :       // If the user is a member of the target group, then we're done.
     260         [ #  # ]:          0 :       if (gidlist[i] == target_gid)
     261                 :          0 :         return true;
     262                 :            :     }
     263                 :            :   }
     264         [ #  # ]:          0 :   if (ngids < 0) {
     265                 :          0 :     cerr << _("Unable to retrieve group list") << endl;
     266                 :          0 :     return false;
     267                 :            :   }
     268                 :            : 
     269                 :            :   // The user is not a member of the target group
     270                 :          0 :   return false;
     271                 :            : }
     272                 :            : 
     273                 :            : /*
     274                 :            :  * Returns a string describing memory resource usage.
     275                 :            :  * Since it seems getrusage() doesn't maintain the mem related fields,
     276                 :            :  * this routine parses /proc/self/statm to get the statistics.
     277                 :            :  */
     278                 :            : string
     279                 :        294 : getmemusage ()
     280                 :            : {
     281 [ +  + ][ +  - ]:        294 :   static long sz = sysconf(_SC_PAGESIZE);
     282                 :            : 
     283                 :            :   long pages;
     284         [ +  - ]:        294 :   ostringstream oss;
     285         [ +  - ]:        294 :   ifstream statm("/proc/self/statm");
     286         [ +  - ]:        294 :   statm >> pages;
     287                 :        294 :   long kb1 = pages * sz / 1024; // total program size; vmsize
     288         [ +  - ]:        294 :   statm >> pages;
     289                 :        294 :   long kb2 = pages * sz / 1024; // resident set size; vmrss
     290         [ +  - ]:        294 :   statm >> pages;
     291                 :        294 :   long kb3 = pages * sz / 1024; // shared pages
     292         [ +  - ]:        294 :   statm >> pages;
     293                 :        294 :   long kb4 = pages * sz / 1024; // text
     294         [ +  - ]:        294 :   statm >> pages;
     295                 :            :   (void) kb4;
     296                 :        294 :   long kb5 = pages * sz / 1024; // library
     297         [ +  - ]:        294 :   statm >> pages;
     298                 :            :   (void) kb5;
     299                 :        294 :   long kb6 = pages * sz / 1024; // data+stack
     300         [ +  - ]:        294 :   statm >> pages;
     301                 :        294 :   long kb7 = pages * sz / 1024; // dirty
     302                 :            :   (void) kb7;
     303                 :            : 
     304 [ +  - ][ +  - ]:        294 :   oss << _F("using %ldvirt/%ldres/%ldshr/%lddata kb, ", kb1, kb2, kb3, kb6);
                 [ +  - ]
     305 [ +  - ][ +  - ]:        294 :   return oss.str();
                 [ +  - ]
     306                 :            : }
     307                 :            : 
     308                 :            : void
     309                 :   14500865 : tokenize(const string& str, vector<string>& tokens,
     310                 :            :          const string& delimiters = " ")
     311                 :            : {
     312                 :            :   // Skip delimiters at beginning.
     313                 :   14500865 :   string::size_type lastPos = str.find_first_not_of(delimiters, 0);
     314                 :            :   // Find first "non-delimiter".
     315                 :   14500865 :   string::size_type pos     = str.find_first_of(delimiters, lastPos);
     316                 :            : 
     317 [ +  + ][ +  + ]:   72469752 :   while (pos != string::npos || lastPos != string::npos)
                 [ +  + ]
     318                 :            :     {
     319                 :            :       // Found a token, add it to the vector.
     320         [ +  - ]:   57968887 :       tokens.push_back(str.substr(lastPos, pos - lastPos));
     321                 :            :       // Skip delimiters.  Note the "not_of"
     322                 :   57968887 :       lastPos = str.find_first_not_of(delimiters, pos);
     323                 :            :       // Find next "non-delimiter"
     324                 :   57968887 :       pos = str.find_first_of(delimiters, lastPos);
     325                 :            :     }
     326                 :   14500865 : }
     327                 :            : 
     328                 :            : // Akin to tokenize(...,...), but allow tokens before the first delimeter, after the
     329                 :            : // last delimiter and allow internal empty tokens
     330                 :            : void
     331                 :         11 : tokenize_full(const string& str, vector<string>& tokens,
     332                 :            :               const string& delimiters = " ")
     333                 :            : {
     334                 :            :   // Check for an empty string or a string of length 1. Neither can have the requested
     335                 :            :   // components.
     336         [ -  + ]:         11 :   if (str.size() <= 1)
     337                 :          0 :     return;
     338                 :            : 
     339                 :            :   // Find the first delimeter.
     340                 :         11 :   string::size_type lastPos = 0;
     341                 :         11 :   string::size_type pos = str.find_first_of(delimiters, lastPos);
     342         [ +  + ]:         11 :   if (pos == string::npos)
     343                 :          2 :     return; // no delimeters
     344                 :            : 
     345                 :            :   /* No leading empty component allowed. */
     346         [ -  + ]:          9 :   if (pos == lastPos)
     347                 :          0 :     ++lastPos;
     348                 :            : 
     349         [ -  + ]:          9 :   assert (lastPos < str.size());
     350         [ +  - ]:          9 :   do
     351                 :            :     {
     352                 :         18 :       pos = str.find_first_of(delimiters, lastPos);
     353         [ +  + ]:         18 :       if (pos == string::npos)
     354                 :          9 :         break; // Final trailing component
     355                 :            :       // Found a token, add it to the vector.
     356         [ +  - ]:          9 :       tokens.push_back(str.substr (lastPos, pos - lastPos));
     357                 :            :       // Skip the delimiter.
     358                 :          9 :       lastPos = pos + 1;
     359                 :            :     }
     360                 :          9 :   while (lastPos < str.size());
     361                 :            : 
     362                 :            :   // A final non-delimited token, if it is not empty.
     363         [ +  - ]:          9 :   if (lastPos < str.size())
     364                 :            :     {
     365         [ -  + ]:          9 :       assert (pos == string::npos);
     366         [ +  - ]:         11 :       tokens.push_back(str.substr (lastPos));
     367                 :            :     }
     368                 :            : }
     369                 :            : 
     370                 :            : // Akin to tokenize(...,"::"), but it also has to deal with C++ template
     371                 :            : // madness.  We do this naively by balancing '<' and '>' characters.  This
     372                 :            : // doesn't eliminate blanks either, so a leading ::scope still works.
     373                 :            : void
     374                 :          0 : tokenize_cxx(const string& str, vector<string>& tokens)
     375                 :            : {
     376                 :          0 :   int angle_count = 0;
     377                 :          0 :   string::size_type pos = 0;
     378                 :          0 :   string::size_type colon_pos = str.find("::");
     379                 :          0 :   string::size_type angle_pos = str.find_first_of("<>");
     380 [ #  # ][ #  # ]:          0 :   while (colon_pos != string::npos &&
         [ #  # ][ #  # ]
     381                 :            :          (angle_count == 0 || angle_pos != string::npos))
     382                 :            :     {
     383 [ #  # ][ #  # ]:          0 :       if (angle_count > 0 || angle_pos < colon_pos)
     384                 :            :         {
     385         [ #  # ]:          0 :           angle_count += str.at(angle_pos) == '<' ? 1 : -1;
     386                 :          0 :           colon_pos = str.find("::", angle_pos + 1);
     387                 :          0 :           angle_pos = str.find_first_of("<>", angle_pos + 1);
     388                 :            :         }
     389                 :            :       else
     390                 :            :         {
     391         [ #  # ]:          0 :           tokens.push_back(str.substr(pos, colon_pos - pos));
     392                 :          0 :           pos = colon_pos + 2;
     393                 :          0 :           colon_pos = str.find("::", pos);
     394                 :          0 :           angle_pos = str.find_first_of("<>", pos);
     395                 :            :         }
     396                 :            :     }
     397         [ #  # ]:          0 :   tokens.push_back(str.substr(pos));
     398                 :          0 : }
     399                 :            : 
     400                 :            : 
     401                 :            : // Resolve an executable name to a canonical full path name, with the
     402                 :            : // same policy as execvp().  A program name not containing a slash
     403                 :            : // will be searched along the $PATH.
     404                 :            : 
     405                 :        880 : string find_executable(const string& name)
     406                 :            : {
     407         [ +  - ]:        880 :   const map<string, string> sysenv;
     408 [ +  - ][ +  - ]:        880 :   return find_executable(name, "", sysenv);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     409                 :            : }
     410                 :            : 
     411                 :       1154 : string find_executable(const string& name, const string& sysroot,
     412                 :            :                        const map<string, string>& sysenv,
     413                 :            :                        const string& env_path)
     414                 :            : {
     415         [ +  - ]:       1154 :   string retpath;
     416                 :            : 
     417 [ +  - ][ +  + ]:       1154 :   if (name.size() == 0)
     418         [ +  - ]:          1 :     return name;
     419                 :            : 
     420                 :            :   struct stat st;
     421                 :            : 
     422 [ +  - ][ +  + ]:       1153 :   if (name.find('/') != string::npos) // slash in the path already?
     423                 :            :     {
     424 [ +  - ][ +  - ]:        204 :       retpath = sysroot + name;
                 [ +  - ]
     425                 :            :     }
     426                 :            :   else // Nope, search $PATH.
     427                 :            :     {
     428                 :            :       const char *path;
     429 [ +  - ][ -  + ]:        949 :       if (sysenv.count(env_path) != 0)
     430 [ #  # ][ #  # ]:          0 :         path = sysenv.find(env_path)->second.c_str();
                 [ #  # ]
     431                 :            :       else
     432         [ +  - ]:        949 :         path = getenv(env_path.c_str());
     433         [ +  - ]:        949 :       if (path)
     434                 :            :         {
     435                 :            :           // Split PATH up.
     436         [ +  - ]:        949 :           vector<string> dirs;
     437 [ +  - ][ +  - ]:        949 :           tokenize(string(path), dirs, string(":"));
         [ +  - ][ +  - ]
                 [ +  - ]
     438                 :            : 
     439                 :            :           // Search the path looking for the first executable of the right name.
     440 [ +  - ][ +  - ]:       4248 :           for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
         [ +  - ][ +  - ]
                 [ +  + ]
     441                 :            :             {
     442 [ +  - ][ +  - ]:       3299 :               string fname = sysroot + *i + "/" + name;
         [ +  - ][ +  - ]
                 [ +  - ]
     443         [ +  - ]:       3299 :               const char *f = fname.c_str();
     444                 :            : 
     445                 :            :               // Look for a normal executable file.
     446   [ +  +  +  - ]:       4238 :               if (access(f, X_OK) == 0
         [ +  - ][ +  + ]
     447                 :        939 :                   && stat(f, &st) == 0
     448                 :            :                   && S_ISREG(st.st_mode))
     449                 :            :                 {
     450         [ +  - ]:       3299 :                   retpath = fname;
     451                 :            :                   break;
     452                 :            :                 }
     453 [ +  - ][ +  + ]:       4248 :             }
                 [ +  - ]
     454                 :            :         }
     455                 :            :     }
     456                 :            : 
     457                 :            : 
     458                 :            :   // Could not find the program on the $PATH.  We'll just fall back to
     459                 :            :   // the unqualified name, which our caller will probably fail with.
     460 [ +  - ][ +  + ]:       1153 :   if (retpath == "")
     461 [ +  - ][ +  - ]:         10 :     retpath = sysroot + name;
                 [ +  - ]
     462                 :            : 
     463                 :            :   // Canonicalize the path name.
     464         [ +  - ]:       1153 :   char *cf = canonicalize_file_name (retpath.c_str());
     465         [ +  + ]:       1153 :   if (cf)
     466                 :            :     {
     467         [ +  - ]:       1137 :       string scf = string(cf);
     468 [ +  - ][ +  - ]:       1137 :       if (sysroot.empty())
     469         [ +  - ]:       1137 :         retpath = scf;
     470                 :            :       else {
     471         [ #  # ]:          0 :         int pos = scf.find(sysroot);
     472         [ #  # ]:          0 :         if (pos == 0)
     473         [ #  # ]:          0 :           retpath = scf;
     474                 :            :         else
     475 [ #  # ][ #  # ]:          0 :           throw runtime_error(_F("find_executable(): file %s not in sysroot %s", cf, sysroot.c_str()));
                 [ #  # ]
     476                 :            :       }
     477         [ +  - ]:       1137 :       free (cf);
     478                 :            :     }
     479                 :            : 
     480 [ +  - ][ +  - ]:       1154 :   return retpath;
     481                 :            : }
     482                 :            : 
     483                 :            : 
     484                 :            : 
     485                 :         70 : const string cmdstr_quoted(const string& cmd)
     486                 :            : {
     487                 :            :         // original cmd : substr1
     488                 :            :         //           or : substr1'substr2
     489                 :            :         //           or : substr1'substr2'substr3......
     490                 :            :         // after quoted :
     491                 :            :         // every substr(even it's empty) is quoted by ''
     492                 :            :         // every single-quote(') is quoted by ""
     493                 :            :         // examples: substr1 --> 'substr1'
     494                 :            :         //           substr1'substr2 --> 'substr1'"'"'substr2'
     495                 :            : 
     496         [ +  - ]:         70 :         string quoted_cmd;
     497         [ +  - ]:         70 :         string quote("'");
     498         [ +  - ]:         70 :         string replace("'\"'\"'");
     499                 :         70 :         string::size_type pos = 0;
     500                 :            : 
     501         [ +  - ]:         70 :         quoted_cmd += quote;
     502 [ +  - ][ #  # ]:         70 :         for (string::size_type quote_pos = cmd.find(quote, pos);
                 [ -  + ]
     503                 :            :                         quote_pos != string::npos;
     504                 :            :                         quote_pos = cmd.find(quote, pos)) {
     505 [ #  # ][ #  # ]:          0 :                 quoted_cmd += cmd.substr(pos, quote_pos - pos);
                 [ #  # ]
     506         [ #  # ]:          0 :                 quoted_cmd += replace;
     507                 :          0 :                 pos = quote_pos + 1;
     508                 :            :         }
     509 [ +  - ][ +  - ]:         70 :         quoted_cmd += cmd.substr(pos, cmd.length() - pos);
         [ +  - ][ +  - ]
     510         [ +  - ]:         70 :         quoted_cmd += quote;
     511                 :            : 
     512 [ +  - ][ +  - ]:         70 :         return quoted_cmd;
     513                 :            : }
     514                 :            : 
     515                 :            : 
     516                 :            : const string
     517                 :          0 : cmdstr_join(const vector<string>& cmds)
     518                 :            : {
     519 [ #  # ][ #  # ]:          0 :   if (cmds.empty())
     520 [ #  # ][ #  # ]:          0 :     throw runtime_error(_("cmdstr_join called with an empty command!"));
     521                 :            : 
     522         [ #  # ]:          0 :   stringstream cmd;
     523 [ #  # ][ #  # ]:          0 :   cmd << cmdstr_quoted(cmds[0]);
                 [ #  # ]
     524         [ #  # ]:          0 :   for (size_t i = 1; i < cmds.size(); ++i)
     525 [ #  # ][ #  # ]:          0 :     cmd << " " << cmdstr_quoted(cmds[i]);
         [ #  # ][ #  # ]
     526                 :            : 
     527 [ #  # ][ #  # ]:          0 :   return cmd.str();
     528                 :            : }
     529                 :            : 
     530                 :            : 
     531                 :            : // signal-safe set of pids
     532                 :            : class spawned_pids_t {
     533                 :            :   private:
     534                 :            :     set<pid_t> pids;
     535                 :            : #ifndef SINGLE_THREADED
     536                 :            :     pthread_mutex_t mux_pids;
     537                 :            : #endif
     538                 :            : 
     539                 :            :   public:
     540                 :         52 :     bool contains (pid_t p)
     541                 :            :       {
     542                 :         52 :         stap_sigmasker masked;
     543                 :            : 
     544                 :            : #ifndef SINGLE_THREADED
     545                 :         52 :         pthread_mutex_lock(&mux_pids);
     546                 :            : #endif
     547         [ +  - ]:         52 :         bool ret = (pids.count(p)==0) ? true : false;
     548                 :            : #ifndef SINGLE_THREADED
     549                 :         52 :         pthread_mutex_unlock(&mux_pids);
     550                 :            : #endif
     551                 :            : 
     552                 :         52 :         return ret;
     553                 :            :       }
     554                 :       3860 :     bool insert (pid_t p)
     555                 :            :       {
     556                 :       3860 :         stap_sigmasker masked;
     557                 :            : 
     558                 :            : #ifndef SINGLE_THREADED
     559                 :       3860 :         pthread_mutex_lock(&mux_pids);
     560                 :            : #endif
     561 [ +  - ][ +  - ]:       3860 :         bool ret = (p > 0) ? pids.insert(p).second : false;
         [ +  - ][ #  # ]
     562                 :            : #ifndef SINGLE_THREADED
     563                 :       3860 :         pthread_mutex_unlock(&mux_pids);
     564                 :            : #endif
     565                 :            : 
     566                 :       3860 :         return ret;
     567                 :            :       }
     568                 :       3860 :     void erase (pid_t p)
     569                 :            :       {
     570                 :       3860 :         stap_sigmasker masked;
     571                 :            : 
     572                 :            : #ifndef SINGLE_THREADED
     573                 :       3860 :         pthread_mutex_lock(&mux_pids);
     574                 :            : #endif
     575         [ +  - ]:       3860 :         pids.erase(p);
     576                 :            : #ifndef SINGLE_THREADED
     577                 :       3860 :         pthread_mutex_unlock(&mux_pids);
     578                 :            : #endif
     579                 :       3860 :       }
     580                 :        250 :     int killall (int sig)
     581                 :            :       {
     582                 :        250 :         int ret = 0;
     583                 :        250 :         stap_sigmasker masked;
     584                 :            : 
     585                 :            : #ifndef SINGLE_THREADED
     586                 :        250 :         pthread_mutex_lock(&mux_pids);
     587                 :            : #endif
     588 [ +  - ][ +  + ]:        716 :         for (set<pid_t>::const_iterator it = pids.begin();
     589         [ +  - ]:        358 :              it != pids.end(); ++it)
     590         [ -  + ]:        108 :           ret = kill(*it, sig) ?: ret;
     591                 :            : #ifndef SINGLE_THREADED
     592                 :        250 :         pthread_mutex_unlock(&mux_pids);
     593                 :            : #endif
     594                 :        250 :         return ret;
     595                 :            :       }
     596                 :       2938 :     spawned_pids_t()
     597                 :       2938 :       {
     598                 :            : #ifndef SINGLE_THREADED
     599                 :       2419 :         pthread_mutex_init(&mux_pids, NULL);
     600                 :            : #endif
     601                 :       2938 :       }
     602                 :       2938 :     ~spawned_pids_t()
     603                 :       2938 :       {
     604                 :            : #ifndef SINGLE_THREADED
     605                 :       2419 :         pthread_mutex_destroy (&mux_pids);
     606                 :            : #endif
     607                 :       2938 :       }
     608                 :            : 
     609                 :            : };
     610                 :       2938 : static spawned_pids_t spawned_pids;
     611                 :            : 
     612                 :            : 
     613                 :            : int
     614                 :       3860 : stap_waitpid(int verbose, pid_t pid)
     615                 :            : {
     616                 :            :   int ret, status;
     617 [ +  + ][ +  - ]:       3860 :   if (verbose > 1 && spawned_pids.contains(pid))
         [ -  + ][ -  + ]
     618 [ #  # ][ #  # ]:          0 :     clog << _F("Spawn waitpid call on unmanaged pid %d", pid) << endl;
         [ #  # ][ #  # ]
     619         [ +  - ]:       3860 :   ret = waitpid(pid, &status, 0);
     620         [ +  - ]:       3860 :   if (ret == pid)
     621                 :            :     {
     622         [ +  - ]:       3860 :       spawned_pids.erase(pid);
     623         [ +  + ]:       3860 :       ret = WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
     624         [ +  + ]:       3860 :       if (verbose > 1)
     625 [ +  - ][ +  - ]:         52 :         clog << _F("Spawn waitpid result (0x%x): %d", status, ret) << endl;
         [ +  - ][ +  - ]
     626                 :            :     }
     627                 :            :   else
     628                 :            :     {
     629         [ #  # ]:          0 :       if (verbose > 1)
     630 [ #  # ][ #  # ]:          0 :         clog << _F("Spawn waitpid error (%d): %s", ret, strerror(errno)) << endl;
         [ #  # ][ #  # ]
     631                 :          0 :       ret = -1;
     632                 :            :     }
     633                 :       3860 :   PROBE2(stap, stap_system__complete, ret, pid);
     634                 :       3860 :   return ret;
     635                 :            : }
     636                 :            : 
     637                 :            : static int
     638                 :         10 : pipe_child_fd(posix_spawn_file_actions_t* fa, int pipefd[2], int childfd)
     639                 :            : {
     640         [ -  + ]:         10 :   if (pipe(pipefd))
     641                 :          0 :     return -1;
     642                 :            : 
     643         [ +  + ]:         10 :   int dir = childfd ? 1 : 0;
     644   [ +  -  +  -  :         30 :   if (!fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) &&
           +  - ][ +  - ]
     645                 :         10 :       !fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) &&
     646                 :         10 :       !posix_spawn_file_actions_adddup2(fa, pipefd[dir], childfd))
     647                 :         10 :     return 0;
     648                 :            : 
     649                 :          0 :   close(pipefd[0]);
     650                 :          0 :   close(pipefd[1]);
     651                 :         10 :   return -1;
     652                 :            : }
     653                 :            : 
     654                 :            : static int
     655                 :         22 : null_child_fd(posix_spawn_file_actions_t* fa, int childfd)
     656                 :            : {
     657         [ +  - ]:         22 :   int flags = childfd ? O_WRONLY : O_RDONLY;
     658                 :         22 :   return posix_spawn_file_actions_addopen(fa, childfd, "/dev/null", flags, 0);
     659                 :            : }
     660                 :            : 
     661                 :            : // Runs a command with a saved PID, so we can kill it from the signal handler
     662                 :            : pid_t
     663                 :       3860 : stap_spawn(int verbose, const vector<string>& args,
     664                 :            :            posix_spawn_file_actions_t* fa, const vector<string>& envVec)
     665                 :            : {
     666                 :       3860 :   string::const_iterator it;
     667         [ +  - ]:       3860 :   it = args[0].begin();
     668                 :            :   const char *cmd;
     669         [ +  - ]:       3860 :   string command;
     670 [ +  + ][ +  - ]:       3860 :   if(*it == '/' && (access(args[0].c_str(), X_OK)==-1)) //checking to see if staprun is executable
         [ -  + ][ -  + ]
     671                 :            :     // XXX PR13274 needs-session to use print_warning()
     672 [ #  # ][ #  # ]:          0 :     clog << _F("WARNING: %s is not executable (%s)", args[0].c_str(), strerror(errno)) << endl;
         [ #  # ][ #  # ]
                 [ #  # ]
     673         [ +  + ]:      26265 :   for (size_t i = 0; i < args.size(); ++i)
     674 [ +  - ][ +  - ]:      22405 :     command += " " + args[i];
                 [ +  - ]
     675         [ +  - ]:       3860 :   cmd = command.c_str();
     676                 :       3860 :   PROBE1(stap, stap_system__start, cmd);
     677         [ +  + ]:       3860 :   if (verbose > 1)
     678 [ +  - ][ +  - ]:         52 :     clog << _("Running") << command << endl;
                 [ +  - ]
     679                 :            : 
     680                 :       3860 :   char const * argv[args.size() + 1];
     681         [ +  + ]:      26265 :   for (size_t i = 0; i < args.size(); ++i)
     682         [ +  - ]:      22405 :     argv[i] = args[i].c_str();
     683                 :       3860 :   argv[args.size()] = NULL;
     684                 :            : 
     685                 :            :   char** env;
     686                 :            :   bool allocated;
     687                 :            :   // environ can be NULL. This has been observed when running under gdb.
     688 [ +  - ][ +  + ]:       3860 :   if(envVec.empty() && environ != NULL)
         [ +  - ][ +  + ]
     689                 :            :   {
     690                 :       3825 :           env = environ;
     691                 :       3825 :           allocated = false;
     692                 :            :   }
     693                 :            :   else
     694                 :            :   {
     695                 :         35 :         allocated = true;
     696 [ +  - ][ +  - ]:         35 :         env = new char*[envVec.size() + 1];
     697                 :            : 
     698         [ +  + ]:       1618 :         for (size_t i = 0; i < envVec.size(); ++i)
     699         [ +  - ]:       1583 :             env[i] = (char*)envVec[i].c_str();
     700                 :         35 :           env[envVec.size()] = NULL;
     701                 :            :   }
     702                 :            : 
     703                 :       3860 :   pid_t pid = 0;
     704                 :            :   int ret = posix_spawnp(&pid, argv[0], fa, NULL,
     705         [ +  - ]:       3860 :                          const_cast<char * const *>(argv), env);
     706         [ +  + ]:       3860 :  if (allocated)
     707         [ +  - ]:         35 :           delete[] env;
     708                 :            : 
     709                 :       3860 :   PROBE2(stap, stap_system__spawn, ret, pid);
     710         [ -  + ]:       3860 :   if (ret != 0)
     711                 :            :     {
     712         [ #  # ]:          0 :       if (verbose > 1)
     713 [ #  # ][ #  # ]:          0 :         clog << _F("Spawn error (%d): %s", ret, strerror(ret)) << endl;
         [ #  # ][ #  # ]
     714                 :          0 :       pid = -1;
     715                 :            :     }
     716                 :            :   else
     717         [ +  - ]:       3860 :     spawned_pids.insert(pid);
     718         [ +  - ]:       3860 :   return pid;
     719                 :            : }
     720                 :            : 
     721                 :            : // The API version of stap_spawn doesn't expose file_actions, for now.
     722                 :            : pid_t
     723                 :        473 : stap_spawn(int verbose, const vector<string>& args)
     724                 :            : {
     725         [ +  - ]:        473 :   return stap_spawn(verbose, args, NULL);
     726                 :            : }
     727                 :            : 
     728                 :            : pid_t
     729                 :          6 : stap_spawn_piped(int verbose, const vector<string>& args,
     730                 :            :                  int *child_in, int *child_out, int* child_err)
     731                 :            : {
     732                 :          6 :   pid_t pid = -1;
     733                 :            :   int infd[2], outfd[2], errfd[2];
     734                 :            :   posix_spawn_file_actions_t fa;
     735         [ -  + ]:          6 :   if (posix_spawn_file_actions_init(&fa) != 0)
     736                 :          0 :     return -1;
     737                 :            : 
     738 [ +  + ][ +  - ]:          6 :   if (child_in && pipe_child_fd(&fa, infd, 0) != 0)
         [ -  + ][ -  + ]
     739                 :          0 :     goto cleanup_fa;
     740 [ +  - ][ +  - ]:          6 :   if (child_out && pipe_child_fd(&fa, outfd, 1) != 0)
         [ -  + ][ -  + ]
     741                 :          0 :     goto cleanup_in;
     742 [ -  + ][ #  # ]:          6 :   if (child_err && pipe_child_fd(&fa, errfd, 2) != 0)
         [ #  # ][ -  + ]
     743                 :          0 :     goto cleanup_out;
     744                 :            : 
     745 [ +  - ][ +  - ]:          6 :   pid = stap_spawn(verbose, args, &fa);
                 [ +  - ]
     746                 :            : 
     747         [ -  + ]:          6 :   if (child_err)
     748                 :            :     {
     749         [ #  # ]:          0 :       if (pid > 0)
     750                 :          0 :         *child_err = errfd[0];
     751                 :            :       else
     752         [ #  # ]:          0 :         close(errfd[0]);
     753         [ #  # ]:          0 :       close(errfd[1]);
     754                 :            :     }
     755                 :            : 
     756                 :            : cleanup_out:
     757         [ +  - ]:          6 :   if (child_out)
     758                 :            :     {
     759         [ +  - ]:          6 :       if (pid > 0)
     760                 :          6 :         *child_out = outfd[0];
     761                 :            :       else
     762         [ #  # ]:          0 :         close(outfd[0]);
     763         [ +  - ]:          6 :       close(outfd[1]);
     764                 :            :     }
     765                 :            : 
     766                 :            : cleanup_in:
     767         [ +  + ]:          6 :   if (child_in)
     768                 :            :     {
     769         [ +  - ]:          4 :       if (pid > 0)
     770                 :          4 :         *child_in = infd[1];
     771                 :            :       else
     772         [ #  # ]:          0 :         close(infd[1]);
     773         [ +  - ]:          4 :       close(infd[0]);
     774                 :            :     }
     775                 :            : 
     776                 :            : cleanup_fa:
     777                 :          6 :   posix_spawn_file_actions_destroy(&fa);
     778                 :            : 
     779                 :          6 :   return pid;
     780                 :            : }
     781                 :            : 
     782                 :            : // Global set of supported localization variables. Make changes here to
     783                 :            : // add or remove variables. List of variables from:
     784                 :            : // http://publib.boulder.ibm.com/infocenter/tivihelp/v8r1/index.jsp?topic=/
     785                 :            : // com.ibm.netcool_OMNIbus.doc_7.3.0/omnibus/wip/install/concept/omn_con_settingyourlocale.html
     786                 :            : const set<string>&
     787                 :         70 : localization_variables()
     788                 :            : {
     789 [ +  + ][ +  - ]:         70 :   static set<string> localeVars;
         [ +  - ][ #  # ]
     790         [ +  + ]:         70 :   if (localeVars.empty())
     791                 :            :     {
     792 [ +  - ][ +  - ]:         39 :       localeVars.insert("LANG");
                 [ +  - ]
     793 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_ALL");
                 [ +  - ]
     794 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_CTYPE");
                 [ +  - ]
     795 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_COLLATE");
                 [ +  - ]
     796 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_MESSAGES");
                 [ +  - ]
     797 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_TIME");
                 [ +  - ]
     798 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_MONETARY");
                 [ +  - ]
     799 [ +  - ][ +  - ]:         39 :       localeVars.insert("LC_NUMERIC");
                 [ +  - ]
     800                 :            :     }
     801                 :         70 :   return localeVars;
     802                 :            : }
     803                 :            : 
     804                 :            : // Runs a command with a saved PID, so we can kill it from the signal handler,
     805                 :            : // and wait for it to finish.
     806                 :            : int
     807                 :       3311 : stap_system(int verbose, const string& description,
     808                 :            :             const vector<string>& args,
     809                 :            :             bool null_out, bool null_err)
     810                 :            : {
     811                 :       3311 :   int ret = 0;
     812                 :            :   posix_spawn_file_actions_t fa;
     813         [ -  + ]:       3311 :   if (posix_spawn_file_actions_init(&fa) != 0)
     814                 :          0 :     return -1;
     815                 :            : 
     816 [ +  + ][ +  - ]:       3322 :   if ((null_out && null_child_fd(&fa, 1) != 0) ||
           [ +  +  -  + ]
                 [ -  + ]
     817                 :         11 :       (null_err && null_child_fd(&fa, 2) != 0))
     818                 :          0 :     ret = -1;
     819                 :            :   else
     820                 :            :     {
     821 [ +  - ][ +  - ]:       3311 :       pid_t pid = stap_spawn(verbose, args, &fa);
                 [ +  - ]
     822                 :       3311 :       ret = pid;
     823         [ +  - ]:       3311 :       if (pid > 0){
     824         [ +  - ]:       3311 :         ret = stap_waitpid(verbose, pid);
     825                 :            : 
     826                 :            :         // XXX PR13274 needs-session to use print_warning()
     827         [ +  + ]:       3311 :         if (ret > 128)
     828 [ +  - ][ +  - ]:          2 :           clog << _F("WARNING: %s exited with signal: %d (%s)",
         [ +  - ][ +  - ]
     829         [ +  - ]:          1 :                      description.c_str(), ret - 128, strsignal(ret - 128)) << endl;
     830         [ +  + ]:       3310 :         else if (ret > 0)
     831 [ +  - ][ +  - ]:         10 :           clog << _F("WARNING: %s exited with status: %d",
         [ +  - ][ +  - ]
     832         [ +  - ]:          5 :                      description.c_str(), ret) << endl;
     833                 :            :       }
     834                 :            :     }
     835                 :            : 
     836                 :       3311 :   posix_spawn_file_actions_destroy(&fa);
     837                 :       3311 :   return ret;
     838                 :            : }
     839                 :            : 
     840                 :            : // Like stap_system, but capture stdout
     841                 :            : int
     842                 :          0 : stap_system_read(int verbose, const vector<string>& args, ostream& out)
     843                 :            : {
     844                 :          0 :   int child_fd = -1;
     845         [ #  # ]:          0 :   pid_t child = stap_spawn_piped(verbose, args, NULL, &child_fd);
     846         [ #  # ]:          0 :   if (child > 0)
     847                 :            :     {
     848                 :            :       // read everything from the child
     849         [ #  # ]:          0 :       stdio_filebuf<char> in(child_fd, ios_base::in);
     850         [ #  # ]:          0 :       out << &in;
     851 [ #  # ][ #  # ]:          0 :       return stap_waitpid(verbose, child);
     852                 :            :     }
     853                 :          0 :   return -1;
     854                 :            : }
     855                 :            : 
     856                 :            : 
     857                 :            : // Send a signal to our spawned commands
     858                 :            : int
     859                 :        250 : kill_stap_spawn(int sig)
     860                 :            : {
     861                 :        250 :   return spawned_pids.killall(sig);
     862                 :            : }
     863                 :            : 
     864                 :            : 
     865                 :            : 
     866                 :       2707 : void assert_regexp_match (const string& name, const string& value, const string& re)
     867                 :            : {
     868                 :            :   typedef map<string,regex_t*> cache;
     869 [ +  + ][ +  - ]:       2707 :   static cache compiled;
         [ +  - ][ #  # ]
     870         [ +  - ]:       2707 :   cache::iterator it = compiled.find (re);
     871                 :       2707 :   regex_t* r = 0;
     872 [ +  - ][ +  + ]:       2707 :   if (it == compiled.end())
     873                 :            :     {
     874         [ +  - ]:       2691 :       r = new regex_t;
     875 [ +  - ][ +  - ]:       2691 :       int rc = regcomp (r, re.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED);
     876         [ -  + ]:       2691 :       assert (rc == 0);
     877         [ +  - ]:       2691 :       compiled[re] = r;
     878                 :            :     }
     879                 :            :   else
     880         [ +  - ]:         16 :     r = it->second;
     881                 :            : 
     882                 :            :   // run regexec
     883 [ +  - ][ +  - ]:       2707 :   int rc = regexec (r, value.c_str(), 0, 0, 0);
     884         [ +  + ]:       2707 :   if (rc)
     885                 :            :     throw runtime_error
     886                 :         62 :       (_F("ERROR: Safety pattern mismatch for %s ('%s' vs. '%s') rc=%d",
     887 [ +  - ][ +  - ]:         62 :           name.c_str(), value.c_str(), re.c_str(), rc));
         [ +  - ][ +  - ]
                 [ +  - ]
     888                 :       2645 : }
     889                 :            : 
     890                 :            : 
     891                 :       2357 : int regexp_match (const string& value, const string& re, vector<string>& matches)
     892                 :            : {
     893                 :            :   typedef map<string,regex_t*> cache;  // separate cache because we use different regcomp options
     894 [ +  + ][ +  - ]:       2357 :   static cache compiled;
         [ +  - ][ #  # ]
     895         [ +  - ]:       2357 :   cache::iterator it = compiled.find (re);
     896                 :       2357 :   regex_t* r = 0;
     897 [ +  - ][ +  + ]:       2357 :   if (it == compiled.end())
     898                 :            :     {
     899         [ +  - ]:       2224 :       r = new regex_t;
     900 [ +  - ][ +  - ]:       2224 :       int rc = regcomp (r, re.c_str(), REG_EXTENDED); /* REG_ICASE? */
     901         [ -  + ]:       2224 :       assert (rc == 0);
     902         [ +  - ]:       2224 :       compiled[re] = r;
     903                 :            :     }
     904                 :            :   else
     905         [ +  - ]:        133 :     r = it->second;
     906                 :            : 
     907                 :            : 
     908                 :            :   // run regexec
     909                 :            : #define maxmatches 10
     910                 :            :   regmatch_t rm[maxmatches];
     911                 :            : 
     912 [ +  - ][ +  - ]:       2357 :   int rc = regexec (r, value.c_str(), maxmatches, rm, 0);
     913         [ +  + ]:       2357 :   if (rc) return rc;
     914                 :            : 
     915 [ +  - ][ +  - ]:       2273 :   matches.erase(matches.begin(), matches.end());
                 [ +  - ]
     916         [ +  + ]:      25003 :   for (unsigned i=0; i<maxmatches; i++) // XXX: ideally, the number of actual subexpressions in re
     917                 :            :     {
     918         [ +  + ]:      22730 :       if (rm[i].rm_so >= 0)
     919 [ +  - ][ +  - ]:       6785 :         matches.push_back(value.substr (rm[i].rm_so, rm[i].rm_eo-rm[i].rm_so));
                 [ +  - ]
     920                 :            :       else
     921 [ +  - ][ +  - ]:      15945 :         matches.push_back("");
                 [ +  - ]
     922                 :            :     }
     923                 :            : 
     924                 :       2357 :   return 0;
     925                 :            : }
     926                 :            : 
     927                 :            : 
     928                 :        115 : bool contains_glob_chars (const string& str)
     929                 :            : {
     930         [ +  + ]:       2298 :   for (unsigned i=0; i<str.size(); i++)
     931                 :            :     {
     932                 :       2198 :       char this_char = str[i];
     933 [ +  + ][ +  - ]:       2198 :       if (this_char == '\\' && (str.size() > i+1))
                 [ +  + ]
     934                 :            :         {
     935                 :            :           // PR13338: skip the escape backslash and the escaped character
     936                 :          1 :           i++;
     937                 :          1 :           continue;
     938                 :            :         }
     939 [ +  + ][ +  + ]:       2197 :       if (this_char == '*' || this_char == '?' || this_char == '[')
                 [ -  + ]
     940                 :         15 :         return true;
     941                 :            :     }
     942                 :            : 
     943                 :        115 :   return false;
     944                 :            : }
     945                 :            : 
     946                 :            : 
     947                 :            : // PR13338: we need these functions to be able to pass through glob metacharacters
     948                 :            : // through the recursive process("...*...") expansion process.
     949                 :         14 : string escape_glob_chars (const string& str)
     950                 :            : {
     951                 :         14 :   string op;
     952 [ +  - ][ +  + ]:        302 :   for (unsigned i=0; i<str.size(); i++)
     953                 :            :     {
     954         [ +  - ]:        288 :       char this_char = str[i];
     955 [ +  - ][ +  - ]:        288 :       if (this_char == '*' || this_char == '?' || this_char == '[')
                 [ +  + ]
     956         [ +  - ]:          1 :         op += '\\';
     957         [ +  - ]:        288 :       op += this_char;
     958                 :            :     }
     959                 :         14 :   return op;
     960                 :            : }
     961                 :            : 
     962                 :         67 : string unescape_glob_chars (const string& str)
     963                 :            : {
     964                 :         67 :   string op;
     965 [ +  - ][ +  + ]:       1538 :   for (unsigned i=0; i<str.size(); i++)
     966                 :            :     {
     967         [ +  - ]:       1471 :       char this_char = str[i];
     968 [ +  + ][ +  - ]:       1471 :       if (this_char == '\\' && (str.size() > i+1) )
         [ +  - ][ +  + ]
     969                 :            :         {
     970 [ +  - ][ +  - ]:          1 :           op += str[i+1];
     971                 :          1 :           i++;
     972                 :          1 :           continue;
     973                 :            :         }
     974         [ +  - ]:       1470 :       op += this_char;
     975                 :            :     }
     976                 :            : 
     977                 :         67 :   return op;
     978                 :            : }
     979                 :            : 
     980                 :            : 
     981                 :            : 
     982                 :            : string
     983                 :       2423 : normalize_machine(const string& machine)
     984                 :            : {
     985                 :            :   // PR4186: Copy logic from coreutils uname (uname -i) to squash
     986                 :            :   // i?86->i386.  Actually, copy logic from linux top-level Makefile
     987                 :            :   // to squash uname -m -> $(SUBARCH).
     988                 :            :   //
     989                 :            :   // This logic needs to match the logic in the stap_get_arch shell
     990                 :            :   // function in stap-env.
     991                 :            :   //
     992                 :            :   // But: RHBZ669082 reminds us that this renaming post-dates some
     993                 :            :   // of the kernel versions we know and love.  So in buildrun.cxx
     994                 :            :   // we undo this renaming for ancient powerpc.
     995                 :            : 
     996 [ -  + ][ #  # ]:       2423 :   if (machine == "i486") return "i386";
     997 [ -  + ][ #  # ]:       2423 :   else if (machine == "i586") return "i386";
     998 [ -  + ][ #  # ]:       2423 :   else if (machine == "i686") return "i386";
     999 [ -  + ][ #  # ]:       2423 :   else if (machine == "sun4u") return "sparc64";
    1000 [ +  - ][ +  - ]:       2423 :   else if (machine.substr(0,3) == "arm") return "arm";
                 [ +  - ]
    1001 [ #  # ][ #  # ]:          0 :   else if (machine == "sa110") return "arm";
    1002 [ #  # ][ #  # ]:          0 :   else if (machine == "s390x") return "s390";
    1003 [ #  # ][ #  # ]:          0 :   else if (machine.substr(0,3) == "ppc") return "powerpc";
                 [ #  # ]
    1004 [ #  # ][ #  # ]:          0 :   else if (machine.substr(0,4) == "mips") return "mips";
                 [ #  # ]
    1005 [ #  # ][ #  # ]:          0 :   else if (machine.substr(0,3) == "sh2") return "sh";
                 [ #  # ]
    1006 [ #  # ][ #  # ]:          0 :   else if (machine.substr(0,3) == "sh3") return "sh";
                 [ #  # ]
    1007 [ #  # ][ #  # ]:          0 :   else if (machine.substr(0,3) == "sh4") return "sh";
                 [ #  # ]
    1008                 :       2423 :   return machine;
    1009                 :            : }
    1010                 :            : 
    1011                 :            : int
    1012                 :         69 : elf_class_from_normalized_machine (const string &machine)
    1013                 :            : {
    1014                 :            :   // Must match kernel machine architectures as used un tapset directory.
    1015                 :            :   // And must match normalization done in normalize_machine ().
    1016   [ +  -  +  - ]:        138 :   if (machine == "i386"
                 [ +  - ]
    1017                 :         69 :       || machine == "arm")         // arm assumes 32-bit
    1018                 :         69 :     return ELFCLASS32;
    1019   [ #  #  #  #  :          0 :   else if (machine == "s390"       // powerpc and s390 always assume 64-bit,
             #  #  #  # ]
                 [ #  # ]
    1020                 :          0 :            || machine == "powerpc" // see normalize_machine ().
    1021                 :          0 :            || machine == "x86_64"
    1022                 :          0 :            || machine == "ia64")
    1023                 :          0 :     return ELFCLASS64;
    1024                 :            : 
    1025         [ #  # ]:          0 :   cerr << _F("Unknown kernel machine architecture '%s', don't know elf class",
    1026         [ #  # ]:          0 :              machine.c_str()) << endl;
    1027                 :         69 :   return -1;
    1028                 :            : }
    1029                 :            : 
    1030                 :            : string
    1031                 :          0 : kernel_release_from_build_tree (const string &kernel_build_tree, int verbose)
    1032                 :            : {
    1033         [ #  # ]:          0 :   string version_file_name = kernel_build_tree + "/include/config/kernel.release";
    1034                 :            :   // The file include/config/kernel.release within the
    1035                 :            :   // build tree is used to pull out the version information
    1036 [ #  # ][ #  # ]:          0 :   ifstream version_file (version_file_name.c_str());
    1037 [ #  # ][ #  # ]:          0 :   if (version_file.fail ())
    1038                 :            :     {
    1039         [ #  # ]:          0 :       if (verbose > 1)
    1040                 :            :         //TRANSLATORS: Missing a file
    1041 [ #  # ][ #  # ]:          0 :         cerr << _F("Missing %s", version_file_name.c_str()) << endl;
         [ #  # ][ #  # ]
                 [ #  # ]
    1042         [ #  # ]:          0 :       return "";
    1043                 :            :     }
    1044                 :            : 
    1045         [ #  # ]:          0 :   string kernel_release;
    1046                 :            :   char c;
    1047 [ #  # ][ #  # ]:          0 :   while (version_file.get(c) && c != '\n')
         [ #  # ][ #  # ]
                 [ #  # ]
    1048         [ #  # ]:          0 :     kernel_release.push_back(c);
    1049                 :            : 
    1050 [ #  # ][ #  # ]:          0 :   return kernel_release;
         [ #  # ][ #  # ]
    1051                 :            : }
    1052                 :            : 
    1053                 :     380699 : std::string autosprintf(const char* format, ...)
    1054                 :            : {
    1055                 :            :   va_list args;
    1056                 :            :   char *str;
    1057                 :     380699 :   va_start (args, format);
    1058                 :     380699 :   int rc = vasprintf (&str, format, args);
    1059         [ -  + ]:     380699 :   if (rc < 0)
    1060                 :            :     {
    1061                 :          0 :       va_end(args);
    1062         [ #  # ]:          0 :       return _F("autosprintf/vasprintf error %d", rc);
    1063                 :            :     }
    1064         [ +  - ]:     380699 :   string s = str;
    1065                 :     380699 :   va_end (args);
    1066                 :     380699 :   free (str);
    1067 [ +  - ][ +  - ]:     380699 :   return s; /* by copy */
    1068                 :            : }
    1069                 :            : 
    1070                 :            : std::string
    1071                 :        880 : get_self_path()
    1072                 :            : {
    1073                 :            :   char buf[1024]; // This really should be enough for anybody...
    1074                 :        880 :   const char *file = "/proc/self/exe";
    1075                 :        880 :   ssize_t len = readlink(file, buf, sizeof(buf) - 1);
    1076         [ +  - ]:        880 :   if (len > 0)
    1077                 :            :     {
    1078                 :        880 :       buf[len] = '\0';
    1079                 :        880 :       file = buf;
    1080                 :            :     }
    1081                 :            :   // otherwise the path is ridiculously large, fall back to /proc/self/exe.
    1082                 :            :   //
    1083         [ +  - ]:        880 :   return std::string(file);
    1084 [ +  - ][ +  - ]:       8814 : }
    1085                 :            : 
    1086                 :            : 
    1087                 :            : #ifndef HAVE_PPOLL
    1088                 :            : // This is a poor-man's ppoll, only used carefully by readers that need to be
    1089                 :            : // interruptible, like remote::run and mutator::run.  It does not provide the
    1090                 :            : // same guarantee of atomicity as on systems with a true ppoll.
    1091                 :            : //
    1092                 :            : // In our use, this would cause trouble if a signal came in any time from the
    1093                 :            : // moment we mask signals to prepare pollfds, to the moment we call poll in
    1094                 :            : // emulation here.  If there's no data on any of the pollfds, we will be stuck
    1095                 :            : // waiting indefinitely.
    1096                 :            : //
    1097                 :            : // Since this is mainly about responsiveness of CTRL-C cleanup, we'll just
    1098                 :            : // throw in a one-second forced timeout to ensure we have a chance to notice
    1099                 :            : // there was an interrupt without too much delay.
    1100                 :            : int
    1101                 :            : ppoll(struct pollfd *fds, nfds_t nfds,
    1102                 :            :       const struct timespec *timeout_ts,
    1103                 :            :       const sigset_t *sigmask)
    1104                 :            : {
    1105                 :            :   sigset_t origmask;
    1106                 :            :   int timeout = (timeout_ts == NULL) ? 1000 // don't block forever...
    1107                 :            :     : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
    1108                 :            :   sigprocmask(SIG_SETMASK, sigmask, &origmask);
    1109                 :            :   int rc = poll(fds, nfds, timeout);
    1110                 :            :   sigprocmask(SIG_SETMASK, &origmask, NULL);
    1111                 :            :   return rc;
    1112                 :            : }
    1113                 :            : #endif
    1114                 :            : 
    1115                 :            : 
    1116                 :            : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */

Generated by: LCOV version 1.9