|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/process/internal_aix.h" | 
|  |  | 
|  | #include <sys/procfs.h> | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <fcntl.h> | 
|  | #include <limits.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_split.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/threading/thread_restrictions.h" | 
|  | #include "base/time/time.h" | 
|  |  | 
|  | // Not defined on AIX by default. | 
|  | #define NAME_MAX 255 | 
|  |  | 
|  | namespace base { | 
|  | namespace internalAIX { | 
|  |  | 
|  | const char kProcDir[] = "/proc"; | 
|  |  | 
|  | const char kStatFile[] = "psinfo";  // AIX specific | 
|  |  | 
|  | FilePath GetProcPidDir(pid_t pid) { | 
|  | return FilePath(kProcDir).Append(IntToString(pid)); | 
|  | } | 
|  |  | 
|  | pid_t ProcDirSlotToPid(const char* d_name) { | 
|  | int i; | 
|  | for (i = 0; i < NAME_MAX && d_name[i]; ++i) { | 
|  | if (!IsAsciiDigit(d_name[i])) { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | if (i == NAME_MAX) | 
|  | return 0; | 
|  |  | 
|  | // Read the process's command line. | 
|  | pid_t pid; | 
|  | std::string pid_string(d_name); | 
|  | if (!StringToInt(pid_string, &pid)) { | 
|  | NOTREACHED(); | 
|  | return 0; | 
|  | } | 
|  | return pid; | 
|  | } | 
|  |  | 
|  | bool ReadProcFile(const FilePath& file, struct psinfo* info) { | 
|  | // Synchronously reading files in /proc is safe. | 
|  | ThreadRestrictions::ScopedAllowIO allow_io; | 
|  | int fileId; | 
|  | if ((fileId = open(file.value().c_str(), O_RDONLY)) < 0) { | 
|  | DLOG(WARNING) << "Failed to open " << file.MaybeAsASCII() | 
|  | << " errno = " << errno; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (read(fileId, info, sizeof(*info)) < 0) { | 
|  | DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII() | 
|  | << " errno = " << errno; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ReadProcStats(pid_t pid, struct psinfo* info) { | 
|  | FilePath stat_file = internalAIX::GetProcPidDir(pid).Append(kStatFile); | 
|  | return ReadProcFile(stat_file, info); | 
|  | } | 
|  |  | 
|  | bool ParseProcStats(struct psinfo& stats_data, | 
|  | std::vector<std::string>* proc_stats) { | 
|  | // The stat file is formatted as: | 
|  | // struct psinfo | 
|  | // see - | 
|  | // https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.files/proc.htm | 
|  | proc_stats->clear(); | 
|  | // PID. | 
|  | proc_stats->push_back(IntToString(stats_data.pr_pid)); | 
|  | // Process name without parentheses. // 1 | 
|  | proc_stats->push_back(stats_data.pr_fname); | 
|  | // Process State (Not available)  // 2 | 
|  | proc_stats->push_back("0"); | 
|  | // Process id of parent  // 3 | 
|  | proc_stats->push_back(IntToString(stats_data.pr_ppid)); | 
|  |  | 
|  | // Process group id // 4 | 
|  | proc_stats->push_back(IntToString(stats_data.pr_pgid)); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | typedef std::map<std::string, std::string> ProcStatMap; | 
|  | void ParseProcStat(const std::string& contents, ProcStatMap* output) { | 
|  | StringPairs key_value_pairs; | 
|  | SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs); | 
|  | for (size_t i = 0; i < key_value_pairs.size(); ++i) { | 
|  | output->insert(key_value_pairs[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats, | 
|  | ProcStatsFields field_num) { | 
|  | DCHECK_GE(field_num, VM_PPID); | 
|  | CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); | 
|  |  | 
|  | int64_t value; | 
|  | return StringToInt64(proc_stats[field_num], &value) ? value : 0; | 
|  | } | 
|  |  | 
|  | size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats, | 
|  | ProcStatsFields field_num) { | 
|  | DCHECK_GE(field_num, VM_PPID); | 
|  | CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); | 
|  |  | 
|  | size_t value; | 
|  | return StringToSizeT(proc_stats[field_num], &value) ? value : 0; | 
|  | } | 
|  |  | 
|  | int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) { | 
|  | struct psinfo stats_data; | 
|  | if (!ReadProcStats(pid, &stats_data)) | 
|  | return 0; | 
|  | std::vector<std::string> proc_stats; | 
|  | if (!ParseProcStats(stats_data, &proc_stats)) | 
|  | return 0; | 
|  |  | 
|  | return GetProcStatsFieldAsInt64(proc_stats, field_num); | 
|  | } | 
|  |  | 
|  | size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, ProcStatsFields field_num) { | 
|  | struct psinfo stats_data; | 
|  | if (!ReadProcStats(pid, &stats_data)) | 
|  | return 0; | 
|  | std::vector<std::string> proc_stats; | 
|  | if (!ParseProcStats(stats_data, &proc_stats)) | 
|  | return 0; | 
|  | return GetProcStatsFieldAsSizeT(proc_stats, field_num); | 
|  | } | 
|  |  | 
|  | }  // namespace internalAIX | 
|  | }  // namespace base |