aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--LICENSE21
-rwxr-xr-xmake9
-rwxr-xr-xsrc/main.c239
4 files changed, 271 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..534cfcc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.clangd
+bin/**
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e4e5954
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 iceyrazor
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/make b/make
new file mode 100755
index 0000000..54d8b21
--- /dev/null
+++ b/make
@@ -0,0 +1,9 @@
+#!/bin/sh
+LIB=""
+
+echo make
+if [[ "$1" == "debug" ]]; then
+ clang -o ./bin/shell ./src/main.c $LIB -Wall -g -fsanitize=address
+else
+ clang -o ./bin/shell ./src/main.c $LIB
+fi
diff --git a/src/main.c b/src/main.c
new file mode 100755
index 0000000..e07319a
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,239 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define LSH_RL_BUFSIZE 1024
+char *lsh_read_line(void)
+{
+ int bufsize = LSH_RL_BUFSIZE;
+ int position = 0;
+ char *buffer = malloc(sizeof(char) * bufsize);
+ int c;
+
+ if (!buffer) {
+ fprintf(stderr, "lsh: allocation error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ while (1) {
+ // Read a character
+ c = getchar();
+
+ // If we hit EOF, replace it with a null character and return.
+ if (c == EOF || c == '\n') {
+ buffer[position] = '\0';
+ return buffer;
+ } else {
+ buffer[position] = c;
+ }
+ position++;
+
+ // If we have exceeded the buffer, reallocate.
+ if (position >= bufsize) {
+ bufsize += LSH_RL_BUFSIZE;
+ buffer = realloc(buffer, bufsize);
+ if (!buffer) {
+ fprintf(stderr, "lsh: allocation error\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+}
+
+#define LSH_TOK_BUFSIZE 64
+#define LSH_TOK_DELIM " \t\r\n\a"
+char **lsh_split_line(char *line)
+{
+ int bufsize = LSH_TOK_BUFSIZE, position = 0;
+ char **tokens = malloc(bufsize * sizeof(char*));
+ char *token;
+
+ if (!tokens) {
+ fprintf(stderr, "lsh: allocation error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ token = strtok(line, LSH_TOK_DELIM);
+ while (token != NULL) {
+ tokens[position] = token;
+ position++;
+
+ if (position >= bufsize) {
+ bufsize += LSH_TOK_BUFSIZE;
+ tokens = realloc(tokens, bufsize * sizeof(char*));
+ if (!tokens) {
+ fprintf(stderr, "lsh: allocation error\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ token = strtok(NULL, LSH_TOK_DELIM);
+ }
+ tokens[position] = NULL;
+ return tokens;
+}
+
+int lsh_launch(char **args)
+{
+ pid_t pid, wpid;
+ int status;
+
+ pid = fork();
+ if (pid == 0) {
+ // Child process
+ if (execvp(args[0], args) == -1) {
+ perror("lsh");
+ }
+ exit(EXIT_FAILURE);
+ } else if (pid < 0) {
+ // Error forking
+ perror("lsh");
+ } else {
+ // Parent process
+ do {
+ wpid = waitpid(pid, &status, WUNTRACED);
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+ }
+
+ return 1;
+}
+
+/*
+ Function Declarations for builtin shell commands:
+ */
+int lsh_cd(char **args);
+int lsh_help(char **args);
+int lsh_exit(char **args);
+
+/*
+ List of builtin commands, followed by their corresponding functions.
+ */
+char *builtin_str[] = {
+ "cd",
+ "help",
+ "exit"
+};
+
+int (*builtin_func[]) (char **) = {
+ &lsh_cd,
+ &lsh_help,
+ &lsh_exit
+};
+
+int lsh_num_builtins() {
+ return sizeof(builtin_str) / sizeof(char *);
+}
+
+/*
+ Builtin function implementations.
+*/
+int lsh_cd(char **args)
+{
+ if (args[1] == NULL) {
+ fprintf(stderr, "lsh: expected argument to \"cd\"\n");
+ } else {
+ if (chdir(args[1]) != 0) {
+ perror("lsh");
+ }
+ }
+ return 1;
+}
+
+int lsh_help(char **args)
+{
+ int i;
+ printf("Stephen Brennan's LSH\n");
+ printf("Type program names and arguments, and hit enter.\n");
+ printf("The following are built in:\n");
+
+ for (i = 0; i < lsh_num_builtins(); i++) {
+ printf(" %s\n", builtin_str[i]);
+ }
+
+ printf("Use the man command for information on other programs.\n");
+ return 1;
+}
+
+int lsh_exit(char **args)
+{
+ return 0;
+}
+
+
+
+int lsh_execute(char **args)
+{
+ int i;
+
+ if (args[0] == NULL) {
+ // An empty command was entered.
+ return 1;
+ }
+
+ for (i = 0; i < lsh_num_builtins(); i++) {
+ if (strcmp(args[0], builtin_str[i]) == 0) {
+ return (*builtin_func[i])(args);
+ }
+ }
+
+ return lsh_launch(args);
+}
+
+
+typedef struct{
+ char *prompt;
+} SHELL_OB;
+
+void lsh_loop(SHELL_OB *shell_obj)
+{
+ char *line;
+ char **args;
+ int status;
+
+ do {
+ printf("%s",shell_obj->prompt);
+ line = lsh_read_line();
+ args = lsh_split_line(line);
+ status = lsh_execute(args);
+
+ free(line);
+ free(args);
+ } while (status);
+}
+
+int main(int argc, char **argv){
+ SHELL_OB shell_obj;
+
+ //very jank lol
+ char *hostname = NULL;
+ long file_size;
+ FILE *hostfile = fopen("/etc/hostname","r");
+ if (hostfile != NULL){
+ fseek(hostfile, 0, SEEK_END);
+ file_size = ftell(hostfile);
+ rewind(hostfile);
+
+ hostname = (char *)malloc(file_size + 1 + 24);
+ fread(hostname, file_size, 1, hostfile);
+ hostname[file_size+1] = '\0';
+
+ fclose(hostfile);
+
+ for (int i = file_size-1; i > -1; i--){
+ hostname[i+1] = hostname[i];
+ }
+ hostname[0] = '@';
+ hostname[file_size] = '\0';
+ } else {
+ hostname = (char *)malloc(1);
+ hostname[0] = '\0';
+ }
+ shell_obj.prompt=strcat(strcat(getenv("USER"), (char *)hostname), "> ");
+
+ lsh_loop(&shell_obj);
+
+ free(hostname);
+ return EXIT_SUCCESS;
+}