1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/linux_util.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <dirent.h> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <errno.h> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <fcntl.h> 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <glib.h> 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdlib.h> 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/stat.h> 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <sys/types.h> 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <unistd.h> 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <vector> 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/command_line.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h" 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/path_service.h" 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/process_util.h" 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h" 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Not needed for OS_CHROMEOS. 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_LINUX) 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottenum LinuxDistroState { 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott STATE_DID_NOT_CHECK = 0, 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott STATE_CHECK_STARTED = 1, 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott STATE_CHECK_FINISHED = 2, 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Helper class for GetLinuxDistro(). 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass LinuxDistroHelper { 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Retrieves the Singleton. 4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen static LinuxDistroHelper* GetInstance() { 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return Singleton<LinuxDistroHelper>::get(); 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The simple state machine goes from: 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED. 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {} 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~LinuxDistroHelper() {} 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Retrieve the current state, if we're in STATE_DID_NOT_CHECK, 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // we automatically move to STATE_CHECK_STARTED so nobody else will 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // do the check. 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LinuxDistroState State() { 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock scoped_lock(lock_); 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (STATE_DID_NOT_CHECK == state_) { 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott state_ = STATE_CHECK_STARTED; 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return STATE_DID_NOT_CHECK; 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return state_; 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Indicate the check finished, move to STATE_CHECK_FINISHED. 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void CheckFinished() { 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::AutoLock scoped_lock(lock_); 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_EQ(STATE_CHECK_STARTED, state_); 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott state_ = STATE_CHECK_FINISHED; 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Lock lock_; 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LinuxDistroState state_; 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif // if defined(OS_LINUX) 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// expected prefix of the target of the /proc/self/fd/%d link for a socket 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char kSocketLinkPrefix[] = "socket:["; 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Parse a symlink in /proc/pid/fd/$x and return the inode number of the 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// socket. 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// inode_out: (output) set to the inode number on success 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor) 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// log: if true, log messages about failure details 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool ProcPathGetInode(ino_t* inode_out, const char* path, bool log = false) { 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(inode_out); 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(path); 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char buf[256]; 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const ssize_t n = readlink(path, buf, sizeof(buf) - 1); 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (n == -1) { 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (log) { 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LOG(WARNING) << "Failed to read the inode number for a socket from /proc" 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "(" << errno << ")"; 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott buf[n] = 0; 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) { 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (log) { 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LOG(WARNING) << "The descriptor passed from the crashing process wasn't a" 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott " UNIX domain socket."; 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char *endptr; 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const unsigned long long int inode_ul = 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10); 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (*endptr != ']') 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (inode_ul == ULLONG_MAX) { 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (log) { 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LOG(WARNING) << "Failed to parse a socket's inode number: the number was " 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "too large. Please report this bug: " << buf; 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *inode_out = inode_ul; 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base { 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Account for the terminating null character. 1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const int kDistroSize = 128 + 1; 1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We use this static string to hold the Linux distro info. If we 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// crash, the crash handler code will send this in the crash dump. 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickchar g_linux_distro[kDistroSize] = 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_CHROMEOS) 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "CrOS"; 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#else // if defined(OS_LINUX) 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "Unknown"; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string GetLinuxDistro() { 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_CHROMEOS) 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return g_linux_distro; 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#elif defined(OS_LINUX) 14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance(); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LinuxDistroState state = distro_state_singleton->State(); 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (STATE_DID_NOT_CHECK == state) { 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We do this check only once per process. If it fails, there's 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // little reason to believe it will work if we attempt to run 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // lsb_release again. 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<std::string> argv; 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott argv.push_back("lsb_release"); 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott argv.push_back("-d"); 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string output; 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott base::GetAppOutput(CommandLine(argv), &output); 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (output.length() > 0) { 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // lsb_release -d should return: Description:<tab>Distro Info 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott static const std::string field = "Description:\t"; 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (output.compare(0, field.length(), field) == 0) { 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SetLinuxDistro(output.substr(field.length())); 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott distro_state_singleton->CheckFinished(); 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return g_linux_distro; 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (STATE_CHECK_STARTED == state) { 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If the distro check above is in progress in some other thread, we're 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // not going to wait for the results. 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return "Unknown"; 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // In STATE_CHECK_FINISHED, no more writing to |linux_distro|. 1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return g_linux_distro; 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTIMPLEMENTED(); 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SetLinuxDistro(const std::string& distro) { 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string trimmed_distro; 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro); 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize); 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool FileDescriptorGetInode(ino_t* inode_out, int fd) { 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(inode_out); 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott struct stat buf; 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (fstat(fd, &buf) < 0) 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!S_ISSOCK(buf.st_mode)) 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *inode_out = buf.st_ino; 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) { 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(pid_out); 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool already_found = false; 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DIR* proc = opendir("/proc"); 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!proc) { 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott LOG(WARNING) << "Cannot open /proc"; 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<pid_t> pids; 208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott struct dirent* dent; 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while ((dent = readdir(proc))) { 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char *endptr; 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10); 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (pid_ul == ULONG_MAX || *endptr) 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pids.push_back(pid_ul); 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott closedir(proc); 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (std::vector<pid_t>::const_iterator 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott i = pids.begin(); i != pids.end(); ++i) { 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const pid_t current_pid = *i; 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char buf[256]; 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid); 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DIR* fd = opendir(buf); 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!fd) 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while ((dent = readdir(fd))) { 229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid, 230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott dent->d_name) >= static_cast<int>(sizeof(buf))) { 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ino_t fd_inode; 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ProcPathGetInode(&fd_inode, buf)) { 236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (fd_inode == socket_inode) { 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (already_found) { 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott closedir(fd); 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott already_found = true; 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *pid_out = current_pid; 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott closedir(fd); 250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return already_found; 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochpid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data) { 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch char buf[256]; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch snprintf(buf, sizeof(buf), "/proc/%d/task", pid); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DIR* task = opendir(buf); 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!task) { 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Cannot open " << buf; 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -1; 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<pid_t> tids; 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch struct dirent* dent; 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while ((dent = readdir(task))) { 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch char *endptr; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tid_ul == ULONG_MAX || *endptr) 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tids.push_back(tid_ul); 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closedir(task); 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_array<char> syscall_data(new char[expected_data.length()]); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<pid_t>::const_iterator 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch i = tids.begin(); i != tids.end(); ++i) { 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const pid_t current_tid = *i; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int fd = open(buf, O_RDONLY); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (fd < 0) 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool read_ret = 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::ReadFromFD(fd, syscall_data.get(), expected_data.length()); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close(fd); 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!read_ret) 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (0 == strncmp(expected_data.c_str(), syscall_data.get(), 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch expected_data.length())) { 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return current_tid; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -1; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace base 298