Created
November 7, 2023 19:09
-
-
Save xarblu/1b6a7a4286e01ede4bbb4af37138ea76 to your computer and use it in GitHub Desktop.
mush - the Memory Unsafe SHell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * mush - the Memory Unsafe SHell | |
| * a crappy shell written in dirty C | |
| * | |
| * A couple words from the dev: | |
| * "I hate this" | |
| * "it can run commands" | |
| * "wow this thing can't even cd" | |
| **/ | |
| #include <linux/limits.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <pwd.h> | |
| #include <string.h> | |
| #include <limits.h> | |
| #include <errno.h> | |
| int main(void) { | |
| for (;;) { | |
| // fetch and display prompt infos | |
| char* username = getpwuid(getuid())->pw_name; | |
| char hostname[HOST_NAME_MAX]; | |
| gethostname(hostname, HOST_NAME_MAX); | |
| char cwd[PATH_MAX]; | |
| getcwd(cwd, PATH_MAX); | |
| printf("%s@%s %s $ ", username, hostname, cwd); | |
| // grab all input up to \n | |
| char input[513]; | |
| scanf("%512[^\n]", input); | |
| while (getchar() != '\n'); | |
| // split '&&' chained commands | |
| int cmds_count = 0; | |
| char** cmds = NULL; | |
| char* cmd = strtok(input, "&&"); | |
| while (cmd != NULL) { | |
| cmds = reallocarray(cmds, cmds_count+1, sizeof(*cmds)); | |
| if (cmds == NULL) { | |
| exit(EXIT_FAILURE); | |
| } | |
| cmds[cmds_count++] = cmd; | |
| cmd = strtok(NULL, "&&"); | |
| } | |
| // run all commands until either finished or one failed | |
| for (int i = 0; i < cmds_count; i++) { | |
| // split cmd into argv for execvp | |
| int exec_argc = 0; | |
| char** exec_argv = NULL; | |
| char* arg = strtok(cmds[i], " "); | |
| while (arg != NULL) { | |
| exec_argv = reallocarray(exec_argv, exec_argc+1, sizeof(*exec_argv)); | |
| if (exec_argv == NULL) { | |
| exit(EXIT_FAILURE); | |
| } | |
| exec_argv[exec_argc++] = arg; | |
| arg = strtok(NULL, " "); | |
| } | |
| // NULL terminate argv | |
| exec_argv[exec_argc] = NULL; | |
| // fork to execute cmd | |
| pid_t cmd_pid = fork(); | |
| switch(cmd_pid) { | |
| case -1: | |
| perror("fork failed"); | |
| exit(EXIT_FAILURE); | |
| case 0: | |
| execvp(exec_argv[0], exec_argv); | |
| // exit with code 127 in case execvp fails | |
| // mimics bash's "command not found" | |
| perror("exec failed"); | |
| exit(127); | |
| } | |
| // wait for forked command | |
| int cmd_status; | |
| waitpid(cmd_pid, &cmd_status, 0); | |
| // print exit code | |
| int exit_code = WEXITSTATUS(cmd_status); | |
| printf("Exit Code: %d\n", exit_code); | |
| // stop if last command exited with error | |
| if (exit_code != 0) { | |
| break; | |
| } | |
| } | |
| } | |
| // if we somehow break from the loop exit with failure | |
| exit(EXIT_FAILURE); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment