1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define TRACE_TAG ADB 18 19 #include "adb_utils.h" 20 #include "adb_unique_fd.h" 21 22 #include <stdlib.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include <algorithm> 28 #include <vector> 29 30 #include <android-base/file.h> 31 #include <android-base/logging.h> 32 #include <android-base/parseint.h> 33 #include <android-base/stringprintf.h> 34 #include <android-base/strings.h> 35 36 #include "adb.h" 37 #include "adb_trace.h" 38 #include "sysdeps.h" 39 40 #ifdef _WIN32 41 # ifndef WIN32_LEAN_AND_MEAN 42 # define WIN32_LEAN_AND_MEAN 43 # endif 44 # include "windows.h" 45 # include "shlobj.h" 46 #else 47 #include <pwd.h> 48 #endif 49 50 51 #if defined(_WIN32) 52 static constexpr char kNullFileName[] = "NUL"; 53 #else 54 static constexpr char kNullFileName[] = "/dev/null"; 55 #endif 56 57 void close_stdin() { 58 int fd = unix_open(kNullFileName, O_RDONLY); 59 if (fd == -1) { 60 PLOG(FATAL) << "failed to open " << kNullFileName; 61 } 62 63 if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) { 64 PLOG(FATAL) << "failed to redirect stdin to " << kNullFileName; 65 } 66 unix_close(fd); 67 } 68 69 bool getcwd(std::string* s) { 70 char* cwd = getcwd(nullptr, 0); 71 if (cwd != nullptr) *s = cwd; 72 free(cwd); 73 return (cwd != nullptr); 74 } 75 76 bool directory_exists(const std::string& path) { 77 struct stat sb; 78 return stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode); 79 } 80 81 std::string escape_arg(const std::string& s) { 82 // Escape any ' in the string (before we single-quote the whole thing). 83 // The correct way to do this for the shell is to replace ' with '\'' --- that is, 84 // close the existing single-quoted string, escape a single single-quote, and start 85 // a new single-quoted string. Like the C preprocessor, the shell will concatenate 86 // these pieces into one string. 87 88 std::string result; 89 result.push_back('\''); 90 91 size_t base = 0; 92 while (true) { 93 size_t found = s.find('\'', base); 94 result.append(s, base, found - base); 95 if (found == s.npos) break; 96 result.append("'\\''"); 97 base = found + 1; 98 } 99 100 result.push_back('\''); 101 return result; 102 } 103 104 // Given a relative or absolute filepath, create the directory hierarchy 105 // as needed. Returns true if the hierarchy is/was setup. 106 bool mkdirs(const std::string& path) { 107 // TODO: all the callers do unlink && mkdirs && adb_creat --- 108 // that's probably the operation we should expose. 109 110 // Implementation Notes: 111 // 112 // Pros: 113 // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR. 114 // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters 115 // (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when 116 // combined with our adb_mkdir() which takes UTF-8). 117 // - Is optimistic wrt thinking that a deep directory hierarchy will exist. 118 // So it does as few stat()s as possible before doing mkdir()s. 119 // Cons: 120 // - Recursive, so it uses stack space relative to number of directory 121 // components. 122 123 // If path points to a symlink to a directory, that's fine. 124 struct stat sb; 125 if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { 126 return true; 127 } 128 129 const std::string parent(android::base::Dirname(path)); 130 131 // If dirname returned the same path as what we passed in, don't go recursive. 132 // This can happen on Windows when walking up the directory hierarchy and not 133 // finding anything that already exists (unlike POSIX that will eventually 134 // find . or /). 135 if (parent == path) { 136 errno = ENOENT; 137 return false; 138 } 139 140 // Recursively make parent directories of 'path'. 141 if (!mkdirs(parent)) { 142 return false; 143 } 144 145 // Now that the parent directory hierarchy of 'path' has been ensured, 146 // create path itself. 147 if (adb_mkdir(path, 0775) == -1) { 148 const int saved_errno = errno; 149 // If someone else created the directory, that is ok. 150 if (directory_exists(path)) { 151 return true; 152 } 153 // There might be a pre-existing file at 'path', or there might have been some other error. 154 errno = saved_errno; 155 return false; 156 } 157 158 return true; 159 } 160 161 std::string dump_hex(const void* data, size_t byte_count) { 162 size_t truncate_len = 16; 163 bool truncated = false; 164 if (byte_count > truncate_len) { 165 byte_count = truncate_len; 166 truncated = true; 167 } 168 169 const uint8_t* p = reinterpret_cast<const uint8_t*>(data); 170 171 std::string line; 172 for (size_t i = 0; i < byte_count; ++i) { 173 android::base::StringAppendF(&line, "%02x", p[i]); 174 } 175 line.push_back(' '); 176 177 for (size_t i = 0; i < byte_count; ++i) { 178 int ch = p[i]; 179 line.push_back(isprint(ch) ? ch : '.'); 180 } 181 182 if (truncated) { 183 line += " [truncated]"; 184 } 185 186 return line; 187 } 188 189 std::string dump_header(const amessage* msg) { 190 unsigned command = msg->command; 191 int len = msg->data_length; 192 char cmd[9]; 193 char arg0[12], arg1[12]; 194 int n; 195 196 for (n = 0; n < 4; n++) { 197 int b = (command >> (n * 8)) & 255; 198 if (b < 32 || b >= 127) break; 199 cmd[n] = (char)b; 200 } 201 if (n == 4) { 202 cmd[4] = 0; 203 } else { 204 // There is some non-ASCII name in the command, so dump the hexadecimal value instead 205 snprintf(cmd, sizeof cmd, "%08x", command); 206 } 207 208 if (msg->arg0 < 256U) 209 snprintf(arg0, sizeof arg0, "%d", msg->arg0); 210 else 211 snprintf(arg0, sizeof arg0, "0x%x", msg->arg0); 212 213 if (msg->arg1 < 256U) 214 snprintf(arg1, sizeof arg1, "%d", msg->arg1); 215 else 216 snprintf(arg1, sizeof arg1, "0x%x", msg->arg1); 217 218 return android::base::StringPrintf("[%s] arg0=%s arg1=%s (len=%d) ", cmd, arg0, arg1, len); 219 } 220 221 std::string dump_packet(const char* name, const char* func, const apacket* p) { 222 std::string result = name; 223 result += ": "; 224 result += func; 225 result += ": "; 226 result += dump_header(&p->msg); 227 result += dump_hex(p->payload.data(), p->payload.size()); 228 return result; 229 } 230 231 std::string perror_str(const char* msg) { 232 return android::base::StringPrintf("%s: %s", msg, strerror(errno)); 233 } 234 235 #if !defined(_WIN32) 236 // Windows version provided in sysdeps_win32.cpp 237 bool set_file_block_mode(borrowed_fd fd, bool block) { 238 int flags = fcntl(fd.get(), F_GETFL, 0); 239 if (flags == -1) { 240 PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd.get(); 241 return false; 242 } 243 flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 244 if (fcntl(fd.get(), F_SETFL, flags) != 0) { 245 PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd.get() << ", flags " << flags; 246 return false; 247 } 248 return true; 249 } 250 #endif 251 252 bool forward_targets_are_valid(const std::string& source, const std::string& dest, 253 std::string* error) { 254 if (android::base::StartsWith(source, "tcp:")) { 255 // The source port may be 0 to allow the system to select an open port. 256 int port; 257 if (!android::base::ParseInt(&source[4], &port) || port < 0) { 258 *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]); 259 return false; 260 } 261 } 262 263 if (android::base::StartsWith(dest, "tcp:")) { 264 // The destination port must be > 0. 265 int port; 266 if (!android::base::ParseInt(&dest[4], &port) || port <= 0) { 267 *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]); 268 return false; 269 } 270 } 271 272 return true; 273 } 274 275 std::string adb_get_homedir_path() { 276 #ifdef _WIN32 277 WCHAR path[MAX_PATH]; 278 const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path); 279 if (FAILED(hr)) { 280 D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str()); 281 return {}; 282 } 283 std::string home_str; 284 if (!android::base::WideToUTF8(path, &home_str)) { 285 return {}; 286 } 287 return home_str; 288 #else 289 if (const char* const home = getenv("HOME")) { 290 return home; 291 } 292 293 struct passwd pwent; 294 struct passwd* result; 295 int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX); 296 if (pwent_max == -1) { 297 pwent_max = 16384; 298 } 299 std::vector<char> buf(pwent_max); 300 int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result); 301 if (rc == 0 && result) { 302 return result->pw_dir; 303 } 304 305 LOG(FATAL) << "failed to get user home directory"; 306 return {}; 307 #endif 308 } 309 310 std::string adb_get_android_dir_path() { 311 std::string user_dir = adb_get_homedir_path(); 312 std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android"; 313 struct stat buf; 314 if (stat(android_dir.c_str(), &buf) == -1) { 315 if (adb_mkdir(android_dir, 0750) == -1) { 316 PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'"; 317 } 318 } 319 return android_dir; 320 } 321 322 std::string GetLogFilePath() { 323 // https://issuetracker.google.com/112588493 324 const char* path = getenv("ANDROID_ADB_LOG_PATH"); 325 if (path) return path; 326 327 #if defined(_WIN32) 328 const char log_name[] = "adb.log"; 329 WCHAR temp_path[MAX_PATH]; 330 331 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx 332 DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path); 333 if (nchars >= arraysize(temp_path) || nchars == 0) { 334 // If string truncation or some other error. 335 LOG(FATAL) << "cannot retrieve temporary file path: " 336 << android::base::SystemErrorCodeToString(GetLastError()); 337 } 338 339 std::string temp_path_utf8; 340 if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) { 341 PLOG(FATAL) << "cannot convert temporary file path from UTF-16 to UTF-8"; 342 } 343 344 return temp_path_utf8 + log_name; 345 #else 346 const char* tmp_dir = getenv("TMPDIR"); 347 if (tmp_dir == nullptr) tmp_dir = "/tmp"; 348 return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid()); 349 #endif 350 } 351 352 [[noreturn]] static void error_exit_va(int error, const char* fmt, va_list va) { 353 fflush(stdout); 354 fprintf(stderr, "%s: ", android::base::Basename(android::base::GetExecutablePath()).c_str()); 355 356 vfprintf(stderr, fmt, va); 357 358 if (error != 0) { 359 fprintf(stderr, ": %s", strerror(error)); 360 } 361 362 putc('\n', stderr); 363 fflush(stderr); 364 365 exit(EXIT_FAILURE); 366 } 367 368 void error_exit(const char* fmt, ...) { 369 va_list va; 370 va_start(va, fmt); 371 error_exit_va(0, fmt, va); 372 va_end(va); 373 } 374 375 void perror_exit(const char* fmt, ...) { 376 va_list va; 377 va_start(va, fmt); 378 error_exit_va(errno, fmt, va); 379 va_end(va); 380 } 381