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