diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2021-04-25 16:28:47 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2021-04-25 16:28:47 +0200 |
| commit | 4a325349867772002e4db87954e0c2ee6955c83d (patch) | |
| tree | 8093076667fb79af23d78fa7f8411efaad5ebddb /src/ps.c | |
| parent | 4bf2054147f3eaa8c9695710fe7ed39cb713e9c5 (diff) | |
| download | coreutils-4a325349867772002e4db87954e0c2ee6955c83d.tar.gz coreutils-4a325349867772002e4db87954e0c2ee6955c83d.tar.bz2 coreutils-4a325349867772002e4db87954e0c2ee6955c83d.zip | |
Added ps basic functionality
Diffstat (limited to 'src/ps.c')
| -rw-r--r-- | src/ps.c | 588 |
1 files changed, 307 insertions, 281 deletions
@@ -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; } |
