aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Cabergs <me@cacharle.xyz>2021-04-25 16:28:47 +0200
committerCharles Cabergs <me@cacharle.xyz>2021-04-25 16:28:47 +0200
commit4a325349867772002e4db87954e0c2ee6955c83d (patch)
tree8093076667fb79af23d78fa7f8411efaad5ebddb
parent4bf2054147f3eaa8c9695710fe7ed39cb713e9c5 (diff)
downloadcoreutils-4a325349867772002e4db87954e0c2ee6955c83d.tar.gz
coreutils-4a325349867772002e4db87954e0c2ee6955c83d.tar.bz2
coreutils-4a325349867772002e4db87954e0c2ee6955c83d.zip
Added ps basic functionality
-rw-r--r--src/ps.c588
1 files changed, 307 insertions, 281 deletions
diff --git a/src/ps.c b/src/ps.c
index bc090ec..3892271 100644
--- a/src/ps.c
+++ b/src/ps.c
@@ -12,272 +12,354 @@
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <grp.h>
+#include <grp.h>
+#include <pwd.h>
+
+/*
+** TODO
+** time formatting
+** bug with random pid without optimization
+** command line args
+** process selection
+*/
#define PROC_DIR "/proc"
-#define TASK_COMM_LEN 32
-
-static int page_size = -1;
-static long clock_tick = -1;
-typedef enum
-{
- FIELD_ARGS,
- FIELD_COMM,
- FIELD_PID,
- FIELD_PPID,
- FIELD_PGID,
- FIELD_ETIME,
- FIELD_TIME,
- FIELD_GROUP,
- FIELD_RGROUP,
- FIELD_USER,
- FIELD_RUSER,
- FIELD_NICE,
- FIELD_TTY,
- FIELD_PCPU,
- FIELD_VSZ,
- FIELD_ADDR,
- FIELD_ADDR,
- FIELD_C,
- FIELD_PRI,
- FIELD_NI,
- FIELD_ADDR,
- FIELD_SZ,
- FIELD_WCHAN,
-} t_field_id;
-
-typedef struct
+struct s_field_info
{
- t_field_id id;
char *specifier;
char *header;
int width;
-} t_field_info;
-
-static t_field_info field_infos[] = {
- {FIELD_ARGS, "args", "COMMAND", 30},
- {FIELD_COMM, "comm", "COMMAND", -1},
- {FIELD_PID, "pid", "PID", 8},
- {FIELD_PPID, "ppid", "PPID", 8},
- {FIELD_PGID, "pgid", "PGID", 8},
- {FIELD_ETIME, "etime", "ELAPSED", -1},
- {FIELD_TIME, "time", "TIME", -1},
- {FIELD_GROUP, "group", "GROUP", -1},
- {FIELD_RGROUP, "rgroup", "RGROUP", -1},
- {FIELD_USER, "user", "USER", -1},
- {FIELD_RUSER, "ruser", "RUSER", -1},
- {FIELD_NICE, "nice", "NI", -1},
- {FIELD_TTY, "tty", "TT", -1},
- {FIELD_PCPU, "pcpu", "%CPU", -1},
- {FIELD_VSZ, "vsz", "VSZ", -1},
- {FIELD_FLAGS, "f", "F", 1},
- {FIELD_STATE, "s", "S", 1},
- {FIELD_C, "c", "C", -1},
- {FIELD_PRI, "pri", "PRI", -1},
- {FIELD_ADDR, "addr", "ADDR", -1},
- {FIELD_SZ, "sz", "SZ", -1},
- {FIELD_WCHAN, "wchan", "WCHAN", -1},
+ void (*print_func)(struct s_field_info *info);
};
+typedef struct s_field_info t_field_info;
+// globals
+#define TASK_COMM_LEN 32
-t_field_info *filed_info_from_specifier(const char *specifier)
-{
- for (size_t i = 0; i < sizeof(field_infos) / sizeof(t_field_info); i++)
- if (strcmp(field_infos[i].specifier, specifier) == 0)
- return (&field_infos[i]);
- return (NULL);
-}
+static int g_page_size = -1;
+static long g_clock_tick = -1;
+
+static char g_file_path[PATH_MAX + 1];
+
+static char g_comm[TASK_COMM_LEN];
-static struct stat proc_statbuf;
-static char *stat_file;
-static char *cmdfile_file;
+static pid_t g_pid;
+static pid_t g_ppid;
+static pid_t g_pgrp;
-void print_field_resource(t_field_info *field_info)
+static uid_t g_uid;
+static gid_t g_gid;
+
+static long g_nice;
+static long g_priority;
+
+static unsigned long long g_starttime;
+
+static int g_tty_nr;
+
+static unsigned long g_vsize;
+static unsigned long g_rss;
+static unsigned g_flags;
+static char g_state;
+static char g_state;
+static unsigned long g_wchan;
+
+void print_func_args(t_field_info *info)
{
- switch (field_info->id)
+ snprintf(g_file_path, PATH_MAX, PROC_DIR"/%d/cmdline", g_pid);
+ FILE *cmdline_file = fopen(g_file_path, "r");
+ if (cmdline_file == NULL)
+ return;
+ int count = 0;
+ int c = EOF;
+ while ((c = fgetc(cmdline_file)) != EOF)
{
- case FIELD_ARGS:
- snprintf(file_path, PATH_MAX, "%s/%d/cmdline", PROC_DIR, pid);
- FILE *cmdline_file = fopen(file_path, "r");
- if (cmdline_file == NULL)
- return;
- int c = EOF;
- while ((c = fgetc(cmdline_file)) != EOF)
- fputc(c, stdout);
+ fputc(c, stdout);
+ count++;
+ if (count > info->width)
break;
+ }
+ while (count < info->width)
+ fputc(' ', stdout);
+}
- case FIELD_COMM:
- char *closing_parent = strrchr(proc_stat.comm + 0, ')');
- if (closing_parent != NULL)
- *closing_parent = '\0';
- printf("%s", proc_stat.comm + 1);
- break;
+void print_func_comm(t_field_info *info)
+{
+ char *closing_parent = strrchr(g_comm, ')');
+ if (closing_parent != NULL)
+ *closing_parent = '\0';
+ printf(
+ "%*s",
+ info->width,
+ g_comm[0] == '(' ? (g_comm + 1) : g_comm
+ );
+}
- case FIELD_PID: printf("%*ld ", info.width, proc_stat.pid); break;
- case FIELD_PPID: printf("%*ld ", info.width, proc_stat.ppid); break;
- case FIELD_PGID: printf("%*ld ", info.width, proc_stat.pgrp); break;
+void print_func_pid(t_field_info *info) { printf("%*d", info->width, g_pid); } // bug without -O flag
+void print_func_ppid(t_field_info *info) { printf("%*d", info->width, g_ppid); }
+void print_func_pgrp(t_field_info *info) { printf("%*d", info->width, g_pgrp); }
- case FIELD_ETIME:
- printf("%6lld ", /*current -*/ proc_stat.starttime / clock_tick);
- break;
- case FIELD_TIME:
- printf("%6lld ", proc_stat.starttime / clock_tick);
- break;
+void print_func_etime(t_field_info *info)
+{
+ printf("%*lld ", info->width, /*current -*/ g_starttime / g_clock_tick);
+}
- case FIELD_GROUP:
- break;
- case FIELD_RGROUP:
- break;
- case FIELD_USER:
- printf("%6d ", proc_statbuf.st_uid);
- break;
- case FIELD_RUSER:
- break;
+void print_func_time(t_field_info *info)
+{
+ printf("%*lld ", info->width, g_starttime / g_clock_tick);
+}
- case FIELD_NICE:
- printf("%3ld ", proc_stat.nice);
- break;
- case FIELD_PRI:
- printf("%3ld ", proc_stat.priority);
- break;
+void print_func_user(t_field_info *info)
+{
+ struct passwd *passwd_ptr = getpwuid(g_uid);
+ if (passwd_ptr == NULL)
+ return;
+ printf("%*.*s", info->width, info->width, passwd_ptr->pw_name);
+}
- case FIELD_TTY:
- printf("%6d ", proc_stat.tty_nr);
- break;
- case FIELD_PCPU:
- break;
- case FIELD_VSZ:
- printf("%5ld ", proc_stat.vsize / page_size);
- break;
- case FIELD_ADDR:
- break;
- case FIELD_FLAGS:
- printf("%o ", 0); //proc_stat.flags,
- break;
- case FIELD_STATE:
- printf("%c ", proc_stat.state);
- break;
+void print_func_group(t_field_info *info)
+{
+ struct group *group_ptr = getgrgid(g_gid);
+ if (group_ptr == NULL)
+ return;
+ printf("%*.*s", info->width, info->width, group_ptr->gr_name);
+}
- case FIELD_C:
- break;
- case FIELD_SZ:
- break;
+void print_func_nice(t_field_info *info) { printf("%*ld", info->width, g_nice); }
+void print_func_priority(t_field_info *info) { printf("%*ld", info->width, g_priority); }
- case FIELD_WCHAN:
- printf("%4ld ", proc_stat.wchan);
- break;
- default:
- exit(1);
+bool find_tty_in_dir(char *dir_path, char dest[PATH_MAX + 1])
+{
+ DIR *dir = opendir(dir_path);
+ if (dir == NULL)
+ return false;
+ struct dirent *entry;
+ strcpy(dest, dir_path);
+ strcat(dest, "/");
+ char *dest_end = dest + strlen(dest);
+ while ((entry = readdir(dir)) != NULL)
+ {
+ strcat(dest, entry->d_name);
+ struct stat statbuf;
+ if (lstat(dest, &statbuf) == -1)
+ return false;
+ if ((statbuf.st_mode & S_IFMT) == S_IFCHR &&
+ statbuf.st_rdev == (dev_t)g_tty_nr)
+ return true;
+ *dest_end = '\0';
+ }
+ return false;
+}
+
+void print_func_tty(t_field_info *info)
+{
+ if (g_tty_nr == 0)
+ {
+ printf("%*c", info->width, '?');
+ return;
+ }
+
+ char tty_path[PATH_MAX + 1] = {0};
+ bool res = find_tty_in_dir("/dev", tty_path) ||
+ find_tty_in_dir("/dev/pts", tty_path);
+ if (!res)
+ {
+ printf("%*c", info->width, '?');
+ return;
}
+ printf("%*s", info->width, tty_path + 5);
}
-char full_format[] = "user pid ppid c stime tty time args";
-char long_format[] = "f s user pid ppid c pri ni addr sz wchan tty time cmd";
-char default_format[] = "pid tty time cmd";
-size_t fields_size = 0;
-t_field_info **field_infos = NULL;
+// sum of 1 if didn't exec and 4 if used super-user privileges
+void print_func_flags(t_field_info *info) { printf("%*o", info->width, 0); }
+void print_func_state(t_field_info *info) { printf("%*c", info->width, g_state); }
+void print_func_wchan(t_field_info *info) { printf("%*lu", info->width, g_wchan); }
+void print_func_sz(t_field_info *info) { printf("%*lu", info->width, g_vsize / g_page_size); }
+void print_func_vsz(t_field_info *info) { printf("%*lu", info->width, g_rss); }
+
+void print_func_cpu(t_field_info *info) { printf("%*u", info->width, 2); }
+void print_func_addr(t_field_info *info) { printf("%*c", info->width, '-'); }
-void field_infos_from_format(char *format)
+static t_field_info field_infos[] =
{
- size_t i;
+ {"args", "COMMAND", -30, &print_func_args},
+ {"comm", "COMMAND", -30, &print_func_comm},
+ {"pid", "PID", 7, &print_func_pid},
+ {"ppid", "PPID", 7, &print_func_ppid},
+ {"pgid", "PGID", 7, &print_func_pgrp},
+ {"etime", "ELAPSED", 10, &print_func_etime},
+ {"time", "TIME", 10, &print_func_time},
+
+ {"group", "GROUP", -8, &print_func_group},
+ {"rgroup", "RGROUP", -8, &print_func_group},
+ {"user", "USER", -8, &print_func_user},
+ {"ruser", "RUSER", -8, &print_func_user}, // real user in /proc/[pid]/status file
+
+ {"nice", "NI", 3, &print_func_nice},
+ {"pri", "PRI", 3, &print_func_priority},
+ {"tty", "TTY", -6, &print_func_tty},
+ {"f", "F", 1, &print_func_flags},
+ {"s", "S", 1, &print_func_state},
+ {"vsz", "VSZ", 9, &print_func_vsz},
+ {"sz", "SZ", 9, &print_func_sz},
+ {"wchan", "WCHAN", -6, &print_func_wchan},
+
+ {"c", "C", 2, &print_func_cpu},
+ {"addr", "ADDR", 4, &print_func_addr},
+};
+
+
+t_field_info *field_info_from_specifier(const char *specifier)
+{
+ for (size_t i = 0; i < sizeof(field_infos) / sizeof(t_field_info); i++)
+ if (strcmp(field_infos[i].specifier, specifier) == 0)
+ return (&field_infos[i]);
+ return (NULL);
+}
+
+static char g_full_format[] = "user pid ppid c stime tty time args";
+static char g_long_format[] = "f s user pid ppid c pri nice addr sz wchan tty time comm";
+static char g_default_format[] = "pid tty time comm";
+
+#define MINOR_MASK 0b01111111111100000000000000000000
+#define MINOR_MASK 0b01111111111100000000000000000000
+static size_t g_fields_size = 0;
+static t_field_info **g_fields = NULL;
+
+void fields_from_format(char *format)
+{
+ size_t i;
for (i = 0; format[i] != '\0'; i++)
if (isspace(format[i]) && isspace(format[i + 1]))
exit(1);
-
- fields_size = 0;
+ g_fields_size = 1;
for (i = 0; format[i] != '\0'; i++)
if (isspace(format[i]))
- fields_size++;
-
- field_infos = malloc(fields_size * sizeof(t_field_info*));
- if (field_infos == NULL)
+ g_fields_size++;
+ g_fields = malloc(g_fields_size * sizeof(t_field_info*));
+ if (g_fields == NULL)
exit(1);
-
i = 0;
char *specifier = NULL;
while ((specifier = strsep(&format, " ,")) != NULL)
{
- field_infos[i] = field_info_from_specifier(specifier);
- if (field_infos[i] == NULL)
+ g_fields[i] = field_info_from_specifier(specifier);
+ if (g_fields[i] == NULL)
+ {
+ fprintf(stderr, "Error: %s: is not a valid specifier\n", specifier);
exit(1);
+ }
i++;
}
}
-void print_header(void)
+void print_fields_headers(void)
{
- for (size_t i = 0; i < fields_size; i++)
- printf("%*s ", field_infos[i].width, field_infos[i].header);
+ for (size_t i = 0; i < g_fields_size; i++)
+ printf("%*s ", g_fields[i]->width, g_fields[i]->header);
+ fputc('\n', stdout);
}
-typedef struct
+/*
+static
+struct
{
- pid_t pid;
- char comm[TASK_COMM_LEN];
- char state;
- pid_t ppid;
- pid_t pgrp;
- int session;
- int tty_nr;
- int tpgid;
- unsigned int flags;
- unsigned long minflt;
- unsigned long cminflt;
- unsigned long majflt;
- unsigned long cmajflt;
- unsigned long utime;
- unsigned long stime;
- long cutime;
- long cstime;
- long priority;
- long nice;
- long num_threads;
- long itrealvalue;
- unsigned long long starttime;
- unsigned long vsize;
- long rss;
- unsigned long rsslim;
- unsigned long startcode;
- unsigned long endcode;
- unsigned long startstack;
- unsigned long kstkesp;
- unsigned long kstkeip;
- unsigned long signal;
- unsigned long blocked;
- unsigned long sigignore;
- unsigned long sigcatch;
- unsigned long wchan;
- unsigned long nswap;
- unsigned long cnswap;
- int exit_signal;
- int processor;
- unsigned int rt_priority;
- unsigned long delayacct_blkio_ticks;
- unsigned long guest_time;
- long cguest_time;
- unsigned long end_data;
- unsigned long start_brk;
- unsigned long arg_start;
- unsigned long arg_end;
- unsigned long env_start;
- unsigned long env_end;
- int exit_code;
-} t_proc_stat;
+ char *specifier;
+ void *store;
+}
+g_stat_file_parsing_entries[] =
+{
+ {"%d", &g_pid},
+ {"%s", &g_comm},
+ {"%c", &g_state},
+ {"%d", &g_ppid},
+ {"%d", &g_pgrp},
+ {"%d", NULL}, // session
+ {"%d", &g_tty_nr},
+ {"%d", NULL}, // tpgid
+ {"%u", &g_flags},
+ {"%lu", NULL}, // minflt
+ {"%lu", NULL}, // cminflt
+ {"%lu", NULL}, // majflt
+ {"%lu", NULL}, // cmajflt
+ {"%lu", NULL}, // utime
+ {"%lu", NULL}, // stime
+ {"%ld", NULL}, // cutime
+ {"%ld", NULL}, // cstime
+ {"%ld", NULL}, // priority
+ {"%ld", &g_nice},
+ {"%ld", NULL}, // num_threads
+ {"%ld", NULL}, // itrealvalue
+ {"%llu", &g_starttime},
+ {"%lu", &g_vsize},
+ {"%ld", NULL}, // rss
+ {"%lu", NULL}, // rsslim
+ {"%lu", NULL}, // startcode
+ {"%lu", NULL}, // endcode
+ {"%lu", NULL}, // startstack
+ {"%lu", NULL}, // kstkesp
+ {"%lu", NULL}, // kstkeip
+ {"%lu", NULL}, // signal
+ {"%lu", NULL}, // blocked
+ {"%lu", NULL}, // sigignore
+ {"%lu", NULL}, // sigcatch
+ {"%lu", &g_wchan},
+ {"%lu", NULL}, // nswap
+ {"%lu", NULL}, // cnswap
+ {"%d", NULL}, // exit_signal
+ {"%d", NULL}, // processor
+ {"%u", NULL}, // rt_priority
+ {"%llu", NULL}, // delayacct_blkio_ticks
+ {"%lu", NULL}, // guest_time
+ {"%ld", NULL}, // cguest_time
+ {"%lu", NULL}, // end_data
+ {"%lu", NULL}, // start_brk
+ {"%lu", NULL}, // arg_start
+ {"%lu", NULL}, // arg_end
+ {"%lu", NULL}, // env_start
+ {"%lu", NULL}, // env_end
+ {"%d", NULL}, // exit_cod
+};
+*/
-int main(int argc, char **argv)
+void parse_stat_file(FILE *stat_file)
{
- field_infos_from_format(default_format);
+ fscanf(
+ stat_file,
+ "%*d %s %c %d %d %*d %d %*d %u %*lu %*lu %*lu %*lu %*lu %*lu %*ld %*ld %*ld "
+ "%ld %*ld %*ld %llu %lu %ld %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu "
+ "%lu %*lu %*lu %*d %*d %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %*d",
+ /* &g_pid, */
+ g_comm,
+ &g_state,
+ &g_ppid,
+ &g_pgrp,
+ &g_tty_nr,
+ &g_flags,
+ &g_nice,
+ &g_starttime,
+ &g_vsize,
+ &g_rss,
+ &g_wchan
+ );
+}
- free(field_infos);
- return;
+int main(int argc, char **argv)
+{
+ g_page_size = getpagesize();
+ g_clock_tick = sysconf(_SC_CLK_TCK);
+
+ char format[] = "sz vsz comm";
- page_size = getpagesize();
- clock_tick = sysconf(_SC_CLK_TCK);
+ fields_from_format(g_long_format);
+ print_fields_headers();
DIR *proc_dir = opendir(PROC_DIR);
if (proc_dir == NULL)
@@ -285,81 +367,25 @@ int main(int argc, char **argv)
struct dirent *proc_dir_entry = NULL;
while ((proc_dir_entry = readdir(proc_dir)) != NULL)
{
- pid_t pid = 0;
- if (sscanf(proc_dir_entry->d_name, "%d", &pid) != 1)
- continue;
-
- char file_path[PATH_MAX + 1] = {'\0'};
- snprintf(file_path, PATH_MAX, "%s/%d/stat", PROC_DIR, pid);
- FILE *stat_file = fopen(file_path, "r");
- if (stat_file == NULL)
+ if (sscanf(proc_dir_entry->d_name, "%d", &g_pid) != 1)
continue;
-
- t_proc_stat proc_stat;
- fscanf(
- stat_file,
- "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld "
- "%llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u "
- "%llu %lu %ld %lu %lu %lu %lu %lu %lu %d",
- &proc_stat.pid,
- &proc_stat.comm,
- &proc_stat.state,
- &proc_stat.ppid,
- &proc_stat.pgrp,
- &proc_stat.session,
- &proc_stat.tty_nr,
- &proc_stat.tpgid,
- &proc_stat.flags,
- &proc_stat.minflt,
- &proc_stat.cminflt,
- &proc_stat.majflt,
- &proc_stat.cmajflt,
- &proc_stat.utime,
- &proc_stat.stime,
- &proc_stat.cutime,
- &proc_stat.cstime,
- &proc_stat.priority,
- &proc_stat.nice,
- &proc_stat.num_threads,
- &proc_stat.itrealvalue,
- &proc_stat.starttime,
- &proc_stat.vsize,
- &proc_stat.rss,
- &proc_stat.rsslim,
- &proc_stat.startcode,
- &proc_stat.endcode,
- &proc_stat.startstack,
- &proc_stat.kstkesp,
- &proc_stat.kstkeip,
- &proc_stat.signal,
- &proc_stat.blocked,
- &proc_stat.sigignore,
- &proc_stat.sigcatch,
- &proc_stat.wchan,
- &proc_stat.nswap,
- &proc_stat.cnswap,
- &proc_stat.exit_signal,
- &proc_stat.processor,
- &proc_stat.rt_priority,
- &proc_stat.delayacct_blkio_ticks,
- &proc_stat.guest_time,
- &proc_stat.cguest_time,
- &proc_stat.end_data,
- &proc_stat.start_brk,
- &proc_stat.arg_start,
- &proc_stat.arg_end,
- &proc_stat.env_start,
- &proc_stat.env_end,
- &proc_stat.exit_code
- );
-
+ snprintf(g_file_path, PATH_MAX, PROC_DIR"/%d/stat", g_pid);
struct stat statbuf;
- if (stat(file_path, &statbuf) == -1)
+ if (stat(g_file_path, &statbuf) == -1)
continue;
-
+ g_uid = statbuf.st_uid;
+ g_gid = statbuf.st_gid;
+ FILE *stat_file = fopen(g_file_path, "r");
+ if (stat_file == NULL)
+ continue;
+ parse_stat_file(stat_file);
+ for (size_t i = 0; i < g_fields_size; i++)
+ {
+ (g_fields[i]->print_func)(g_fields[i]);
+ fputc(' ', stdout);
+ }
fputc('\n', stdout);
- break;
}
-
+ closedir(proc_dir);
return 0;
}