Skip to content

Instantly share code, notes, and snippets.

@xarblu
Created November 7, 2023 19:09
Show Gist options
  • Select an option

  • Save xarblu/1b6a7a4286e01ede4bbb4af37138ea76 to your computer and use it in GitHub Desktop.

Select an option

Save xarblu/1b6a7a4286e01ede4bbb4af37138ea76 to your computer and use it in GitHub Desktop.
mush - the Memory Unsafe SHell
/**
* 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