mirror of
https://github.com/samsonjs/csc360-a1-shell.git
synced 2026-03-25 08:45:52 +00:00
98 lines
2.2 KiB
C
98 lines
2.2 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h> /* waitpid */
|
|
#include <sys/wait.h> /* waitpid */
|
|
#include <unistd.h>
|
|
|
|
#include "exec.h"
|
|
#include "utils.h"
|
|
#include "main.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 */
|
|
char *msg = (char *)myxmalloc (MSGLEN);
|
|
sprintf (msg, RED "%s: %s" CLEAR, argv[0], strerror (errno));
|
|
queue_message (msg);
|
|
free (msg);
|
|
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 */
|
|
printf (RED "\nCannot execute '%s' (%s)\n" CLEAR, argv[0],
|
|
strerror(errno));
|
|
free (filename);
|
|
_exit (EXIT_FAILURE);
|
|
}
|
|
else
|
|
{ /* error, pid < 0 */
|
|
queue_message (RED "Unable to fork(), uh oh..." CLEAR);
|
|
}
|
|
free (filename);
|
|
return pid;
|
|
}
|