/* * A simple shell with some basic features. * * Sami Samhuri 0327342 * January 31, 2006 * CSC 360, Assignment 1 * * exec.c -- fork and execute a program * $Id: exec.c 184 2006-01-29 08:53:30Z sjs $ */ /*#define _GNU_SOURCE*/ #include #include #include #include #include /* waitpid */ #include /* waitpid */ #include #include "exec.h" #include "utils.h" char *is_executable(char *file) { if (strchr(file, '/')) { /* process absolute and relative paths directly */ if (access(file, X_OK) == 0) return strdup(file); else return NULL; } char *path = strdup(getenv("PATH")); int file_len = strlen(file); char *dir = strtok(path, ":"); char *filename = NULL; while (dir) { filename = (char *)myxmalloc(strlen(dir) + file_len + 2); sprintf(filename, "%s/%s", dir, file); if (access(filename, X_OK) == 0) break; free(filename); filename = NULL; dir = strtok(NULL, ":"); } xfree(path); return filename; } pid_t exec_command(char **argv, int background) { int status; pid_t pid; char *filename; if (!(filename = is_executable(argv[0]))) { /* error, not executable */ fprintf(stderr, RED "%s: %s\n" CLEAR, argv[0], strerror(errno)); return -1; } if ((pid = fork()) > 0) { /* parent */ if (background) waitpid(pid, &status, WNOHANG); else waitpid(pid, &status, 0); } else if (pid == 0) { /* child */ /* kludge, briefly wait for the job to be created so that if the * command exits quickly, the job is found and removed. otherwise there * are zombie jobs erroneously lying around. note, this isn't guaranteed * to work, it just seems to be enough time in tests here. */ usleep(100); execv(filename, argv); /* if we get here there was an error, display it */ fprintf(stderr, RED "\nCannot execute '%s' (%s)\n" CLEAR, argv[0], strerror(errno)); free(filename); _exit(EXIT_FAILURE); } else { /* error, pid < 0 */ fprintf(stderr, RED "Unable to fork(), uh oh...\n" CLEAR); } free(filename); return pid; }