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