1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/process/process_iterator.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/process/internal_linux.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace base { 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace { 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Reads the |field_num|th field from |proc_stats|. 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Returns an empty string on failure. 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This version only handles VM_COMM and VM_STATE, which are the only fields 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// that are strings. 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::string GetProcStatsFieldAsString( 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const std::vector<std::string>& proc_stats, 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) internal::ProcStatsFields field_num) { 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) { 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return std::string(); 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (proc_stats.size() > static_cast<size_t>(field_num)) 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return proc_stats[field_num]; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 0; 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// line arguments. Returns true if successful. 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Note: /proc/<pid>/cmdline contains command line arguments separated by single 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// null characters. We tokenize it into a vector of strings using '\0' as a 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// delimiter. 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) { 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Synchronously reading files in /proc is safe. 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThreadRestrictions::ScopedAllowIO allow_io; 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline"); 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string cmd_line; 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!ReadFileToString(cmd_line_file, &cmd_line)) 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string delimiters; 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) delimiters.push_back('\0'); 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Tokenize(cmd_line, delimiters, proc_cmd_line_args); 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessIterator::ProcessIterator(const ProcessFilter* filter) 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : filter_(filter) { 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) procfs_dir_ = opendir(internal::kProcDir); 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessIterator::~ProcessIterator() { 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (procfs_dir_) { 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) closedir(procfs_dir_); 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) procfs_dir_ = NULL; 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ProcessIterator::CheckForNextProcess() { 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // TODO(port): skip processes owned by different UID 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pid_t pid = kNullProcessId; 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<std::string> cmd_line_args; 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string stats_data; 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<std::string> proc_stats; 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Arbitrarily guess that there will never be more than 200 non-process 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // files in /proc. Hardy has 53 and Lucid has 61. 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int skipped = 0; 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int kSkipLimit = 200; 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (skipped < kSkipLimit) { 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) dirent* slot = readdir(procfs_dir_); 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // all done looking through /proc? 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!slot) 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If not a process, keep looking for one. 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pid = internal::ProcDirSlotToPid(slot->d_name); 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!pid) { 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) skipped++; 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!GetProcCmdline(pid, &cmd_line_args)) 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!internal::ReadProcStats(pid, &stats_data)) 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!internal::ParseProcStats(stats_data, &proc_stats)) 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string runstate = 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) GetProcStatsFieldAsString(proc_stats, internal::VM_STATE); 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (runstate.size() != 1) { 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped? 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Allowed values: D R S T Z 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (runstate[0] != 'Z') 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Nope, it's a zombie; somebody isn't cleaning up after their children. 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.) 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // There could be a lot of zombies, can't really decrement i here. 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (skipped >= kSkipLimit) { 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) entry_.pid_ = pid; 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) entry_.ppid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PPID); 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) entry_.gid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PGRP); 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end()); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value(); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool NamedProcessIterator::IncludeEntry() { 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (executable_name_ != entry().exe_file()) 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ProcessIterator::IncludeEntry(); 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace base 138