home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * $Source: /unixb/home/unixlib/source/unixlib37/src/sys/c/RCS/exec,v $
- * $Date: 1996/11/06 22:01:42 $
- * $Revision: 1.4 $
- * $State: Rel $
- * $Author: unixlib $
- *
- * $Log: exec,v $
- * Revision 1.4 1996/11/06 22:01:42 unixlib
- * Yet more changes by NB, PB and SC.
- *
- * Revision 1.3 1996/10/30 21:59:00 unixlib
- * Massive changes made by Nick Burret and Peter Burwood.
- *
- * Revision 1.2 1996/05/06 09:03:14 unixlib
- * Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
- * Saved for 3.7a release.
- *
- * Revision 1.1 1996/04/19 21:34:24 simon
- * Initial revision
- *
- ***************************************************************************/
-
- static const char rcs_id[] = "$Id: exec,v 1.4 1996/11/06 22:01:42 unixlib Rel $";
-
- #include <errno.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/param.h>
- #include <sys/unix.h>
- #include <sys/syslib.h>
- #include <sys/debug.h>
- #include <sys/swis.h>
- #include <sys/wait.h>
-
- #ifdef DEBUG
- #include <sys/os.h>
- #endif
-
- /* Execute path with all arguments after path until a NULL
- pointer and environment from 'environ'. */
-
- int
- execl (const char *path, const char *arg, ...)
- {
- const char *argv[MAXCOMMANDLEN >> 2];
- unsigned int i;
- va_list args;
-
- argv[0] = arg;
-
- va_start (args, arg);
- i = 1;
- do
- {
- if (i >= (MAXCOMMANDLEN >> 2))
- {
- errno = E2BIG;
- return -1;
- }
- argv[i] = va_arg (args, const char *);
- } while (argv[i++] != NULL);
- va_end (args);
-
- return execve (path, (char **)argv, (char **)environ);
- }
-
- /* Execute path with all arguments after path until a NULL pointer,
- and the argument after that for environment. */
-
- int
- execle (const char *path, const char *arg, ...)
- {
- const char *argv[MAXCOMMANDLEN >> 2];
- const char **envp;
- unsigned int i;
- va_list args;
-
- va_start(args, arg);
- argv[0] = arg;
- i = 1;
- do
- {
- if (i >= (MAXCOMMANDLEN >> 2))
- {
- errno = E2BIG;
- return -1;
- }
- argv[i] = va_arg(args, const char *);
- } while (argv[i++] != NULL);
-
- envp = va_arg(args, const char **);
- va_end (args);
-
- return execve (path, (char **)argv, (char **)envp);
- }
-
- /* Execute file, searching in the 'path' environment variable if
- it contains no slashes, with all arguments after file until a
- NULL pointer and environment from 'environ'. */
- int
- execlp (const char *file, const char *arg, ...)
- {
- const char *argv[MAXCOMMANDLEN >> 2];
- unsigned int i;
- va_list args;
-
- argv[0] = arg;
- va_start (args, arg);
-
- i = 1;
- do {
- if (i >= (MAXCOMMANDLEN >> 2))
- {
- errno = E2BIG;
- return -1;
- }
- argv[i] = va_arg (args, const char *);
- } while (argv[i++] != NULL);
-
- va_end (args);
-
- return execvp (file, (char **)argv);
- }
-
- /* Execute path with arguments argv and environment from 'environ'. */
- int
- execv (const char *path, char **argv)
- {
- return execve (path, argv, environ);
- }
-
- /* Execute file, searching in the 'path' environment variable if it
- contains no slashes, with arguments argv and environment from
- 'environ'. */
- int
- execvp (const char *name, char **argv)
- {
- /* Path searching has not been implemented. */
- return execve (name, argv, environ);
- }
-
- /* #define DEBUG */
-
- #ifdef DEBUG
- #define ushift(p,v,c) ((p) = __ushift((unsigned char *)p,v,c,"(" #p ")"))
- #define ushift2(p,v,c,t) ((p) = (t)__ushift((unsigned char *)p,v,c,"(" #p ")"))
- #define showmove(s,n,p,r) (os_print(s "("), os_print(n), os_prhex((int)p), os_print(") -> "), os_prhex((int)r), os_nl())
- #undef memcpy
- #define memcpy(d,s,n) (os_print("memcpy("), os_prhex((int)(d)), os_print(","), os_prhex((int)(s)), os_print(","), \
- os_prhex((int)(n)), os_print(")"), os_nl(), __memcpy(d,s,n))
-
- static void *
- __ushift (register unsigned char *p, register unsigned int v, register unsigned int c, char *n)
- {
- register void *r = ((p >= __base && p < __rwlimit) ? p + c
- : (p >= __lomem && p < __break) ? p + v : p);
- showmove ("ushift", n, p, r);
- return r;
- }
-
- #else
-
- #define ushift(p,v,c) ((p) = __ushift((unsigned char *)p,v,c))
- #define ushift2(p,v,c,t) ((p) = (t)__ushift((unsigned char *)p,v,c))
-
- static void *
- __ushift (register unsigned char *p, register unsigned int v, register unsigned int c)
- {
- return ((p >= __base && p < __rwlimit) ? p + c
- : (p >= __lomem && p < __break) ? p + v : p);
- }
-
- #endif
-
- #ifdef DEBUG
- #define dshift(p,v,c) ((p) = __dshift((unsigned char *)p,v,c,"(" #p ")"))
- #define dshift2(p,v,c,t) ((p) = (t)__dshift((unsigned char *)p,v,c,"(" #p ")"))
-
- static void *
- __dshift (register unsigned char *p, register unsigned int v, register unsigned int c, char *n)
- {
- register void *q1 = p - c;
- register void *q2 = p - v;
- register void *r = ((q1 >= __base && q1 < __rwlimit) ? q1
- : (q2 >= __lomem && q2 < __break) ? q2 : p);
- showmove ("dshift", n, p, r);
- return r;
- }
-
- #else
-
- #define dshift(p,v,c) ((p) = __dshift((unsigned char *)p,v,c))
- #define dshift2(p,v,c,t) ((p) = (t)__dshift((unsigned char *)p,v,c))
-
- static void *
- __dshift (register unsigned char *p, register unsigned int v, register unsigned int c)
- {
- register void *q1 = p - c;
- register void *q2 = p - v;
-
- /* this is only safe when 2 * maximum application space size < start of dynamic areas */
- return ((q1 >= __base && q1 < __rwlimit) ? q1
- : (q2 >= __lomem && q2 < __break) ? q2 : p);
- }
-
- #endif
-
-
- _kernel_oserror *__exerr;
-
- int
- execve (const char *execname, char **argv, char **envp)
- {
- register struct proc *u = __u;
- register int i, l;
- register char *s1, *s2, *s3;
- register struct env *e;
- char *name;
- void (*__exec) (char *);
- char cli[MAXCOMMANDLEN];
-
- #ifdef DEBUG
- __debug ("execve: entered function. Parameters are:");
- printf ("------------------------------------------next bit\n");
- printf ("execname = '%s'\n", execname);
- printf ("argv = ");
- i = -1;
- while (argv[++i])
- printf ("argv[%d] = '%s', ", i, argv[i]);
- printf ("\nenvp = ");
- i = -1;
- while (envp[++i])
- printf ("envp[%d] = '%s', ", i, envp[i]);
- printf ("\n");
- #endif
-
- if (!execname || !argv || !envp)
- {
- errno = EINVAL;
- return (-1);
- }
-
- if (*execname != '*')
- name = __uname ((char *)execname, 0);
- else
- name = (char *)execname;
-
- /* check MAXCOMMANDLEN */
-
- #ifdef DEBUG
- os_print ("checking MAXCOMMANDLEN\n\r");
- #endif
-
- /* Move through the command arguments, cumulating the lengths
- to determine whether our command line will be >= MAXCOMMANDLEN. */
- l = strlen (name) + 1;
- for (i = 0; argv[i] && l < MAXCOMMANDLEN; l += strlen (argv[i]) + 1, i++);
- if (l >= MAXCOMMANDLEN)
- {
- errno = E2BIG;
- return (-1);
- }
-
- /* If we are a process with no parent, we just verify the command line
- lengths and call the process. */
- if (!u->status.has_parent)
- {
- s2 = cli;
- s3 = name;
- #ifdef DEBUG
- os_print ("Taking a shortcut\n\r");
- #endif
- if (*s3 != '*')
- *s2++ = '/';
- while (*s2++ = *s3++);
- s2[-1] = ' ';
- if (argv[0])
- for (i = 1; s3 = argv[i]; i++)
- {
- while (*s2++ = *s3++);
- s2[-1] = ' ';
- }
- s2[-1] = 0;
- __reset ();
-
- /* If the cli is >= MAXPATHLEN, we will need the aid of
- DDE utils. */
- if (strlen (cli) >= MAXPATHLEN)
- {
- int r[10];
- char *temp = strchr (cli, ' ');
- #ifdef DEBUG
- os_print ("Shortcut requires DDE\n\r");
- #endif
- /* Check that the actual command is not greater than
- RISC OS's maximum path length. */
- if ((temp - cli) >= MAXPATHLEN)
- {
- errno = E2BIG;
- return -1;
- }
- /* Set the command line size within DDE utils. */
- r[0] = strlen (temp + 1) + 1;
- if (os_swi (DDEUtils_SetCLSize, r))
- {
- /* We're buggered if DDE utils isn't on this system. */
- errno = E2BIG;
- return -1;
- }
- r[0] = (int) temp + 1;
- os_swi (DDEUtils_SetCL, r);
- *temp = '\0';
- #ifdef DEBUG
- os_print ("Shortcut - DDE setup\n\r");
- #endif
- }
-
- /* if the DAs are being used, then delete the dynamic area first.
- This is safe to do before the os_cli call since cli is on the stack
- and hence not in the DA. */
- if (__dynamic_num != -1)
- __dynamic_area_exit ();
- /* Pass the command to os_cli (which never returns). */
- os_cli (cli);
- /* something ugly must have happened to get here, so just exit. */
- __exit_no_code ();
- }
-
- /* If we arrive here, we have a parent process. */
-
- /* check for overlapping argv arrays */
- #ifdef DEBUG
- os_print ("Doing it the long way\n\r");
- #endif
-
- l = argv - u->argv;
- if (l < 0)
- l = -l;
-
- if (l <= i)
- {
- errno = EINVAL;
- return (-1);
- }
-
- /* check free memory */
-
- #ifdef DEBUG
- os_print ("__rwlimit: "), os_prhex ((unsigned int)__rwlimit), os_nl();
- os_print ("__stack_limit: "), os_prhex ((unsigned int)__stack_limit), os_nl();
- #endif
-
- if (((unsigned int) __base & ~0xff) == 0x8000)
- {
- __codeshift = ((char *) __stack - (char *) __stack_limit) - 512 - __exlen;
- #ifdef __4K_BOUNDARY
- /* align down to 4K boundary. */
- __codeshift = __codeshift & ~4095;
- #endif
- if (__dynamic_num == -1) /* heap not in a dynamic area */
- __exshift = __codeshift;
- else
- __exshift = 0;
- }
- else
- __codeshift = (__exshift = 0);
-
- /* __codeshift needs to be something > 0, but how much is a suitable miniumum ? */
- if (__codeshift < MAXCOMMANDLEN)
- {
- errno = ENOMEM;
- return (-1);
- }
-
- #ifdef DEBUG
- os_print ("__exlen: "), os_prhex ((unsigned int)__exlen), os_nl ();
- os_print ("__codeshift: "), os_prhex ((unsigned int)__codeshift), os_nl ();
- os_print ("__exshift: "), os_prhex ((unsigned int)__exshift), os_nl ();
- #endif
-
- /* copy name into u->argb */
-
- s1 = u->argb;
- s2 = cli;
- s3 = name;
- if (*s3 != '*')
- *s2++ = '/';
- while (*s1++ = *s2++ = *s3++);
- s2[-1] = ' ';
-
- /* write cli args, u->argv[] & u->argc */
-
- if (argv[0])
- {
- #ifdef DEBUG
- printf ("if argv[0] = '%s'\n", argv[0]);
- #endif
- s3 = argv[0];
- u->argv[0] = s1;
- while (*s1++ = *s3++);
-
- for (i = 1; s3 = argv[i]; i++)
- {
- u->argv[i] = s1;
- while (*s1++ = *s2++ = *s3++);
- s2[-1] = ' ';
- }
- }
- else
- {
- i = 0;
- *s1 = 0;
- }
-
- u->argv[u->argc = i] = 0;
-
- /* terminate cli */
-
- s2[-1] = 0;
-
- #ifdef DEBUG
- os_print ("cli set up : ");
- os_print (cli);
- os_print ("\n\r");
- #endif
-
- if (strlen (cli) >= MAXPATHLEN) /* We need to use DDE utils for this */
- {
- int r[10];
- char *temp = cli;
- if (*temp == '*')
- temp++;
- while (*temp == ' ')
- temp++; /* command starts star, space - right pain */
-
- temp = strchr (temp, ' ');
- #ifdef DEBUG
- os_print ("long way requires DDE : ");
- os_print (cli);
- os_print ("\n\r");
- #endif
- if ((temp - cli) >= MAXPATHLEN)
- {
- errno = E2BIG;
- return (-1);
- } /* still too long */
- r[0] = strlen (temp + 1) + 1;
- if (os_swi (DDEUtils_SetCLSize, r))
- {
- errno = E2BIG;
- return (-1);
- } /* no DDE utils */
- r[0] = (int) temp + 1;
- os_swi (DDEUtils_SetCL, r);
- *temp = '\0';
- #ifdef DEBUG
- os_print ("DDE utils set up\n\r");
- #endif
- }
-
- #ifdef DEBUG
- __debug ("execve() (argv)");
- #endif
-
- /* File descriptors open in the existing process image remain open
- in the new process image, unless they have the 'FD_CLOEXEC'
- flag set. O_EXECCL is an alias for FD_CLOEXEC. */
- for (i = 0; i < MAXFD; i++)
- if (u->file[i].oflag & O_EXECCL)
- close (i);
-
- /* Stop any interval timers that might be running. Technically
- the new process should inherit the pending alarms. */
- __stop_itimers ();
-
- u->status.has_parent = 0;
-
- #ifdef DEBUG
- __debug ("execve()");
- #endif
-
- /* Remove environment handlers. */
-
- e = __Oenv;
- for (i = 0; i < 13; i++)
- __wrenv (i, e->h + i);
-
- /* shift __u pointers if necessary */
-
- if (__exshift || __codeshift)
- {
- register unsigned int v = __exshift;
- register unsigned int c = __codeshift;
- register struct proc *u = __u;
-
- for (i = 0; i < u->argc; i++)
- ushift (u->argv[i], v, c);
- ushift (u->argv, v, c);
- ushift (u->argb, v, c);
- for (i = 0; i < MAXFD; i++)
- if (u->file[i].dup)
- ushift (u->file[i].dup, v, c);
- for (i = 0; i < MAXTTY; i++)
- {
- if (u->tty[i].out)
- ushift2 (u->tty[i].out, v, c, int (*)(int));
- if (u->tty[i].in)
- ushift2 (u->tty[i].in, v, c, int (*)(void));
- if (u->tty[i].scan)
- ushift2 (u->tty[i].scan, v, c, int (*)(int));
- if (u->tty[i].init)
- ushift2 (u->tty[i].init, v, c, int (*)(void));
- if (u->tty[i].flush)
- ushift2 (u->tty[i].flush, v, c, int (*)(void));
-
- #ifndef __TTY_STATIC_BUFS
- if (u->tty[i].del)
- ushift (u->tty[i].del, v, c);
- if (u->tty[i].buf)
- ushift (u->tty[i].buf, v, c);
- #endif
- if (u->tty[i].ptr)
- ushift (u->tty[i].ptr, v, c);
- }
- ushift (u->tty, v, c);
-
- /* If itimers are malloc'd then they should probably be shifted here. */
-
- __exec = (void (*)(char *)) ((char *) __stack_limit + __codeshift);
- }
- else
- __exec = __exptr;
-
- {
- int r[10];
- char *v[1];
-
- v[0] = (char *) __u + __exshift;
- r[0] = (int) "UnixLib$env";
- r[1] = (int) v;
- r[2] = 4;
- r[3] = 0;
- r[4] = 1;
- os_swi (OS_SetVarVal, r);
- }
-
- /* copy up m/code routine and heap */
-
- if (__codeshift)
- {
- int regs[10];
-
- memcpy ((char *) __exec, (char *) __exptr, __exlen);
- /* SynchroniseCodeAreas. This call is okay even if it isn't necessary
- on pre-StrongARM machines. */
- regs[0] = 1;
- regs[1] = (int)__exec;
- regs[2] = regs[1] + __exlen - 4;
- os_swi (OS_SynchroniseCodeAreas, regs);
- }
- if (__exshift)
- memcpy ((char *) __lomem + __exshift, (char *) __lomem,
- (char *) __break - (char *) __lomem);
-
- /* call it... */
-
- #ifdef DEBUG
- os_print ("Final call : ");
- os_print (cli);
- os_print ("\n\r");
- #endif
-
- __funcall ((*__exec), (cli)); /* HACK ME ?? */
-
- /* never reached */
-
- return (0);
- }
-
- void
- __exret (void)
- {
- register struct env *e;
- int i;
-
- /* shift heap and __u pointers back down */
-
- if (__exshift || __codeshift)
- {
- register unsigned int v = __exshift;
- register unsigned int c = __codeshift;
- register struct proc *u = __u;
- register int i;
-
- if (__exshift)
- memcpy ((char *) __lomem, (char *) __lomem + __exshift, (char *) __break - (char *) __lomem);
- dshift (u->tty, v, c);
- for (i = 0; i < MAXTTY; i++)
- {
- if (u->tty[i].out)
- dshift2 (u->tty[i].out, v, c, int (*)(int));
- if (u->tty[i].in)
- dshift2 (u->tty[i].in, v, c, int (*)(void));
- if (u->tty[i].scan)
- dshift2 (u->tty[i].scan, v, c, int (*)(int));
- if (u->tty[i].init)
- dshift2 (u->tty[i].init, v, c, int (*)(void));
- if (u->tty[i].flush)
- dshift2 (u->tty[i].flush, v, c, int (*)(void));
-
- #ifndef __TTY_STATIC_BUFS
- if (u->tty[i].del)
- dshift (u->tty[i].del, v, c);
- if (u->tty[i].buf)
- dshift (u->tty[i].buf, v, c);
- #endif
- if (u->tty[i].ptr)
- dshift (u->tty[i].ptr, v, c);
- }
- for (i = 0; i < MAXFD; i++)
- if (u->file[i].dup)
- dshift (u->file[i].dup, v, c);
- dshift (u->argb, v, c);
- dshift (u->argv, v, c);
- for (i = 0; i < u->argc; i++)
- dshift (u->argv[i], v, c);
- }
-
- /* reinstall handlers */
-
- e = __Cenv;
- for (i = 0; i < 13; i++)
- __wrenv (i, e->h + i);
-
- {
- int r[10];
-
- r[0] = (int) "UnixLib$env";
- r[1] = r[3] = r[4] = 0;
- r[2] = -1;
- os_swi (OS_SetVarVal, r);
- }
-
- #ifdef DEBUG
- __debug ("__exret()");
- #endif
-
- __u->status.has_parent = 1;
-
- if (__exerr)
- {
- __seterr (__exerr);
- i = __W_EXITCODE (EXIT_FAILURE, SIGERR);
- }
- else
- i = __W_EXITCODE (__intenv ("Sys$ReturnCode", 0), 0);
-
- #ifdef DEBUG
- os_print ("return = ");
- os_prhex (i);
- os_print ("\r\n");
- #endif
-
- if (___vret)
- __funcall ((*___vret), (i));
- else /* oh fuck... */
- _exit (1);
- }
-