Home | History | Annotate | Download | only in kati
      1 // Copyright 2015 Google Inc. All rights reserved
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // +build ignore
     16 
     17 #include "fileutil.h"
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <glob.h>
     22 #include <limits.h>
     23 #include <signal.h>
     24 #include <sys/stat.h>
     25 #include <sys/types.h>
     26 #include <sys/wait.h>
     27 #include <unistd.h>
     28 #if defined(__APPLE__)
     29 #include <mach-o/dyld.h>
     30 #endif
     31 
     32 #include <unordered_map>
     33 
     34 #include "log.h"
     35 #include "strutil.h"
     36 
     37 bool Exists(StringPiece filename) {
     38   CHECK(filename.size() < PATH_MAX);
     39   struct stat st;
     40   if (stat(filename.as_string().c_str(), &st) < 0) {
     41     return false;
     42   }
     43   return true;
     44 }
     45 
     46 double GetTimestampFromStat(const struct stat& st) {
     47 #if defined(__linux__)
     48   return st.st_mtime + st.st_mtim.tv_nsec * 0.001 * 0.001 * 0.001;
     49 #else
     50   return st.st_mtime;
     51 #endif
     52 }
     53 
     54 double GetTimestamp(StringPiece filename) {
     55   CHECK(filename.size() < PATH_MAX);
     56   struct stat st;
     57   if (stat(filename.as_string().c_str(), &st) < 0) {
     58     return -2.0;
     59   }
     60   return GetTimestampFromStat(st);
     61 }
     62 
     63 int RunCommand(const string& shell, const string& cmd,
     64                RedirectStderr redirect_stderr,
     65                string* s) {
     66   string cmd_escaped = cmd;
     67   EscapeShell(&cmd_escaped);
     68   string cmd_with_shell = shell + " -c \"" + cmd_escaped + "\"";
     69   const char* argv[] = {
     70     "/bin/sh", "-c", cmd_with_shell.c_str(), NULL
     71   };
     72 
     73   int pipefd[2];
     74   if (pipe(pipefd) != 0)
     75     PERROR("pipe failed");
     76   int pid;
     77   if ((pid = vfork())) {
     78     int status;
     79     close(pipefd[1]);
     80     while (true) {
     81       int result = waitpid(pid, &status, WNOHANG);
     82       if (result < 0)
     83         PERROR("waitpid failed");
     84 
     85       while (true) {
     86         char buf[4096];
     87         ssize_t r = read(pipefd[0], buf, 4096);
     88         if (r < 0)
     89           PERROR("read failed");
     90         if (r == 0)
     91           break;
     92         s->append(buf, buf+r);
     93       }
     94 
     95       if (result != 0) {
     96         break;
     97       }
     98     }
     99     close(pipefd[0]);
    100 
    101     return status;
    102   } else {
    103     close(pipefd[0]);
    104     if (redirect_stderr == RedirectStderr::STDOUT) {
    105       if (dup2(pipefd[1], 2) < 0)
    106         PERROR("dup2 failed");
    107     } else if (redirect_stderr == RedirectStderr::DEV_NULL) {
    108       int fd = open("/dev/null", O_WRONLY);
    109       if (dup2(fd, 2) < 0)
    110         PERROR("dup2 failed");
    111       close(fd);
    112     }
    113     if (dup2(pipefd[1], 1) < 0)
    114       PERROR("dup2 failed");
    115     close(pipefd[1]);
    116 
    117     execvp(argv[0], const_cast<char**>(argv));
    118     PLOG("execvp for %s failed", argv[0]);
    119     kill(getppid(), SIGTERM);
    120     _exit(1);
    121   }
    122 }
    123 
    124 void GetExecutablePath(string* path) {
    125 #if defined(__linux__)
    126   char mypath[PATH_MAX + 1];
    127   ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
    128   if (l < 0) {
    129     PERROR("readlink for /proc/self/exe");
    130   }
    131   mypath[l] = '\0';
    132   *path = mypath;
    133 #elif defined(__APPLE__)
    134   char mypath[PATH_MAX + 1];
    135   uint32_t size = PATH_MAX;
    136   if (_NSGetExecutablePath(mypath, &size) != 0) {
    137     ERROR("_NSGetExecutablePath failed");
    138   }
    139   mypath[size] = 0;
    140   *path = mypath;
    141 #else
    142 #error "Unsupported OS"
    143 #endif
    144 }
    145 
    146 namespace {
    147 
    148 class GlobCache {
    149  public:
    150   ~GlobCache() {
    151     Clear();
    152   }
    153 
    154   void Get(const char* pat, vector<string>** files) {
    155     auto p = cache_.emplace(pat, nullptr);
    156     if (p.second) {
    157       vector<string>* files = p.first->second = new vector<string>;
    158       if (strcspn(pat, "?*[\\") != strlen(pat)) {
    159         glob_t gl;
    160         glob(pat, GLOB_NOSORT, NULL, &gl);
    161         for (size_t i = 0; i < gl.gl_pathc; i++) {
    162           files->push_back(gl.gl_pathv[i]);
    163         }
    164         globfree(&gl);
    165       } else {
    166         if (Exists(pat))
    167           files->push_back(pat);
    168       }
    169     }
    170     *files = p.first->second;
    171   }
    172 
    173   const unordered_map<string, vector<string>*>& GetAll() const {
    174     return cache_;
    175   }
    176 
    177   void Clear() {
    178     for (auto& p : cache_) {
    179       delete p.second;
    180     }
    181     cache_.clear();
    182   }
    183 
    184  private:
    185   unordered_map<string, vector<string>*> cache_;
    186 };
    187 
    188 static GlobCache g_gc;
    189 
    190 }  // namespace
    191 
    192 void Glob(const char* pat, vector<string>** files) {
    193   g_gc.Get(pat, files);
    194 }
    195 
    196 const unordered_map<string, vector<string>*>& GetAllGlobCache() {
    197   return g_gc.GetAll();
    198 }
    199 
    200 void ClearGlobCache() {
    201   g_gc.Clear();
    202 }
    203