blob: 7ebb8ec200fd34a925d3177885f53e9e6e5f3663 [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 Willemsen3ce083f2017-10-11 22:17:48 -070063int RunCommand(const string& shell,
64 const string& shellflag,
65 const string& cmd,
66 RedirectStderr redirect_stderr,
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090067 string* s) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -070068 const char* argv[] = {NULL, NULL, NULL, NULL};
Dan Willemsen064be222016-09-30 20:17:14 -070069 string cmd_with_shell;
70 if (shell[0] != '/' || shell.find_first_of(" $") != string::npos) {
71 string cmd_escaped = cmd;
72 EscapeShell(&cmd_escaped);
73 cmd_with_shell = shell + " " + shellflag + " \"" + cmd_escaped + "\"";
74 argv[0] = "/bin/sh";
75 argv[1] = "-c";
76 argv[2] = cmd_with_shell.c_str();
77 } else {
78 // If the shell isn't complicated, we don't need to wrap in /bin/sh
79 argv[0] = shell.c_str();
80 argv[1] = shellflag.c_str();
81 argv[2] = cmd.c_str();
82 }
Shinichiro Hamaji348a9602016-02-18 17:20:08 +090083
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090084 int pipefd[2];
85 if (pipe(pipefd) != 0)
86 PERROR("pipe failed");
87 int pid;
88 if ((pid = vfork())) {
89 int status;
90 close(pipefd[1]);
91 while (true) {
92 int result = waitpid(pid, &status, WNOHANG);
93 if (result < 0)
94 PERROR("waitpid failed");
95
96 while (true) {
97 char buf[4096];
Shinichiro Hamaji706c27f2016-04-11 18:35:06 +090098 ssize_t r = HANDLE_EINTR(read(pipefd[0], buf, 4096));
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090099 if (r < 0)
100 PERROR("read failed");
101 if (r == 0)
102 break;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700103 s->append(buf, buf + r);
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900104 }
105
106 if (result != 0) {
107 break;
108 }
109 }
110 close(pipefd[0]);
111
112 return status;
113 } else {
114 close(pipefd[0]);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900115 if (redirect_stderr == RedirectStderr::STDOUT) {
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900116 if (dup2(pipefd[1], 2) < 0)
117 PERROR("dup2 failed");
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900118 } else if (redirect_stderr == RedirectStderr::DEV_NULL) {
119 int fd = open("/dev/null", O_WRONLY);
120 if (dup2(fd, 2) < 0)
121 PERROR("dup2 failed");
122 close(fd);
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900123 }
124 if (dup2(pipefd[1], 1) < 0)
125 PERROR("dup2 failed");
126 close(pipefd[1]);
127
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900128 execvp(argv[0], const_cast<char**>(argv));
Shinichiro Hamaji7cf19352016-01-26 15:32:44 +0900129 PLOG("execvp for %s failed", argv[0]);
130 kill(getppid(), SIGTERM);
131 _exit(1);
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900132 }
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900133}
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900134
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900135void GetExecutablePath(string* path) {
136#if defined(__linux__)
137 char mypath[PATH_MAX + 1];
138 ssize_t l = readlink("/proc/self/exe", mypath, PATH_MAX);
139 if (l < 0) {
140 PERROR("readlink for /proc/self/exe");
141 }
142 mypath[l] = '\0';
143 *path = mypath;
144#elif defined(__APPLE__)
145 char mypath[PATH_MAX + 1];
Shinichiro Hamajie6ec1182015-07-31 15:02:35 +0900146 uint32_t size = PATH_MAX;
147 if (_NSGetExecutablePath(mypath, &size) != 0) {
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900148 ERROR("_NSGetExecutablePath failed");
149 }
Shinichiro Hamajie6ec1182015-07-31 15:02:35 +0900150 mypath[size] = 0;
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900151 *path = mypath;
152#else
153#error "Unsupported OS"
154#endif
155}
156
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900157namespace {
158
159class GlobCache {
160 public:
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700161 ~GlobCache() { Clear(); }
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900162
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}