Last active
December 12, 2016 21:14
-
-
Save akoskovacs/b3157961d4e039ba53da84e578a5c28f to your computer and use it in GitHub Desktop.
Really dumb 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
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <sys/wait.h> | |
| #define HAVE_READLINE | |
| #ifdef HAVE_READLINE | |
| # include <readline/readline.h> | |
| # include <readline/history.h> | |
| #endif | |
| #define PATH_MAX 256 | |
| static const char const *MY_PATH[] = { "/bin/", "/usr/bin/", "/sbin/", NULL }; | |
| static const int MAX_ARGS = 10; | |
| static const char *mygetwd(void) | |
| { | |
| static char path[PATH_MAX]; | |
| getcwd(path, PATH_MAX-1); | |
| path[PATH_MAX-1] = '\0'; | |
| return path; | |
| } | |
| static void dump_argv(char **argv) { | |
| int i; | |
| for (i = 0; argv && argv[i] != NULL; i++) { | |
| printf("%d. - '%s'\n", i, argv[i]); | |
| } | |
| } | |
| static const char *find_exec(const char *command) | |
| { | |
| static char npath[PATH_MAX]; | |
| const char **path_p = MY_PATH; | |
| struct stat sb; | |
| if (command == NULL) { | |
| return NULL; | |
| } | |
| /* Absolute and relative paths are easy (no work for us) */ | |
| if ((command[0] == '/') // absolute | |
| || ((command[0] == '.') && command[1] == '/')) { // relative | |
| return command; | |
| } | |
| while (*path_p != NULL) { | |
| strncpy(npath, *path_p, PATH_MAX-1); | |
| npath[PATH_MAX-1] = '\0'; | |
| strncat(npath, command, PATH_MAX-1); | |
| npath[PATH_MAX-1] = '\0'; | |
| if ((stat(npath, &sb)) == -1) { | |
| if (errno == ENOENT) { | |
| path_p++; | |
| continue; | |
| } | |
| } else { | |
| // Regular file, great | |
| if (S_ISREG(sb.st_mode)) { | |
| if ((sb.st_mode & S_IXUSR) || (sb.st_mode & S_IXGRP) | |
| || (sb.st_mode & S_IXOTH)) { | |
| // Great, it's executable | |
| return npath; | |
| } else { | |
| fprintf(stderr, "ERROR: The file is not executable!\n"); | |
| break; | |
| } | |
| } else { | |
| fprintf(stderr, "ERROR: The file is not regular!\n"); | |
| break; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| static pid_t myexec_argv(char **argv) | |
| { | |
| int status; | |
| extern char **environ; | |
| const char *fullprog = NULL; | |
| fullprog = find_exec(argv[0]); | |
| /* Cannot find executable :( */ | |
| if (fullprog == NULL) { | |
| fprintf(stderr, "Cannot find executable '%s'!\n", argv[0]); | |
| return -1; | |
| } | |
| // dump_argv(argv); | |
| pid_t proc = fork(); | |
| if (proc == 0) { | |
| /* in child */ | |
| if (execve(fullprog, argv, environ) == -1) { | |
| fprintf(stderr, "ERROR: Cannot start program! :(\n"); | |
| perror("execve()"); | |
| return -1; | |
| } | |
| } else if (proc != -1) { | |
| /* in parent */ | |
| if (waitpid(proc, &status, WUNTRACED | WCONTINUED) == -1) { | |
| perror("waitpid()"); | |
| return -1; | |
| } | |
| } | |
| return proc; | |
| } | |
| static int myexec_bultin(char **argv) | |
| { | |
| if ((strcmp(argv[0], "cd")) == 0) { | |
| if (argv[1] != NULL) { | |
| if (chdir(argv[1]) == -1) { | |
| fprintf(stderr, "ERROR: Can't change directory!\n"); | |
| perror("chdir()"); | |
| } | |
| } else { | |
| fprintf(stderr, "ERROR: But, where to go? Need a directory!\n"); | |
| } | |
| return 1; | |
| } else if ((strcmp(argv[0], "exit")) == 0) { | |
| exit(0); | |
| } | |
| return 0; | |
| } | |
| static pid_t myexec(char *command) | |
| { | |
| char *saveptr = NULL; | |
| char *argv[MAX_ARGS]; | |
| char *nexttok = NULL; | |
| int argv_i = 0; | |
| while ((nexttok = strtok_r(command, " \t\n", &saveptr)) != NULL) { | |
| if (argv_i < MAX_ARGS) { | |
| argv[argv_i++] = nexttok; | |
| } else { | |
| fprintf(stderr, "ERROR: Too many arguments!\n"); | |
| return 0; | |
| } | |
| command = NULL; | |
| } | |
| argv[argv_i] = NULL; | |
| if (argv[0] == NULL) { | |
| fprintf(stderr, "ERROR: No program to run.\n"); | |
| return 0; | |
| } | |
| if (!myexec_bultin(argv)) { | |
| return myexec_argv(argv); | |
| } | |
| return 0; | |
| } | |
| int main() | |
| { | |
| char command[PATH_MAX]; | |
| char prompt[PATH_MAX]; | |
| char *cmd = command; | |
| printf("Dumb Shell v0.1\n"); | |
| printf("Copyleft (C) Ákos Kovács - 2016\n\n"); | |
| while (1) { | |
| snprintf(prompt, PATH_MAX, "[%s] > ", mygetwd()); | |
| #ifdef HAVE_READLINE | |
| cmd = readline(prompt); | |
| if (cmd != NULL && cmd[0] != '\0') { | |
| add_history(cmd); | |
| } | |
| #else | |
| printf("%s", prompt); | |
| fgets(command, PATH_MAX-1, stdin); | |
| command[PATH_MAX-1] = '\0'; | |
| #endif /* HAVE_READLINE */ | |
| myexec(cmd); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment