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)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <sys/sysctl.h>
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace base {
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessIterator::ProcessIterator(const ProcessFilter* filter)
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : index_of_kinfo_proc_(),
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      filter_(filter) {
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool done = false;
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int try_num = 1;
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int max_tries = 10;
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  do {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t len = 0;
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      LOG(ERROR) << "failed to get the size needed for the process list";
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kinfo_procs_.resize(0);
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      done = true;
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Leave some spare room for process table growth (more could show up
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // between when we check and now)
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      num_of_kinfo_proc += 16;
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kinfo_procs_.resize(num_of_kinfo_proc);
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // If we get a mem error, it just means we need a bigger buffer, so
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // loop around again.  Anything else is a real error and give up.
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (errno != ENOMEM) {
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          LOG(ERROR) << "failed to get the process list";
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kinfo_procs_.resize(0);
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          done = true;
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      } else {
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Got the list, just make sure we're sized exactly right
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kinfo_procs_.resize(num_of_kinfo_proc);
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        done = true;
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } while (!done && (try_num++ < max_tries));
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!done) {
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(ERROR) << "failed to collect the process list in a few tries";
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kinfo_procs_.resize(0);
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ProcessIterator::~ProcessIterator() {
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ProcessIterator::CheckForNextProcess() {
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string data;
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t length;
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    length = 0;
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      LOG(ERROR) << "failed to figure out the buffer size for a command line";
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    data.resize(length);
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      LOG(ERROR) << "failed to fetch a commandline";
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::string delimiters;
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    delimiters.push_back('\0');
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Tokenize(data, delimiters, &entry_.cmd_line_args_);
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t exec_name_end = data.find('\0');
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (exec_name_end == std::string::npos) {
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      LOG(ERROR) << "command line data didn't match expected format";
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry_.pid_ = kinfo.ki_pid;
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry_.ppid_ = kinfo.ki_ppid;
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry_.gid_ = kinfo.ki_pgid;
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t last_slash = data.rfind('/', exec_name_end);
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (last_slash == std::string::npos) {
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry_.exe_file_.assign(data, 0, exec_name_end);
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry_.exe_file_.assign(data, last_slash + 1,
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              exec_name_end - last_slash - 1);
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Start w/ the next entry next time through
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ++index_of_kinfo_proc_;
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return true;
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return false;
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool NamedProcessIterator::IncludeEntry() {
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (executable_name_ != entry().exe_file())
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return ProcessIterator::IncludeEntry();
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace base
125