Last active
May 4, 2024 19:41
-
-
Save oriapp/07e1c0b7cb0412537146092558a89d5f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <dirent.h> | |
#include <string.h> | |
#include <ctype.h> | |
#include <sys/sysinfo.h> | |
#include <sys/types.h> | |
#include <pwd.h> | |
#define BUFFER_SIZE 512 | |
struct Process | |
{ | |
int pid; | |
char *name; | |
char state; | |
unsigned long memory; | |
char *user; | |
}; | |
/** | |
* @brief Converts bytes to a human-readable format. | |
* | |
* @param bytes Number of bytes. | |
* @return Human-readable string representing the bytes. | |
*/ | |
char *bytesToHumanReadable(unsigned long bytes) | |
{ | |
const char *suffix[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; | |
int i = 0; | |
double dblBytes = bytes; | |
while (dblBytes >= 1024 && i < (sizeof(suffix) / sizeof(suffix[0])) - 1) | |
{ | |
dblBytes /= 1024; | |
i++; | |
} | |
static char output[BUFFER_SIZE]; | |
snprintf(output, sizeof(output), "%.2f %s", dblBytes, suffix[i]); | |
return output; | |
} | |
/** | |
* @brief Converts seconds to a human-readable format. | |
* | |
* @param seconds Number of seconds. | |
* @return Human-readable string representing the time. | |
*/ | |
char *secondsToHumanReadable(unsigned long seconds) | |
{ | |
unsigned long days = seconds / (24 * 3600); | |
seconds = seconds % (24 * 3600); | |
unsigned long hours = seconds / 3600; | |
seconds %= 3600; | |
unsigned long minutes = seconds / 60; | |
seconds %= 60; | |
static char output[BUFFER_SIZE]; | |
snprintf(output, sizeof(output), "%lu days, %lu hours, %lu minutes, %lu seconds", days, hours, minutes, seconds); | |
return output; | |
} | |
/** | |
* @brief Retrieves the username corresponding to a UID. | |
* | |
* @param uid UID of the user. | |
* @return Username corresponding to the UID. | |
*/ | |
char *getUsername(uid_t uid) | |
{ | |
struct passwd *pwd = getpwuid(uid); | |
if (pwd != NULL) | |
{ | |
return pwd->pw_name; | |
} | |
else | |
{ | |
return "Unknown"; | |
} | |
} | |
/** | |
* @brief Reads process information from the /proc directory. | |
* | |
* @param processes Pointer to store the process information. | |
* @return Number of processes read, or -1 on failure. | |
*/ | |
int readProcesses(struct Process **processes) | |
{ | |
DIR *dir; | |
struct dirent *ent; | |
FILE *fp; | |
char path[BUFFER_SIZE]; | |
char line[BUFFER_SIZE]; | |
int count = 0; | |
int maxProcesses = 1024; | |
*processes = malloc(maxProcesses * sizeof(struct Process)); | |
if (*processes == NULL) | |
{ | |
perror("Failed to allocate memory"); | |
return -1; | |
} | |
if ((dir = opendir("/proc")) != NULL) | |
{ | |
while ((ent = readdir(dir)) != NULL) | |
{ | |
if (isdigit(ent->d_name[0])) | |
{ | |
sprintf(path, "/proc/%s/stat", ent->d_name); | |
if ((fp = fopen(path, "r")) != NULL) | |
{ | |
if (fgets(line, sizeof(line), fp) != NULL) | |
{ | |
sscanf(line, "%d", &((*processes)[count].pid)); | |
char name[BUFFER_SIZE]; | |
char state; | |
if (sscanf(line, "%*d (%[^)]) %c", name, &state) == 2) | |
{ | |
(*processes)[count].name = strdup(name); | |
(*processes)[count].state = state; | |
} | |
else | |
{ | |
(*processes)[count].name = strdup("(unknown)"); | |
(*processes)[count].state = ' '; | |
} | |
count++; | |
} | |
fclose(fp); | |
} | |
} | |
} | |
closedir(dir); | |
} | |
else | |
{ | |
perror("Failed to open /proc directory"); | |
free(*processes); | |
return -1; | |
} | |
return count; | |
} | |
/** | |
* @brief Frees memory allocated for process information. | |
* | |
* @param processes Pointer to the array of processes. | |
* @param numProcesses Number of processes in the array. | |
*/ | |
void freeProcesses(struct Process *processes, int numProcesses) | |
{ | |
for (int i = 0; i < numProcesses; i++) | |
{ | |
free(processes[i].name); | |
free(processes[i].user); | |
} | |
free(processes); | |
} | |
/** | |
* @brief Prints process information. | |
* | |
* @param processes Array of processes. | |
* @param numProcesses Number of processes in the array. | |
*/ | |
void printProcesses(struct Process *processes, int numProcesses) | |
{ | |
printf("%-8s %-20s %-8s %-8s %-8s\n", "PID", "NAME", "STATE", "MEMORY", "USER"); | |
printf("----------------------------------------------------------------------------------\n"); | |
for (int i = 0; i < numProcesses; i++) | |
{ | |
printf("%-8d %-20s %-8c %-8s %-8s\n", processes[i].pid, processes[i].name, processes[i].state, bytesToHumanReadable(processes[i].memory), processes[i].user); | |
} | |
} | |
/** | |
* @brief Prints system information. | |
*/ | |
void printSystemInfo() | |
{ | |
struct sysinfo info; | |
if (sysinfo(&info) == 0) | |
{ | |
printf("\nSystem Information:\n"); | |
printf("Uptime: %s\n", secondsToHumanReadable(info.uptime)); | |
printf("Load Average (1min/5min/15min): %.2f %.2f %.2f\n", info.loads[0] / 65536.0, info.loads[1] / 65536.0, info.loads[2] / 65536.0); | |
printf("Total RAM: %s\n", bytesToHumanReadable(info.totalram * info.mem_unit)); | |
printf("Free RAM: %s\n", bytesToHumanReadable(info.freeram * info.mem_unit)); | |
printf("Total Swap: %s\n", bytesToHumanReadable(info.totalswap * info.mem_unit)); | |
printf("Free Swap: %s\n", bytesToHumanReadable(info.freeswap * info.mem_unit)); | |
} | |
else | |
{ | |
perror("Failed to get system information"); | |
} | |
} | |
/** | |
* @brief Calculates memory usage for each process. | |
* | |
* @param processes Array of processes. | |
* @param numProcesses Number of processes in the array. | |
*/ | |
void calculateProcessMemory(struct Process *processes, int numProcesses) | |
{ | |
FILE *fp; | |
char path[BUFFER_SIZE]; | |
char line[BUFFER_SIZE]; | |
for (int i = 0; i < numProcesses; i++) | |
{ | |
sprintf(path, "/proc/%d/statm", processes[i].pid); | |
fp = fopen(path, "r"); | |
if (fp != NULL) | |
{ | |
if (fgets(line, sizeof(line), fp) != NULL) | |
{ | |
unsigned long size, resident, shared; | |
sscanf(line, "%lu %lu %lu", &size, &resident, &shared); | |
// Memory is represented in pages, use resident set size (RSS) as memory usage | |
processes[i].memory = resident * sysconf(_SC_PAGESIZE); | |
} | |
fclose(fp); | |
} | |
} | |
} | |
int main() | |
{ | |
struct Process *processes; | |
int numProcesses; | |
numProcesses = readProcesses(&processes); | |
if (numProcesses == -1) | |
{ | |
return 1; | |
} | |
// Calculate memory usage for each process | |
calculateProcessMemory(processes, numProcesses); | |
// Retrieve usernames for processes | |
for (int i = 0; i < numProcesses; i++) | |
{ | |
uid_t uid; | |
char path[BUFFER_SIZE]; | |
FILE *fp; | |
sprintf(path, "/proc/%d/status", processes[i].pid); | |
fp = fopen(path, "r"); | |
if (fp != NULL) | |
{ | |
char line[BUFFER_SIZE]; | |
while (fgets(line, sizeof(line), fp)) | |
{ | |
if (strncmp(line, "Uid:", 4) == 0) | |
{ | |
sscanf(line, "Uid: %d", &uid); | |
processes[i].user = strdup(getUsername(uid)); | |
break; | |
} | |
} | |
fclose(fp); | |
} | |
} | |
printProcesses(processes, numProcesses); | |
printSystemInfo(); | |
freeProcesses(processes, numProcesses); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment