123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- /* Copyright (C) 2016 Jeremiah Orians
- * This file is part of mescc-tools.
- *
- * mescc-tools is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * mescc-tools is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with mescc-tools. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/wait.h>
- #define FALSE 0
- //CONSTANT FALSE 0
- #define TRUE 1
- //CONSTANT TRUE 1
- #define max_string 4096
- //CONSTANT max_string 4096
- #define max_args 256
- //CONSTANT max_args 256
- char* numerate_number(int a);
- int match(char* a, char* b);
- void file_print(char* s, FILE* f);
- char** tokens;
- int command_done;
- int VERBOSE;
- int STRICT;
- int envp_length;
- /* Function for purging line comments */
- void collect_comment(FILE* input)
- {
- int c;
- do
- {
- c = fgetc(input);
- if(-1 == c)
- {
- file_print("IMPROPERLY TERMINATED LINE COMMENT!\nABORTING HARD\n", stderr);
- exit(EXIT_FAILURE);
- }
- } while('\n' != c);
- }
- /* Function for collecting RAW strings and removing the " that goes with them */
- int collect_string(FILE* input, int index, char* target)
- {
- int c;
- do
- {
- c = fgetc(input);
- if(-1 == c)
- { /* We never should hit EOF while collecting a RAW string */
- file_print("IMPROPERLY TERMINATED RAW string!\nABORTING HARD\n", stderr);
- exit(EXIT_FAILURE);
- }
- else if('"' == c)
- { /* Made it to the end */
- c = 0;
- }
- target[index] = c;
- index = index + 1;
- } while(0 != c);
- return index;
- }
- /* Function to collect an individual argument or purge a comment */
- char* collect_token(FILE* input)
- {
- char* token = calloc(max_string, sizeof(char));
- char c;
- int i = 0;
- do
- {
- c = fgetc(input);
- if(-1 == c)
- { /* Deal with end of file */
- file_print("execution complete\n", stderr);
- exit(EXIT_SUCCESS);
- }
- else if((' ' == c) || ('\t' == c))
- { /* space and tab are token seperators */
- c = 0;
- }
- else if('\n' == c)
- { /* Command terminates at end of line */
- c = 0;
- command_done = 1;
- }
- else if('"' == c)
- { /* RAW strings are everything between a pair of "" */
- i = collect_string(input, i, token);
- c = 0;
- }
- else if('#' == c)
- { /* Line comments to aid the humans */
- collect_comment(input);
- c = 0;
- command_done = 1;
- }
- else if('\\' == c)
- { /* Support for end of line escapes, drops the char after */
- fgetc(input);
- c = 0;
- }
- token[i] = c;
- i = i + 1;
- } while (0 != c);
- if(1 == i)
- { /* Nothing worth returning */
- free(token);
- return NULL;
- }
- return token;
- }
- char* copy_string(char* target, char* source)
- {
- while(0 != source[0])
- {
- target[0] = source[0];
- target = target + 1;
- source = source + 1;
- }
- return target;
- }
- int string_length(char* a)
- {
- int i = 0;
- while(0 != a[i]) i = i + 1;
- return i;
- }
- char* prepend_string(char* add, char* base)
- {
- char* ret = calloc(max_string, sizeof(char));
- copy_string(copy_string(ret, add), base);
- return ret;
- }
- char* find_char(char* string, char a)
- {
- if(0 == string[0]) return NULL;
- while(a != string[0])
- {
- string = string + 1;
- if(0 == string[0]) return string;
- }
- return string;
- }
- char* prematch(char* search, char* field)
- {
- do
- {
- if(search[0] != field[0]) return NULL;
- search = search + 1;
- field = field + 1;
- } while(0 != search[0]);
- return field;
- }
- char* env_lookup(char* token, char** envp)
- {
- if(NULL == envp) return NULL;
- int i = 0;
- char* ret = NULL;
- do
- {
- ret = prematch(token, envp[i]);
- if(NULL != ret) return ret;
- i = i + 1;
- } while(NULL != envp[i]);
- return NULL;
- }
- char* find_executable(char* name, char* PATH)
- {
- if(('.' == name[0]) || ('/' == name[0]))
- { /* assume names that start with . or / are relative or absolute */
- return name;
- }
- char* next = find_char(PATH, ':');
- char* trial;
- FILE* t;
- while(NULL != next)
- {
- next[0] = 0;
- trial = prepend_string(PATH, prepend_string("/", name));
- t = fopen(trial, "r");
- if(NULL != t)
- {
- fclose(t);
- return trial;
- }
- PATH = next + 1;
- next = find_char(PATH, ':');
- free(trial);
- }
- return NULL;
- }
- /* Function to check if the token is an envar and if it is get the pos of = */
- int check_envar(char* token)
- {
- int j;
- int equal_found;
- equal_found = 0;
- int found;
- char c;
- for(j = 0; j < string_length(token); j = j + 1)
- {
- if(token[j] == '=')
- { /* After = can be anything */
- equal_found = 1;
- break;
- }
- else
- { /* Should be A-z */
- found = 0;
- /* Represented numerically; 0 = 48 through 9 = 57 */
- for(c = 48; c <= 57; c = c + 1)
- {
- if(token[j] == c)
- {
- found = 1;
- }
- }
- /* Represented numerically; A = 65 through z = 122 */
- for(c = 65; c <= 122; c = c + 1)
- {
- if(token[j] == c)
- {
- found = 1;
- }
- }
- if(found == 0)
- { /* In all likelihood this isn't actually an environment variable */
- return 1;
- }
- }
- }
- if(equal_found == 0)
- { /* Not an envar */
- return 1;
- }
- return 0;
- }
- /* Function for executing our programs with desired arguments */
- void execute_commands(FILE* script, char** envp, int envp_length)
- {
- char* PATH;
- char* USERNAME;
- int i;
- int status;
- char* result;
- int j;
- int is_envar;
- char* program;
- int f;
- while(1)
- {
- tokens = calloc(max_args, sizeof(char*));
- PATH = env_lookup("PATH=", envp);
- if(NULL != PATH)
- {
- PATH = calloc(max_string, sizeof(char));
- copy_string(PATH, env_lookup("PATH=", envp));
- }
- USERNAME = env_lookup("LOGNAME=", envp);
- if((NULL == PATH) && (NULL == USERNAME))
- {
- PATH = calloc(max_string, sizeof(char));
- copy_string(PATH, "/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
- }
- else if(NULL == PATH)
- {
- PATH = prepend_string("/home/", prepend_string(USERNAME,"/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"));
- }
- i = 0;
- status = 0;
- command_done = 0;
- do
- {
- result = collect_token(script);
- if(0 != result)
- { /* Not a comment string but an actual argument */
- tokens[i] = result;
- i = i + 1;
- }
- } while(0 == command_done);
- if(VERBOSE && (0 < i))
- {
- file_print(" +> ", stdout);
- for(j = 0; j < i; j = j + 1)
- {
- file_print(tokens[j], stdout);
- fputc(' ', stdout);
- }
- file_print("\n", stdout);
- }
- if(0 < i)
- { /* Not a line comment */
- is_envar = 0;
- if(check_envar(tokens[0]) == 0)
- { /* It's an envar! */
- is_envar = 1;
- envp[envp_length] = tokens[0]; /* Since arrays are 0 indexed */
- envp_length = envp_length + 1;
- }
- if(is_envar == 0)
- { /* Stuff to exec */
- program = find_executable(tokens[0], PATH);
- if(NULL == program)
- {
- file_print(tokens[0], stderr);
- file_print("Some weird shit went down with: ", stderr);
- file_print("\n", stderr);
- exit(EXIT_FAILURE);
- }
- f = fork();
- if (f == -1)
- {
- file_print("fork() failure", stderr);
- exit(EXIT_FAILURE);
- }
- else if (f == 0)
- { /* child */
- /* execve() returns only on error */
- execve(program, tokens, envp);
- /* Prevent infinite loops */
- _exit(EXIT_SUCCESS);
- }
- /* Otherwise we are the parent */
- /* And we should wait for it to complete */
- waitpid(f, &status, 0);
- if(STRICT && (0 != status))
- { /* Clearly the script hit an issue that should never have happened */
- file_print("Subprocess error ", stderr);
- file_print(numerate_number(status), stderr);
- file_print("\nABORTING HARD\n", stderr);
- /* stop to prevent damage */
- exit(EXIT_FAILURE);
- }
- }
- /* Then go again */
- }
- }
- }
- int main(int argc, char** argv, char** envp)
- {
- VERBOSE = FALSE;
- STRICT = FALSE;
- char* filename = "kaem.run";
- FILE* script = NULL;
- /* Get envp_length */
- envp_length = 1;
- while(envp[envp_length] != NULL)
- {
- envp_length = envp_length + 1;
- }
- char** nenvp = calloc(envp_length + max_args + 1, sizeof(char*));
- int i;
- for(i = 0; i < envp_length; i = i + 1)
- {
- nenvp[i] = envp[i];
- }
- for(i = envp_length; i < (envp_length + max_args); i = i + 1)
- {
- nenvp[i] = "";
- }
- i = 1;
- while(i <= argc)
- {
- if(NULL == argv[i])
- {
- i = i + 1;
- }
- else if(match(argv[i], "-h") || match(argv[i], "--help"))
- {
- file_print("kaem only accepts --help, --version, --file, --verbose, --nightmare-mode or no arguments\n", stdout);
- exit(EXIT_SUCCESS);
- }
- else if(match(argv[i], "-f") || match(argv[i], "--file"))
- {
- filename = argv[i + 1];
- i = i + 2;
- }
- else if(match(argv[i], "n") || match(argv[i], "--nightmare-mode"))
- {
- file_print("Begin nightmare", stdout);
- envp = NULL;
- i = i + 1;
- }
- else if(match(argv[i], "-V") || match(argv[i], "--version"))
- {
- file_print("kaem version 0.6.0\n", stdout);
- exit(EXIT_SUCCESS);
- }
- else if(match(argv[i], "--verbose"))
- {
- VERBOSE = TRUE;
- i = i + 1;
- }
- else if(match(argv[i], "--strict"))
- {
- STRICT = TRUE;
- i = i + 1;
- }
- else
- {
- file_print("UNKNOWN ARGUMENT\n", stdout);
- exit(EXIT_FAILURE);
- }
- }
- script = fopen(filename, "r");
- if(NULL == script)
- {
- file_print("The file: ", stderr);
- file_print(filename, stderr);
- file_print(" can not be opened!\n", stderr);
- exit(EXIT_FAILURE);
- }
- execute_commands(script, nenvp, envp_length);
- fclose(script);
- return EXIT_SUCCESS;
- }
|