1 // Copyright (c) 2012 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/internal_aix.h"
6 
7 #include <sys/procfs.h>
8 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <unistd.h>
13 
14 #include <map>
15 #include <string>
16 #include <vector>
17 
18 #include "base/files/file_util.h"
19 #include "base/logging.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "base/time/time.h"
25 
26 // Not defined on AIX by default.
27 #define NAME_MAX 255
28 
29 namespace base {
30 namespace internalAIX {
31 
32 const char kProcDir[] = "/proc";
33 
34 const char kStatFile[] = "psinfo";  // AIX specific
35 
GetProcPidDir(pid_t pid)36 FilePath GetProcPidDir(pid_t pid) {
37   return FilePath(kProcDir).Append(NumberToString(pid));
38 }
39 
ProcDirSlotToPid(const char * d_name)40 pid_t ProcDirSlotToPid(const char* d_name) {
41   int i;
42   for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
43     if (!IsAsciiDigit(d_name[i])) {
44       return 0;
45     }
46   }
47   if (i == NAME_MAX)
48     return 0;
49 
50   // Read the process's command line.
51   pid_t pid;
52   std::string pid_string(d_name);
53   if (!StringToInt(pid_string, &pid)) {
54     NOTREACHED();
55     return 0;
56   }
57   return pid;
58 }
59 
ReadProcFile(const FilePath & file,struct psinfo * info)60 bool ReadProcFile(const FilePath& file, struct psinfo* info) {
61   // Synchronously reading files in /proc is safe.
62   ThreadRestrictions::ScopedAllowIO allow_io;
63   int fileId;
64   if ((fileId = open(file.value().c_str(), O_RDONLY)) < 0) {
65     DPLOG(WARNING) << "Failed to open " << file.MaybeAsASCII();
66     return false;
67   }
68 
69   if (read(fileId, info, sizeof(*info)) < 0) {
70     DPLOG(WARNING) << "Failed to read " << file.MaybeAsASCII();
71     return false;
72   }
73 
74   return true;
75 }
76 
ReadProcStats(pid_t pid,struct psinfo * info)77 bool ReadProcStats(pid_t pid, struct psinfo* info) {
78   FilePath stat_file = internalAIX::GetProcPidDir(pid).Append(kStatFile);
79   return ReadProcFile(stat_file, info);
80 }
81 
ParseProcStats(struct psinfo & stats_data,std::vector<std::string> * proc_stats)82 bool ParseProcStats(struct psinfo& stats_data,
83                     std::vector<std::string>* proc_stats) {
84   // The stat file is formatted as:
85   // struct psinfo
86   // see -
87   // https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.files/proc.htm
88   proc_stats->clear();
89   // PID.
90   proc_stats->push_back(NumberToString(stats_data.pr_pid));
91   // Process name without parentheses. // 1
92   proc_stats->push_back(stats_data.pr_fname);
93   // Process State (Not available)  // 2
94   proc_stats->push_back("0");
95   // Process id of parent  // 3
96   proc_stats->push_back(NumberToString(stats_data.pr_ppid));
97 
98   // Process group id // 4
99   proc_stats->push_back(NumberToString(stats_data.pr_pgid));
100 
101   return true;
102 }
103 
104 typedef std::map<std::string, std::string> ProcStatMap;
ParseProcStat(const std::string & contents,ProcStatMap * output)105 void ParseProcStat(const std::string& contents, ProcStatMap* output) {
106   StringPairs key_value_pairs;
107   SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
108   for (size_t i = 0; i < key_value_pairs.size(); ++i) {
109     output->insert(key_value_pairs[i]);
110   }
111 }
112 
GetProcStatsFieldAsInt64(const std::vector<std::string> & proc_stats,ProcStatsFields field_num)113 int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
114                                  ProcStatsFields field_num) {
115   DCHECK_GE(field_num, VM_PPID);
116   CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
117 
118   int64_t value;
119   return StringToInt64(proc_stats[field_num], &value) ? value : 0;
120 }
121 
GetProcStatsFieldAsSizeT(const std::vector<std::string> & proc_stats,ProcStatsFields field_num)122 size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
123                                 ProcStatsFields field_num) {
124   DCHECK_GE(field_num, VM_PPID);
125   CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
126 
127   size_t value;
128   return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
129 }
130 
ReadProcStatsAndGetFieldAsInt64(pid_t pid,ProcStatsFields field_num)131 int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
132   struct psinfo stats_data;
133   if (!ReadProcStats(pid, &stats_data))
134     return 0;
135   std::vector<std::string> proc_stats;
136   if (!ParseProcStats(stats_data, &proc_stats))
137     return 0;
138 
139   return GetProcStatsFieldAsInt64(proc_stats, field_num);
140 }
141 
ReadProcStatsAndGetFieldAsSizeT(pid_t pid,ProcStatsFields field_num)142 size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, ProcStatsFields field_num) {
143   struct psinfo stats_data;
144   if (!ReadProcStats(pid, &stats_data))
145     return 0;
146   std::vector<std::string> proc_stats;
147   if (!ParseProcStats(stats_data, &proc_stats))
148     return 0;
149   return GetProcStatsFieldAsSizeT(proc_stats, field_num);
150 }
151 
152 }  // namespace internalAIX
153 }  // namespace base
154