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  
close_stdin()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  
getcwd(std::string * s)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  
directory_exists(const std::string & path)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  
escape_arg(const std::string & s)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.
mkdirs(const std::string & path)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  
dump_hex(const void * data,size_t byte_count)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  
dump_header(const amessage * msg)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  
dump_packet(const char * name,const char * func,const apacket * p)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  
perror_str(const char * msg)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
set_file_block_mode(borrowed_fd fd,bool block)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  
forward_targets_are_valid(const std::string & source,const std::string & dest,std::string * error)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  
adb_get_homedir_path()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  
adb_get_android_dir_path()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  
GetLogFilePath()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