Added CProcessStatisticsReader to avoid having to parse /proc/all (#35)

* Added CProcessStatisticsReader to avoid having to parse /proc/all

* Took @awesomekling's feedbacks into account

* Fixed indentation and replaced tabs by spaces
This commit is contained in:
GuillaumeGas 2019-05-16 18:47:47 +02:00 committed by Andreas Kling
parent 174639b7f0
commit 0ba4ceb2cd
Notes: sideshowbarker 2024-07-19 14:05:51 +09:00
5 changed files with 164 additions and 81 deletions

View file

@ -0,0 +1,100 @@
#include "CProcessStatisticsReader.h"
#include "CFile.h"
#include <stdio.h>
#include <pwd.h>
CProcessStatisticsReader::CProcessStatisticsReader()
{
setpwent();
while (auto* passwd = getpwent())
m_usernames.set(passwd->pw_uid, passwd->pw_name);
endpwent();
}
HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_map()
{
HashMap<pid_t, CProcessStatistics> res;
update_map(res);
return res;
}
void CProcessStatisticsReader::update_map(HashMap<pid_t, CProcessStatistics>& map)
{
CFile file("/proc/all");
if (!file.open(CIODevice::ReadOnly)) {
fprintf(stderr, "CProcessHelper : failed to open /proc/all: %s\n", file.error_string());
return;
}
for (;;) {
auto line = file.read_line(1024);
if (line.is_empty())
break;
auto chomped = String((const char*)line.pointer(), line.size() - 1, Chomp);
auto parts = chomped.split_view(',');
if (parts.size() < 18)
break;
bool ok = false;
CProcessStatistics process;
process.pid = parts[0].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid pid\n", parts[0].characters());
return;
}
process.nsched = parts[1].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid nsched value\n", parts[1].characters());
return;
}
uid_t uid = parts[5].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid uid value\n", parts[5].characters());
return;
}
process.uid = uid;
process.username = get_username_from_uid(uid);
process.priority = parts[16];
process.syscalls = parts[17].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid syscalls count value\n", parts[17].characters());
return;
}
process.state = parts[7];
process.name = parts[11];
process.linear = parts[12].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid amount of linear address space used\n", parts[12].characters());
return;
}
process.physical = parts[13].to_uint(ok);
if (!ok) {
fprintf(stderr, "CProcessHelper : couldn't convert %s to a valid amount of physical address space used\n", parts[13].characters());
return;
}
map.set(process.pid, process);
}
}
String CProcessStatisticsReader::get_username_from_uid(const uid_t uid)
{
auto it = m_usernames.find(uid);
if (it != m_usernames.end())
return (*it).value;
else
return String::format("%u", uid);
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <AK/AKString.h>
#include <AK/HashMap.h>
struct CProcessStatistics {
pid_t pid;
unsigned nsched;
String name;
String state;
String username;
uid_t uid;
String priority;
size_t linear;
size_t physical;
unsigned syscalls;
};
class CProcessStatisticsReader {
public:
CProcessStatisticsReader();
HashMap<pid_t, CProcessStatistics> get_map();
private:
void update_map(HashMap<pid_t, CProcessStatistics>& map);
String get_username_from_uid(const uid_t uid);
HashMap<uid_t, String> m_usernames;
};

View file

@ -16,7 +16,8 @@ OBJS = \
CTimer.o \
CEventLoop.o \
CConfigFile.o \
CEvent.o
CEvent.o \
CProcessStatisticsReader.o
LIBRARY = libcore.a
DEFINES += -DUSERLAND

View file

@ -2,7 +2,7 @@
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <LibCore/CFile.h>
#include <LibCore/CProcessStatisticsReader.h>
#include <AK/AKString.h>
static void print_usage_and_exit()
@ -13,40 +13,16 @@ static void print_usage_and_exit()
static int kill_all(const String& process_name, const unsigned signum)
{
CFile file("/proc/all");
if (!file.open(CIODevice::ReadOnly)) {
fprintf(stderr, "killall failed to open /proc/all\n");
return 3;
HashMap<pid_t, CProcessStatistics> processes = CProcessStatisticsReader().get_map();
for (auto& it : processes) {
if (it.value.name == process_name) {
int ret = kill(it.value.pid, signum);
if (ret < 0)
perror("kill");
}
}
for (;;) {
auto line = file.read_line(1024);
if (line.is_empty())
break;
auto chomped = String((const char*)line.pointer(), line.size() - 1, Chomp);
auto parts = chomped.split_view(',');
if (parts.size() < 18)
break;
bool ok = false;
pid_t pid = parts[0].to_uint(ok);
String name = parts[11];
if (!ok) {
fprintf(stderr, "killall failed : couldn't convert %s to a valid pid\n", parts[0].characters());
return 4;
}
if (name == process_name) {
int ret = kill(pid, signum);
if (ret < 0)
perror("kill");
}
}
return 0;
}
@ -60,12 +36,12 @@ int main(int argc, char** argv)
print_usage_and_exit();
if (argc == 3) {
name_argi = 2;
name_argi = 2;
if (argv[1][0] != '-')
print_usage_and_exit();
signum = String(&argv[1][1]).to_uint(ok);
signum = String(&argv[1][1]).to_uint(ok);
if (!ok) {
printf("'%s' is not a valid signal number\n", &argv[1][1]);
return 2;

View file

@ -2,55 +2,32 @@
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <LibCore/CFile.h>
#include <LibCore/CProcessStatisticsReader.h>
#include <AK/AKString.h>
#include <AK/Vector.h>
#include <AK/ArgsParser.h>
#include <AK/HashMap.h>
static int pid_of(const String& process_name, bool single_shot, bool omit_pid, pid_t pid)
{
bool displayed_at_least_one = false;
CFile file("/proc/all");
if (!file.open(CIODevice::ReadOnly)) {
fprintf(stderr, "pidof failed to open /proc/all\n");
return 2;
}
HashMap<pid_t, CProcessStatistics> processes = CProcessStatisticsReader().get_map();
for (auto& it : processes) {
if (it.value.name == process_name) {
if (!omit_pid || (omit_pid && it.value.pid != pid)) {
printf("%d ", it.value.pid);
displayed_at_least_one = true;
for (;;) {
auto line = file.read_line(1024);
if (line.is_empty())
break;
auto chomped = String((const char*)line.pointer(), line.size() - 1, Chomp);
auto parts = chomped.split_view(',');
if (parts.size() < 18)
break;
bool ok = false;
pid_t current_pid = parts[0].to_uint(ok);
String name = parts[11];
if (!ok) {
fprintf(stderr, "pidof failed : couldn't convert %s to a valid pid\n", parts[0].characters());
return 3;
}
if (name == process_name) {
if (!omit_pid || (omit_pid && current_pid != pid)) {
printf("%d ", current_pid);
displayed_at_least_one = true;
if (single_shot)
break;
}
}
if (single_shot)
break;
}
}
}
if (displayed_at_least_one)
printf("\n");
printf("\n");
return 0;
}
@ -72,16 +49,16 @@ int main(int argc, char** argv)
bool ok = false;
String pid_str = args.get("o");
if (pid_str == "%PPID")
pid = getppid();
else
pid = pid_str.to_uint(ok);
if (pid_str == "%PPID")
pid = getppid();
else
pid = pid_str.to_uint(ok);
}
// We should have one single value : the process name
Vector<String> values = args.get_single_values();
if (values.size() == 0) {
args_parser.print_usage();
args_parser.print_usage();
return 0;
}