Initial Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
dist/
|
||||
17
Makefile
Normal file
17
Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
CC ?= gcc
|
||||
|
||||
SOURCES := $(wildcard src/*.c)
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
all: dist/msh
|
||||
|
||||
dist/msh: $(SOURCES) dist
|
||||
$(CC) -o $@ $(SOURCES)
|
||||
|
||||
dist:
|
||||
mkdir -p dist
|
||||
|
||||
clean:
|
||||
rm -rf dist
|
||||
135
src/msh.c
Normal file
135
src/msh.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#define ESC \x1B
|
||||
|
||||
|
||||
const int LINESIZE = 512;
|
||||
|
||||
int cd(int argc, char** argv) {
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "Usage: cd <directory>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return chdir(argv[0]);
|
||||
}
|
||||
|
||||
|
||||
void pretty_path_home(char** path) {
|
||||
char* home = secure_getenv("HOME");
|
||||
int home_len = strlen(home);
|
||||
|
||||
if (strncmp(home, *path, home_len) == 0) {
|
||||
(*path)[home_len-1] = '~';
|
||||
*path = *path + (home_len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* tokens[LINESIZE] = {};
|
||||
char** args;
|
||||
char line[LINESIZE] = {};
|
||||
char* tokenwork;
|
||||
char* token;
|
||||
char* newline;
|
||||
int ntokens = 0;
|
||||
|
||||
int i;
|
||||
int result;
|
||||
|
||||
int pid;
|
||||
int laststatus = 0;
|
||||
|
||||
int wstatus;
|
||||
char pwd[LINESIZE] = {};
|
||||
char* pwd_disp;
|
||||
|
||||
char* user;
|
||||
char* host;
|
||||
|
||||
struct utsname uts = {};
|
||||
|
||||
user = secure_getenv("USER");
|
||||
|
||||
result = uname(&uts);
|
||||
if (result != 0) {
|
||||
fprintf(stderr, "Error: %s\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
host = uts.nodename;
|
||||
|
||||
while(1) {
|
||||
getcwd(pwd, LINESIZE - 1);
|
||||
pwd_disp = pwd;
|
||||
|
||||
pretty_path_home(&pwd_disp);
|
||||
|
||||
if (laststatus != 0) {
|
||||
fprintf(stdout, "❌");
|
||||
}
|
||||
fprintf(stdout, "%s@%s %s$ ", user, host, pwd_disp);
|
||||
char* fgets_res = fgets(line, LINESIZE, stdin);
|
||||
|
||||
if (fgets_res == NULL) {
|
||||
printf("^D\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
newline = strrchr(line, '\n');
|
||||
if (newline != NULL) {
|
||||
newline[0] = 0;
|
||||
}
|
||||
|
||||
for (tokenwork = line, i = 0; ; tokenwork = NULL, i++) {
|
||||
token = strtok(tokenwork, " \t");
|
||||
if (token == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
tokens[i] = token;
|
||||
}
|
||||
|
||||
ntokens = i;
|
||||
tokens[ntokens] = NULL;
|
||||
args = &tokens[1];
|
||||
|
||||
if (ntokens == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Shell builtins
|
||||
if (strcmp("exit", tokens[0]) == 0) {
|
||||
printf("Goodbye!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp("cd", tokens[0]) == 0) {
|
||||
laststatus = cd(ntokens - 1, args);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Execute command
|
||||
pid = fork();
|
||||
|
||||
if(pid == 0) {
|
||||
return execvpe(tokens[0], tokens, NULL);
|
||||
} else {
|
||||
waitpid(pid, &wstatus, 0);
|
||||
|
||||
laststatus = WEXITSTATUS(wstatus);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user