blob: bcf629f4d8a621ee9632dfbdb2aa61a36c146a3b [file] [log] [blame]
[email protected]af824362011-12-04 14:19:411// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process_util.h"
6
7#include <ctype.h>
8#include <dirent.h>
9#include <dlfcn.h>
10#include <errno.h>
11#include <fcntl.h>
[email protected]dfa049e2013-02-07 02:57:2212#include <sys/sysctl.h>
[email protected]af824362011-12-04 14:19:4113#include <sys/time.h>
14#include <sys/types.h>
[email protected]af824362011-12-04 14:19:4115#include <sys/user.h>
[email protected]dfa049e2013-02-07 02:57:2216#include <sys/wait.h>
[email protected]af824362011-12-04 14:19:4117#include <time.h>
18#include <unistd.h>
19
[email protected]af824362011-12-04 14:19:4120#include "base/logging.h"
[email protected]af824362011-12-04 14:19:4121#include "base/string_tokenizer.h"
22#include "base/string_util.h"
[email protected]dfa049e2013-02-07 02:57:2223#include "base/strings/string_number_conversions.h"
[email protected]5ae0b763e2013-02-07 23:01:3924#include "base/strings/string_split.h"
[email protected]af824362011-12-04 14:19:4125#include "base/sys_info.h"
26
27namespace base {
28
29ProcessId GetParentProcessId(ProcessHandle process) {
30 struct kinfo_proc info;
31 size_t length;
32 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
33
34 if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
35 return -1;
36
37 return info.ki_ppid;
38}
39
40FilePath GetProcessExecutablePath(ProcessHandle process) {
41 char pathname[PATH_MAX];
42 size_t length;
43 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process };
44
45 length = sizeof(pathname);
46
47 if (sysctl(mib, arraysize(mib), pathname, &length, NULL, 0) < 0 ||
48 length == 0) {
49 return FilePath();
50 }
51
52 return FilePath(std::string(pathname));
53}
54
55ProcessIterator::ProcessIterator(const ProcessFilter* filter)
56 : index_of_kinfo_proc_(),
57 filter_(filter) {
58
59 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
60
61 bool done = false;
62 int try_num = 1;
63 const int max_tries = 10;
64
65 do {
66 size_t len = 0;
[email protected]6d7f55f2013-05-14 10:12:5667 if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
[email protected]af824362011-12-04 14:19:4168 LOG(ERROR) << "failed to get the size needed for the process list";
69 kinfo_procs_.resize(0);
70 done = true;
71 } else {
72 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
73 // Leave some spare room for process table growth (more could show up
74 // between when we check and now)
75 num_of_kinfo_proc += 16;
76 kinfo_procs_.resize(num_of_kinfo_proc);
77 len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
78 if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
79 // If we get a mem error, it just means we need a bigger buffer, so
80 // loop around again. Anything else is a real error and give up.
81 if (errno != ENOMEM) {
82 LOG(ERROR) << "failed to get the process list";
83 kinfo_procs_.resize(0);
84 done = true;
85 }
86 } else {
87 // Got the list, just make sure we're sized exactly right
88 size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
89 kinfo_procs_.resize(num_of_kinfo_proc);
90 done = true;
91 }
92 }
93 } while (!done && (try_num++ < max_tries));
94
95 if (!done) {
96 LOG(ERROR) << "failed to collect the process list in a few tries";
97 kinfo_procs_.resize(0);
98 }
99}
100
101ProcessIterator::~ProcessIterator() {
102}
103
104bool ProcessIterator::CheckForNextProcess() {
105 std::string data;
106
[email protected]6d7f55f2013-05-14 10:12:56107 for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
[email protected]af824362011-12-04 14:19:41108 size_t length;
109 struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
110 int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
111
112 if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
113 continue;
114
115 length = 0;
116 if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
117 LOG(ERROR) << "failed to figure out the buffer size for a command line";
118 continue;
119 }
120
121 data.resize(length);
122
123 if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
124 LOG(ERROR) << "failed to fetch a commandline";
125 continue;
126 }
127
128 std::string delimiters;
129 delimiters.push_back('\0');
130 Tokenize(data, delimiters, &entry_.cmd_line_args_);
131
132 size_t exec_name_end = data.find('\0');
133 if (exec_name_end == std::string::npos) {
134 LOG(ERROR) << "command line data didn't match expected format";
135 continue;
136 }
137
138 entry_.pid_ = kinfo.ki_pid;
139 entry_.ppid_ = kinfo.ki_ppid;
140 entry_.gid_ = kinfo.ki_pgid;
141
142 size_t last_slash = data.rfind('/', exec_name_end);
143 if (last_slash == std::string::npos) {
144 entry_.exe_file_.assign(data, 0, exec_name_end);
145 } else {
146 entry_.exe_file_.assign(data, last_slash + 1,
147 exec_name_end - last_slash - 1);
148 }
149
150 // Start w/ the next entry next time through
151 ++index_of_kinfo_proc_;
152
153 return true;
154 }
155 return false;
156}
157
158bool NamedProcessIterator::IncludeEntry() {
[email protected]6d7f55f2013-05-14 10:12:56159 if (executable_name_ != entry().exe_file())
[email protected]af824362011-12-04 14:19:41160 return false;
161
162 return ProcessIterator::IncludeEntry();
163}
164
[email protected]af824362011-12-04 14:19:41165void EnableTerminationOnOutOfMemory() {
166 DLOG(WARNING) << "Not feasible.";
167}
168
169void EnableTerminationOnHeapCorruption() {
170 // Nothing to do.
171}
172
173bool AdjustOOMScore(ProcessId process, int score) {
174 NOTIMPLEMENTED();
175 return false;
176}
177
178} // namespace base