procfs extensions and ps command
This commit is contained in:
parent
ff429a7d07
commit
6f94ce2296
@ -1,8 +1,17 @@
|
||||
#include <system.h>
|
||||
#include <logging.h>
|
||||
#include <fs.h>
|
||||
#include <version.h>
|
||||
#include <process.h>
|
||||
|
||||
#define PROCFS_STANDARD_ENTRIES 5
|
||||
#define PROCFS_PROCDIR_ENTRIES 2
|
||||
|
||||
struct procfs_entry {
|
||||
int id;
|
||||
char * name;
|
||||
read_type_t func;
|
||||
};
|
||||
|
||||
static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) {
|
||||
fs_node_t * fnode = malloc(sizeof(fs_node_t));
|
||||
@ -21,12 +30,113 @@ static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) {
|
||||
return fnode;
|
||||
}
|
||||
|
||||
struct procfs_entry {
|
||||
int id;
|
||||
char * name;
|
||||
read_type_t func;
|
||||
uint32_t proc_cmdline_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
char buf[1024];
|
||||
process_t * proc = process_from_pid(node->inode);
|
||||
|
||||
if (!proc) {
|
||||
/* wat */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
char * _buf = buf;
|
||||
char ** args = proc->cmdline;
|
||||
while (*args) {
|
||||
strcpy(_buf, *args);
|
||||
_buf += strlen(_buf);
|
||||
if (*(args+1)) {
|
||||
strcpy(_buf, "\036");
|
||||
_buf += strlen(_buf);
|
||||
}
|
||||
args++;
|
||||
}
|
||||
|
||||
size_t _bsize = strlen(buf);
|
||||
if (offset > _bsize) return 0;
|
||||
if (size > _bsize - offset) size = _bsize - offset;
|
||||
|
||||
memcpy(buffer, buf + offset, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
char buf[2048];
|
||||
process_t * proc = process_from_pid(node->inode);
|
||||
|
||||
if (!proc) {
|
||||
/* wat */
|
||||
return 0;
|
||||
}
|
||||
|
||||
char state = process_is_ready(proc) ? 'R' : 'S';
|
||||
|
||||
sprintf(buf,
|
||||
"Name:\t%s\n" /* name */
|
||||
"State:\t%c\n" /* yeah, do this at some point */
|
||||
"Tgid:\t%d\n" /* group ? group : pid */
|
||||
"Pid:\t%d\n" /* pid */
|
||||
"Uid:\t%d\n"
|
||||
, proc->name, state, proc->group ? proc->group : proc->id, proc->id, proc->user);
|
||||
|
||||
size_t _bsize = strlen(buf);
|
||||
if (offset > _bsize) return 0;
|
||||
if (size > _bsize - offset) size = _bsize - offset;
|
||||
|
||||
memcpy(buffer, buf + offset, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static struct procfs_entry procdir_entries[] = {
|
||||
{1, "cmdline", proc_cmdline_func},
|
||||
{2, "status", proc_status_func},
|
||||
};
|
||||
|
||||
static struct dirent * readdir_procfs_procdir(fs_node_t *node, uint32_t index) {
|
||||
if (index < PROCFS_PROCDIR_ENTRIES) {
|
||||
struct dirent * out = malloc(sizeof(struct dirent));
|
||||
memset(out, 0x00, sizeof(struct dirent));
|
||||
out->ino = procdir_entries[index].id;
|
||||
strcpy(out->name, procdir_entries[index].name);
|
||||
return out;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fs_node_t * finddir_procfs_procdir(fs_node_t * node, char * name) {
|
||||
if (!name) return NULL;
|
||||
|
||||
for (int i = 0; i < PROCFS_PROCDIR_ENTRIES; ++i) {
|
||||
if (!strcmp(name, procdir_entries[i].name)) {
|
||||
fs_node_t * out = procfs_generic_create(procdir_entries[i].name, procdir_entries[i].func);
|
||||
out->inode = node->inode;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static fs_node_t * procfs_procdir_create(pid_t pid) {
|
||||
fs_node_t * fnode = malloc(sizeof(fs_node_t));
|
||||
memset(fnode, 0x00, sizeof(fs_node_t));
|
||||
fnode->inode = pid;
|
||||
sprintf(fnode->name, "%d", pid);
|
||||
fnode->uid = 0;
|
||||
fnode->gid = 0;
|
||||
fnode->flags = FS_DIRECTORY;
|
||||
fnode->read = NULL;
|
||||
fnode->write = NULL;
|
||||
fnode->open = NULL;
|
||||
fnode->close = NULL;
|
||||
fnode->readdir = readdir_procfs_procdir;
|
||||
fnode->finddir = finddir_procfs_procdir;
|
||||
return fnode;
|
||||
}
|
||||
|
||||
uint32_t cpuinfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
||||
return 0;
|
||||
}
|
||||
@ -94,13 +204,12 @@ uint32_t version_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static struct procfs_entry std_entries[] = {
|
||||
{0, "cpuinfo", cpuinfo_func},
|
||||
{1, "meminfo", meminfo_func},
|
||||
{2, "uptime", uptime_func},
|
||||
{3, "cmdline", cmdline_func},
|
||||
{4, "version", version_func},
|
||||
{-1, "cpuinfo", cpuinfo_func},
|
||||
{-2, "meminfo", meminfo_func},
|
||||
{-3, "uptime", uptime_func},
|
||||
{-4, "cmdline", cmdline_func},
|
||||
{-5, "version", version_func},
|
||||
};
|
||||
|
||||
static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) {
|
||||
@ -111,8 +220,31 @@ static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) {
|
||||
strcpy(out->name, std_entries[index].name);
|
||||
return out;
|
||||
}
|
||||
/* XXX process entries */
|
||||
return NULL;
|
||||
int i = index - PROCFS_STANDARD_ENTRIES + 1;
|
||||
|
||||
debug_print(WARNING, "%d %d %d", i, index, PROCFS_STANDARD_ENTRIES);
|
||||
|
||||
pid_t pid = 0;
|
||||
|
||||
foreach(lnode, process_list) {
|
||||
i--;
|
||||
if (i == 0) {
|
||||
process_t * proc = (process_t *)lnode->value;
|
||||
pid = proc->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dirent * out = malloc(sizeof(struct dirent));
|
||||
memset(out, 0x00, sizeof(struct dirent));
|
||||
out->ino = pid;
|
||||
sprintf(out->name, "%d", pid);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static fs_node_t * finddir_procfs_root(fs_node_t * node, char * name) {
|
||||
@ -121,7 +253,13 @@ static fs_node_t * finddir_procfs_root(fs_node_t * node, char * name) {
|
||||
|
||||
if (name[0] >= '0' && name[0] <= '9') {
|
||||
/* XXX process entries */
|
||||
return NULL;
|
||||
pid_t pid = atoi(name);
|
||||
process_t * proc = process_from_pid(pid);
|
||||
if (!proc) {
|
||||
return NULL;
|
||||
}
|
||||
fs_node_t * out = procfs_procdir_create(pid);
|
||||
return out;
|
||||
}
|
||||
|
||||
for (int i = 0; i < PROCFS_STANDARD_ENTRIES; ++i) {
|
||||
|
@ -72,6 +72,8 @@ typedef struct process {
|
||||
char * description; /* Process description */
|
||||
user_t user; /* Effective user */
|
||||
|
||||
char ** cmdline;
|
||||
|
||||
pid_t group; /* Process thread group */
|
||||
pid_t job; /* Process job group */
|
||||
pid_t session; /* Session group */
|
||||
@ -124,4 +126,6 @@ void sleep_until(process_t * process, unsigned long seconds, unsigned long subse
|
||||
|
||||
volatile process_t * current_process;
|
||||
|
||||
list_t * process_list;
|
||||
|
||||
#endif
|
||||
|
@ -55,6 +55,8 @@ exec(
|
||||
current_process->name = malloc(strlen(path) + 1);
|
||||
memcpy(current_process->name, path, strlen(path) + 1);
|
||||
|
||||
current_process->cmdline = argv;
|
||||
|
||||
/* Alright, we've read the binary, time to load the loadable sections */
|
||||
/* Verify the magic */
|
||||
if ( header->e_ident[0] != ELFMAG0 ||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <logging.h>
|
||||
|
||||
tree_t * process_tree; /* Parent->Children tree */
|
||||
list_t * process_list; /* Flat storage */
|
||||
list_t * process_queue; /* Ready queue */
|
||||
list_t * reap_queue; /* Processes to reap */
|
||||
list_t * sleep_queue;
|
||||
@ -28,6 +29,7 @@ char * default_name = "[unnamed]";
|
||||
*/
|
||||
void initialize_process_tree() {
|
||||
process_tree = tree_create();
|
||||
process_list = list_create();
|
||||
process_queue = list_create();
|
||||
reap_queue = list_create();
|
||||
sleep_queue = list_create();
|
||||
@ -126,6 +128,7 @@ void delete_process(process_t * proc) {
|
||||
/* Remove the entry. */
|
||||
spin_lock(&tree_lock);
|
||||
tree_remove(process_tree, entry);
|
||||
list_delete(process_list, list_find(process_list, proc));
|
||||
spin_unlock(&tree_lock);
|
||||
|
||||
free(proc);
|
||||
@ -150,6 +153,7 @@ process_t * spawn_init() {
|
||||
init->id = 0; /* Init is PID 1 */
|
||||
init->group = 0;
|
||||
init->name = strdup("init"); /* Um, duh. */
|
||||
init->cmdline = NULL;
|
||||
init->user = 0; /* UID 0 */
|
||||
init->group = 0; /* Task group 0 */
|
||||
init->status = 0; /* Run status */
|
||||
@ -237,6 +241,7 @@ process_t * spawn_process(volatile process_t * parent) {
|
||||
proc->group = proc->id; /* Set the GID */
|
||||
proc->name = strdup(default_name); /* Use the default name */
|
||||
proc->description = NULL; /* No description */
|
||||
proc->cmdline = parent->cmdline;
|
||||
|
||||
/* Copy permissions */
|
||||
proc->user = parent->user;
|
||||
@ -303,6 +308,7 @@ process_t * spawn_process(volatile process_t * parent) {
|
||||
proc->tree_entry = entry;
|
||||
spin_lock(&tree_lock);
|
||||
tree_node_insert_child_node(process_tree, parent->tree_entry, entry);
|
||||
list_insert(process_list, (void *)proc);
|
||||
spin_unlock(&tree_lock);
|
||||
|
||||
/* Return the new process */
|
||||
@ -454,7 +460,7 @@ int sleep_on(list_t * queue) {
|
||||
}
|
||||
|
||||
int process_is_ready(process_t * proc) {
|
||||
if (proc->sched_node.prev != NULL || proc->sched_node.next != NULL) return 1;
|
||||
if (proc->sched_node.prev != NULL || proc->sched_node.next != NULL || process_queue->head == &proc->sched_node) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -203,11 +203,12 @@ static int execve(const char * filename, char *const argv[], char *const envp[])
|
||||
while (envp[envc]) { ++envc; }
|
||||
}
|
||||
debug_print(INFO, "Allocating space for arguments...");
|
||||
char ** argv_ = malloc(sizeof(char *) * argc);
|
||||
char ** argv_ = malloc(sizeof(char *) * (argc + 1));
|
||||
for (int j = 0; j < argc; ++j) {
|
||||
argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char));
|
||||
memcpy(argv_[j], argv[j], strlen(argv[j]) + 1);
|
||||
}
|
||||
argv_[argc] = 0;
|
||||
char ** envp_;
|
||||
if (envp && envc) {
|
||||
envp_ = malloc(sizeof(char *) * (envc + 1));
|
||||
|
@ -237,7 +237,6 @@ int main (int argc, char * argv[]) {
|
||||
qsort(ents_array, numents, sizeof(struct dirent *), entcmp);
|
||||
|
||||
if (long_mode) {
|
||||
printf("printing listing\n");
|
||||
for (int i = 0; i < numents; i++) {
|
||||
print_entry_long(ents_array[i]->d_name, p);
|
||||
}
|
||||
|
147
userspace/core/ps.c
Normal file
147
userspace/core/ps.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* ps
|
||||
*
|
||||
* print a list of running processes
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "lib/list.h"
|
||||
|
||||
#define LINE_LEN 4096
|
||||
|
||||
void print_username(int uid) {
|
||||
FILE * passwd = fopen("/etc/passwd", "r");
|
||||
char line[LINE_LEN];
|
||||
|
||||
while (fgets(line, LINE_LEN, passwd) != NULL) {
|
||||
|
||||
line[strlen(line)-1] = '\0';
|
||||
|
||||
char *p, *tokens[10], *last;
|
||||
int i = 0;
|
||||
for ((p = strtok_r(line, ":", &last)); p; (p = strtok_r(NULL, ":", &last)), i++) {
|
||||
if (i < 511) tokens[i] = p;
|
||||
}
|
||||
tokens[i] = NULL;
|
||||
|
||||
if (atoi(tokens[2]) == uid) {
|
||||
printf("%-8s", tokens[0]);
|
||||
fclose(passwd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
printf("%-8d", uid);
|
||||
fclose(passwd);
|
||||
}
|
||||
|
||||
void print_entry(struct dirent * dent) {
|
||||
char tmp[256], buf[4096];
|
||||
FILE * f;
|
||||
int read = 1;
|
||||
char line[LINE_LEN];
|
||||
|
||||
int pid, uid;
|
||||
|
||||
snprintf(tmp, 256, "/proc/%s/status", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
|
||||
while (fgets(line, LINE_LEN, f) != NULL) {
|
||||
if (strstr(line, "Pid:") == line) {
|
||||
sscanf(line, "%s %d", &buf, &pid);
|
||||
} else if (strstr(line, "Uid:") == line) {
|
||||
sscanf(line, "%s %d", &buf, &uid);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
print_username(uid);
|
||||
printf(" %5d ", pid);
|
||||
|
||||
snprintf(tmp, 256, "/proc/%s/cmdline", dent->d_name);
|
||||
f = fopen(tmp, "r");
|
||||
memset(buf, 0x00, 4096);
|
||||
read = fread(buf, 1, 4096, f);
|
||||
fclose(f);
|
||||
|
||||
buf[read] = '\0';
|
||||
for (int i = 0; i < read; ++i) {
|
||||
if (buf[i] == '\036') {
|
||||
buf[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
void show_usage(int argc, char * argv[]) {
|
||||
printf(
|
||||
"ps - list running processes\n"
|
||||
"\n"
|
||||
"usage: %s [-A] [format]\n"
|
||||
"\n"
|
||||
" -A \033[3mignored\033[0m\n"
|
||||
" -? \033[3mshow this help text\033[0m\n"
|
||||
"\n", argv[0]);
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
|
||||
/* Parse arguments */
|
||||
int show_all = 0;
|
||||
|
||||
if (argc > 1) {
|
||||
int index, c;
|
||||
while ((c = getopt(argc, argv, "A?")) != -1) {
|
||||
switch (c) {
|
||||
case 'A':
|
||||
show_all = 1;
|
||||
break;
|
||||
case '?':
|
||||
show_usage(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the directory */
|
||||
DIR * dirp = opendir("/proc");
|
||||
|
||||
/* Read the entries in the directory */
|
||||
list_t * ents_list = list_create();
|
||||
|
||||
struct dirent * ent = readdir(dirp);
|
||||
while (ent != NULL) {
|
||||
if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
|
||||
struct dirent * entcpy = malloc(sizeof(struct dirent));
|
||||
memcpy(entcpy, ent, sizeof(struct dirent));
|
||||
list_insert(ents_list, (void *)entcpy);
|
||||
}
|
||||
|
||||
ent = readdir(dirp);
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
foreach(entry, ents_list) {
|
||||
print_entry(entry->value);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vim: tabstop=4
|
||||
* vim: shiftwidth=4
|
||||
* vim: noexpandtab
|
||||
*/
|
Loading…
Reference in New Issue
Block a user