LTP GCOV extension - code coverage report
Current view: directory - src/libutil - util.cc
Test: app.info
Date: 2004-12-21 Instrumented lines: 291
Code covered: 75.6 % Executed lines: 220

       1                 : #include "config.h"
       2                 : 
       3                 : #include <iostream>
       4                 : #include <cerrno>
       5                 : #include <cstdio>
       6                 : #include <sstream>
       7                 : 
       8                 : #include <sys/types.h>
       9                 : #include <sys/stat.h>
      10                 : #include <sys/wait.h>
      11                 : #include <unistd.h>
      12                 : #include <dirent.h>
      13                 : #include <fcntl.h>
      14                 : #include <signal.h>
      15                 : 
      16                 : #include "util.hh"
      17                 : 
      18                 : 
      19              51 : string thisSystem = SYSTEM;
      20                 : 
      21                 : 
      22                 : Error::Error(const format & f)
      23              14 : {
      24               7 :     err = f.str();
      25                 : }
      26                 : 
      27                 : 
      28                 : SysError::SysError(const format & f)
      29               0 :     : Error(format("%1%: %2%") % f.str() % strerror(errno))
      30               0 : {
      31                 : }
      32                 : 
      33                 : 
      34                 : string getEnv(const string & key, const string & def)
      35             477 : {
      36             477 :     char * value = getenv(key.c_str());
      37             477 :     return value ? string(value) : def;
      38                 : }
      39                 : 
      40                 : 
      41                 : Path absPath(Path path, Path dir)
      42              68 : {
      43              68 :     if (path[0] != '/') {
      44              41 :         if (dir == "") {
      45              26 :             char buf[PATH_MAX];
      46              26 :             if (!getcwd(buf, sizeof(buf)))
      47               0 :                 throw SysError("cannot get cwd");
      48              26 :             dir = buf;
      49                 :         }
      50              41 :         path = dir + "/" + path;
      51                 :     }
      52              68 :     return canonPath(path);
      53                 : }
      54                 : 
      55                 : 
      56                 : Path canonPath(const Path & path)
      57             494 : {
      58             494 :     string s;
      59                 : 
      60             494 :     if (path[0] != '/')
      61               0 :         throw Error(format("not an absolute path: `%1%'") % path);
      62                 : 
      63             494 :     string::const_iterator i = path.begin(), end = path.end();
      64                 : 
      65            6014 :     while (1) {
      66                 : 
      67                 :         /* Skip slashes. */
      68            6014 :         while (i != end && *i == '/') i++;
      69            3251 :         if (i == end) break;
      70                 : 
      71                 :         /* Ignore `.'. */
      72            2757 :         if (*i == '.' && (i + 1 == end || i[1] == '/'))
      73              27 :             i++;
      74                 : 
      75                 :         /* If `..', delete the last component. */
      76            2730 :         else if (*i == '.' && i + 1 < end && i[1] == '.' && 
      77                 :             (i + 2 == end || i[2] == '/'))
      78                 :         {
      79               0 :             if (!s.empty()) s.erase(s.rfind('/'));
      80               0 :             i += 2;
      81                 :         }
      82                 : 
      83                 :         /* Normal component; copy it. */
      84                 :         else {
      85            2730 :             s += '/';
      86           33628 :             while (i != end && *i != '/') s += *i++;
      87                 :         }
      88                 :     }
      89                 : 
      90             494 :     return s.empty() ? "/" : s;
      91                 : }
      92                 : 
      93                 : 
      94                 : Path dirOf(const Path & path)
      95             317 : {
      96             317 :     unsigned int pos = path.rfind('/');
      97             317 :     if (pos == string::npos)
      98               0 :         throw Error(format("invalid file name: %1%") % path);
      99             317 :     return Path(path, 0, pos);
     100                 : }
     101                 : 
     102                 : 
     103                 : string baseNameOf(const Path & path)
     104             125 : {
     105             125 :     unsigned int pos = path.rfind('/');
     106             125 :     if (pos == string::npos)
     107               0 :         throw Error(format("invalid file name %1% ") % path);
     108             125 :     return string(path, pos + 1);
     109                 : }
     110                 : 
     111                 : 
     112                 : bool pathExists(const Path & path)
     113             208 : {
     114             208 :     int res;
     115             208 :     struct stat st;
     116             208 :     res = lstat(path.c_str(), &st);
     117             208 :     if (!res) return true;
     118             102 :     if (errno != ENOENT && errno != ENOTDIR)
     119               0 :         throw SysError(format("getting status of %1%") % path);
     120             102 :     return false;
     121                 : }
     122                 : 
     123                 : 
     124                 : Path readLink(const Path & path)
     125               2 : {
     126               2 :     struct stat st;
     127               2 :     if (lstat(path.c_str(), &st))
     128               0 :         throw SysError(format("getting status of `%1%'") % path);
     129               2 :     if (!S_ISLNK(st.st_mode))
     130               0 :         throw Error(format("`%1%' is not a symlink") % path);
     131               2 :     char buf[st.st_size];
     132               2 :     if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
     133               0 :         throw SysError(format("reading symbolic link `%1%'") % path);
     134               2 :     return string(buf, st.st_size);
     135                 : }
     136                 : 
     137                 : 
     138                 : Strings readDirectory(const Path & path)
     139              44 : {
     140              44 :     Strings names;
     141                 : 
     142              44 :     AutoCloseDir dir = opendir(path.c_str());
     143              44 :     if (!dir) throw SysError(format("opening directory `%1%'") % path);
     144                 : 
     145             161 :     struct dirent * dirent;
     146             161 :     while (errno = 0, dirent = readdir(dir)) { /* sic */
     147             117 :         checkInterrupt();
     148             117 :         string name = dirent->d_name;
     149             117 :         if (name == "." || name == "..") continue;
     150              29 :         names.push_back(name);
     151                 :     }
     152              44 :     if (errno) throw SysError(format("reading directory `%1%'") % path);
     153                 : 
     154              44 :     return names;
     155                 : }
     156                 : 
     157                 : 
     158                 : static void _deletePath(const Path & path)
     159              25 : {
     160              25 :     checkInterrupt();
     161                 : 
     162              25 :     printMsg(lvlVomit, format("%1%") % path);
     163                 : 
     164              25 :     struct stat st;
     165              25 :     if (lstat(path.c_str(), &st))
     166               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
     167                 : 
     168              25 :     if (S_ISDIR(st.st_mode)) {
     169              22 :         Strings names = readDirectory(path);
     170                 : 
     171                 :         /* Make the directory writable. */
     172              22 :         if (!(st.st_mode & S_IWUSR)) {
     173               0 :             if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1)
     174               0 :                 throw SysError(format("making `%1%' writable") % path);
     175                 :         }
     176                 : 
     177              25 :         for (Strings::iterator i = names.begin(); i != names.end(); ++i)
     178               3 :             _deletePath(path + "/" + *i);
     179                 :     }
     180                 : 
     181              25 :     if (remove(path.c_str()) == -1)
     182               0 :         throw SysError(format("cannot unlink `%1%'") % path);
     183                 : }
     184                 : 
     185                 : 
     186                 : void deletePath(const Path & path)
     187              22 : {
     188              22 :     startNest(nest, lvlDebug,
     189                 :         format("recursively deleting path `%1%'") % path);
     190              22 :     _deletePath(path);
     191                 : }
     192                 : 
     193                 : 
     194                 : void makePathReadOnly(const Path & path)
     195              96 : {
     196              96 :     checkInterrupt();
     197                 : 
     198              96 :     struct stat st;
     199              96 :     if (lstat(path.c_str(), &st))
     200               0 :         throw SysError(format("getting attributes of path `%1%'") % path);
     201                 : 
     202              96 :     if (!S_ISLNK(st.st_mode) && (st.st_mode & S_IWUSR)) {
     203              94 :         if (chmod(path.c_str(), st.st_mode & ~S_IWUSR) == -1)
     204               0 :             throw SysError(format("making `%1%' read-only") % path);
     205                 :     }
     206                 : 
     207              96 :     if (S_ISDIR(st.st_mode)) {
     208              12 :         Strings names = readDirectory(path);
     209              26 :         for (Strings::iterator i = names.begin(); i != names.end(); ++i)
     210              14 :             makePathReadOnly(path + "/" + *i);
     211                 :     }
     212                 : }
     213                 : 
     214                 : 
     215                 : static Path tempName()
     216              22 : {
     217              22 :     static int counter = 0;
     218              22 :     Path tmpRoot = canonPath(getEnv("TMPDIR", "/tmp"));
     219              22 :     return (format("%1%/nix-%2%-%3%") % tmpRoot % getpid() % counter++).str();
     220                 : }
     221                 : 
     222                 : 
     223                 : Path createTempDir()
     224              22 : {
     225              22 :     while (1) {
     226              22 :         checkInterrupt();
     227              22 :         Path tmpDir = tempName();
     228              22 :         if (mkdir(tmpDir.c_str(), 0777) == 0) return tmpDir;
     229               0 :         if (errno != EEXIST)
     230               0 :             throw SysError(format("creating directory `%1%'") % tmpDir);
     231                 :     }
     232                 : }
     233                 : 
     234                 : 
     235                 : void writeStringToFile(const Path & path, const string & s)
     236              53 : {
     237                 :     AutoCloseFD fd = open(path.c_str(),
     238              53 :         O_CREAT | O_EXCL | O_WRONLY, 0666);
     239              53 :     if (fd == -1)
     240               0 :         throw SysError(format("creating file `%1%'") % path);
     241              53 :     writeFull(fd, (unsigned char *) s.c_str(), s.size());
     242                 : }
     243                 : 
     244                 : 
     245                 : LogType logType = ltPretty;
     246                 : Verbosity verbosity = lvlInfo;
     247                 : 
     248                 : static int nestingLevel = 0;
     249                 : 
     250                 : 
     251                 : Nest::Nest()
     252             964 : {
     253             964 :     nest = false;
     254                 : }
     255                 : 
     256                 : 
     257                 : Nest::~Nest()
     258            1928 : {
     259             964 :     close();
     260                 : }
     261                 : 
     262                 : 
     263                 : static string escVerbosity(Verbosity level)
     264               0 : {
     265               0 :     int l = (int) level;
     266               0 :     ostringstream st;
     267               0 :     st << l;
     268               0 :     return st.str();
     269                 : }
     270                 : 
     271                 : 
     272                 : void Nest::open(Verbosity level, const format & f)
     273             102 : {
     274             102 :     if (level <= verbosity) {
     275             102 :         if (logType == ltEscapes)
     276               0 :             cerr << "\033[" << escVerbosity(level) << "p"
     277                 :                  << f.str() << "\n";
     278                 :         else
     279             102 :             printMsg_(level, f);
     280             102 :         nest = true;
     281             102 :         nestingLevel++;
     282                 :     }
     283                 : }
     284                 : 
     285                 : 
     286                 : void Nest::close()
     287             984 : {
     288             984 :     if (nest) {
     289             102 :         nestingLevel--;
     290             102 :         if (logType == ltEscapes)
     291               0 :             cerr << "\033[q";
     292             102 :         nest = false;
     293                 :     }
     294                 : }
     295                 : 
     296                 : 
     297                 : void printMsg_(Verbosity level, const format & f)
     298            2927 : {
     299            2927 :     checkInterrupt();
     300            2927 :     if (level > verbosity) return;
     301            2927 :     string prefix;
     302            2927 :     if (logType == ltPretty)
     303            8840 :         for (int i = 0; i < nestingLevel; i++)
     304            5913 :             prefix += "|   ";
     305               0 :     else if (logType == ltEscapes && level != lvlInfo)
     306               0 :         prefix = "\033[" + escVerbosity(level) + "s";
     307            2927 :     cerr << format("%1%%2%\n") % prefix % f.str();
     308                 : }
     309                 : 
     310                 : 
     311                 : void readFull(int fd, unsigned char * buf, size_t count)
     312              62 : {
     313              62 :     while (count) {
     314              31 :         checkInterrupt();
     315              31 :         ssize_t res = read(fd, (char *) buf, count);
     316              31 :         if (res == -1) {
     317               0 :             if (errno == EINTR) continue;
     318               0 :             throw SysError("reading from file");
     319                 :         }
     320              31 :         if (res == 0) throw Error("unexpected end-of-file");
     321              31 :         count -= res;
     322              31 :         buf += res;
     323                 :     }
     324                 : }
     325                 : 
     326                 : 
     327                 : void writeFull(int fd, const unsigned char * buf, size_t count)
     328             849 : {
     329             849 :     while (count) {
     330             424 :         checkInterrupt();
     331             424 :         ssize_t res = write(fd, (char *) buf, count);
     332             424 :         if (res == -1) {
     333               0 :             if (errno == EINTR) continue;
     334               0 :             throw SysError("writing to file");
     335                 :         }
     336             424 :         count -= res;
     337             424 :         buf += res;
     338                 :     }
     339                 : }
     340                 : 
     341                 : 
     342                 : 
     343                 : //////////////////////////////////////////////////////////////////////
     344                 : 
     345                 : 
     346               0 : AutoDelete::AutoDelete(const string & p) : path(p)
     347               0 : {
     348               0 :     del = true;
     349                 : }
     350                 : 
     351                 : AutoDelete::~AutoDelete()
     352               0 : {
     353               0 :     if (del) deletePath(path);
     354                 : }
     355                 : 
     356                 : void AutoDelete::cancel()
     357               0 : {
     358               0 :     del = false;
     359                 : }
     360                 : 
     361                 : 
     362                 : 
     363                 : //////////////////////////////////////////////////////////////////////
     364                 : 
     365                 : 
     366                 : AutoCloseFD::AutoCloseFD()
     367             855 : {
     368             855 :     fd = -1;
     369                 : }
     370                 : 
     371                 : 
     372                 : AutoCloseFD::AutoCloseFD(int fd)
     373             115 : {
     374             115 :     this->fd = fd;
     375                 : }
     376                 : 
     377                 : 
     378                 : AutoCloseFD::~AutoCloseFD()
     379            1940 : {
     380             970 :     try {
     381             970 :         close();
     382               0 :     } catch (Error & e) {
     383               0 :         printMsg(lvlError, format("error (ignored): %1%") % e.msg());
     384                 :     }
     385                 : }
     386                 : 
     387                 : 
     388                 : void AutoCloseFD::operator =(int fd)
     389             104 : {
     390             104 :     if (this->fd != fd) close();
     391             104 :     this->fd = fd;
     392                 : }
     393                 : 
     394                 : 
     395                 : AutoCloseFD::operator int()
     396             579 : {
     397             579 :     return fd;
     398                 : }
     399                 : 
     400                 : 
     401                 : void AutoCloseFD::close()
     402            1206 : {
     403            1206 :     if (fd != -1) {
     404             252 :         if (::close(fd) == -1)
     405                 :             /* This should never happen. */
     406               0 :             throw SysError("closing file descriptor");
     407             252 :         fd = -1;
     408                 :     }
     409                 : }
     410                 : 
     411                 : 
     412                 : bool AutoCloseFD::isOpen()
     413              22 : {
     414              22 :     return fd != -1;
     415                 : }
     416                 : 
     417                 : 
     418                 : void Pipe::create()
     419              41 : {
     420              41 :     int fds[2];
     421              41 :     if (pipe(fds) != 0) throw SysError("creating pipe");
     422              41 :     readSide = fds[0];
     423              41 :     writeSide = fds[1];
     424                 : }
     425                 : 
     426                 : 
     427                 : 
     428                 : //////////////////////////////////////////////////////////////////////
     429                 : 
     430                 : 
     431                 : AutoCloseDir::AutoCloseDir()
     432               0 : {
     433               0 :     dir = 0;
     434                 : }
     435                 : 
     436                 : 
     437                 : AutoCloseDir::AutoCloseDir(DIR * dir)
     438              44 : {
     439              44 :     this->dir = dir;
     440                 : }
     441                 : 
     442                 : 
     443                 : AutoCloseDir::~AutoCloseDir()
     444              88 : {
     445              44 :     if (dir) closedir(dir);
     446                 : }
     447                 : 
     448                 : 
     449                 : void AutoCloseDir::operator =(DIR * dir)
     450               0 : {
     451               0 :     this->dir = dir;
     452                 : }
     453                 : 
     454                 : 
     455                 : AutoCloseDir::operator DIR *()
     456             205 : {
     457             205 :     return dir;
     458                 : }
     459                 : 
     460                 : 
     461                 : 
     462                 : //////////////////////////////////////////////////////////////////////
     463                 : 
     464                 : 
     465                 : Pid::Pid()
     466             270 : {
     467             270 :     pid = -1;
     468             270 :     separatePG = false;
     469                 : }
     470                 : 
     471                 : 
     472                 : Pid::~Pid()
     473             540 : {
     474             270 :     kill();
     475                 : }
     476                 : 
     477                 : 
     478                 : void Pid::operator =(pid_t pid)
     479              62 : {
     480              62 :     if (this->pid != pid) kill();
     481              62 :     this->pid = pid;
     482                 : }
     483                 : 
     484                 : 
     485                 : Pid::operator pid_t()
     486             378 : {
     487             378 :     return pid;
     488                 : }
     489                 : 
     490                 : 
     491                 : void Pid::kill()
     492             332 : {
     493             332 :     if (pid == -1) return;
     494                 :     
     495               0 :     printMsg(lvlError, format("killing process %1%") % pid);
     496                 : 
     497                 :     /* Send a KILL signal to the child.  If it has its own process
     498                 :        group, send the signal to every process in the child process
     499                 :        group (which hopefully includes *all* its children). */
     500               0 :     if (::kill(separatePG ? -pid : pid, SIGKILL) != 0)
     501               0 :         printMsg(lvlError, (SysError(format("killing process %1%") % pid).msg()));
     502                 : 
     503                 :     /* Wait until the child dies, disregarding the exit status. */
     504               0 :     int status;
     505               0 :     while (waitpid(pid, &status, 0) == -1)
     506               0 :         if (errno != EINTR) printMsg(lvlError,
     507                 :             (SysError(format("waiting for process %1%") % pid).msg()));
     508                 : 
     509               0 :     pid = -1;
     510                 : }
     511                 : 
     512                 : 
     513                 : int Pid::wait(bool block)
     514              35 : {
     515              35 :     while (1) {
     516              35 :         int status;
     517              35 :         int res = waitpid(pid, &status, block ? 0 : WNOHANG);
     518              35 :         if (res == pid) {
     519              35 :             pid = -1;
     520              35 :             return status;
     521                 :         }
     522               0 :         if (res == 0 && !block) return -1;
     523               0 :         if (errno != EINTR)
     524               0 :             throw SysError("cannot get child exit status");
     525                 :     }
     526                 : }
     527                 : 
     528                 : 
     529                 : void Pid::setSeparatePG(bool separatePG)
     530              24 : {
     531              24 :     this->separatePG = separatePG;
     532                 : }
     533                 : 
     534                 : 
     535                 : 
     536                 : //////////////////////////////////////////////////////////////////////
     537                 : 
     538                 : 
     539                 : volatile sig_atomic_t _isInterrupted = 0;
     540                 : 
     541                 : void _interrupted()
     542               0 : {
     543                 :     /* Block user interrupts while an exception is being handled.
     544                 :        Throwing an exception while another exception is being handled
     545                 :        kills the program! */
     546               0 :     if (!uncaught_exception()) {
     547               0 :         _isInterrupted = 0;
     548               0 :         throw Error("interrupted by the user");
     549                 :     }
     550                 : }
     551                 : 
     552                 : 
     553                 : 
     554                 : //////////////////////////////////////////////////////////////////////
     555                 : 
     556                 : 
     557                 : string packStrings(const Strings & strings)
     558              55 : {
     559              55 :     string d;
     560             152 :     for (Strings::const_iterator i = strings.begin();
     561                 :          i != strings.end(); ++i)
     562                 :     {
     563              97 :         unsigned int len = i->size();
     564              97 :         d += len & 0xff;
     565              97 :         d += (len >> 8) & 0xff;
     566              97 :         d += (len >> 16) & 0xff;
     567              97 :         d += (len >> 24) & 0xff;
     568              97 :         d += *i;
     569                 :     }
     570               0 :     return d;
     571                 : }
     572                 : 
     573                 :     
     574                 : Strings unpackStrings(const string & s)
     575              52 : {
     576              52 :     Strings strings;
     577                 :     
     578              52 :     string::const_iterator i = s.begin();
     579                 :     
     580             169 :     while (i != s.end()) {
     581                 : 
     582             117 :         if (i + 4 > s.end())
     583               0 :             throw Error(format("short db entry: `%1%'") % s);
     584                 :         
     585             117 :         unsigned int len;
     586             117 :         len = (unsigned char) *i++;
     587             117 :         len |= ((unsigned char) *i++) << 8;
     588             117 :         len |= ((unsigned char) *i++) << 16;
     589             117 :         len |= ((unsigned char) *i++) << 24;
     590                 :         
     591             117 :         if (i + len > s.end())
     592               0 :             throw Error(format("short db entry: `%1%'") % s);
     593                 : 
     594             117 :         strings.push_back(string(i, i + len));
     595             117 :         i += len;
     596                 :     }
     597                 :     
     598               0 :     return strings;
     599                 : }
     600                 : 
     601                 : 
     602                 : string statusToString(int status)
     603               1 : {
     604               1 :     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
     605               1 :         if (WIFEXITED(status))
     606               1 :             return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
     607               0 :         else if (WIFSIGNALED(status))
     608               0 :             return (format("failed due to signal %1%") % WTERMSIG(status)).str();
     609                 :         else
     610               0 :             return "died abnormally";
     611               0 :     } else return "succeeded";
     612                 : }
     613                 : 
     614                 : 
     615                 : bool statusOk(int status)
     616              33 : {
     617              33 :     return WIFEXITED(status) && WEXITSTATUS(status) == 0;
     618                 : }
     619                 : 
     620                 : 
     621                 : bool string2Int(const string & s, int & n)
     622               8 : {
     623               8 :     istringstream str(s);
     624               8 :     str >> n;
     625               8 :     return str && str.eof();
     626              51 : }

Generated by: LTP GCOV extension version 1.1