LTP GCOV extension - code coverage report
Current view: directory - src/libutil - util.cc
Test: app.info
Date: 2008-11-20 Instrumented lines: 511
Code covered: 63.6 % Executed lines: 325

       1                 : #include "config.h"
       2                 : 
       3                 : #ifdef __CYGWIN__
       4                 : #include <windows.h>
       5                 : #endif
       6                 : 
       7                 : #include <iostream>
       8                 : #include <cerrno>
       9                 : #include <cstdio>
      10                 : #include <cstdlib>
      11                 : #include <sstream>
      12                 : #include <cstring>
      13                 : 
      14                 : #include <sys/stat.h>
      15                 : #include <sys/wait.h>
      16                 : #include <sys/types.h>
      17                 : #include <fcntl.h>
      18                 : 
      19                 : #include "util.hh"
      20                 : 
      21                 : 
      22                 : extern char * * environ;
      23                 : 
      24                 : 
      25                 : namespace nix {
      26                 : 
      27                 : 
      28             273 : BaseError::BaseError(const format & f)
      29                 : {
      30             273 :     err = f.str();
      31             273 : }
      32                 : 
      33                 : 
      34              14 : BaseError & BaseError::addPrefix(const format & f)
      35                 : {
      36              14 :     err = f.str() + err;
      37              14 :     return *this;
      38                 : }
      39                 : 
      40                 : 
      41               0 : SysError::SysError(const format & f)
      42                 :     : Error(format("%1%: %2%") % f.str() % strerror(errno))
      43               0 :     , errNo(errno)
      44                 : {
      45               0 : }
      46                 : 
      47                 : 
      48            8256 : string getEnv(const string & key, const string & def)
      49                 : {
      50            8256 :     char * value = getenv(key.c_str());
      51            8256 :     return value ? string(value) : def;
      52                 : }
      53                 : 
      54                 : 
      55            1574 : Path absPath(Path path, Path dir)
      56                 : {
      57            1574 :     if (path[0] != '/') {
      58             439 :         if (dir == "") {
      59                 :             char buf[PATH_MAX];
      60             147 :             if (!getcwd(buf, sizeof(buf)))
      61               0 :                 throw SysError("cannot get cwd");
      62             147 :             dir = buf;
      63                 :         }
      64             439 :         path = dir + "/" + path;
      65                 :     }
      66            1574 :     return canonPath(path);
      67                 : }
      68                 : 
      69                 : 
      70            9612 : Path canonPath(const Path & path, bool resolveSymlinks)
      71                 : {
      72            9612 :     string s;
      73                 : 
      74            9612 :     if (path[0] != '/')
      75               0 :         throw Error(format("not an absolute path: `%1%'") % path);
      76                 : 
      77            9612 :     string::const_iterator i = path.begin(), end = path.end();
      78            9612 :     string temp;
      79                 : 
      80                 :     /* Count the number of times we follow a symlink and stop at some
      81                 :        arbitrary (but high) limit to prevent infinite loops. */
      82            9612 :     unsigned int followCount = 0, maxFollow = 1024;
      83                 : 
      84           64437 :     while (1) {
      85                 : 
      86                 :         /* Skip slashes. */
      87           74049 :         while (i != end && *i == '/') i++;
      88           74049 :         if (i == end) break;
      89                 : 
      90                 :         /* Ignore `.'. */
      91           64437 :         if (*i == '.' && (i + 1 == end || i[1] == '/'))
      92             321 :             i++;
      93                 : 
      94                 :         /* If `..', delete the last component. */
      95           64116 :         else if (*i == '.' && i + 1 < end && i[1] == '.' && 
      96                 :             (i + 2 == end || i[2] == '/'))
      97                 :         {
      98              20 :             if (!s.empty()) s.erase(s.rfind('/'));
      99              20 :             i += 2;
     100                 :         }
     101                 : 
     102                 :         /* Normal component; copy it. */
     103                 :         else {
     104           64096 :             s += '/';
     105           64096 :             while (i != end && *i != '/') s += *i++;
     106                 : 
     107                 :             /* If s points to a symlink, resolve it and restart (since
     108                 :                the symlink target might contain new symlinks). */
     109           64096 :             if (resolveSymlinks && isLink(s)) {
     110               0 :                 if (++followCount >= maxFollow)
     111               0 :                     throw Error(format("infinite symlink recursion in path `%1%'") % path);
     112                 :                 temp = absPath(readLink(s), dirOf(s))
     113               0 :                     + string(i, end);
     114               0 :                 i = temp.begin(); /* restart */
     115               0 :                 end = temp.end();
     116               0 :                 s = "";
     117                 :                 /* !!! potential for infinite loop */
     118                 :             }
     119                 :         }
     120                 :     }
     121                 : 
     122            9612 :     return s.empty() ? "/" : s;
     123                 : }
     124                 : 
     125                 : 
     126            8759 : Path dirOf(const Path & path)
     127                 : {
     128            8759 :     Path::size_type pos = path.rfind('/');
     129            8759 :     if (pos == string::npos)
     130               0 :         throw Error(format("invalid file name `%1%'") % path);
     131            8759 :     return pos == 0 ? "/" : Path(path, 0, pos);
     132                 : }
     133                 : 
     134                 : 
     135          123681 : string baseNameOf(const Path & path)
     136                 : {
     137          123681 :     Path::size_type pos = path.rfind('/');
     138          123681 :     if (pos == string::npos)
     139               0 :         throw Error(format("invalid file name `%1%'") % path);
     140          123681 :     return string(path, pos + 1);
     141                 : }
     142                 : 
     143                 : 
     144           64975 : bool pathExists(const Path & path)
     145                 : {
     146                 :     int res;
     147                 :     struct stat st;
     148           64975 :     res = lstat(path.c_str(), &st);
     149           64975 :     if (!res) return true;
     150           14619 :     if (errno != ENOENT && errno != ENOTDIR)
     151               0 :         throw SysError(format("getting status of %1%") % path);
     152           14619 :     return false;
     153                 : }
     154                 : 
     155                 : 
     156            1004 : Path readLink(const Path & path)
     157                 : {
     158            1004 :     checkInterrupt();
     159                 :     struct stat st;
     160            1004 :     if (lstat(path.c_str(), &st))
     161               0 :         throw SysError(format("getting status of `%1%'") % path);
     162            1004 :     if (!S_ISLNK(st.st_mode))
     163               0 :         throw Error(format("`%1%' is not a symlink") % path);
     164            1004 :     char buf[st.st_size];
     165            1004 :     if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
     166               0 :         throw SysError(format("reading symbolic link `%1%'") % path);
     167            1004 :     return string(buf, st.st_size);
     168                 : }
     169                 : 
     170                 : 
     171             365 : bool isLink(const Path & path)
     172                 : {
     173                 :     struct stat st;
     174             365 :     if (lstat(path.c_str(), &st))
     175               0 :         throw SysError(format("getting status of `%1%'") % path);
     176             365 :     return S_ISLNK(st.st_mode);
     177                 : }
     178                 : 
     179                 : 
     180             961 : Strings readDirectory(const Path & path)
     181                 : {
     182             961 :     Strings names;
     183                 : 
     184            1922 :     AutoCloseDir dir = opendir(path.c_str());
     185             961 :     if (!dir) throw SysError(format("opening directory `%1%'") % path);
     186                 : 
     187                 :     struct dirent * dirent;
     188            8529 :     while (errno = 0, dirent = readdir(dir)) { /* sic */
     189            6607 :         checkInterrupt();
     190            6607 :         string name = dirent->d_name;
     191           15136 :         if (name == "." || name == "..") continue;
     192            4685 :         names.push_back(name);
     193                 :     }
     194             961 :     if (errno) throw SysError(format("reading directory `%1%'") % path);
     195                 : 
     196             961 :     return names;
     197                 : }
     198                 : 
     199                 : 
     200           11713 : string readFile(int fd)
     201                 : {
     202                 :     struct stat st;
     203           11713 :     if (fstat(fd, &st) == -1)
     204               0 :         throw SysError("statting file");
     205                 :     
     206           11713 :     unsigned char * buf = new unsigned char[st.st_size];
     207           11713 :     AutoDeleteArray<unsigned char> d(buf);
     208           11713 :     readFull(fd, buf, st.st_size);
     209                 : 
     210           11713 :     return string((char *) buf, st.st_size);
     211                 : }
     212                 : 
     213                 : 
     214            6538 : string readFile(const Path & path)
     215                 : {
     216            6538 :     AutoCloseFD fd = open(path.c_str(), O_RDONLY);
     217            6538 :     if (fd == -1)
     218               0 :         throw SysError(format("opening file `%1%'") % path);
     219            6538 :     return readFile(fd);
     220                 : }
     221                 : 
     222                 : 
     223            5385 : void writeFile(const Path & path, const string & s)
     224                 : {
     225            5385 :     AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
     226            5385 :     if (fd == -1)
     227               0 :         throw SysError(format("opening file `%1%'") % path);
     228            5385 :     writeFull(fd, (unsigned char *) s.c_str(), s.size());
     229            5385 : }
     230                 : 
     231                 : 
     232                 : static void _computePathSize(const Path & path,
     233               0 :     unsigned long long & bytes, unsigned long long & blocks)
     234                 : {
     235               0 :     checkInterrupt();
     236                 : 
     237                 :     struct stat st;
     238               0 :     if (lstat(path.c_str(), &st))
     239               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
     240                 : 
     241               0 :     bytes += st.st_size;
     242               0 :     blocks += st.st_blocks;
     243                 : 
     244               0 :     if (S_ISDIR(st.st_mode)) {
     245               0 :         Strings names = readDirectory(path);
     246                 : 
     247               0 :         for (Strings::iterator i = names.begin(); i != names.end(); ++i)
     248               0 :             _computePathSize(path + "/" + *i, bytes, blocks);
     249                 :     }
     250               0 : }
     251                 : 
     252                 : 
     253                 : void computePathSize(const Path & path,
     254               0 :     unsigned long long & bytes, unsigned long long & blocks)
     255                 : {
     256               0 :     bytes = 0;
     257               0 :     blocks = 0;
     258               0 :     _computePathSize(path, bytes, blocks);
     259               0 : }
     260                 : 
     261                 : 
     262                 : static void _deletePath(const Path & path, unsigned long long & bytesFreed,
     263            3003 :     unsigned long long & blocksFreed)
     264                 : {
     265            3003 :     checkInterrupt();
     266                 : 
     267            3003 :     printMsg(lvlVomit, format("%1%") % path);
     268                 : 
     269                 :     struct stat st;
     270            3003 :     if (lstat(path.c_str(), &st))
     271               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
     272                 : 
     273            3003 :     bytesFreed += st.st_size;
     274            3003 :     blocksFreed += st.st_blocks;
     275                 : 
     276            3003 :     if (S_ISDIR(st.st_mode)) {
     277             228 :         Strings names = readDirectory(path);
     278                 : 
     279                 :         /* Make the directory writable. */
     280             228 :         if (!(st.st_mode & S_IWUSR)) {
     281              64 :             if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
     282               0 :                 throw SysError(format("making `%1%' writable") % path);
     283                 :         }
     284                 : 
     285             394 :         for (Strings::iterator i = names.begin(); i != names.end(); ++i)
     286             394 :             _deletePath(path + "/" + *i, bytesFreed, blocksFreed);
     287                 :     }
     288                 : 
     289            3003 :     if (remove(path.c_str()) == -1)
     290               0 :         throw SysError(format("cannot unlink `%1%'") % path);
     291            3003 : }
     292                 : 
     293                 : 
     294              47 : void deletePath(const Path & path)
     295                 : {
     296                 :     unsigned long long dummy1, dummy2;
     297              47 :     deletePath(path, dummy1, dummy2);
     298              47 : }
     299                 : 
     300                 : 
     301                 : void deletePath(const Path & path, unsigned long long & bytesFreed,
     302            2837 :     unsigned long long & blocksFreed)
     303                 : {
     304            2837 :     startNest(nest, lvlDebug,
     305                 :         format("recursively deleting path `%1%'") % path);
     306            2837 :     bytesFreed = 0;
     307            2837 :     blocksFreed = 0;
     308            2837 :     _deletePath(path, bytesFreed, blocksFreed);
     309            2837 : }
     310                 : 
     311                 : 
     312               0 : void makePathReadOnly(const Path & path)
     313                 : {
     314               0 :     checkInterrupt();
     315                 : 
     316                 :     struct stat st;
     317               0 :     if (lstat(path.c_str(), &st))
     318               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
     319                 : 
     320               0 :     if (!S_ISLNK(st.st_mode) && (st.st_mode & S_IWUSR)) {
     321               0 :         if (chmod(path.c_str(), st.st_mode & ~S_IWUSR) == -1)
     322               0 :             throw SysError(format("making `%1%' read-only") % path);
     323                 :     }
     324                 : 
     325               0 :     if (S_ISDIR(st.st_mode)) {
     326               0 :         Strings names = readDirectory(path);
     327               0 :         for (Strings::iterator i = names.begin(); i != names.end(); ++i)
     328               0 :             makePathReadOnly(path + "/" + *i);
     329                 :     }
     330               0 : }
     331                 : 
     332                 : 
     333                 : static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
     334             162 :     int & counter)
     335                 : {
     336             162 :     tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
     337             162 :     if (includePid)
     338              50 :         return (format("%1%/%2%-%3%-%4%") % tmpRoot % prefix % getpid() % counter++).str();
     339                 :     else
     340             112 :         return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str();
     341                 : }
     342                 : 
     343                 : 
     344                 : Path createTempDir(const Path & tmpRoot, const Path & prefix,
     345             162 :     bool includePid, bool useGlobalCounter)
     346                 : {
     347                 :     static int globalCounter = 0;
     348             162 :     int localCounter = 0;
     349             162 :     int & counter(useGlobalCounter ? globalCounter : localCounter);
     350                 :     
     351               0 :     while (1) {
     352             162 :         checkInterrupt();
     353             162 :         Path tmpDir = tempName(tmpRoot, prefix, includePid, counter);
     354             324 :         if (mkdir(tmpDir.c_str(), 0777) == 0) {
     355                 :             /* Explicitly set the group of the directory.  This is to
     356                 :                work around around problems caused by BSD's group
     357                 :                ownership semantics (directories inherit the group of
     358                 :                the parent).  For instance, the group of /tmp on
     359                 :                FreeBSD is "wheel", so all directories created in /tmp
     360                 :                will be owned by "wheel"; but if the user is not in
     361                 :                "wheel", then "tar" will fail to unpack archives that
     362                 :                have the setgid bit set on directories. */
     363             162 :             if (chown(tmpDir.c_str(), (uid_t) -1, getegid()) != 0)
     364               0 :                 throw SysError(format("setting group of directory `%1%'") % tmpDir);
     365             162 :             return tmpDir;
     366                 :         }
     367               0 :         if (errno != EEXIST)
     368               0 :             throw SysError(format("creating directory `%1%'") % tmpDir);
     369                 :     }
     370                 : }
     371                 : 
     372                 : 
     373            1098 : Paths createDirs(const Path & path)
     374                 : {
     375            1098 :     Paths created;
     376            2196 :     if (path == "/") return created;
     377            1098 :     if (!pathExists(path)) {
     378              32 :         created = createDirs(dirOf(path));
     379              32 :         if (mkdir(path.c_str(), 0777) == -1)
     380               0 :             throw SysError(format("creating directory `%1%'") % path);
     381              32 :         created.push_back(path);
     382                 :     }
     383            1098 :     return created;
     384                 : }
     385                 : 
     386                 : 
     387             175 : void writeStringToFile(const Path & path, const string & s)
     388                 : {
     389                 :     AutoCloseFD fd(open(path.c_str(),
     390             175 :         O_CREAT | O_EXCL | O_WRONLY, 0666));
     391             175 :     if (fd == -1)
     392               0 :         throw SysError(format("creating file `%1%'") % path);
     393             175 :     writeFull(fd, (unsigned char *) s.c_str(), s.size());
     394             175 : }
     395                 : 
     396                 : 
     397                 : LogType logType = ltPretty;
     398                 : Verbosity verbosity = lvlInfo;
     399                 : 
     400                 : static int nestingLevel = 0;
     401                 : 
     402                 : 
     403            7745 : Nest::Nest()
     404                 : {
     405            7745 :     nest = false;
     406            7745 : }
     407                 : 
     408                 : 
     409            7745 : Nest::~Nest()
     410                 : {
     411            7745 :     close();
     412            7745 : }
     413                 : 
     414                 : 
     415              10 : static string escVerbosity(Verbosity level)
     416                 : {
     417              10 :     return int2String((int) level);
     418                 : }
     419                 : 
     420                 : 
     421             145 : void Nest::open(Verbosity level, const format & f)
     422                 : {
     423             145 :     if (level <= verbosity) {
     424             145 :         if (logType == ltEscapes)
     425                 :             std::cerr << "\033[" << escVerbosity(level) << "p"
     426               6 :                       << f.str() << "\n";
     427                 :         else
     428             139 :             printMsg_(level, f);
     429             145 :         nest = true;
     430             145 :         nestingLevel++;
     431                 :     }
     432             145 : }
     433                 : 
     434                 : 
     435            7745 : void Nest::close()
     436                 : {
     437            7745 :     if (nest) {
     438             145 :         nestingLevel--;
     439             145 :         if (logType == ltEscapes)
     440               6 :             std::cerr << "\033[q";
     441             145 :         nest = false;
     442                 :     }
     443            7745 : }
     444                 : 
     445                 : 
     446            3591 : void printMsg_(Verbosity level, const format & f)
     447                 : {
     448            3591 :     checkInterrupt();
     449            3591 :     if (level > verbosity) return;
     450            3591 :     string prefix;
     451            3591 :     if (logType == ltPretty)
     452            3603 :         for (int i = 0; i < nestingLevel; i++)
     453              20 :             prefix += "|   ";
     454               8 :     else if (logType == ltEscapes && level != lvlInfo)
     455               4 :         prefix = "\033[" + escVerbosity(level) + "s";
     456            3591 :     string s = (format("%1%%2%\n") % prefix % f.str()).str();
     457            3591 :     writeToStderr((const unsigned char *) s.c_str(), s.size());
     458                 : }
     459                 : 
     460                 : 
     461              91 : void warnOnce(bool & haveWarned, const format & f)
     462                 : {
     463              91 :     if (!haveWarned) {
     464              65 :         printMsg(lvlError, format("warning: %1%") % f.str());
     465              65 :         haveWarned = true;
     466                 :     }
     467              91 : }
     468                 : 
     469                 : 
     470            6318 : static void defaultWriteToStderr(const unsigned char * buf, size_t count)
     471                 : {
     472                 :     try {
     473            6318 :         writeFull(STDERR_FILENO, buf, count);
     474               0 :     } catch (SysError & e) {
     475                 :         /* ignore EPIPE etc. */
     476                 :     }
     477            6318 : }
     478                 : 
     479                 : 
     480                 : void (*writeToStderr) (const unsigned char * buf, size_t count) = defaultWriteToStderr;
     481                 : 
     482                 : 
     483           21132 : void readFull(int fd, unsigned char * buf, size_t count)
     484                 : {
     485           63232 :     while (count) {
     486           21060 :         checkInterrupt();
     487           21060 :         ssize_t res = read(fd, (char *) buf, count);
     488           21060 :         if (res == -1) {
     489               0 :             if (errno == EINTR) continue;
     490               0 :             throw SysError("reading from file");
     491                 :         }
     492           21060 :         if (res == 0) throw EndOfFile("unexpected end-of-file");
     493           20968 :         count -= res;
     494           20968 :         buf += res;
     495                 :     }
     496           21040 : }
     497                 : 
     498                 : 
     499           40665 : void writeFull(int fd, const unsigned char * buf, size_t count)
     500                 : {
     501          121921 :     while (count) {
     502           40591 :         checkInterrupt();
     503           40591 :         ssize_t res = write(fd, (char *) buf, count);
     504           40591 :         if (res == -1) {
     505               0 :             if (errno == EINTR) continue;
     506               0 :             throw SysError("writing to file");
     507                 :         }
     508           40591 :         count -= res;
     509           40591 :         buf += res;
     510                 :     }
     511           40665 : }
     512                 : 
     513                 : 
     514               1 : string drainFD(int fd)
     515                 : {
     516               1 :     string result;
     517                 :     unsigned char buffer[4096];
     518               6 :     while (1) {
     519               7 :         checkInterrupt();
     520               7 :         ssize_t rd = read(fd, buffer, sizeof buffer);
     521               7 :         if (rd == -1) {
     522               0 :             if (errno != EINTR)
     523               0 :                 throw SysError("reading from file");
     524                 :         }
     525               7 :         else if (rd == 0) break;
     526               6 :         else result.append((char *) buffer, rd);
     527                 :     }
     528               0 :     return result;
     529                 : }
     530                 : 
     531                 : 
     532                 : 
     533                 : //////////////////////////////////////////////////////////////////////
     534                 : 
     535                 : 
     536              47 : AutoDelete::AutoDelete(const string & p, bool recursive) : path(p)
     537                 : {
     538              47 :     del = true;
     539              47 :     this->recursive = recursive;
     540              47 : }
     541                 : 
     542              47 : AutoDelete::~AutoDelete()
     543                 : {
     544                 :     try {
     545              47 :         if (del) {
     546              47 :             if (recursive)
     547              47 :                 deletePath(path);
     548                 :             else {
     549               0 :                 if (remove(path.c_str()) == -1)
     550               0 :                     throw SysError(format("cannot unlink `%1%'") % path);
     551                 :             }
     552                 :         }
     553               0 :     } catch (...) {
     554               0 :         ignoreException();
     555                 :     }
     556              47 : }
     557                 : 
     558               0 : void AutoDelete::cancel()
     559                 : {
     560               0 :     del = false;
     561               0 : }
     562                 : 
     563                 : 
     564                 : 
     565                 : //////////////////////////////////////////////////////////////////////
     566                 : 
     567                 : 
     568           34511 : AutoCloseFD::AutoCloseFD()
     569                 : {
     570           34511 :     fd = -1;
     571           34511 : }
     572                 : 
     573                 : 
     574           29072 : AutoCloseFD::AutoCloseFD(int fd)
     575                 : {
     576           29072 :     this->fd = fd;
     577           29072 : }
     578                 : 
     579                 : 
     580               0 : AutoCloseFD::AutoCloseFD(const AutoCloseFD & fd)
     581                 : {
     582                 :     /* Copying a AutoCloseFD isn't allowed (who should get to close
     583                 :        it?).  But as a edge case, allow copying of closed
     584                 :        AutoCloseFDs.  This is necessary due to tiresome reasons
     585                 :        involving copy constructor use on default object values in STL
     586                 :        containers (like when you do `map[value]' where value isn't in
     587                 :        the map yet). */
     588               0 :     this->fd = fd.fd;
     589               0 :     if (this->fd != -1) abort();
     590               0 : }
     591                 : 
     592                 : 
     593           63626 : AutoCloseFD::~AutoCloseFD()
     594                 : {
     595                 :     try {
     596           63626 :         close();
     597               0 :     } catch (...) {
     598               0 :         ignoreException();
     599                 :     }
     600           63626 : }
     601                 : 
     602                 : 
     603           29224 : void AutoCloseFD::operator =(int fd)
     604                 : {
     605           29224 :     if (this->fd != fd) close();
     606           29224 :     this->fd = fd;
     607           29224 : }
     608                 : 
     609                 : 
     610          106739 : AutoCloseFD::operator int() const
     611                 : {
     612          106739 :     return fd;
     613                 : }
     614                 : 
     615                 : 
     616           94241 : void AutoCloseFD::close()
     617                 : {
     618           94241 :     if (fd != -1) {
     619           30529 :         if (::close(fd) == -1)
     620                 :             /* This should never happen. */
     621               0 :             throw SysError("closing file descriptor");
     622           30529 :         fd = -1;
     623                 :     }
     624           94241 : }
     625                 : 
     626                 : 
     627               3 : bool AutoCloseFD::isOpen()
     628                 : {
     629               3 :     return fd != -1;
     630                 : }
     631                 : 
     632                 : 
     633                 : /* Pass responsibility for closing this fd to the caller. */
     634           28022 : int AutoCloseFD::borrow()
     635                 : {
     636           28022 :     int oldFD = fd;
     637           28022 :     fd = -1;
     638           28022 :     return oldFD;
     639                 : }
     640                 : 
     641                 : 
     642             413 : void Pipe::create()
     643                 : {
     644                 :     int fds[2];
     645             413 :     if (pipe(fds) != 0) throw SysError("creating pipe");
     646             413 :     readSide = fds[0];
     647             413 :     writeSide = fds[1];
     648             413 : }
     649                 : 
     650                 : 
     651                 : 
     652                 : //////////////////////////////////////////////////////////////////////
     653                 : 
     654                 : 
     655               0 : AutoCloseDir::AutoCloseDir()
     656                 : {
     657               0 :     dir = 0;
     658               0 : }
     659                 : 
     660                 : 
     661             961 : AutoCloseDir::AutoCloseDir(DIR * dir)
     662                 : {
     663             961 :     this->dir = dir;
     664             961 : }
     665                 : 
     666                 : 
     667             961 : AutoCloseDir::~AutoCloseDir()
     668                 : {
     669             961 :     if (dir) closedir(dir);
     670             961 : }
     671                 : 
     672                 : 
     673               0 : void AutoCloseDir::operator =(DIR * dir)
     674                 : {
     675               0 :     this->dir = dir;
     676               0 : }
     677                 : 
     678                 : 
     679            8529 : AutoCloseDir::operator DIR *()
     680                 : {
     681            8529 :     return dir;
     682                 : }
     683                 : 
     684                 : 
     685                 : 
     686                 : //////////////////////////////////////////////////////////////////////
     687                 : 
     688                 : 
     689             841 : Pid::Pid()
     690                 : {
     691             841 :     pid = -1;
     692             841 :     separatePG = false;
     693             841 :     killSignal = SIGKILL;
     694             841 : }
     695                 : 
     696                 : 
     697            1115 : Pid::~Pid()
     698                 : {
     699            1115 :     kill();
     700            1115 : }
     701                 : 
     702                 : 
     703             502 : void Pid::operator =(pid_t pid)
     704                 : {
     705             502 :     if (this->pid != pid) kill();
     706             502 :     this->pid = pid;
     707             502 :     killSignal = SIGKILL; // reset signal to default
     708             502 : }
     709                 : 
     710                 : 
     711            1974 : Pid::operator pid_t()
     712                 : {
     713            1974 :     return pid;
     714                 : }
     715                 : 
     716                 : 
     717            1617 : void Pid::kill()
     718                 : {
     719            1617 :     if (pid == -1) return;
     720                 :     
     721               0 :     printMsg(lvlError, format("killing process %1%") % pid);
     722                 : 
     723                 :     /* Send the requested signal to the child.  If it has its own
     724                 :        process group, send the signal to every process in the child
     725                 :        process group (which hopefully includes *all* its children). */
     726               0 :     if (::kill(separatePG ? -pid : pid, killSignal) != 0)
     727               0 :         printMsg(lvlError, (SysError(format("killing process %1%") % pid).msg()));
     728                 : 
     729                 :     /* Wait until the child dies, disregarding the exit status. */
     730                 :     int status;
     731               0 :     while (waitpid(pid, &status, 0) == -1) {
     732               0 :         checkInterrupt();
     733               0 :         if (errno != EINTR) printMsg(lvlError,
     734                 :             (SysError(format("waiting for process %1%") % pid).msg()));
     735                 :     }
     736                 : 
     737               0 :     pid = -1;
     738                 : }
     739                 : 
     740                 : 
     741             316 : int Pid::wait(bool block)
     742                 : {
     743               0 :     while (1) {
     744                 :         int status;
     745             316 :         int res = waitpid(pid, &status, block ? 0 : WNOHANG);
     746             316 :         if (res == pid) {
     747             316 :             pid = -1;
     748             316 :             return status;
     749                 :         }
     750               0 :         if (res == 0 && !block) return -1;
     751               0 :         if (errno != EINTR)
     752               0 :             throw SysError("cannot get child exit status");
     753               0 :         checkInterrupt();
     754                 :     }
     755                 : }
     756                 : 
     757                 : 
     758             132 : void Pid::setSeparatePG(bool separatePG)
     759                 : {
     760             132 :     this->separatePG = separatePG;
     761             132 : }
     762                 : 
     763                 : 
     764              20 : void Pid::setKillSignal(int signal)
     765                 : {
     766              20 :     this->killSignal = signal;
     767              20 : }
     768                 : 
     769                 : 
     770               0 : void killUser(uid_t uid)
     771                 : {
     772               0 :     debug(format("killing all processes running under uid `%1%'") % uid);
     773                 : 
     774               0 :     assert(uid != 0); /* just to be safe... */
     775                 : 
     776                 :     /* The system call kill(-1, sig) sends the signal `sig' to all
     777                 :        users to which the current process can send signals.  So we
     778                 :        fork a process, switch to uid, and send a mass kill. */
     779                 : 
     780               0 :     Pid pid;
     781               0 :     pid = fork();
     782               0 :     switch (pid) {
     783                 : 
     784                 :     case -1:
     785               0 :         throw SysError("unable to fork");
     786                 : 
     787                 :     case 0:
     788                 :         try { /* child */
     789                 : 
     790               0 :             if (setuid(uid) == -1) abort();
     791                 : 
     792               0 :             while (true) {
     793               0 :                 if (kill(-1, SIGKILL) == 0) break;
     794               0 :                 if (errno == ESRCH) break; /* no more processes */
     795               0 :                 if (errno != EINTR)
     796               0 :                     throw SysError(format("cannot kill processes for uid `%1%'") % uid);
     797                 :             }
     798                 : 
     799               0 :         } catch (std::exception & e) {
     800                 :             std::cerr << format("killing processes beloging to uid `%1%': %1%")
     801               0 :                 % uid % e.what() << std::endl;
     802               0 :             quickExit(1);
     803                 :         }
     804               0 :         quickExit(0);
     805                 :     }
     806                 :     
     807                 :     /* parent */
     808               0 :     if (pid.wait(true) != 0)
     809               0 :         throw Error(format("cannot kill processes for uid `%1%'") % uid);
     810                 : 
     811                 :     /* !!! We should really do some check to make sure that there are
     812                 :        no processes left running under `uid', but there is no portable
     813                 :        way to do so (I think).  The most reliable way may be `ps -eo
     814                 :        uid | grep -q $uid'. */
     815               0 : }
     816                 : 
     817                 : 
     818                 : //////////////////////////////////////////////////////////////////////
     819                 : 
     820                 : 
     821               1 : string runProgram(Path program, bool searchPath, const Strings & args)
     822                 : {
     823               1 :     checkInterrupt();
     824                 :     
     825                 :     /* Create a pipe. */
     826               1 :     Pipe pipe;
     827               1 :     pipe.create();
     828                 : 
     829                 :     /* Fork. */
     830               1 :     Pid pid;
     831               1 :     pid = fork();
     832               1 :     switch (pid) {
     833                 : 
     834                 :     case -1:
     835               0 :         throw SysError("unable to fork");
     836                 : 
     837                 :     case 0: /* child */
     838                 :         try {
     839               0 :             pipe.readSide.close();
     840                 : 
     841               0 :             if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
     842               0 :                 throw SysError("dupping stdout");
     843                 : 
     844               0 :             std::vector<const char *> cargs; /* careful with c_str()! */
     845               0 :             cargs.push_back(program.c_str());
     846               0 :             for (Strings::const_iterator i = args.begin(); i != args.end(); ++i)
     847               0 :                 cargs.push_back(i->c_str());
     848               0 :             cargs.push_back(0);
     849                 : 
     850               0 :             if (searchPath)
     851               0 :                 execvp(program.c_str(), (char * *) &cargs[0]);
     852                 :             else
     853               0 :                 execv(program.c_str(), (char * *) &cargs[0]);
     854               0 :             throw SysError(format("executing `%1%'") % program);
     855                 :             
     856               0 :         } catch (std::exception & e) {
     857               0 :             std::cerr << "error: " << e.what() << std::endl;
     858                 :         }
     859               0 :         quickExit(1);
     860                 :     }
     861                 : 
     862                 :     /* Parent. */
     863                 : 
     864               1 :     pipe.writeSide.close();
     865                 : 
     866               1 :     string result = drainFD(pipe.readSide);
     867                 : 
     868                 :     /* Wait for the child to finish. */
     869               1 :     int status = pid.wait(true);
     870               1 :     if (!statusOk(status))
     871                 :         throw Error(format("program `%1%' %2%")
     872               0 :             % program % statusToString(status));
     873                 : 
     874               1 :     return result;
     875                 : }
     876                 : 
     877                 : 
     878             140 : void closeMostFDs(const set<int> & exceptions)
     879                 : {
     880             140 :     int maxFD = 0;
     881             140 :     maxFD = sysconf(_SC_OPEN_MAX);
     882          143500 :     for (int fd = 0; fd < maxFD; ++fd)
     883          143360 :         if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO
     884                 :             && exceptions.find(fd) == exceptions.end())
     885          142934 :             close(fd); /* ignore result */
     886             140 : }
     887                 : 
     888                 : 
     889               0 : void quickExit(int status)
     890                 : {
     891                 : #ifdef __CYGWIN__
     892                 :     /* Hack for Cygwin: _exit() doesn't seem to work quite right,
     893                 :        since some Berkeley DB code appears to be called when a child
     894                 :        exits through _exit() (e.g., because execve() failed).  So call
     895                 :        the Windows API directly. */
     896                 :     ExitProcess(status);
     897                 : #else
     898               0 :     _exit(status);
     899                 : #endif
     900                 : }
     901                 : 
     902                 : 
     903               0 : void setuidCleanup()
     904                 : {
     905                 :     /* Don't trust the environment. */
     906               0 :     environ = 0;
     907                 : 
     908                 :     /* Make sure that file descriptors 0, 1, 2 are open. */
     909               0 :     for (int fd = 0; fd <= 2; ++fd) {
     910                 :         struct stat st;
     911               0 :         if (fstat(fd, &st) == -1) abort();
     912                 :     }
     913               0 : }
     914                 : 
     915                 : 
     916                 : //////////////////////////////////////////////////////////////////////
     917                 : 
     918                 : 
     919                 : volatile sig_atomic_t _isInterrupted = 0;
     920                 : 
     921               0 : void _interrupted()
     922                 : {
     923                 :     /* Block user interrupts while an exception is being handled.
     924                 :        Throwing an exception while another exception is being handled
     925                 :        kills the program! */
     926               0 :     if (!std::uncaught_exception()) {
     927               0 :         _isInterrupted = 0;
     928               0 :         throw Interrupted("interrupted by the user");
     929                 :     }
     930               0 : }
     931                 : 
     932                 : 
     933                 : 
     934                 : //////////////////////////////////////////////////////////////////////
     935                 : 
     936                 : 
     937               0 : string packStrings(const Strings & strings)
     938                 : {
     939               0 :     string d;
     940               0 :     for (Strings::const_iterator i = strings.begin();
     941                 :          i != strings.end(); ++i)
     942                 :     {
     943               0 :         unsigned int len = i->size();
     944               0 :         d += len & 0xff;
     945               0 :         d += (len >> 8) & 0xff;
     946               0 :         d += (len >> 16) & 0xff;
     947               0 :         d += (len >> 24) & 0xff;
     948               0 :         d += *i;
     949                 :     }
     950               0 :     return d;
     951                 : }
     952                 : 
     953                 :     
     954               0 : Strings unpackStrings(const string & s)
     955                 : {
     956               0 :     Strings strings;
     957                 :     
     958               0 :     string::const_iterator i = s.begin();
     959                 :     
     960               0 :     while (i != s.end()) {
     961                 : 
     962               0 :         if (i + 4 > s.end())
     963               0 :             throw Error(format("short db entry: `%1%'") % s);
     964                 :         
     965                 :         unsigned int len;
     966               0 :         len = (unsigned char) *i++;
     967               0 :         len |= ((unsigned char) *i++) << 8;
     968               0 :         len |= ((unsigned char) *i++) << 16;
     969               0 :         len |= ((unsigned char) *i++) << 24;
     970                 : 
     971               0 :         if (len == 0xffffffff) return strings; /* explicit end-of-list */
     972                 :         
     973               0 :         if (i + len > s.end())
     974               0 :             throw Error(format("short db entry: `%1%'") % s);
     975                 : 
     976               0 :         strings.push_back(string(i, i + len));
     977               0 :         i += len;
     978                 :     }
     979                 :     
     980               0 :     return strings;
     981                 : }
     982                 : 
     983                 : 
     984           18239 : Strings tokenizeString(const string & s, const string & separators)
     985                 : {
     986           18239 :     Strings result;
     987           36478 :     string::size_type pos = s.find_first_not_of(separators, 0);
     988           63515 :     while (pos != string::npos) {
     989           45276 :         string::size_type end = s.find_first_of(separators, pos + 1);
     990           45276 :         if (end == string::npos) end = s.size();
     991           45276 :         string token(s, pos, end - pos);
     992           45276 :         result.push_back(token);
     993           45276 :         pos = s.find_first_not_of(separators, end);
     994                 :     }
     995               0 :     return result;
     996                 : }
     997                 : 
     998                 : 
     999               6 : string statusToString(int status)
    1000                 : {
    1001               6 :     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
    1002               6 :         if (WIFEXITED(status))
    1003               6 :             return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
    1004               0 :         else if (WIFSIGNALED(status)) {
    1005               0 :             int sig = WTERMSIG(status);
    1006                 : #if HAVE_STRSIGNAL
    1007               0 :             const char * description = strsignal(sig);
    1008               0 :             return (format("failed due to signal %1% (%2%)") % sig % description).str();
    1009                 : #else
    1010                 :             return (format("failed due to signal %1%") % sig).str();
    1011                 : #endif
    1012                 :         }
    1013                 :         else
    1014               0 :             return "died abnormally";
    1015               0 :     } else return "succeeded";
    1016                 : }
    1017                 : 
    1018                 : 
    1019             131 : bool statusOk(int status)
    1020                 : {
    1021             131 :     return WIFEXITED(status) && WEXITSTATUS(status) == 0;
    1022                 : }
    1023                 : 
    1024                 : 
    1025            1146 : string int2String(int n)
    1026                 : {
    1027            1146 :     std::ostringstream str;
    1028            1146 :     str << n;
    1029            1146 :     return str.str();
    1030                 : }
    1031                 : 
    1032                 : 
    1033           13252 : bool string2Int(const string & s, int & n)
    1034                 : {
    1035           13252 :     std::istringstream str(s);
    1036           13252 :     str >> n;
    1037           13252 :     return str && str.get() == EOF;
    1038                 : }
    1039                 : 
    1040                 : 
    1041              27 : bool string2Int(const string & s, long long & n)
    1042                 : {
    1043              27 :     std::istringstream str(s);
    1044              27 :     str >> n;
    1045              27 :     return str && str.get() == EOF;
    1046                 : }
    1047                 : 
    1048                 : 
    1049            1009 : bool hasSuffix(const string & s, const string & suffix)
    1050                 : {
    1051            1009 :     return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix;
    1052                 : }
    1053                 : 
    1054                 : 
    1055               0 : void ignoreException()
    1056                 : {
    1057                 :     try {
    1058               0 :         throw;
    1059               0 :     } catch (std::exception & e) {
    1060               0 :         printMsg(lvlError, format("error (ignored): %1%") % e.what());
    1061                 :     }
    1062               0 : }
    1063                 : 
    1064               0 :  
    1065            1106 : }

Generated by: LTP GCOV extension version 1.6