2 Copyright © 2008, The AROS Development Team. All rights reserved.
5 POSIX function execve().
10 #include <exec/types.h>
11 #include <exec/lists.h>
12 #include <proto/exec.h>
13 #include <proto/dos.h>
14 #include <aros/debug.h>
15 #include <dos/filesystem.h>
26 #include "__arosc_privdata.h"
29 /* Return TRUE if there are any white spaces in the string */
30 BOOL
containswhite(const char *str
)
33 if(isspace(*str
++)) return TRUE
;
37 /* Escape the string and quote it */
38 char *escape(const char *str
)
40 const char *strptr
= str
;
41 char *escaped
, *escptr
;
42 /* Additional two characters for '"', and one for '\0' */
43 int bufsize
= strlen(str
) + 3;
44 /* Take into account characters to ecape */
45 while(*strptr
!= '\0')
55 escptr
= escaped
= (char*) malloc(bufsize
);
59 for(strptr
= str
; *strptr
!= '\0'; strptr
++)
67 *escptr
++ = (*strptr
== '\n' ? 'N' : *strptr
);
79 /* Append arg string to argptr increasing argptr if needed */
80 char * appendarg(char *argptr
, int *argptrsize
, const char *arg
)
82 while(strlen(argptr
) + strlen(arg
) + 2 > *argptrsize
)
85 argptr
= realloc(argptr
, *argptrsize
);
95 BPTR
DupFHFromfd(int fd
, ULONG mode
);
97 LONG
exec_command(BPTR seglist
, char *taskname
, char *args
, ULONG stacksize
)
99 BPTR oldin
= MKBADDR(NULL
), oldout
= MKBADDR(NULL
), olderr
= MKBADDR(NULL
);
105 in
= DupFHFromfd(STDIN_FILENO
, FMF_READ
);
106 out
= DupFHFromfd(STDOUT_FILENO
, FMF_WRITE
);
107 err
= DupFHFromfd(STDERR_FILENO
, FMF_WRITE
);
110 oldin
= SelectInput(in
);
112 oldout
= SelectOutput(out
);
114 olderr
= SelectError(err
);
116 oldtaskname
= FindTask(NULL
)->tc_Node
.ln_Name
;
117 FindTask(NULL
)->tc_Node
.ln_Name
= taskname
;
118 SetProgramName(taskname
);
120 udata
= FindTask(NULL
)->tc_UserData
;
121 FindTask(NULL
)->tc_UserData
= NULL
;
122 returncode
= RunCommand(
128 FindTask(NULL
)->tc_UserData
= udata
;
130 FindTask(NULL
)->tc_Node
.ln_Name
= oldtaskname
;
131 SetProgramName(oldtaskname
);
142 SelectOutput(oldout
);
153 /*****************************************************************************
161 const char *filename
,
166 Executes a file with given name.
169 filename - Name of the file to execute.
170 argv - Array of arguments provided to main() function of the executed
172 envp - Array of environment variables passed as environment to the
176 Returns -1 and sets errno appropriately in case of error, otherwise
189 ******************************************************************************/
192 char firstline
[128]; /* buffer to read first line of the script */
193 char *inter
= NULL
; /* interpreter in case of script */
194 char *interargs
= ""; /* interpreter arguments */
197 int argptrsize
= 1024;
198 char *argptr
= (char*) malloc(argptrsize
); /* arguments buffer for
201 char *varname
, *varvalue
;
204 struct CommandLineInterface
*cli
= Cli();
205 char *afilename
= NULL
;
207 struct Process
*me
= (struct Process
*)FindTask(NULL
);
208 struct MinList tempenv
;
209 struct LocalVar
*varNode
;
210 struct Node
*tempNode
;
213 if (filename
== NULL
|| filename
[0] == '\0' || argv
== NULL
)
219 /* Let's check if it's a script */
220 if((program
= fopen(filename
, "r")))
222 if(fgetc(program
) == '#' && fgetc(program
) == '!')
224 /* It is a script, let's read the first line */
225 if(fgets(firstline
, sizeof(firstline
) - 1, program
))
227 /* delete end of line if present */
228 if(firstline
[0] && firstline
[strlen(firstline
)-1] == '\n')
229 firstline
[strlen(firstline
)-1] = '\0';
231 while(isblank(*linebuf
)) linebuf
++;
234 /* Interpreter name is here */
236 while(*linebuf
!= '\0' && !isblank(*linebuf
)) linebuf
++;
240 while(isblank(*linebuf
)) linebuf
++;
242 /* Interpreter arguments are here */
252 /* Simply assume it doesn't exist */
253 saved_errno
= ENOENT
;
257 /* Build RunCommand argument string by escaping and appending all
260 arg
= (inter
!= NULL
? &interargs
: (char**) argv
+ 1);
263 if(containswhite(*arg
))
265 escaped
= escape(*arg
);
267 saved_errno
= ENOMEM
;
270 argptr
= appendarg(argptr
, &argptrsize
, escaped
);
274 argptr
= appendarg(argptr
, &argptrsize
, *arg
);
277 saved_errno
= ENOMEM
;
281 /* If interpreter args were first then we have to insert script name
283 if(arg
== &interargs
)
285 argptr
= appendarg(argptr
, &argptrsize
, filename
);
287 saved_errno
= ENOMEM
;
290 /* Follow with argv */
291 arg
= (char**) argv
+ 1;
296 /* End argptr with '\n' */
297 if(strlen(argptr
) > 0)
298 argptr
[strlen(argptr
) - 1] = '\n';
300 strcat(argptr
, "\n");
302 /* Get the path for LoadSeg() */
303 afilename
= strdup(__path_u2a(inter
? inter
: (char*) filename
));
310 /* let's make some sanity tests */
313 if(stat(inter
? inter
: (char*) filename
, &st
) == 0)
315 if(!(st
.st_mode
& S_IXUSR
) && !(st
.st_mode
& S_IXGRP
) && !(st
.st_mode
& S_IXOTH
))
317 /* file is not executable */
318 saved_errno
= EACCES
;
324 /* couldn't stat file */
329 /* Store environment variables */
332 /* Backup and clear the environment */
334 ForeachNodeSafe(&me
->pr_LocalVars
, varNode
, tempNode
)
336 Remove((struct Node
*) varNode
);
337 AddTail((struct List
*) &tempenv
, (struct Node
*) varNode
);
340 NEWLIST(&me
->pr_LocalVars
);
344 varvalue
= strchr(*env
, '=');
345 if(!varvalue
|| varvalue
== *env
)
347 /* No variable value? Empty variable name? */
348 saved_errno
= EINVAL
;
351 varname
= malloc(1 + varvalue
- *env
);
354 saved_errno
= ENOMEM
;
358 strncat(varname
, *env
, varvalue
- *env
);
361 setenv(varname
, varvalue
, 1);
367 /* Load and run the command */
368 if((seglist
= LoadSeg((CONST_STRPTR
) afilename
)))
374 /* Everything went fine, execve won't return so we can free the old
375 environment variables */
376 ForeachNodeSafe(&tempenv
, varNode
, tempNode
)
378 FreeMem(varNode
->lv_Value
, varNode
->lv_Len
);
379 Remove((struct Node
*)varNode
);
384 struct vfork_data
*udata
= FindTask(NULL
)->tc_UserData
;
385 if(udata
&& udata
->magic
== VFORK_MAGIC
)
387 /* This execve() was called from vfork()ed process. We are going
388 to switch from stack borrowed from the parent process to the
389 original stack of this process. First we have to store all
390 local variables in udata to let them survive the stack change */
391 udata
->exec_seglist
= seglist
;
392 udata
->exec_arguments
= argptr
;
393 udata
->exec_stacksize
= cli
->cli_DefaultStack
* CLI_DEFAULTSTACK_UNIT
;
394 udata
->exec_taskname
= (inter
? inter
: argv
[0]);
396 /* Set this so we know that execve was called */
397 udata
->child_executed
= 1;
399 D(bug("Restoring child stack to %p < %p < %p\n",
400 udata
->child_SPLower
,
402 udata
->child_SPUpper
)
405 /* Restoring child stack */
407 udata
->child
->tc_SPLower
= udata
->child_SPLower
;
408 udata
->child
->tc_SPUpper
= udata
->child_SPUpper
;
409 /* Since we are switching to child's stack and in return jmp_buf we
410 have parent's stack pointer saved, we have to set stack value in
411 jmp_buf to child's stack pointer, otherwise it will be outside
412 tc_SPLower-tc_SPUpper range after longjmp and exception will
414 /* Create space on child stack for the return address written during longjmp. Otherwise
415 data on the stack would be overwritten. */
416 udata
->child_startup
.as_startup_jmp_buf
[0].regs
[STACK_INDEX
] = (unsigned long) udata
->child_SPReg
- sizeof(APTR
);
417 AROS_GET_SP
= udata
->child_SPReg
;
420 D(bug("Calling daddy\n"));
421 /* Now call parent process, so it will resume his work */
422 Signal(GETUDATA
->parent
, 1 << GETUDATA
->parent_signal
);
424 GETUDATA
->exec_returncode
= exec_command(
425 GETUDATA
->exec_seglist
,
426 GETUDATA
->exec_taskname
,
427 GETUDATA
->exec_arguments
,
428 GETUDATA
->exec_stacksize
431 free(GETUDATA
->exec_arguments
);
433 D(bug("exiting from forked execve()\n"));
434 _exit(GETUDATA
->exec_returncode
);
438 returncode
= exec_command(
440 (inter
? inter
: argv
[0]),
442 cli
->cli_DefaultStack
* CLI_DEFAULTSTACK_UNIT
447 D(bug("exiting from non-forked execve()\n"));
453 /* most likely file is not a executable */
454 saved_errno
= ENOEXEC
;
459 /* Restore environment in case of error */
460 NEWLIST(&me
->pr_LocalVars
);
461 ForeachNodeSafe(&tempenv
, varNode
, tempNode
)
463 Remove((struct Node
*) varNode
);
464 AddTail((struct List
*) &me
->pr_LocalVars
, (struct Node
*) varNode
);
468 if(afilename
!= NULL
) free(afilename
);
469 if(saved_errno
) errno
= saved_errno
;