Initial commit
This commit is contained in:
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# C
|
||||||
|
*.out
|
||||||
|
*.gch
|
||||||
|
vgcore.*
|
||||||
|
# Build
|
||||||
|
bin/
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Local
|
||||||
|
compile_commands.json
|
||||||
|
.doc
|
||||||
20
Makefile
Normal file
20
Makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
LIBRARIES = -lreadline -Iinclude
|
||||||
|
RELEASE_ARGS = -DRELEASEBUILD
|
||||||
|
SOURCES = ./src/* ./cmd/dfs.c
|
||||||
|
OUTPUT_DIR = ./bin
|
||||||
|
OUTPUT_BIN = ${OUTPUT_DIR}/PROG
|
||||||
|
OUTPUT = -o ${OUTPUT_BIN}
|
||||||
|
|
||||||
|
INSTALL_NAME = dfsh
|
||||||
|
|
||||||
|
build: output_dir
|
||||||
|
gcc -Wall -std=gnu99 ${RELEASE_ARGS} ${SOURCES} ${OUTPUT:PROG=dfsh} ${LIBRARIES}
|
||||||
|
|
||||||
|
debug: output_dir
|
||||||
|
gcc -Wall -std=gnu99 -g ${SOURCES} ${OUTPUT:PROG=dfsh} ${LIBRARIES}
|
||||||
|
|
||||||
|
output_dir:
|
||||||
|
mkdir -p ${OUTPUT_DIR}
|
||||||
|
|
||||||
|
install:
|
||||||
|
mv ${OUTPUT_BIN:PROG=dfsh} /usr/sbin/${INSTALL_NAME}
|
||||||
10
README.md
Normal file
10
README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
**IMPORTANT** this shell is **NOT** meant to be used for any serious applications.
|
||||||
|
This is for academic purposes only!
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
341
cmd/dfs.c
Normal file
341
cmd/dfs.c
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
#include "dfs.h"
|
||||||
|
|
||||||
|
#define clear() printf("\033[H\033[J")
|
||||||
|
|
||||||
|
static char *prompt = NULL;
|
||||||
|
static size_t commandRun = 0;
|
||||||
|
|
||||||
|
union pipe {
|
||||||
|
int fileDesc[2];
|
||||||
|
struct {
|
||||||
|
int read;
|
||||||
|
int write;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *builtinFunctions[] = {
|
||||||
|
"exit",
|
||||||
|
"author",
|
||||||
|
"cd",
|
||||||
|
"nomorenumbers"
|
||||||
|
};
|
||||||
|
|
||||||
|
int (*builtinFunc[]) (char **) = {
|
||||||
|
&builtinExit,
|
||||||
|
&builtinAuthor,
|
||||||
|
&builtinCD,
|
||||||
|
&builtinNMN
|
||||||
|
};
|
||||||
|
|
||||||
|
int builtinExit(char **args) {
|
||||||
|
#if RL_READLINE_VERSION < 0x0602
|
||||||
|
rl_clear_history();
|
||||||
|
#else
|
||||||
|
clear_history();
|
||||||
|
#endif
|
||||||
|
free(args);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int builtinAuthor(char **args) {
|
||||||
|
static const char* message =
|
||||||
|
"Author: Spencer\n"
|
||||||
|
"Description: \n"
|
||||||
|
"Ask for the source code!\n"
|
||||||
|
"\n";
|
||||||
|
printf("%s", message);
|
||||||
|
free(args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int builtinCD(char **dir) {
|
||||||
|
int status = 0;
|
||||||
|
char *oldPWD = getenv("PWD");
|
||||||
|
char *changeDir = malloc(sizeof(char *));
|
||||||
|
if (dir[1] != NULL) {
|
||||||
|
char c = *dir[1];
|
||||||
|
switch (c) {
|
||||||
|
case '~':
|
||||||
|
changeDir = realloc(changeDir, strlen(getenv("HOME") + strlen(dir[1])));
|
||||||
|
strcpy(changeDir, getenv("HOME"));
|
||||||
|
strcat(changeDir, dir[1]+1);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
changeDir = realloc(changeDir, strlen(getenv("OLDPWD")));
|
||||||
|
strcpy(changeDir, getenv("OLDPWD"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
changeDir = dir[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (chdir(changeDir) != 0) {
|
||||||
|
status = 1;
|
||||||
|
printf("bash: cd: error\n");
|
||||||
|
} else {
|
||||||
|
setenv("PWD", dir[1], 1);
|
||||||
|
setenv("OLDPWD", oldPWD, 1);
|
||||||
|
free(prompt);
|
||||||
|
prompt = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (chdir(getenv("HOME")) != 0) {
|
||||||
|
status = 1;
|
||||||
|
printf("Bash: cd: error\n");
|
||||||
|
} else {
|
||||||
|
setenv("PWD", getenv("HOME"), 1);
|
||||||
|
setenv("OLDPWD", oldPWD, 1);
|
||||||
|
free(prompt);
|
||||||
|
prompt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(changeDir);
|
||||||
|
changeDir = NULL;
|
||||||
|
free(dir);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int builtinNMN(char **args) {
|
||||||
|
free(args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void failedTest() {
|
||||||
|
static const char* message =
|
||||||
|
"\n"
|
||||||
|
"We must change our default passwords; however, it seems you have typed it in wrong!!\n"
|
||||||
|
"\n";
|
||||||
|
printf("%s", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int runCommand(char *command) {
|
||||||
|
int status = 0;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0) { // Child process
|
||||||
|
if(execlp("bash", "bash", "-c", command, NULL) == -1) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
} else if (pid < 0) {
|
||||||
|
printf("Error forking...\n");
|
||||||
|
status = 1;
|
||||||
|
} else { // Parent process
|
||||||
|
do {
|
||||||
|
waitpid(pid, &status, WUNTRACED);
|
||||||
|
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **splitCMD(const char *line) {
|
||||||
|
size_t size = 8;
|
||||||
|
size_t pos = 0;
|
||||||
|
char **args = malloc(size * sizeof(char*));
|
||||||
|
char *arg = NULL;
|
||||||
|
|
||||||
|
char *lineTest = NULL;
|
||||||
|
lineTest = strdup(line);
|
||||||
|
|
||||||
|
if(line == NULL) {
|
||||||
|
*args=NULL;
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = strtok(lineTest, " \t\r\n\a");
|
||||||
|
while (arg != NULL) {
|
||||||
|
args[pos] = arg;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if (pos >= size) {
|
||||||
|
size += 1;
|
||||||
|
args = realloc(args, size * sizeof(char*));
|
||||||
|
|
||||||
|
}
|
||||||
|
arg = strtok(NULL, " \t\r\n\a");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(arg);
|
||||||
|
free(lineTest);
|
||||||
|
args[pos] = NULL;
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
int execCommand(char *command) {
|
||||||
|
char **commandARGS = splitCMD(command);
|
||||||
|
for (size_t i = 0; i < (sizeof(builtinFunctions) / sizeof(char *)); i++) {
|
||||||
|
if (strcmp(commandARGS[0], builtinFunctions[i]) == 0) {
|
||||||
|
return (*builtinFunc[i])(commandARGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(commandARGS);
|
||||||
|
return runCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initShell() {
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
using_history();
|
||||||
|
|
||||||
|
// Setting random time seed
|
||||||
|
srand(time(0));
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
runCommand("uname -a");
|
||||||
|
|
||||||
|
fd = fopen("/etc/motd", "r");
|
||||||
|
if (fd != NULL) {
|
||||||
|
char c;
|
||||||
|
c = fgetc(fd);
|
||||||
|
printf("\n");
|
||||||
|
while (c != EOF) {
|
||||||
|
printf("%c", c);
|
||||||
|
c = fgetc(fd);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getPrompt() {
|
||||||
|
pid_t pid;
|
||||||
|
union pipe input, output;
|
||||||
|
FILE *outputFileD;
|
||||||
|
size_t len = 0;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
static size_t promptCap = 0;
|
||||||
|
|
||||||
|
pipe(input.fileDesc);
|
||||||
|
pipe(output.fileDesc);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0) { // Child process
|
||||||
|
close(input.write);
|
||||||
|
close(output.read);
|
||||||
|
|
||||||
|
dup2(input.read, STDIN_FILENO);
|
||||||
|
dup2(output.write, STDOUT_FILENO);
|
||||||
|
close(STDERR_FILENO); // Do not print errors to the screen
|
||||||
|
|
||||||
|
execlp("bash", "bash", "-i", "-c", "\
|
||||||
|
ver=$(bash --version | head -n 1 | awk \'{print $4}\' | grep -o \".\\..\");\
|
||||||
|
check_ver=$(echo -e \"${ver}\n4.3\" | sort -V | head -n 1);\
|
||||||
|
if [[ \"${ver}\" == \"${check_ver}\" ]]; then\
|
||||||
|
echo \"[${USER}@${HOSTNAME} ${PWD##*/}]$ \";\
|
||||||
|
else\
|
||||||
|
echo \"${PS1@P}\";\
|
||||||
|
fi\
|
||||||
|
", NULL);
|
||||||
|
} else if (pid < 0) { // Error forking
|
||||||
|
printf("Error forking\n");
|
||||||
|
} else { // Parent process
|
||||||
|
close(input.read);
|
||||||
|
close(output.write);
|
||||||
|
|
||||||
|
outputFileD = fdopen(output.read, "r");
|
||||||
|
|
||||||
|
len = getline(&prompt, &promptCap, outputFileD);
|
||||||
|
|
||||||
|
if (prompt[len - 1] == '\n') {
|
||||||
|
prompt[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(outputFileD);
|
||||||
|
do {
|
||||||
|
waitpid(pid, &status, WUNTRACED);
|
||||||
|
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int randomNum(int limit) {
|
||||||
|
int num = 0;
|
||||||
|
if (limit != 0) {
|
||||||
|
num = rand()%limit + 1;
|
||||||
|
} else {
|
||||||
|
num = rand();
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shellTest() {
|
||||||
|
int status = 1;
|
||||||
|
char *line = NULL;
|
||||||
|
|
||||||
|
line = readline("Default password? (abc123): ");
|
||||||
|
|
||||||
|
if (line != NULL) {
|
||||||
|
if(!strcmp(line, "abc123")) {
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void postCommand() {
|
||||||
|
commandRun++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startShell() {
|
||||||
|
char *line = NULL;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
while ((line = readline(getPrompt())) != NULL) {
|
||||||
|
if (strlen(line) != 0) { // Checking if prompt returns empty
|
||||||
|
status = shellTest();
|
||||||
|
if (status == 0) { // Passed test
|
||||||
|
add_history(line);
|
||||||
|
execCommand(line);
|
||||||
|
postCommand();
|
||||||
|
} else { // Failed test
|
||||||
|
failedTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
free(prompt);
|
||||||
|
prompt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleBreak(){
|
||||||
|
signal(SIGINT, handleBreak);
|
||||||
|
printf("\n");
|
||||||
|
rl_on_new_line();
|
||||||
|
rl_replace_line("", 0);
|
||||||
|
rl_redisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
initShell();
|
||||||
|
signal(SIGINT, handleBreak);
|
||||||
|
startShell();
|
||||||
|
#if RL_READLINE_VERSION < 0x0602
|
||||||
|
rl_clear_history();
|
||||||
|
#else
|
||||||
|
clear_history();
|
||||||
|
#endif
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
4
include/dfs.h
Normal file
4
include/dfs.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
int builtinExit(char **args);
|
||||||
|
int builtinAuthor(char **args);
|
||||||
|
int builtinCD(char **dir);
|
||||||
|
int builtinNMN(char **args);
|
||||||
0
include/util.h
Normal file
0
include/util.h
Normal file
0
src/util.c
Normal file
0
src/util.c
Normal file
Reference in New Issue
Block a user