blob: 4cf653b7d49f572ea4bc9349e9796d5ecb2755e3 [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// 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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "fileutil.h"
18
19#include <errno.h>
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +090020#include <fcntl.h>
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090021#include <glob.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include <limits.h>
Shinichiro Hamaji7cf19352016-01-26 15:32:44 +090023#include <signal.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090024#include <sys/stat.h>
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090025#include <sys/types.h>
26#include <sys/wait.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090027#include <unistd.h>
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +090028#if defined(__APPLE__)
29#include <mach-o/dyld.h>
30#endif
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090031
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +090032#include <unordered_map>
33
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090034#include "log.h"
Shinichiro Hamaji348a9602016-02-18 17:20:08 +090035#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036
37bool Exists(StringPiece filename) {
38 CHECK(filename.size() < PATH_MAX);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090039 struct stat st;
Shinichiro Hamajifda79432015-07-05 03:17:34 +090040 if (stat(filename.as_string().c_str(), &st) < 0) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090041 return false;
42 }
43 return true;
44}
Shinichiro Hamajifda79432015-07-05 03:17:34 +090045
Shinichiro Hamaji6ce977d2015-10-15 16:01:16 +090046double 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
Shinichiro Hamajifda79432015-07-05 03:17:34 +090054double 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 }
Shinichiro Hamaji6ce977d2015-10-15 16:01:16 +090060 return GetTimestampFromStat(st);
Shinichiro Hamajifda79432015-07-05 03:17:34 +090061}
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090062
Dan Willemsen064be222016-09-30 20:17:14 -070063int RunCommand(const string& shell, const string& shellflag,
64 const string& cmd, RedirectStderr redirect_stderr,
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090065 string* s) {
Dan Willemsen064be222016-09-30 20:17:14 -070066 const char* argv[] = { NULL, NULL, NULL, NULL };
67 string cmd_with_shell;
68 if (shell[0] != '/' || shell.find_first_of(" $") != string::npos) {
69 string cmd_escaped = cmd;
70 EscapeShell(&cmd_escaped);
71 cmd_with_shell = shell + " " + shellflag + " \"" + cmd_escaped + "\"";
72 argv[0] = "/bin/sh";
73 argv[1] = "-c";
74 argv[2] = cmd_with_shell.c_str();
75 } else {
76 // If the shell isn't complicated, we don't need to wrap in /bin/sh
77 argv[0] = shell.c_str();
78 argv[1] = shellflag.c_str();
79 argv[2] = cmd.c_str();
80 }
Shinichiro Hamaji348a9602016-02-18 17:20:08 +090081
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090082 int pipefd[2];
83 if (pipe(pipefd) != 0)
84 PERROR("pipe failed");
85 int pid;
86 if ((pid = vfork())) {
87 int status;
88 close(pipefd[1]);
89 while (true) {
90 int result = waitpid(pid, &status, WNOHANG);
91 if (result < 0)
92 PERROR("waitpid failed");
93
94 while (true) {
95 char buf[4096];
Shinichiro Hamaji706c27f2016-04-11 18:35:06 +090096 ssize_t r = HANDLE_EINTR(read(pipefd[0], buf, 4096));
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090097 if (r < 0)
98 PERROR("read failed");
99 if (r == 0)
100 break;
101 s->append(buf, buf+r);
102 }
103
104 if (result != 0) {
105 break;
106 }
107 }
108 close(pipefd[0]);
109
110 return status;
111 } else {
112 close(pipefd[0]);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900113 if (redirect_stderr == RedirectStderr::STDOUT) {
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900114 if (dup2(pipefd[1], 2) < 0)
115 PERROR("dup2 failed");
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900116 } else if (redirect_stderr == RedirectStderr::DEV_NULL) {
117 int fd = open("/dev/null", O_WRONLY);
118 if (dup2(fd, 2) < 0)
119 PERROR("dup2 failed");
120 close(fd);
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900121 }
122 if (dup2(pipefd[1], 1) < 0)
123 PERROR("dup2 failed");
124 close(pipefd[1]);
125
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900126 execvp(argv[0], const_cast<char**>(argv));
Shinichiro Hamaji7cf19352016-01-26 15:32:44 +0900127 PLOG("execvp for %s failed", argv[0]);
128 kill(getppid(), SIGTERM);
129 _exit(1);
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900130 }
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900131}
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900132
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900133void GetExecutablePath(string* path) {
134#if defined(__linux__)
135 char mypath[PATH_MAX + 1];
136 ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
137 if (l < 0) {
138 PERROR("readlink for /proc/self/exe");
139 }
140 mypath[l] = '\0';
141 *path = mypath;
142#elif defined(__APPLE__)
143 char mypath[PATH_MAX + 1];
Shinichiro Hamajie6ec1182015-07-31 15:02:35 +0900144 uint32_t size = PATH_MAX;
145 if (_NSGetExecutablePath(mypath, &size) != 0) {
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900146 ERROR("_NSGetExecutablePath failed");
147 }
Shinichiro Hamajie6ec1182015-07-31 15:02:35 +0900148 mypath[size] = 0;
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900149 *path = mypath;
150#else
151#error "Unsupported OS"
152#endif
153}
154
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900155namespace {
156
157class GlobCache {
158 public:
159 ~GlobCache() {
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900160 Clear();
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900161 }
162
163 void Get(const char* pat, vector<string>** files) {
164 auto p = cache_.emplace(pat, nullptr);
165 if (p.second) {
166 vector<string>* files = p.first->second = new vector<string>;
167 if (strcspn(pat, "?*[\\") != strlen(pat)) {
168 glob_t gl;
Shinichiro Hamaji9f6343c2016-05-03 01:05:32 +0900169 glob(pat, 0, NULL, &gl);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900170 for (size_t i = 0; i < gl.gl_pathc; i++) {
171 files->push_back(gl.gl_pathv[i]);
172 }
173 globfree(&gl);
174 } else {
175 if (Exists(pat))
176 files->push_back(pat);
177 }
178 }
179 *files = p.first->second;
180 }
181
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900182 const unordered_map<string, vector<string>*>& GetAll() const {
183 return cache_;
184 }
185
186 void Clear() {
187 for (auto& p : cache_) {
188 delete p.second;
189 }
190 cache_.clear();
191 }
192
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900193 private:
194 unordered_map<string, vector<string>*> cache_;
195};
196
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900197static GlobCache g_gc;
198
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900199} // namespace
200
201void Glob(const char* pat, vector<string>** files) {
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900202 g_gc.Get(pat, files);
203}
204
205const unordered_map<string, vector<string>*>& GetAllGlobCache() {
206 return g_gc.GetAll();
207}
208
209void ClearGlobCache() {
210 g_gc.Clear();
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900211}