Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 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 | |
Mostyn Bramley-Moore | 44e8d10 | 2015-11-10 11:27:39 +0000 | [diff] [blame] | 15 | #include <errno.h> // errno, ENAMETOOLONG |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 16 | #include <limits.h> |
Lukacs Berki | 4de9894 | 2016-09-09 09:23:36 +0000 | [diff] [blame] | 17 | #include <linux/magic.h> |
Thiago Farina | fdc7f98 | 2015-04-27 23:01:34 +0000 | [diff] [blame] | 18 | #include <pwd.h> |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 19 | #include <signal.h> |
jmmv | 3cb1aef | 2019-03-14 07:38:00 -0700 | [diff] [blame] | 20 | #include <spawn.h> |
Douglas Dawson | 5ca52f7 | 2016-07-13 16:38:40 +0000 | [diff] [blame] | 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 23 | #include <string.h> // strerror |
Thiago Farina | 8a67da4 | 2015-05-05 18:04:50 +0000 | [diff] [blame] | 24 | #include <sys/socket.h> |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 25 | #include <sys/stat.h> |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 26 | #include <sys/statfs.h> |
Damien Martin-Guillerez | 27b9475 | 2015-03-23 13:00:28 +0000 | [diff] [blame] | 27 | #include <sys/types.h> |
Thiago Farina | fdc7f98 | 2015-04-27 23:01:34 +0000 | [diff] [blame] | 28 | #include <unistd.h> |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 29 | |
Han-Wen Nienhuys | 36fbe63 | 2015-04-21 13:58:08 +0000 | [diff] [blame] | 30 | #include "src/main/cpp/blaze_util.h" |
Thiago Farina | 7f9357f | 2015-04-23 13:57:43 +0000 | [diff] [blame] | 31 | #include "src/main/cpp/blaze_util_platform.h" |
Han-Wen Nienhuys | 36fbe63 | 2015-04-21 13:58:08 +0000 | [diff] [blame] | 32 | #include "src/main/cpp/util/errors.h" |
Thiago Farina | 7f9357f | 2015-04-23 13:57:43 +0000 | [diff] [blame] | 33 | #include "src/main/cpp/util/exit_code.h" |
Han-Wen Nienhuys | 36fbe63 | 2015-04-21 13:58:08 +0000 | [diff] [blame] | 34 | #include "src/main/cpp/util/file.h" |
ccalvarin | 7383976 | 2018-03-23 15:35:00 -0700 | [diff] [blame] | 35 | #include "src/main/cpp/util/logging.h" |
ccalvarin | ac69da0 | 2018-06-05 15:27:26 -0700 | [diff] [blame] | 36 | #include "src/main/cpp/util/path.h" |
Thiago Farina | 3832033 | 2015-05-18 09:12:21 +0000 | [diff] [blame] | 37 | #include "src/main/cpp/util/port.h" |
Han-Wen Nienhuys | 36fbe63 | 2015-04-21 13:58:08 +0000 | [diff] [blame] | 38 | #include "src/main/cpp/util/strings.h" |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 39 | |
| 40 | namespace blaze { |
| 41 | |
ccalvarin | c5a5880 | 2018-03-29 11:13:24 -0700 | [diff] [blame] | 42 | using blaze_util::GetLastErrorString; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 43 | using std::string; |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 44 | using std::vector; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 45 | |
Kristina Chodorow | 9396335 | 2015-03-20 19:11:19 +0000 | [diff] [blame] | 46 | string GetOutputRoot() { |
Lukacs Berki | 30bed8f | 2015-10-26 12:18:24 +0000 | [diff] [blame] | 47 | string base; |
Thiago Farina | 2a2b352 | 2017-07-04 04:14:32 -0400 | [diff] [blame] | 48 | string home = GetHomeDir(); |
| 49 | if (!home.empty()) { |
Lukacs Berki | 30bed8f | 2015-10-26 12:18:24 +0000 | [diff] [blame] | 50 | base = home; |
Damien Martin-Guillerez | 27b9475 | 2015-03-23 13:00:28 +0000 | [diff] [blame] | 51 | } else { |
Thiago Farina | 2a2b352 | 2017-07-04 04:14:32 -0400 | [diff] [blame] | 52 | char buf[2048]; |
Lukacs Berki | 30bed8f | 2015-10-26 12:18:24 +0000 | [diff] [blame] | 53 | struct passwd pwbuf; |
| 54 | struct passwd *pw = NULL; |
| 55 | int uid = getuid(); |
| 56 | int r = getpwuid_r(uid, &pwbuf, buf, 2048, &pw); |
| 57 | if (r != -1 && pw != NULL) { |
| 58 | base = pw->pw_dir; |
| 59 | } |
Damien Martin-Guillerez | 27b9475 | 2015-03-23 13:00:28 +0000 | [diff] [blame] | 60 | } |
Lukacs Berki | 30bed8f | 2015-10-26 12:18:24 +0000 | [diff] [blame] | 61 | |
Thiago Farina | 2a2b352 | 2017-07-04 04:14:32 -0400 | [diff] [blame] | 62 | if (!base.empty()) { |
Lukacs Berki | 30bed8f | 2015-10-26 12:18:24 +0000 | [diff] [blame] | 63 | return blaze_util::JoinPath(base, ".cache/bazel"); |
| 64 | } |
| 65 | |
| 66 | return "/tmp"; |
Kristina Chodorow | 9396335 | 2015-03-20 19:11:19 +0000 | [diff] [blame] | 67 | } |
| 68 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 69 | void WarnFilesystemType(const string& output_base) { |
| 70 | struct statfs buf = {}; |
| 71 | if (statfs(output_base.c_str(), &buf) < 0) { |
ccalvarin | 7383976 | 2018-03-23 15:35:00 -0700 | [diff] [blame] | 72 | BAZEL_LOG(WARNING) << "couldn't get file system type information for '" |
| 73 | << output_base << "': " << strerror(errno); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 74 | return; |
| 75 | } |
| 76 | |
Lukacs Berki | 4de9894 | 2016-09-09 09:23:36 +0000 | [diff] [blame] | 77 | if (buf.f_type == NFS_SUPER_MAGIC) { |
ccalvarin | 7383976 | 2018-03-23 15:35:00 -0700 | [diff] [blame] | 78 | BAZEL_LOG(WARNING) << "Output base '" << output_base |
| 79 | << "' is on NFS. This may lead to surprising failures " |
| 80 | "and undetermined behavior."; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 81 | } |
| 82 | } |
| 83 | |
| 84 | string GetSelfPath() { |
nharmata | d79ec03 | 2019-03-06 14:54:15 -0800 | [diff] [blame] | 85 | // The file to which this symlink points could change contents or go missing |
| 86 | // concurrent with execution of the Bazel client, so we don't eagerly resolve |
| 87 | // it. |
| 88 | return "/proc/self/exe"; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 89 | } |
| 90 | |
Laszlo Csomor | 943d3cf | 2016-11-07 14:27:21 +0000 | [diff] [blame] | 91 | uint64_t GetMillisecondsMonotonic() { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 92 | struct timespec ts = {}; |
| 93 | clock_gettime(CLOCK_MONOTONIC, &ts); |
Laszlo Csomor | 943d3cf | 2016-11-07 14:27:21 +0000 | [diff] [blame] | 94 | return ts.tv_sec * 1000LL + (ts.tv_nsec / 1000000LL); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 95 | } |
| 96 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 97 | void SetScheduling(bool batch_cpu_scheduling, int io_nice_level) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 98 | if (batch_cpu_scheduling) { |
| 99 | sched_param param = {}; |
| 100 | param.sched_priority = 0; |
| 101 | if (sched_setscheduler(0, SCHED_BATCH, ¶m)) { |
ccalvarin | 8448f57 | 2018-04-06 12:42:09 -0700 | [diff] [blame] | 102 | BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR) |
| 103 | << "sched_setscheduler(SCHED_BATCH) failed: " << GetLastErrorString(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 104 | } |
| 105 | } |
| 106 | |
| 107 | if (io_nice_level >= 0) { |
| 108 | if (blaze_util::sys_ioprio_set( |
| 109 | IOPRIO_WHO_PROCESS, getpid(), |
| 110 | IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, io_nice_level)) < 0) { |
ccalvarin | 8448f57 | 2018-04-06 12:42:09 -0700 | [diff] [blame] | 111 | BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR) |
| 112 | << "ioprio_set() with class " << IOPRIO_CLASS_BE << " and level " |
| 113 | << io_nice_level << " failed: " << GetLastErrorString(); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 114 | } |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | string GetProcessCWD(int pid) { |
| 119 | char server_cwd[PATH_MAX] = {}; |
| 120 | if (readlink( |
Googler | 9588b81 | 2015-07-23 11:49:37 +0000 | [diff] [blame] | 121 | ("/proc/" + ToString(pid) + "/cwd").c_str(), |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 122 | server_cwd, sizeof(server_cwd)) < 0) { |
| 123 | return ""; |
| 124 | } |
| 125 | |
| 126 | return string(server_cwd); |
| 127 | } |
| 128 | |
Thiago Farina | 01f3600 | 2015-04-08 15:59:08 +0000 | [diff] [blame] | 129 | bool IsSharedLibrary(const string &filename) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 130 | return blaze_util::ends_with(filename, ".so"); |
| 131 | } |
| 132 | |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 133 | static string Which(const string &executable) { |
Laszlo Csomor | 0d10749 | 2019-03-13 09:04:27 -0700 | [diff] [blame] | 134 | string path(GetPathEnv("PATH")); |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 135 | if (path.empty()) { |
cushon | 849df36 | 2018-05-14 01:51:45 -0700 | [diff] [blame] | 136 | return ""; |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 137 | } |
| 138 | |
Thiago Farina | 2a2b352 | 2017-07-04 04:14:32 -0400 | [diff] [blame] | 139 | vector<string> pieces = blaze_util::Split(path, ':'); |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 140 | for (auto piece : pieces) { |
| 141 | if (piece.empty()) { |
| 142 | piece = "."; |
| 143 | } |
| 144 | |
| 145 | struct stat file_stat; |
| 146 | string candidate = blaze_util::JoinPath(piece, executable); |
| 147 | if (access(candidate.c_str(), X_OK) == 0 && |
| 148 | stat(candidate.c_str(), &file_stat) == 0 && |
| 149 | S_ISREG(file_stat.st_mode)) { |
| 150 | return candidate; |
| 151 | } |
| 152 | } |
| 153 | return ""; |
| 154 | } |
| 155 | |
cushon | 849df36 | 2018-05-14 01:51:45 -0700 | [diff] [blame] | 156 | string GetSystemJavabase() { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 157 | // if JAVA_HOME is defined, then use it as default. |
Laszlo Csomor | 0d10749 | 2019-03-13 09:04:27 -0700 | [diff] [blame] | 158 | string javahome = GetPathEnv("JAVA_HOME"); |
Thiago Farina | 2a2b352 | 2017-07-04 04:14:32 -0400 | [diff] [blame] | 159 | if (!javahome.empty()) { |
Philipp Wollermann | 8db450f | 2019-02-03 09:26:07 -0800 | [diff] [blame] | 160 | string javac = blaze_util::JoinPath(javahome, "bin/javac"); |
| 161 | if (access(javac.c_str(), X_OK) == 0) { |
| 162 | return javahome; |
| 163 | } |
| 164 | BAZEL_LOG(WARNING) |
| 165 | << "Ignoring JAVA_HOME, because it must point to a JDK, not a JRE."; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | // which javac |
Laszlo Csomor | 48513d7 | 2016-12-21 12:47:40 +0000 | [diff] [blame] | 169 | string javac_dir = Which("javac"); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 170 | if (javac_dir.empty()) { |
cushon | 849df36 | 2018-05-14 01:51:45 -0700 | [diff] [blame] | 171 | return ""; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | // Resolve all symlinks. |
| 175 | char resolved_path[PATH_MAX]; |
| 176 | if (realpath(javac_dir.c_str(), resolved_path) == NULL) { |
cushon | 849df36 | 2018-05-14 01:51:45 -0700 | [diff] [blame] | 177 | return ""; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 178 | } |
| 179 | javac_dir = resolved_path; |
| 180 | |
| 181 | // dirname dirname |
| 182 | return blaze_util::Dirname(blaze_util::Dirname(javac_dir)); |
| 183 | } |
| 184 | |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 185 | // Called from a signal handler! |
| 186 | static bool GetStartTime(const string& pid, string* start_time) { |
| 187 | string statfile = "/proc/" + pid + "/stat"; |
| 188 | string statline; |
| 189 | |
Laszlo Csomor | 49970e0 | 2016-11-28 08:55:47 +0000 | [diff] [blame] | 190 | if (!blaze_util::ReadFile(statfile, &statline)) { |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 191 | return false; |
| 192 | } |
| 193 | |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 194 | vector<string> stat_entries = blaze_util::Split(statline, ' '); |
| 195 | if (stat_entries.size() < 22) { |
ccalvarin | 8448f57 | 2018-04-06 12:42:09 -0700 | [diff] [blame] | 196 | BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) |
| 197 | << "Format of stat file at " << statfile |
| 198 | << " is unknown: " << GetLastErrorString(); |
Lukacs Berki | a34c4fe | 2016-09-05 11:14:43 +0000 | [diff] [blame] | 199 | } |
| 200 | |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 201 | // Start time since startup in jiffies. This combined with the PID should be |
| 202 | // unique. |
| 203 | *start_time = stat_entries[21]; |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 204 | return true; |
| 205 | } |
| 206 | |
jmmv | 3cb1aef | 2019-03-14 07:38:00 -0700 | [diff] [blame] | 207 | int ConfigureDaemonProcess(posix_spawnattr_t* attrp, |
| 208 | const StartupOptions* options) { |
| 209 | // No interesting platform-specific details to configure on this platform. |
| 210 | return 0; |
| 211 | } |
| 212 | |
lberki | f2014a1 | 2017-05-10 04:30:39 -0400 | [diff] [blame] | 213 | void WriteSystemSpecificProcessIdentifier( |
| 214 | const string& server_dir, pid_t server_pid) { |
| 215 | string pid_string = ToString(server_pid); |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 216 | |
| 217 | string start_time; |
lberki | f2014a1 | 2017-05-10 04:30:39 -0400 | [diff] [blame] | 218 | if (!GetStartTime(pid_string, &start_time)) { |
ccalvarin | 8448f57 | 2018-04-06 12:42:09 -0700 | [diff] [blame] | 219 | BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) |
| 220 | << "Cannot get start time of process " << pid_string << ": " |
| 221 | << GetLastErrorString(); |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 222 | } |
| 223 | |
| 224 | string start_time_file = blaze_util::JoinPath(server_dir, "server.starttime"); |
Laszlo Csomor | 49970e0 | 2016-11-28 08:55:47 +0000 | [diff] [blame] | 225 | if (!blaze_util::WriteFile(start_time, start_time_file)) { |
ccalvarin | 8448f57 | 2018-04-06 12:42:09 -0700 | [diff] [blame] | 226 | BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) |
| 227 | << "Cannot write start time in server dir " << server_dir << ": " |
| 228 | << GetLastErrorString(); |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 229 | } |
| 230 | } |
| 231 | |
| 232 | // On Linux we use a combination of PID and start time to identify the server |
| 233 | // process. That is supposed to be unique unless one can start more processes |
| 234 | // than there are PIDs available within a single jiffy. |
mschaller | fd37b51 | 2017-07-11 18:21:36 +0200 | [diff] [blame] | 235 | bool VerifyServerProcess(int pid, const string& output_base) { |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 236 | string start_time; |
| 237 | if (!GetStartTime(ToString(pid), &start_time)) { |
Lukacs Berki | 0bb79c6 | 2016-09-08 11:45:51 +0000 | [diff] [blame] | 238 | // Cannot read PID file from /proc . Process died meantime, all is good. No |
| 239 | // stale server is present. |
Lukacs Berki | 119dd4b | 2016-07-13 15:28:42 +0000 | [diff] [blame] | 240 | return false; |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 241 | } |
| 242 | |
| 243 | string recorded_start_time; |
Laszlo Csomor | 49970e0 | 2016-11-28 08:55:47 +0000 | [diff] [blame] | 244 | bool file_present = blaze_util::ReadFile( |
Lukacs Berki | b29db48 | 2016-05-04 09:39:48 +0000 | [diff] [blame] | 245 | blaze_util::JoinPath(output_base, "server/server.starttime"), |
| 246 | &recorded_start_time); |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 247 | |
lberki | f2014a1 | 2017-05-10 04:30:39 -0400 | [diff] [blame] | 248 | // If start time file got deleted, but PID file didn't, assume that this is an |
Lukacs Berki | ee44c38 | 2016-09-14 10:53:37 +0000 | [diff] [blame] | 249 | // old Blaze process that doesn't know how to write start time files yet. |
| 250 | return !file_present || recorded_start_time == start_time; |
| 251 | } |
Lukacs Berki | 43e620b | 2016-05-02 11:47:40 +0000 | [diff] [blame] | 252 | |
Dave MacLachlan | 6b747ee | 2016-07-20 10:00:44 +0000 | [diff] [blame] | 253 | // Not supported. |
| 254 | void ExcludePathFromBackup(const string &path) { |
| 255 | } |
| 256 | |
jmmv | a96369c | 2017-07-10 18:14:36 +0200 | [diff] [blame] | 257 | int32_t GetExplicitSystemLimit(const int resource) { |
| 258 | return -1; |
| 259 | } |
| 260 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 261 | } // namespace blaze |