15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/linux_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dirent.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
2258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/launch.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Not needed for OS_CHROMEOS.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum LinuxDistroState {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATE_DID_NOT_CHECK  = 0,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATE_CHECK_STARTED  = 1,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATE_CHECK_FINISHED = 2,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class for GetLinuxDistro().
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LinuxDistroHelper {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieves the Singleton.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static LinuxDistroHelper* GetInstance() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<LinuxDistroHelper>::get();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The simple state machine goes from:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~LinuxDistroHelper() {}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve the current state, if we're in STATE_DID_NOT_CHECK,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we automatically move to STATE_CHECK_STARTED so nobody else will
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // do the check.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinuxDistroState State() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock scoped_lock(lock_);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (STATE_DID_NOT_CHECK == state_) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_ = STATE_CHECK_STARTED;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return STATE_DID_NOT_CHECK;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return state_;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicate the check finished, move to STATE_CHECK_FINISHED.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckFinished() {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock scoped_lock(lock_);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(STATE_CHECK_STARTED, state_);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = STATE_CHECK_FINISHED;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock_;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinuxDistroState state_;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // if defined(OS_LINUX)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Account for the terminating null character.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kDistroSize = 128 + 1;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We use this static string to hold the Linux distro info. If we
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// crash, the crash handler code will send this in the crash dump.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)char g_linux_distro[kDistroSize] =
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CrOS";
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_ANDROID)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Android";
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else  // if defined(OS_LINUX)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Unknown";
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetLinuxDistro() {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_linux_distro;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinuxDistroState state = distro_state_singleton->State();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (STATE_CHECK_FINISHED == state)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return g_linux_distro;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (STATE_CHECK_STARTED == state)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "Unknown"; // Don't wait for other thread to finish.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state, STATE_DID_NOT_CHECK);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We do this check only once per process. If it fails, there's
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // little reason to believe it will work if we attempt to run
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lsb_release again.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> argv;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back("lsb_release");
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back("-d");
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::GetAppOutput(CommandLine(argv), &output);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (output.length() > 0) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // lsb_release -d should return: Description:<tab>Distro Info
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char field[] = "Description:\t";
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (output.compare(0, strlen(field), field) == 0) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetLinuxDistro(output.substr(strlen(field)));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  distro_state_singleton->CheckFinished();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_linux_distro;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "Unknown";
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetLinuxDistro(const std::string& distro) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string trimmed_distro;
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TrimWhitespaceASCII(distro, base::TRIM_ALL, &trimmed_distro);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool* syscall_supported) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buf[256];
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (syscall_supported != NULL)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *syscall_supported = false;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DIR* task = opendir(buf);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!task) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Cannot open " << buf;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<pid_t> tids;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct dirent* dent;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((dent = readdir(task))) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char* endptr;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tid_ul == ULONG_MAX || *endptr)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tids.push_back(tid_ul);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closedir(task);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<char[]> syscall_data(new char[expected_data.length()]);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<pid_t>::const_iterator
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i = tids.begin(); i != tids.end(); ++i) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const pid_t current_tid = *i;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fd = open(buf, O_RDONLY);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fd < 0)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (syscall_supported != NULL)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *syscall_supported = true;
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    bool read_ret = ReadFromFD(fd, syscall_data.get(), expected_data.length());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(fd);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!read_ret)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (0 == strncmp(expected_data.c_str(), syscall_data.get(),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     expected_data.length())) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return current_tid;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
181