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 constexpr char kNullFileName[] = "NUL"; 53 #else 54 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 fatal_errno("failed to open %s", kNullFileName); 61 } 62 63 if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) { 64 fatal_errno("failed to redirect stdin to %s", 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 std::string result = s; 83 84 // Escape any ' in the string (before we single-quote the whole thing). 85 // The correct way to do this for the shell is to replace ' with '\'' --- that is, 86 // close the existing single-quoted string, escape a single single-quote, and start 87 // a new single-quoted string. Like the C preprocessor, the shell will concatenate 88 // these pieces into one string. 89 for (size_t i = 0; i < s.size(); ++i) { 90 if (s[i] == '\'') { 91 result.insert(i, "'\\'"); 92 i += 2; 93 } 94 } 95 96 // Prefix and suffix the whole string with '. 97 result.insert(result.begin(), '\''); 98 result.push_back('\''); 99 return result; 100 } 101 102 // Given a relative or absolute filepath, create the directory hierarchy 103 // as needed. Returns true if the hierarchy is/was setup. 104 bool mkdirs(const std::string& path) { 105 // TODO: all the callers do unlink && mkdirs && adb_creat --- 106 // that's probably the operation we should expose. 107 108 // Implementation Notes: 109 // 110 // Pros: 111 // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR. 112 // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters 113 // (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when 114 // combined with our adb_mkdir() which takes UTF-8). 115 // - Is optimistic wrt thinking that a deep directory hierarchy will exist. 116 // So it does as few stat()s as possible before doing mkdir()s. 117 // Cons: 118 // - Recursive, so it uses stack space relative to number of directory 119 // components. 120 121 // If path points to a symlink to a directory, that's fine. 122 struct stat sb; 123 if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { 124 return true; 125 } 126 127 const std::string parent(android::base::Dirname(path)); 128 129 // If dirname returned the same path as what we passed in, don't go recursive. 130 // This can happen on Windows when walking up the directory hierarchy and not 131 // finding anything that already exists (unlike POSIX that will eventually 132 // find . or /). 133 if (parent == path) { 134 errno = ENOENT; 135 return false; 136 } 137 138 // Recursively make parent directories of 'path'. 139 if (!mkdirs(parent)) { 140 return false; 141 } 142 143 // Now that the parent directory hierarchy of 'path' has been ensured, 144 // create path itself. 145 if (adb_mkdir(path, 0775) == -1) { 146 const int saved_errno = errno; 147 // If someone else created the directory, that is ok. 148 if (directory_exists(path)) { 149 return true; 150 } 151 // There might be a pre-existing file at 'path', or there might have been some other error. 152 errno = saved_errno; 153 return false; 154 } 155 156 return true; 157 } 158 159 std::string dump_hex(const void* data, size_t byte_count) { 160 size_t truncate_len = 16; 161 bool truncated = false; 162 if (byte_count > truncate_len) { 163 byte_count = truncate_len; 164 truncated = true; 165 } 166 167 const uint8_t* p = reinterpret_cast<const uint8_t*>(data); 168 169 std::string line; 170 for (size_t i = 0; i < byte_count; ++i) { 171 android::base::StringAppendF(&line, "%02x", p[i]); 172 } 173 line.push_back(' '); 174 175 for (size_t i = 0; i < byte_count; ++i) { 176 int ch = p[i]; 177 line.push_back(isprint(ch) ? ch : '.'); 178 } 179 180 if (truncated) { 181 line += " [truncated]"; 182 } 183 184 return line; 185 } 186 187 std::string perror_str(const char* msg) { 188 return android::base::StringPrintf("%s: %s", msg, strerror(errno)); 189 } 190 191 #if !defined(_WIN32) 192 // Windows version provided in sysdeps_win32.cpp 193 bool set_file_block_mode(int fd, bool block) { 194 int flags = fcntl(fd, F_GETFL, 0); 195 if (flags == -1) { 196 PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd; 197 return false; 198 } 199 flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 200 if (fcntl(fd, F_SETFL, flags) != 0) { 201 PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd << ", flags " << flags; 202 return false; 203 } 204 return true; 205 } 206 #endif 207 208 bool forward_targets_are_valid(const std::string& source, const std::string& dest, 209 std::string* error) { 210 if (android::base::StartsWith(source, "tcp:")) { 211 // The source port may be 0 to allow the system to select an open port. 212 int port; 213 if (!android::base::ParseInt(&source[4], &port) || port < 0) { 214 *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]); 215 return false; 216 } 217 } 218 219 if (android::base::StartsWith(dest, "tcp:")) { 220 // The destination port must be > 0. 221 int port; 222 if (!android::base::ParseInt(&dest[4], &port) || port <= 0) { 223 *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]); 224 return false; 225 } 226 } 227 228 return true; 229 } 230 231 std::string adb_get_homedir_path() { 232 #ifdef _WIN32 233 WCHAR path[MAX_PATH]; 234 const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path); 235 if (FAILED(hr)) { 236 D("SHGetFolderPathW failed: %s", android::base::SystemErrorCodeToString(hr).c_str()); 237 return {}; 238 } 239 std::string home_str; 240 if (!android::base::WideToUTF8(path, &home_str)) { 241 return {}; 242 } 243 return home_str; 244 #else 245 if (const char* const home = getenv("HOME")) { 246 return home; 247 } 248 249 struct passwd pwent; 250 struct passwd* result; 251 int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX); 252 std::vector<char> buf(pwent_max); 253 int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result); 254 if (rc == 0 && result) { 255 return result->pw_dir; 256 } 257 258 LOG(FATAL) << "failed to get user home directory"; 259 return {}; 260 #endif 261 } 262 263 std::string adb_get_android_dir_path() { 264 std::string user_dir = adb_get_homedir_path(); 265 std::string android_dir = user_dir + OS_PATH_SEPARATOR + ".android"; 266 struct stat buf; 267 if (stat(android_dir.c_str(), &buf) == -1) { 268 if (adb_mkdir(android_dir.c_str(), 0750) == -1) { 269 PLOG(FATAL) << "Cannot mkdir '" << android_dir << "'"; 270 } 271 } 272 return android_dir; 273 } 274 275 void AdbCloser::Close(int fd) { 276 adb_close(fd); 277 } 278 279 int syntax_error(const char* fmt, ...) { 280 fprintf(stderr, "adb: usage: "); 281 282 va_list ap; 283 va_start(ap, fmt); 284 vfprintf(stderr, fmt, ap); 285 va_end(ap); 286 287 fprintf(stderr, "\n"); 288 return 1; 289 } 290 291 std::string GetLogFilePath() { 292 #if defined(_WIN32) 293 const char log_name[] = "adb.log"; 294 WCHAR temp_path[MAX_PATH]; 295 296 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx 297 DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path); 298 if (nchars >= arraysize(temp_path) || nchars == 0) { 299 // If string truncation or some other error. 300 fatal("cannot retrieve temporary file path: %s\n", 301 android::base::SystemErrorCodeToString(GetLastError()).c_str()); 302 } 303 304 std::string temp_path_utf8; 305 if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) { 306 fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8"); 307 } 308 309 return temp_path_utf8 + log_name; 310 #else 311 const char* tmp_dir = getenv("TMPDIR"); 312 if (tmp_dir == nullptr) tmp_dir = "/tmp"; 313 return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid()); 314 #endif 315 } 316