process_iterator_freebsd.cc 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright (c) 2013 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. #include "base/process/process_iterator.h"
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <stddef.h>
  8. #include <sys/sysctl.h>
  9. #include <unistd.h>
  10. #include "base/logging.h"
  11. #include "base/strings/string_split.h"
  12. #include "base/strings/string_util.h"
  13. namespace base {
  14. ProcessIterator::ProcessIterator(const ProcessFilter* filter)
  15. : index_of_kinfo_proc_(),
  16. filter_(filter) {
  17. int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
  18. bool done = false;
  19. int try_num = 1;
  20. const int max_tries = 10;
  21. do {
  22. size_t len = 0;
  23. if (sysctl(mib, std::size(mib), NULL, &len, NULL, 0) < 0) {
  24. LOG(ERROR) << "failed to get the size needed for the process list";
  25. kinfo_procs_.resize(0);
  26. done = true;
  27. } else {
  28. size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
  29. // Leave some spare room for process table growth (more could show up
  30. // between when we check and now)
  31. num_of_kinfo_proc += 16;
  32. kinfo_procs_.resize(num_of_kinfo_proc);
  33. len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
  34. if (sysctl(mib, std::size(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
  35. // If we get a mem error, it just means we need a bigger buffer, so
  36. // loop around again. Anything else is a real error and give up.
  37. if (errno != ENOMEM) {
  38. LOG(ERROR) << "failed to get the process list";
  39. kinfo_procs_.resize(0);
  40. done = true;
  41. }
  42. } else {
  43. // Got the list, just make sure we're sized exactly right
  44. size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
  45. kinfo_procs_.resize(num_of_kinfo_proc);
  46. done = true;
  47. }
  48. }
  49. } while (!done && (try_num++ < max_tries));
  50. if (!done) {
  51. LOG(ERROR) << "failed to collect the process list in a few tries";
  52. kinfo_procs_.resize(0);
  53. }
  54. }
  55. ProcessIterator::~ProcessIterator() {
  56. }
  57. bool ProcessIterator::CheckForNextProcess() {
  58. std::string data;
  59. for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
  60. size_t length;
  61. struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
  62. int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
  63. if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
  64. continue;
  65. length = 0;
  66. if (sysctl(mib, std::size(mib), NULL, &length, NULL, 0) < 0) {
  67. LOG(ERROR) << "failed to figure out the buffer size for a command line";
  68. continue;
  69. }
  70. data.resize(length);
  71. if (sysctl(mib, std::size(mib), &data[0], &length, NULL, 0) < 0) {
  72. LOG(ERROR) << "failed to fetch a commandline";
  73. continue;
  74. }
  75. std::string delimiters;
  76. delimiters.push_back('\0');
  77. entry_.cmd_line_args_ = SplitString(data, delimiters,
  78. KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
  79. size_t exec_name_end = data.find('\0');
  80. if (exec_name_end == std::string::npos) {
  81. LOG(ERROR) << "command line data didn't match expected format";
  82. continue;
  83. }
  84. entry_.pid_ = kinfo.ki_pid;
  85. entry_.ppid_ = kinfo.ki_ppid;
  86. entry_.gid_ = kinfo.ki_pgid;
  87. size_t last_slash = data.rfind('/', exec_name_end);
  88. if (last_slash == std::string::npos) {
  89. entry_.exe_file_.assign(data, 0, exec_name_end);
  90. } else {
  91. entry_.exe_file_.assign(data, last_slash + 1,
  92. exec_name_end - last_slash - 1);
  93. }
  94. // Start w/ the next entry next time through
  95. ++index_of_kinfo_proc_;
  96. return true;
  97. }
  98. return false;
  99. }
  100. bool NamedProcessIterator::IncludeEntry() {
  101. if (executable_name_ != entry().exe_file())
  102. return false;
  103. return ProcessIterator::IncludeEntry();
  104. }
  105. } // namespace base