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