mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
- Rewrote execve() from scratch and documented it.
git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@15113 87f5fb63-7c3d-0410-a384-fd976d0f7a62
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* $Id: unistd_execve.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $
|
||||
* $Id: unistd_execve.c,v 1.2 2006-08-01 19:01:17 obarthel Exp $
|
||||
*
|
||||
* :ts=4
|
||||
*
|
||||
@ -41,25 +41,215 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Try to find a file, given its full path name. Since it's possible that
|
||||
the path name may reference volumes, devices or assignments which are
|
||||
not currently valid we'll turn off DOS requesters while looking. */
|
||||
STATIC int
|
||||
find_file_and_parent(
|
||||
char * path,
|
||||
BPTR * parent_lock_ptr,
|
||||
struct FileInfoBlock * fib)
|
||||
/* This gets handed around when trying to locate a program or a script
|
||||
interpreter which knows how to do the job. */
|
||||
struct program_info
|
||||
{
|
||||
struct Segment * resident_command; /* If not NULL, points to a valid
|
||||
resident command */
|
||||
BPTR home_dir; /* If not ZERO refers to the directory
|
||||
in which the command to be executed
|
||||
can be found */
|
||||
BPTR segment_list; /* If not ZERO refers to a command
|
||||
loaded into memory */
|
||||
char * program_name; /* Points to the name of the command */
|
||||
char * interpreter_name; /* If not NULL the name of the command
|
||||
interpreter to use */
|
||||
char * interpreter_args; /* If not NULL these are additional
|
||||
arguments to be passedto the command
|
||||
interpreter */
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Try to find a resident command by name; returns a pointer to the Segment
|
||||
data structure ready to use, or NULL if none could be found */
|
||||
static struct Segment *
|
||||
find_resident_command(const char * command_name)
|
||||
{
|
||||
struct Segment * seg;
|
||||
|
||||
/* This must be done under Forbid() since dos.library does not have
|
||||
a more sophisticated arbitration method for this yet... */
|
||||
Forbid();
|
||||
|
||||
seg = FindSegment((STRPTR)name,NULL,0);
|
||||
if(seg != NULL)
|
||||
{
|
||||
/* Check if that's a disable command or something else. */
|
||||
if((seg->seg_UC < 0) && ((seg->seg_UC > CMD_INTERNAL) || (seg->seg_UC <= CMD_DISABLED)))
|
||||
{
|
||||
seg = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unless it's a built-in command, mark it as having another user. */
|
||||
if(seg->seg_UC >= 0)
|
||||
seg->seg_UC++;
|
||||
}
|
||||
}
|
||||
|
||||
Permit();
|
||||
|
||||
return(seg);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Try to read the first line of a script file */
|
||||
static int
|
||||
get_first_script_line(const char * path,char ** line_ptr)
|
||||
{
|
||||
BPTR script_file;
|
||||
int result = -1;
|
||||
char * script_line = NULL;
|
||||
size_t script_line_size = 0;
|
||||
LONG c;
|
||||
|
||||
(*line_ptr) = NULL;
|
||||
|
||||
script_file = Open(path,MODE_OLDFILE);
|
||||
if(script_file == ZERO)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Make file access a little more robust. */
|
||||
SetVBuf(script_file,NULL,BUF_LINE,1024);
|
||||
|
||||
while((c = FGetC(script_file)) != -1)
|
||||
{
|
||||
/* Still enough room in the buffer? We always reserve
|
||||
enough memory for the next character and a NUL
|
||||
to terminate the string with. */
|
||||
if(script_line_length + 2 > script_line_size)
|
||||
{
|
||||
char * new_script_line;
|
||||
|
||||
/* Always reserve a little more memory than needed,
|
||||
and one extra byte to allow us to to NUL-terminate
|
||||
the string. */
|
||||
new_script_line = realloc(script_line,script_line_length + 10);
|
||||
if(new_script_line == NULL)
|
||||
{
|
||||
__set_error(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
script_line = new_script_line;
|
||||
script_line_size = script_line_length + 10;
|
||||
}
|
||||
|
||||
script_line[script_line_length++] = c;
|
||||
|
||||
/* Stop when we hit a line feed or unprintable character */
|
||||
if(c == '\n' || c < ' ' || (c >= 128 && c < 160))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for read error */
|
||||
if(c == -1 && IoErr() != 0)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Provide for NUL-termination. */
|
||||
if(script_line_size > 0)
|
||||
{
|
||||
/* Also strip all trailing blank spaces; that includes
|
||||
line feed and carriage return characters. */
|
||||
while(script_line_length > 0 && isspace(script_line[script_line_length-1]))
|
||||
script_line_length--;
|
||||
|
||||
script_line[script_line_length] = '\0';
|
||||
}
|
||||
|
||||
(*line_ptr) = script_line;
|
||||
|
||||
result = 0;
|
||||
|
||||
out:
|
||||
|
||||
if(script_file != ZERO)
|
||||
Close(script_file);
|
||||
|
||||
if(script_line != NULL)
|
||||
free(script_line);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Release all the resources allocate for the program information, as produced
|
||||
by the find_command() function */
|
||||
static void
|
||||
free_program_info(struct program_info * pi)
|
||||
{
|
||||
if(pi != NULL)
|
||||
{
|
||||
if(pi->resident_command != NULL)
|
||||
{
|
||||
Forbid();
|
||||
|
||||
if(pi->resident_command->seg_UC > 0)
|
||||
pi->resident_command->seg_UC--;
|
||||
|
||||
Permit();
|
||||
}
|
||||
|
||||
if(pi->interpreter_name != NULL)
|
||||
free(pi->interpreter_name);
|
||||
|
||||
if(pi->interpreter_args != NULL)
|
||||
free(pi->interpreter_args);
|
||||
|
||||
if(pi->program_name != NULL)
|
||||
free(pi->program_name);
|
||||
|
||||
if(pi->home_dir != ZERO)
|
||||
UnLock(pi->home_dir);
|
||||
|
||||
if(pi->segment_list)
|
||||
UnLoadSeg(pi->segment_list);
|
||||
|
||||
free(pi);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Try to find a command by name; if the name does not include any path
|
||||
information, try the dos.library resident command list */
|
||||
static int
|
||||
find_command(char * path,struct program_info ** result_ptr)
|
||||
{
|
||||
struct name_translation_info nti;
|
||||
char * script_line = NULL;
|
||||
struct program_info * pi;
|
||||
APTR old_window_ptr;
|
||||
BPTR file_lock = ZERO;
|
||||
int result = -1;
|
||||
BPTR file_lock;
|
||||
BPTR old_dir;
|
||||
int error;
|
||||
|
||||
(*parent_lock_ptr) = ZERO;
|
||||
(*result_ptr) = NULL;
|
||||
|
||||
/* We don't want to show any dos.library requesters while we
|
||||
are looking */
|
||||
old_window_ptr = __set_process_window((APTR)-1);
|
||||
|
||||
pi = malloc(sizeof(*pi));
|
||||
if(pi == NULL)
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(pi,0,sizeof(*pi));
|
||||
|
||||
error = __translate_unix_to_amiga_path_name(&path,&nti);
|
||||
if(error != 0)
|
||||
{
|
||||
@ -67,64 +257,187 @@ find_file_and_parent(
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ZZZ we ought to walk down the assignment list all on our
|
||||
own rather than trusting the Lock() to find the right
|
||||
kind of file */
|
||||
file_lock = Lock(path,SHARED_LOCK);
|
||||
if(file_lock == ZERO)
|
||||
/* No relative or absolute path given? */
|
||||
if(FilePart(path) == (STRPTR)path)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
/* Try to find the command on the resident list */
|
||||
pi->resident_command = find_resident_command(path);
|
||||
if(pi->resident_command == NULL)
|
||||
{
|
||||
__set_errno(ENOENT);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct MsgPort * file_system;
|
||||
struct DevProc * dvp = NULL;
|
||||
BOOL done = FALSE;
|
||||
LONG io_err;
|
||||
int error = 0;
|
||||
|
||||
/* Now for the simple stuff. Find a command or command script file
|
||||
under the path name given. Handle multi-volume assignments, such as
|
||||
referring to "C:" gracefully */
|
||||
file_system = GetFileSysTask();
|
||||
|
||||
do
|
||||
{
|
||||
dvp = GetDeviceProc(path,dvp);
|
||||
if(dvp != NULL)
|
||||
{
|
||||
SetFileSysTask(dvp->dvp_Port);
|
||||
|
||||
old_dir = CurrentDir(dvp->dvp_Lock);
|
||||
|
||||
/* First try: let's assume that that the file is
|
||||
executable */
|
||||
pi->segment_list = LoadSeg(path);
|
||||
if(pi->segment_list != ZERO)
|
||||
{
|
||||
/* Remember where that file came from so that
|
||||
"PROGDIR:" will work */
|
||||
pi->home_dir = DupLock(dvp->dvp_Lock);
|
||||
if(pi->home_dir != ZERO)
|
||||
{
|
||||
/* Also remember the name of the command */
|
||||
pi->program_name = strdup(path);
|
||||
if(pi->program_name != NULL)
|
||||
done = TRUE;
|
||||
else
|
||||
error = ENOMEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = __translate_io_error_to_errno(IoErr());
|
||||
}
|
||||
}
|
||||
|
||||
io_err = IoErr();
|
||||
|
||||
/* If that didn't work and we might be dealing with a script
|
||||
file, have a closer look at it. */
|
||||
if(error == 0 && !done && (io_err == ERROR_OBJECT_NOT_FOUND || io_err == ERROR_OBJECT_WRONG_TYPE || io_err == ERROR_BAD_HUNK))
|
||||
{
|
||||
/* Could that be an ARexx or shell script? */
|
||||
if(get_first_script_line(path,&script_line) == 0)
|
||||
{
|
||||
if(strncmp(script_line,"/*",2) == SAME)
|
||||
{
|
||||
/* That's an ARexx script */
|
||||
pi->interpreter_name = strdup("RX");
|
||||
if(pi->interpreter_name != NULL)
|
||||
done = TRUE;
|
||||
else
|
||||
error = ENOMEM;
|
||||
}
|
||||
else if (strncmp(script_line,"#!",2) == SAME)
|
||||
{
|
||||
char * name;
|
||||
char * args;
|
||||
|
||||
/* That's probably a shell script */
|
||||
name = &script_line[2];
|
||||
while((*name) != '\0' && isspace(*name))
|
||||
name++;
|
||||
|
||||
/* Do we have a command name? */
|
||||
if((*name) != '\0')
|
||||
{
|
||||
/* Find out if there are any script parameters */
|
||||
args = name;
|
||||
while((*args) != '\0' && !isspace(*args))
|
||||
args++;
|
||||
|
||||
if((*args) != '\0')
|
||||
{
|
||||
(*args++) = '\0';
|
||||
|
||||
while((*args) != '\0' && isspace(*args))
|
||||
args++;
|
||||
}
|
||||
|
||||
/* Remember the parameters, if any */
|
||||
if((*args) != '\0')
|
||||
{
|
||||
pi->interpreter_args = strdup(args);
|
||||
if(pi->interpreter_args == NULL)
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
/* And remember the interpreter name. */
|
||||
if(error == 0)
|
||||
{
|
||||
pi->interpreter_name = strdup(name);
|
||||
if(pi->interpreter_name != NULL)
|
||||
done = TRUE;
|
||||
else
|
||||
error = ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(script_line);
|
||||
script_line = NULL;
|
||||
}
|
||||
|
||||
/* If that still didn't work, check if the file has
|
||||
the script bit set */
|
||||
if(error == 0 && !done)
|
||||
{
|
||||
BPTR file_lock;
|
||||
|
||||
file_lock = Lock(path,SHARED_LOCK);
|
||||
if(file_lock != ZERO)
|
||||
{
|
||||
D_S(struct FileInfoBlock,fib);
|
||||
|
||||
if(Examine(file_lock,fib))
|
||||
{
|
||||
if(fib->fib_Protection & FIBF_SCRIPT)
|
||||
{
|
||||
/* If it's an AmigaDOS script, remember
|
||||
to run it through the Execute command */
|
||||
pi->interpreter_name = strdup("Execute");
|
||||
if(pi->interpreter_name != NULL)
|
||||
done = TRUE;
|
||||
else
|
||||
error = ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = __translate_io_error_to_errno(IoErr());
|
||||
}
|
||||
|
||||
UnLock(file_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurrentDir(old_dir);
|
||||
}
|
||||
}
|
||||
while(!done && error == 0 && dvp != NULL && (dvp->dvp_Flags & DVPF_ASSIGN));
|
||||
|
||||
SetFileSysTask(file_system);
|
||||
|
||||
if(error != 0)
|
||||
{
|
||||
__set_errno(error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(CANNOT Examine(file_lock,fib))
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* This must be a file. */
|
||||
if(fib->fib_DirEntryType >= 0)
|
||||
{
|
||||
__set_errno(EISDIR);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* And it should be executable. */
|
||||
if(fib->fib_Protection & FIBF_EXECUTE)
|
||||
{
|
||||
__set_errno(ENOEXEC);
|
||||
goto out;
|
||||
}
|
||||
|
||||
(*parent_lock_ptr) = ParentDir(file_lock);
|
||||
if((*parent_lock_ptr) == ZERO)
|
||||
{
|
||||
LONG io_error;
|
||||
|
||||
io_error = IoErr();
|
||||
if(io_error == 0)
|
||||
io_error = ERROR_OBJECT_WRONG_TYPE;
|
||||
|
||||
__set_errno(__translate_io_error_to_errno(io_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
(*result_ptr) = pi;
|
||||
|
||||
out:
|
||||
|
||||
if(file_lock != ZERO)
|
||||
UnLock(file_lock);
|
||||
if(script_line != NULL)
|
||||
free(script_line);
|
||||
|
||||
if(result != 0)
|
||||
{
|
||||
if((*parent_lock_ptr) != ZERO)
|
||||
{
|
||||
UnLock(*parent_lock_ptr);
|
||||
(*parent_lock_ptr) = ZERO;
|
||||
}
|
||||
}
|
||||
if(pi != NULL)
|
||||
free_program_info(pi);
|
||||
|
||||
__set_process_window(old_window_ptr);
|
||||
|
||||
@ -133,6 +446,9 @@ find_file_and_parent(
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Scan the string, looking for characters which need to be
|
||||
escape with a '*' if that string is to be quoted and the
|
||||
contents should remain in the same form */
|
||||
static size_t
|
||||
count_extra_escape_chars(const char * string,size_t len)
|
||||
{
|
||||
@ -152,8 +468,10 @@ count_extra_escape_chars(const char * string,size_t len)
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Scan a string for characters which may require that the string
|
||||
should be quoted */
|
||||
STATIC BOOL
|
||||
string_needs_escaping(const char * string,size_t len)
|
||||
string_needs_quoting(const char * string,size_t len)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
size_t i;
|
||||
@ -174,6 +492,10 @@ string_needs_escaping(const char * string,size_t len)
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Figure out how many characters would go into a string composed of
|
||||
individual arguments. This takes into account the lengths of
|
||||
the individual argument strings, the separator characters, the
|
||||
quote characters and any escape characters. */
|
||||
static size_t
|
||||
get_arg_string_length(char *const argv[])
|
||||
{
|
||||
@ -190,7 +512,7 @@ get_arg_string_length(char *const argv[])
|
||||
{
|
||||
if((*s) != '\"')
|
||||
{
|
||||
if(string_needs_escaping(s,len))
|
||||
if(string_needs_quoting(s,len))
|
||||
len += 1 + count_extra_escape_chars(s,len) + 1;
|
||||
}
|
||||
|
||||
@ -206,6 +528,10 @@ get_arg_string_length(char *const argv[])
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Put together an argument string from a list of individual
|
||||
components, quoting characters, escape characters and
|
||||
separator characters. You're supposed to have enough memory
|
||||
reserved for the whole string to fit */
|
||||
static void
|
||||
build_arg_string(char *const argv[],char * arg_string)
|
||||
{
|
||||
@ -225,7 +551,7 @@ build_arg_string(char *const argv[],char * arg_string)
|
||||
else
|
||||
(*arg_string++) = ' ';
|
||||
|
||||
if((*s) != '\"' && string_needs_escaping(s,len))
|
||||
if((*s) != '\"' && string_needs_quoting(s,len))
|
||||
{
|
||||
(*arg_string++) = '\"';
|
||||
|
||||
@ -254,265 +580,144 @@ int
|
||||
execve(const char *path, char *const argv[], char *const envp[])
|
||||
{
|
||||
struct Process * this_process = (struct Process *)FindTask(NULL);
|
||||
D_S(struct FileInfoBlock,fib);
|
||||
char old_program_name[256]
|
||||
BPTR parent_dir = ZERO;
|
||||
BPTR old_dir;
|
||||
BPTR script_file = ZERO;
|
||||
int result = -1;
|
||||
char * interpreter_line = NULL;
|
||||
size_t interpreter_line_size = 0;
|
||||
size_t interpreter_line_length = 0;
|
||||
char * interpreter_name = NULL;
|
||||
char * interpreter_args = NULL;
|
||||
struct program_info * pi;
|
||||
char * arg_string = NULL;
|
||||
size_t arg_string_len = 0;
|
||||
size_t parameter_string_len;
|
||||
BPTR segment_list = ZERO;
|
||||
BOOL success = FALSE;
|
||||
int error;
|
||||
LONG rc;
|
||||
LONG c;
|
||||
|
||||
/* We begin by looking at the file or command to be run. */
|
||||
if(find_file_and_parent(path,&parent_dir,fib) != 0)
|
||||
/* We begin by trying to find the command to execute */
|
||||
if(find_command((char *)path,&pi) != 0)
|
||||
goto out;
|
||||
|
||||
/* Now open that file again so that we can check if it's
|
||||
a script file. */
|
||||
old_dir = CurrentDir(parent_dir);
|
||||
script_file = Open(fib->fib_FileName,MODE_OLDFILE);
|
||||
CurrentDir(old_dir);
|
||||
|
||||
if(script_file == ZERO)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
SetVBuf(script_file,NULL,BUF_LINE,1024);
|
||||
|
||||
/* Check if the first line begins with "#!" and if so,
|
||||
read what else can be found in that line. */
|
||||
c = FGetC(script_file);
|
||||
if(c == '#')
|
||||
{
|
||||
c = FGetC(script_file);
|
||||
if(c == '!')
|
||||
{
|
||||
/* Skip leading blank spaces. */
|
||||
do
|
||||
{
|
||||
c = FGetC(script_file);
|
||||
if(c == -1)
|
||||
break;
|
||||
}
|
||||
while(isspace(c));
|
||||
|
||||
if(c != -1)
|
||||
{
|
||||
/* Read everything that follows. */
|
||||
while((c = FGetC(script_file)) != -1)
|
||||
{
|
||||
/* Still enough room in the buffer? We always reserve
|
||||
enough memory for the next character and a NUL
|
||||
to terminate the string with. */
|
||||
if(interpreter_line_length + 2 > interpreter_line_size)
|
||||
{
|
||||
char * new_interpreter_line;
|
||||
|
||||
/* Always reserve a little more memory than needed,
|
||||
and one extra byte to allow us to to NUL-terminate
|
||||
the string. */
|
||||
new_interpreter_line = realloc(interpreter_line,interpreter_line_length + 10);
|
||||
if(new_interpreter_line == NULL)
|
||||
{
|
||||
__set_error(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
interpreter_line = new_interpreter_line;
|
||||
interpreter_line_size = interpreter_line_length + 10;
|
||||
}
|
||||
|
||||
interpreter_line[interpreter_line_length++] = c;
|
||||
if(c == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
/* Provide for NUL-termination. */
|
||||
if(interpreter_line_size > 0)
|
||||
{
|
||||
/* Also strip all trailing blank spaces; that includes
|
||||
line feed and carriage return characters. */
|
||||
while(interpreter_line_length > 0 && isspace(interpreter_line[interpreter_line_length-1]))
|
||||
interpreter_line_length--;
|
||||
|
||||
interpreter_line[interpreter_line_length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(c == -1)
|
||||
{
|
||||
LONG io_error;
|
||||
|
||||
/* Check if we just hit the end of the file or whethere
|
||||
there was a genuine problem. */
|
||||
io_error = IoErr();
|
||||
if(io_error != 0)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(io_error));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
Close(script_file);
|
||||
script_file = ZERO;
|
||||
|
||||
if(interpreter_line_size > 0)
|
||||
{
|
||||
interpreter_name = interpreter_line;
|
||||
|
||||
for(i = 0 ; i < interpreter_line_size ; i++)
|
||||
{
|
||||
if(isspace(interpreter_name[i]))
|
||||
{
|
||||
interpreter_name[i] = '\0';
|
||||
|
||||
interpreter_args = &interpreter_name[i+1];
|
||||
|
||||
while((*interpreter_args) != '\0' && isspace(*interpreter_args))
|
||||
interpreter_args++;
|
||||
|
||||
if((*interpreter_args) == '\0')
|
||||
interpreter_args = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We'll need to know how much memory to reserve for the
|
||||
parameters anyway */
|
||||
parameter_string_len = get_arg_string_length(argv);
|
||||
|
||||
if(interpreter_name != NULL)
|
||||
/* Do we have to use a script interpreter? */
|
||||
if(pi->interpreter_name != NULL)
|
||||
{
|
||||
struct name_translation_info nti;
|
||||
size_t interpreter_args_len;
|
||||
size_t len;
|
||||
struct program_info * pi_interpreter;
|
||||
|
||||
UnLock(parent_dir);
|
||||
parent_dir = ZERO;
|
||||
|
||||
if(find_file_and_parent(interpreter_name,&parent_dir,fib) != 0)
|
||||
/* Now try to find the command corresponding to the
|
||||
interpreter given */
|
||||
if(find_command(pi->interpreter_name,&pi_interpreter) != 0)
|
||||
goto out;
|
||||
|
||||
error = __translate_unix_to_amiga_path_name(&path,&nti);
|
||||
if(error != 0)
|
||||
/* We only try to resolve the name once. If this is still
|
||||
not a command we can launch, we chicken out */
|
||||
if(pi_interpreter->interpreter_name != NULL)
|
||||
{
|
||||
__set_errno(error);
|
||||
free_program_info(pi_interpreter);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(interpreter_args != NULL)
|
||||
interpreter_args_len = strlen(interpreter_args);
|
||||
/* Just remember the arguments that need to be passed
|
||||
to the interpreter */
|
||||
pi_interpreter->interpreter_args = pi->interpreter_args;
|
||||
pi->interpreter_args = NULL;
|
||||
|
||||
free_program_info(pi);
|
||||
pi = pi_interpreter;
|
||||
|
||||
/* Reserve as much memory as is required for the
|
||||
interpreter's parameters and the command's
|
||||
arguments */
|
||||
if(pi->interpreter_args != NULL)
|
||||
{
|
||||
arg_string_len = strlen(pi->interpreter_args);
|
||||
|
||||
arg_string = malloc(arg_string_len + 1 + parameter_string_len + 1 + 1);
|
||||
if(arg_string == NULL)
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(arg_string,pi->interpreter_args,arg_string_len);
|
||||
|
||||
if(parameter_string_len > 0)
|
||||
arg_string[arg_string_len++] = ' ';
|
||||
}
|
||||
else
|
||||
interpreter_args_len = 0;
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
arg_string = malloc(interpreter_args_len + 1 + len + parameter_string_len + 1 + 1);
|
||||
if(arg_string == NULL)
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
arg_string = malloc(parameter_string_len + 1 + 1);
|
||||
}
|
||||
|
||||
if(interpreter_args_len > 0)
|
||||
{
|
||||
memcpy(arg_string,interpreter_args,interpreter_args_len);
|
||||
arg_string_len += interpreter_args_len;
|
||||
|
||||
arg_string[arg_string_len++] = ' ';
|
||||
}
|
||||
|
||||
memcpy(&arg_string[arg_string_len],path,len);
|
||||
arg_string_len += len;
|
||||
|
||||
if(parameter_string_len > 0)
|
||||
arg_string[arg_string_len++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_string = malloc(parameter_string_len + 1 + 1);
|
||||
if(arg_string == NULL)
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If that didn't work, we quit here */
|
||||
if(arg_string == NULL)
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Any command parameters to take care of? */
|
||||
if(parameter_string_len > 0)
|
||||
{
|
||||
build_arg_string(argv,&arg_string[arg_string_len]);
|
||||
arg_string_len += parameter_string_len;
|
||||
}
|
||||
|
||||
/* Add the terminating new line character and a NUL,
|
||||
to be nice... */
|
||||
arg_string[arg_string_len++] = '\n';
|
||||
arg_string[arg_string_len] = '\0';
|
||||
|
||||
old_dir = CurrentDir(parent_dir);
|
||||
segment_list = LoadSeg(fib->fib_FileName);
|
||||
CurrentDir(old_dir);
|
||||
|
||||
if(segment_list == ZERO)
|
||||
{
|
||||
__set_errno(ENOENT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Change the shell's program name */
|
||||
GetProgramName(old_program_name,sizeof(old_program_name));
|
||||
SetProgramName(fib->fib_FileName);
|
||||
SetProgramName(pi->program_name);
|
||||
|
||||
/* Change the command's home directory, so that "PROGDIR:"
|
||||
can be used */
|
||||
old_dir = ThisProcess->pr_HomeDir;
|
||||
ThisProcess->pr_HomeDir = parent_dir;
|
||||
ThisProcess->pr_HomeDir = pi->home_dir;
|
||||
|
||||
/* Reset the break signal before the program starts */
|
||||
SetSignal(0,SIGBREAKF_CTRL_C);
|
||||
|
||||
rc = RunCommand(segment_list,Cli()->cli_DefaultStack * sizeof(LONG),arg_string,arg_string_len);
|
||||
/* Now try to run the program with the accumulated parameters */
|
||||
rc = RunCommand((pi->resident_command != NULL) ? pi->resident_command->seg_Seg : pi->segment_list,Cli()->cli_DefaultStack * sizeof(LONG),arg_string,arg_string_len);
|
||||
|
||||
/* Restore the home directory */
|
||||
ThisProcess->pr_HomeDir = old_dir;
|
||||
|
||||
/* Restore the program name */
|
||||
SetProgramName(old_program_name);
|
||||
|
||||
/* Did we launch the program? */
|
||||
if(rc == -1)
|
||||
{
|
||||
SetProgramName(old_program_name);
|
||||
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Looks good, doesn't it? */
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
|
||||
/* Clean up... */
|
||||
if(pi != NULL)
|
||||
free_program_info(pi);
|
||||
|
||||
if(arg_string != NULL)
|
||||
free(arg_string);
|
||||
|
||||
if(parent_dir != ZERO)
|
||||
UnLock(parent_dir);
|
||||
|
||||
if(script_file != ZERO)
|
||||
Close(script_file);
|
||||
|
||||
if(interpreter_line != NULL)
|
||||
free(interpreter_line);
|
||||
|
||||
if(segment_list != ZERO)
|
||||
UnLoadSeg(segment_list);
|
||||
|
||||
/* If things went well, we can actually quit now. */
|
||||
if(success)
|
||||
exit(result);
|
||||
|
||||
return(result);
|
||||
/* This function only returns control to the caller
|
||||
if something went wrong... */
|
||||
return(-1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user