diff --git a/shell.c b/shell.c index f4fe04e..7bc4713 100644 --- a/shell.c +++ b/shell.c @@ -88,9 +88,62 @@ void parse(char* line, command_t* p_cmd) { } } +/** + * Determines if the executable in p_cmd (i.e., p_cmd->argv[0]) can be found + * in one of the directories in $PATH. Returns true if so, else false. + * If the executable is found in $PATH, then p_cmd->argv[0] is mutated to be + * the absolute path of the executable. + * + * To see the format of $PATH, run `echo $PATH` in your terminal, which should + * output something like + * /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/mnt/learncli/bin + * + * For example, suppose the executable is "ls". This function needs to find its + * absolute path in the file system. For the $PATH above, + * it appends "/ls" to the first directory, resulting in + * /usr/local/sbin/ls. However, this file does not exist, and same for the next + * two directories. However, /usr/bin/ls exists, so p_cmd->argv[0] is set to + * "/usr/bin/ls", and the function returns true. + * + * If the executable is "doesnotexist", then this function would not find that + * file after checking all directories in $PATH, so it would return false. + * + * Note: This behaves similarly to the `which` command, e.g., `which ls`. + * + * To access $PATH within C, use getenv. + * For example, char* path = getenv("PATH"); + * + * To parse PATH, we recommend strtok, as described in the docstring for the + * parse function. + * + * To check if a file exists, use access with amode F_OK + * (https://pubs.opengroup.org/onlinepubs/009695299/functions/access.html). + * + * @param p_cmd + * @return true (if command in PATH) | false (if command not in PATH). Remember + * to mutate p_cmd->argv[0] to be the full path of the executable if it is in + * PATH + */ bool find_full_path(command_t* p_cmd) { - // TODO: - return true; + char* path_tokens = strtok(getenv("PATH"), ":"); + + while (path_tokens != NULL) { + char* full_path = (char*)malloc(MAX_ARG_LEN * sizeof(char)); + strcpy(full_path, path_tokens); + strcat(full_path, "/"); + strcat(full_path, p_cmd->argv[0]); + + if (access(full_path, F_OK) == 0) { + strcpy(p_cmd->argv[0], full_path); + free(full_path); + return true; + } + + free(full_path); + path_tokens = strtok(NULL, ":"); + } + + return false; } int execute(command_t* p_cmd) {