summary refs log tree commit diff
diff options
context:
space:
mode:
authorSingustromo <singustromo@disroot.org>2024-05-19 03:49:20 +0200
committerSingustromo <singustromo@disroot.org>2024-05-19 03:49:20 +0200
commitb5834f69641f54110c78d8d642cb6afa5b3a124e (patch)
tree2612d86b71f1d67612b7d929b516777827e8ab29
parent5cd0bbde6fbe6325d00bb5e1b2b7331757f0dcf3 (diff)
downloadoperating-systems_3_clash-b5834f69641f54110c78d8d642cb6afa5b3a124e.tar.gz
operating-systems_3_clash-b5834f69641f54110c78d8d642cb6afa5b3a124e.zip
Crude first implementation
-rw-r--r--Makefile8
-rw-r--r--src/clash.c148
-rw-r--r--src/clash.h0
-rw-r--r--src/plist.c4
4 files changed, 151 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index 59ba575..9e6f02c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,12 @@
-.PHONY: clean test test-spec
-
-SHELL = /bin/bash
+.PHONY: clean
 
 CC = gcc
-CFLAGS = -Wall -Werror -std=c11 -pedantic -D_XOPEN_SOURCE=700
+CFLAGS = -std=c11 -pedantic -Wall -Werror -D_XOPEN_SOURCE=700 -O0 -g
 VPATH=src # search for a prerequisite in those directories (delimiter is :)
 
 BUILD_TARGET=clash
 BUILD_DIR=bin
-OBJS = $(patsubst %.o, $(BUILD_DIR)/%.o, plist.o $(BUILD_TARGET).o)
+OBJS = $(patsubst %.o, $(BUILD_DIR)/%.o, plist.o strictmem.o $(BUILD_TARGET).o)
 
 $(BUILD_TARGET): $(OBJS)
 	$(CC) -o $@ $(CFLAGS) $(OBJS)
diff --git a/src/clash.c b/src/clash.c
index e41edc3..2717e1f 100644
--- a/src/clash.c
+++ b/src/clash.c
@@ -1,8 +1,152 @@
+#include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
+
+#include <unistd.h>
+#include <string.h>             // e.g. strtok
+#include <linux/limits.h>       // e.g. PATH_MAX
+#include <sys/wait.h>
 
-#include "clash.h"
 #include "plist.h"
 
-int main(int argc, char* argv[]) {
+#define PROMPTSIZE 1337
+#define MAX_PARAMETERS 50
+
+static int getline_skew(char *buffer, int limit);
+
+static bool update_current_path(char *path);
+static void print_prompt(char *current_path, int child_exitcode, int job_count);
+
+static int process_commandline(char *prompt, char **command, char *parameters[]);
+
+int main(int argc, char *argv[]) {
+        char current_path[PATH_MAX];
+        char prompt[PROMPTSIZE];
+
+        if (! update_current_path(current_path))
+                exit(EXIT_FAILURE);
+
+        int prompt_length, cmdline_arg_count;
+        prompt_length = cmdline_arg_count = 0;
+
+        char *command = NULL, *cmdline[MAX_PARAMETERS];
+        int background_jobs = 0;
+
+        print_prompt(current_path, 0, 0);
+        while ((prompt_length = getline_skew(prompt, PROMPTSIZE)) > 0) {
+                if (prompt_length == 1) {
+                        print_prompt(current_path, 0, 0);
+                        continue;
+                } else if (prompt_length > PROMPTSIZE) {
+                        fprintf(stderr, "[!] input line is too long!\n");
+                        print_prompt(current_path, 0, 0);
+                        continue;
+                }
+
+                if ((cmdline_arg_count = process_commandline(prompt, &command, cmdline)) < 1) {
+                        printf("[!] ");
+                        print_prompt(current_path, 0, 0);
+                        continue;
+                }
+
+                bool background_job = false;
+
+                // Determine, if it should be executed in the background
+                if (strcmp(cmdline[cmdline_arg_count -1], "&") == 0) { // we only check last token
+                        cmdline[cmdline_arg_count -1] = NULL; // for exec
+                        background_job = true;
+                } else 
+                        cmdline[cmdline_arg_count] = NULL;
+
+                int wstatus = 0; // status information of child process
+                pid_t child_pid = fork();
+                if (child_pid == -1) {
+                        perror("[!] fork");
+                        print_prompt(current_path, 0, background_jobs);
+                        continue;
+                } else if (child_pid == 0) // child process
+                       if (execvp(command, cmdline) == -1) // command failed?
+                                exit(EXIT_FAILURE);
+
+                if (! background_job) {
+                        do {
+                                child_pid = wait(&wstatus);
+                        } while (! WIFEXITED(wstatus) && ! WIFSIGNALED(wstatus));
+                } else {
+                        insertElement(child_pid, prompt);
+                        printf("[%d] %d\n", ++background_jobs, child_pid);
+                }
+
+                print_prompt(current_path, WEXITSTATUS(wstatus), background_jobs);
+        }
+
+        puts("\0"); // terminate output properly
         exit(EXIT_SUCCESS);
 }
+
+/* Saves address of tokens into command pointer and parameter pointer array
+ * command is duplicated into array[0]
+ *
+ * @returns     token count (0 on error)
+ */
+static int process_commandline(char *prompt, char **command, char *parameters[]) {
+        char *previous_token, *current_token;
+        int token_index = 0;
+
+        *command = strtok(prompt, "\n\t "); // do not include new line
+        if (! *command) return token_index;
+
+        // according to specification argv[0]
+        parameters[token_index++] = *command;
+
+        previous_token = prompt;
+        while ((current_token = strtok(NULL, "\n\t ")) != NULL) {
+                if (previous_token > prompt)
+                        parameters[token_index++] = previous_token;
+
+                previous_token = current_token;
+        }
+
+        if (previous_token > prompt) // still need to save pointer of another token?
+                parameters[token_index++] = previous_token;
+
+        return token_index;
+}
+
+static void print_prompt(char *current_path, int child_exitcode, int job_count) {
+        if (child_exitcode != 0)
+                printf("[%d] ", child_exitcode);
+
+        printf("%s: ", current_path);
+}
+
+static bool update_current_path(char *path) {
+        if (getcwd(path, PATH_MAX) == NULL) {
+                perror("[!] unable to get current working directory");
+                return false;
+        }
+
+        return true;
+}
+
+/*
+ * Reads data until new line or up to (limit -1) characters (NUL byte)
+ * If limit is reached, it truncates the rest of the line and
+ * updates the character count accordingly. Omits new line
+ *
+ * @returns     character count (counts new line)
+ */
+static int getline_skew(char *buffer, int limit) {
+        int c, charcount;
+
+        for (charcount = 0; (c = getchar()) != EOF && c != '\n'; ++charcount)
+                if (charcount < limit) // otherwise seek further
+                        buffer[charcount] = c;
+
+        if (c == '\n' && charcount < limit)
+                buffer[charcount++] = c;
+
+        buffer[(charcount < limit) ? charcount: limit -1] = '\0';
+
+        return charcount;
+}
diff --git a/src/clash.h b/src/clash.h
deleted file mode 100644
index e69de29..0000000
--- a/src/clash.h
+++ /dev/null
diff --git a/src/plist.c b/src/plist.c
index 2767e34..9a60330 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -20,8 +20,8 @@ static struct queue_element *head;
 void walkList(bool (*callback) (pid_t, const char *)) {
         struct queue_element* current = head;
 
-        while (current && (callback(current->pid, current->cmdLine) != 0))
-                ;
+        while (current && (callback(current->pid, current->cmdLine) == false))
+                current = current->next;
 }
 
 int insertElement(pid_t pid, const char *cmdLine) {