csc360-a1-shell/c/exec.c

83 lines
2.3 KiB
C

/*
* 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* waitpid */
#include <sys/wait.h> /* waitpid */
#include <unistd.h>
#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;
}