home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / unix / unixlib_1 / !UnixLib37_src_sys_c_exec < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-09  |  15.6 KB  |  675 lines

  1. /****************************************************************************
  2.  *
  3.  * $Source: /unixb/home/unixlib/source/unixlib37/src/sys/c/RCS/exec,v $
  4.  * $Date: 1996/11/06 22:01:42 $
  5.  * $Revision: 1.4 $
  6.  * $State: Rel $
  7.  * $Author: unixlib $
  8.  *
  9.  * $Log: exec,v $
  10.  * Revision 1.4  1996/11/06 22:01:42  unixlib
  11.  * Yet more changes by NB, PB and SC.
  12.  *
  13.  * Revision 1.3  1996/10/30 21:59:00  unixlib
  14.  * Massive changes made by Nick Burret and Peter Burwood.
  15.  *
  16.  * Revision 1.2  1996/05/06 09:03:14  unixlib
  17.  * Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
  18.  * Saved for 3.7a release.
  19.  *
  20.  * Revision 1.1  1996/04/19 21:34:24  simon
  21.  * Initial revision
  22.  *
  23.  ***************************************************************************/
  24.  
  25. static const char rcs_id[] = "$Id: exec,v 1.4 1996/11/06 22:01:42 unixlib Rel $";
  26.  
  27. #include <errno.h>
  28. #include <stdarg.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31.  
  32. #include <fcntl.h>
  33. #include <unistd.h>
  34. #include <sys/param.h>
  35. #include <sys/unix.h>
  36. #include <sys/syslib.h>
  37. #include <sys/debug.h>
  38. #include <sys/swis.h>
  39. #include <sys/wait.h>
  40.  
  41. #ifdef DEBUG
  42. #include <sys/os.h>
  43. #endif
  44.  
  45. /* Execute path with all arguments after path until a NULL
  46.    pointer and environment from 'environ'.  */
  47.  
  48. int
  49. execl (const char *path, const char *arg, ...)
  50. {
  51.   const char *argv[MAXCOMMANDLEN >> 2];
  52.   unsigned int i;
  53.   va_list args;
  54.  
  55.   argv[0] = arg;
  56.  
  57.   va_start (args, arg);
  58.   i = 1;
  59.   do
  60.     {
  61.       if (i >= (MAXCOMMANDLEN >> 2))
  62.         {
  63.           errno = E2BIG;
  64.           return -1;
  65.         }
  66.       argv[i] = va_arg (args, const char *);
  67.     } while (argv[i++] != NULL);
  68.   va_end (args);
  69.  
  70.   return execve (path, (char **)argv, (char **)environ);
  71. }
  72.  
  73. /* Execute path with all arguments after path until a NULL pointer,
  74.    and the argument after that for environment.  */
  75.  
  76. int
  77. execle (const char *path, const char *arg, ...)
  78. {
  79.   const char *argv[MAXCOMMANDLEN >> 2];
  80.   const char **envp;
  81.   unsigned int i;
  82.   va_list args;
  83.  
  84.   va_start(args, arg);
  85.   argv[0] = arg;
  86.   i = 1;
  87.   do
  88.     {
  89.       if (i >= (MAXCOMMANDLEN >> 2))
  90.         {
  91.           errno = E2BIG;
  92.           return -1;
  93.         }
  94.       argv[i] = va_arg(args, const char *);
  95.     } while (argv[i++] != NULL);
  96.  
  97.   envp = va_arg(args, const char **);
  98.   va_end (args);
  99.  
  100.   return execve (path, (char **)argv, (char **)envp);
  101. }
  102.  
  103. /* Execute file, searching in the 'path' environment variable if
  104.    it contains no slashes, with all arguments after file until a
  105.    NULL pointer and environment from 'environ'.  */
  106. int
  107. execlp (const char *file, const char *arg, ...)
  108. {
  109.   const char *argv[MAXCOMMANDLEN >> 2];
  110.   unsigned int i;
  111.   va_list args;
  112.  
  113.   argv[0] = arg;
  114.   va_start (args, arg);
  115.  
  116.   i = 1;
  117.   do {
  118.       if (i >= (MAXCOMMANDLEN >> 2))
  119.         {
  120.           errno = E2BIG;
  121.           return -1;
  122.         }
  123.     argv[i] = va_arg (args, const char *);
  124.   } while (argv[i++] != NULL);
  125.  
  126.   va_end (args);
  127.  
  128.   return execvp (file, (char **)argv);
  129. }
  130.  
  131. /* Execute path with arguments argv and environment from 'environ'.  */
  132. int
  133. execv (const char *path, char **argv)
  134. {
  135.   return execve (path, argv, environ);
  136. }
  137.  
  138. /* Execute file, searching in the 'path' environment variable if it
  139.    contains no slashes, with arguments argv and environment from
  140.    'environ'.  */
  141. int
  142. execvp (const char *name, char **argv)
  143. {
  144.   /* Path searching has not been implemented.  */
  145.   return execve (name, argv, environ);
  146. }
  147.  
  148. /* #define DEBUG */
  149.  
  150. #ifdef DEBUG
  151. #define ushift(p,v,c) ((p) = __ushift((unsigned char *)p,v,c,"(" #p ")"))
  152. #define ushift2(p,v,c,t) ((p) = (t)__ushift((unsigned char *)p,v,c,"(" #p ")"))
  153. #define showmove(s,n,p,r) (os_print(s "("), os_print(n), os_prhex((int)p), os_print(") -> "), os_prhex((int)r), os_nl())
  154. #undef memcpy
  155. #define memcpy(d,s,n) (os_print("memcpy("), os_prhex((int)(d)), os_print(","), os_prhex((int)(s)), os_print(","), \
  156.                        os_prhex((int)(n)), os_print(")"), os_nl(), __memcpy(d,s,n))
  157.  
  158. static void *
  159. __ushift (register unsigned char *p, register unsigned int v, register unsigned int c, char *n)
  160. {
  161.   register void *r = ((p >= __base && p < __rwlimit) ? p + c
  162.               : (p >= __lomem && p < __break) ? p + v : p);
  163.   showmove ("ushift", n, p, r);
  164.   return r;
  165. }
  166.  
  167. #else
  168.  
  169. #define ushift(p,v,c) ((p) = __ushift((unsigned char *)p,v,c))
  170. #define ushift2(p,v,c,t) ((p) = (t)__ushift((unsigned char *)p,v,c))
  171.  
  172. static void *
  173. __ushift (register unsigned char *p, register unsigned int v, register unsigned int c)
  174. {
  175.   return ((p >= __base && p < __rwlimit) ? p + c
  176.       : (p >= __lomem && p < __break) ? p + v : p);
  177. }
  178.  
  179. #endif
  180.  
  181. #ifdef DEBUG
  182. #define dshift(p,v,c) ((p) = __dshift((unsigned char *)p,v,c,"(" #p ")"))
  183. #define dshift2(p,v,c,t) ((p) = (t)__dshift((unsigned char *)p,v,c,"(" #p ")"))
  184.  
  185. static void *
  186. __dshift (register unsigned char *p, register unsigned int v, register unsigned int c, char *n)
  187. {
  188.   register void *q1 = p - c;
  189.   register void *q2 = p - v;
  190.   register void *r = ((q1 >= __base && q1 < __rwlimit) ? q1
  191.               : (q2 >= __lomem && q2 < __break) ? q2 : p);
  192.   showmove ("dshift", n, p, r);
  193.   return r;
  194. }
  195.  
  196. #else
  197.  
  198. #define dshift(p,v,c) ((p) = __dshift((unsigned char *)p,v,c))
  199. #define dshift2(p,v,c,t) ((p) = (t)__dshift((unsigned char *)p,v,c))
  200.  
  201. static void *
  202. __dshift (register unsigned char *p, register unsigned int v, register unsigned int c)
  203. {
  204.   register void *q1 = p - c;
  205.   register void *q2 = p - v;
  206.  
  207.   /* this is only safe when 2 * maximum application space size < start of dynamic areas */
  208.   return ((q1 >= __base && q1 < __rwlimit) ? q1
  209.       : (q2 >= __lomem && q2 < __break) ? q2 : p);
  210. }
  211.  
  212. #endif
  213.  
  214.  
  215. _kernel_oserror *__exerr;
  216.  
  217. int
  218. execve (const char *execname, char **argv, char **envp)
  219. {
  220.   register struct proc *u = __u;
  221.   register int i, l;
  222.   register char *s1, *s2, *s3;
  223.   register struct env *e;
  224.   char *name;
  225.   void (*__exec) (char *);
  226.   char cli[MAXCOMMANDLEN];
  227.  
  228. #ifdef DEBUG
  229.   __debug ("execve: entered function. Parameters are:");
  230.   printf ("------------------------------------------next bit\n");
  231.   printf ("execname = '%s'\n", execname);
  232.   printf ("argv = ");
  233.   i = -1;
  234.   while (argv[++i])
  235.     printf ("argv[%d] = '%s', ", i, argv[i]);
  236.   printf ("\nenvp = ");
  237.   i = -1;
  238.   while (envp[++i])
  239.     printf ("envp[%d] = '%s', ", i, envp[i]);
  240.   printf ("\n");
  241. #endif
  242.  
  243.   if (!execname || !argv || !envp)
  244.     {
  245.       errno = EINVAL;
  246.       return (-1);
  247.     }
  248.  
  249.   if (*execname != '*')
  250.     name = __uname ((char *)execname, 0);
  251.   else
  252.     name = (char *)execname;
  253.  
  254. /* check MAXCOMMANDLEN */
  255.  
  256. #ifdef DEBUG
  257.   os_print ("checking MAXCOMMANDLEN\n\r");
  258. #endif
  259.  
  260.   /* Move through the command arguments, cumulating the lengths
  261.      to determine whether our command line will be >= MAXCOMMANDLEN.  */
  262.   l = strlen (name) + 1;
  263.   for (i = 0; argv[i] && l < MAXCOMMANDLEN; l += strlen (argv[i]) + 1, i++);
  264.   if (l >= MAXCOMMANDLEN)
  265.     {
  266.       errno = E2BIG;
  267.       return (-1);
  268.     }
  269.  
  270.   /* If we are a process with no parent, we just verify the command line
  271.      lengths and call the process.  */
  272.   if (!u->status.has_parent)
  273.     {
  274.       s2 = cli;
  275.       s3 = name;
  276. #ifdef DEBUG
  277.       os_print ("Taking a shortcut\n\r");
  278. #endif
  279.       if (*s3 != '*')
  280.     *s2++ = '/';
  281.       while (*s2++ = *s3++);
  282.       s2[-1] = ' ';
  283.       if (argv[0])
  284.     for (i = 1; s3 = argv[i]; i++)
  285.       {
  286.         while (*s2++ = *s3++);
  287.         s2[-1] = ' ';
  288.       }
  289.       s2[-1] = 0;
  290.       __reset ();
  291.  
  292.       /* If the cli is >= MAXPATHLEN, we will need the aid of
  293.          DDE utils.  */
  294.       if (strlen (cli) >= MAXPATHLEN)
  295.     {
  296.       int r[10];
  297.       char *temp = strchr (cli, ' ');
  298. #ifdef DEBUG
  299.       os_print ("Shortcut requires DDE\n\r");
  300. #endif
  301.       /* Check that the actual command is not greater than
  302.          RISC OS's maximum path length.  */
  303.       if ((temp - cli) >= MAXPATHLEN)
  304.         {
  305.           errno = E2BIG;
  306.           return -1;
  307.         }
  308.       /* Set the command line size within DDE utils.  */
  309.       r[0] = strlen (temp + 1) + 1;
  310.       if (os_swi (DDEUtils_SetCLSize, r))
  311.         {
  312.           /* We're buggered if DDE utils isn't on this system.  */
  313.           errno = E2BIG;
  314.           return -1;
  315.         }
  316.       r[0] = (int) temp + 1;
  317.       os_swi (DDEUtils_SetCL, r);
  318.       *temp = '\0';
  319. #ifdef DEBUG
  320.       os_print ("Shortcut - DDE setup\n\r");
  321. #endif
  322.     }
  323.  
  324.       /* if the DAs are being used, then delete the dynamic area first.
  325.          This is safe to do before the os_cli call since cli is on the stack
  326.          and hence not in the DA.  */
  327.       if (__dynamic_num != -1)
  328.     __dynamic_area_exit ();
  329.       /* Pass the command to os_cli (which never returns).  */
  330.       os_cli (cli);
  331.       /* something ugly must have happened to get here, so just exit.  */
  332.       __exit_no_code ();
  333.     }
  334.  
  335.   /* If we arrive here, we have a parent process.  */
  336.  
  337. /* check for overlapping argv arrays */
  338. #ifdef DEBUG
  339.   os_print ("Doing it the long way\n\r");
  340. #endif
  341.  
  342.   l = argv - u->argv;
  343.   if (l < 0)
  344.     l = -l;
  345.  
  346.   if (l <= i)
  347.     {
  348.       errno = EINVAL;
  349.       return (-1);
  350.     }
  351.  
  352. /* check free memory */
  353.  
  354. #ifdef DEBUG
  355.   os_print ("__rwlimit: "), os_prhex ((unsigned int)__rwlimit), os_nl();
  356.   os_print ("__stack_limit: "), os_prhex ((unsigned int)__stack_limit), os_nl();
  357. #endif
  358.  
  359.   if (((unsigned int) __base & ~0xff) == 0x8000)
  360.     {
  361.       __codeshift = ((char *) __stack - (char *) __stack_limit) - 512 - __exlen;
  362. #ifdef __4K_BOUNDARY
  363.       /* align down to 4K boundary. */
  364.       __codeshift = __codeshift & ~4095;
  365. #endif
  366.       if (__dynamic_num == -1)    /* heap not in a dynamic area */
  367.     __exshift = __codeshift;
  368.       else
  369.     __exshift = 0;
  370.     }
  371.   else
  372.     __codeshift = (__exshift = 0);
  373.  
  374.   /* __codeshift needs to be something > 0, but how much is a suitable miniumum ? */
  375.   if (__codeshift < MAXCOMMANDLEN)
  376.     {
  377.       errno = ENOMEM;
  378.       return (-1);
  379.     }
  380.  
  381. #ifdef DEBUG
  382.   os_print ("__exlen: "), os_prhex ((unsigned int)__exlen), os_nl ();
  383.   os_print ("__codeshift: "), os_prhex ((unsigned int)__codeshift), os_nl ();
  384.   os_print ("__exshift: "), os_prhex ((unsigned int)__exshift), os_nl ();
  385. #endif
  386.  
  387. /* copy name into u->argb */
  388.  
  389.   s1 = u->argb;
  390.   s2 = cli;
  391.   s3 = name;
  392.   if (*s3 != '*')
  393.     *s2++ = '/';
  394.   while (*s1++ = *s2++ = *s3++);
  395.   s2[-1] = ' ';
  396.  
  397. /* write cli args, u->argv[] & u->argc */
  398.  
  399.   if (argv[0])
  400.     {
  401. #ifdef DEBUG
  402.       printf ("if argv[0] = '%s'\n", argv[0]);
  403. #endif
  404.       s3 = argv[0];
  405.       u->argv[0] = s1;
  406.       while (*s1++ = *s3++);
  407.  
  408.       for (i = 1; s3 = argv[i]; i++)
  409.     {
  410.       u->argv[i] = s1;
  411.       while (*s1++ = *s2++ = *s3++);
  412.       s2[-1] = ' ';
  413.     }
  414.     }
  415.   else
  416.     {
  417.       i = 0;
  418.       *s1 = 0;
  419.     }
  420.  
  421.   u->argv[u->argc = i] = 0;
  422.  
  423. /* terminate cli */
  424.  
  425.   s2[-1] = 0;
  426.  
  427. #ifdef DEBUG
  428.   os_print ("cli set up : ");
  429.   os_print (cli);
  430.   os_print ("\n\r");
  431. #endif
  432.  
  433.   if (strlen (cli) >= MAXPATHLEN)    /* We need to use DDE utils for this */
  434.     {
  435.       int r[10];
  436.       char *temp = cli;
  437.       if (*temp == '*')
  438.     temp++;
  439.       while (*temp == ' ')
  440.     temp++;            /* command starts star, space - right pain */
  441.  
  442.       temp = strchr (temp, ' ');
  443. #ifdef DEBUG
  444.       os_print ("long way requires DDE : ");
  445.       os_print (cli);
  446.       os_print ("\n\r");
  447. #endif
  448.       if ((temp - cli) >= MAXPATHLEN)
  449.     {
  450.       errno = E2BIG;
  451.       return (-1);
  452.     }            /* still too long */
  453.       r[0] = strlen (temp + 1) + 1;
  454.       if (os_swi (DDEUtils_SetCLSize, r))
  455.     {
  456.       errno = E2BIG;
  457.       return (-1);
  458.     }            /* no DDE utils */
  459.       r[0] = (int) temp + 1;
  460.       os_swi (DDEUtils_SetCL, r);
  461.       *temp = '\0';
  462. #ifdef DEBUG
  463.       os_print ("DDE utils set up\n\r");
  464. #endif
  465.     }
  466.  
  467. #ifdef DEBUG
  468.   __debug ("execve() (argv)");
  469. #endif
  470.  
  471.   /* File descriptors open in the existing process image remain open
  472.      in the new process image, unless they have the 'FD_CLOEXEC'
  473.      flag set.  O_EXECCL is an alias for FD_CLOEXEC.  */
  474.   for (i = 0; i < MAXFD; i++)
  475.     if (u->file[i].oflag & O_EXECCL)
  476.       close (i);
  477.  
  478.   /* Stop any interval timers that might be running.  Technically
  479.      the new process should inherit the pending alarms.  */
  480.   __stop_itimers ();
  481.  
  482.   u->status.has_parent = 0;
  483.  
  484. #ifdef DEBUG
  485.   __debug ("execve()");
  486. #endif
  487.  
  488.   /* Remove environment handlers.  */
  489.  
  490.   e = __Oenv;
  491.   for (i = 0; i < 13; i++)
  492.     __wrenv (i, e->h + i);
  493.  
  494. /* shift __u pointers if necessary */
  495.  
  496.   if (__exshift || __codeshift)
  497.     {
  498.       register unsigned int v = __exshift;
  499.       register unsigned int c = __codeshift;
  500.       register struct proc *u = __u;
  501.  
  502.       for (i = 0; i < u->argc; i++)
  503.     ushift (u->argv[i], v, c);
  504.       ushift (u->argv, v, c);
  505.       ushift (u->argb, v, c);
  506.       for (i = 0; i < MAXFD; i++)
  507.     if (u->file[i].dup)
  508.       ushift (u->file[i].dup, v, c);
  509.       for (i = 0; i < MAXTTY; i++)
  510.     {
  511.       if (u->tty[i].out)
  512.         ushift2 (u->tty[i].out, v, c, int (*)(int));
  513.       if (u->tty[i].in)
  514.         ushift2 (u->tty[i].in, v, c, int (*)(void));
  515.       if (u->tty[i].scan)
  516.         ushift2 (u->tty[i].scan, v, c, int (*)(int));
  517.       if (u->tty[i].init)
  518.         ushift2 (u->tty[i].init, v, c, int (*)(void));
  519.       if (u->tty[i].flush)
  520.         ushift2 (u->tty[i].flush, v, c, int (*)(void));
  521.  
  522. #ifndef __TTY_STATIC_BUFS
  523.       if (u->tty[i].del)
  524.         ushift (u->tty[i].del, v, c);
  525.       if (u->tty[i].buf)
  526.         ushift (u->tty[i].buf, v, c);
  527. #endif
  528.       if (u->tty[i].ptr)
  529.         ushift (u->tty[i].ptr, v, c);
  530.     }
  531.       ushift (u->tty, v, c);
  532.  
  533.       /* If itimers are malloc'd then they should probably be shifted here.  */
  534.  
  535.       __exec = (void (*)(char *)) ((char *) __stack_limit + __codeshift);
  536.     }
  537.   else
  538.     __exec = __exptr;
  539.  
  540.   {
  541.     int r[10];
  542.     char *v[1];
  543.  
  544.     v[0] = (char *) __u + __exshift;
  545.     r[0] = (int) "UnixLib$env";
  546.     r[1] = (int) v;
  547.     r[2] = 4;
  548.     r[3] = 0;
  549.     r[4] = 1;
  550.     os_swi (OS_SetVarVal, r);
  551.   }
  552.  
  553. /* copy up m/code routine and heap */
  554.  
  555.   if (__codeshift)
  556.     {
  557.       int regs[10];
  558.  
  559.       memcpy ((char *) __exec, (char *) __exptr, __exlen);
  560.       /* SynchroniseCodeAreas. This call is okay even if it isn't necessary
  561.          on pre-StrongARM machines.  */
  562.       regs[0] = 1;
  563.       regs[1] = (int)__exec;
  564.       regs[2] = regs[1] + __exlen - 4;
  565.       os_swi (OS_SynchroniseCodeAreas, regs);
  566.     }
  567.   if (__exshift)
  568.     memcpy ((char *) __lomem + __exshift, (char *) __lomem,
  569.             (char *) __break - (char *) __lomem);
  570.  
  571. /* call it... */
  572.  
  573. #ifdef DEBUG
  574.   os_print ("Final call : ");
  575.   os_print (cli);
  576.   os_print ("\n\r");
  577. #endif
  578.  
  579.   __funcall ((*__exec), (cli));    /* HACK ME ?? */
  580.  
  581. /* never reached */
  582.  
  583.   return (0);
  584. }
  585.  
  586. void
  587. __exret (void)
  588. {
  589.   register struct env *e;
  590.   int i;
  591.  
  592. /* shift heap and __u pointers back down */
  593.  
  594.   if (__exshift || __codeshift)
  595.     {
  596.       register unsigned int v = __exshift;
  597.       register unsigned int c = __codeshift;
  598.       register struct proc *u = __u;
  599.       register int i;
  600.  
  601.       if (__exshift)
  602.     memcpy ((char *) __lomem, (char *) __lomem + __exshift, (char *) __break - (char *) __lomem);
  603.       dshift (u->tty, v, c);
  604.       for (i = 0; i < MAXTTY; i++)
  605.     {
  606.       if (u->tty[i].out)
  607.         dshift2 (u->tty[i].out, v, c, int (*)(int));
  608.       if (u->tty[i].in)
  609.         dshift2 (u->tty[i].in, v, c, int (*)(void));
  610.       if (u->tty[i].scan)
  611.         dshift2 (u->tty[i].scan, v, c, int (*)(int));
  612.       if (u->tty[i].init)
  613.         dshift2 (u->tty[i].init, v, c, int (*)(void));
  614.       if (u->tty[i].flush)
  615.         dshift2 (u->tty[i].flush, v, c, int (*)(void));
  616.  
  617. #ifndef __TTY_STATIC_BUFS
  618.       if (u->tty[i].del)
  619.         dshift (u->tty[i].del, v, c);
  620.       if (u->tty[i].buf)
  621.         dshift (u->tty[i].buf, v, c);
  622. #endif
  623.       if (u->tty[i].ptr)
  624.         dshift (u->tty[i].ptr, v, c);
  625.     }
  626.       for (i = 0; i < MAXFD; i++)
  627.     if (u->file[i].dup)
  628.       dshift (u->file[i].dup, v, c);
  629.       dshift (u->argb, v, c);
  630.       dshift (u->argv, v, c);
  631.       for (i = 0; i < u->argc; i++)
  632.     dshift (u->argv[i], v, c);
  633.     }
  634.  
  635. /* reinstall handlers */
  636.  
  637.   e = __Cenv;
  638.   for (i = 0; i < 13; i++)
  639.     __wrenv (i, e->h + i);
  640.  
  641.   {
  642.     int r[10];
  643.  
  644.     r[0] = (int) "UnixLib$env";
  645.     r[1] = r[3] = r[4] = 0;
  646.     r[2] = -1;
  647.     os_swi (OS_SetVarVal, r);
  648.   }
  649.  
  650. #ifdef DEBUG
  651.   __debug ("__exret()");
  652. #endif
  653.  
  654.   __u->status.has_parent = 1;
  655.  
  656.   if (__exerr)
  657.     {
  658.       __seterr (__exerr);
  659.       i = __W_EXITCODE (EXIT_FAILURE, SIGERR);
  660.     }
  661.   else
  662.     i = __W_EXITCODE (__intenv ("Sys$ReturnCode", 0), 0);
  663.  
  664. #ifdef DEBUG
  665.   os_print ("return = ");
  666.   os_prhex (i);
  667.   os_print ("\r\n");
  668. #endif
  669.  
  670.   if (___vret)
  671.     __funcall ((*___vret), (i));
  672.   else                /* oh fuck... */
  673.     _exit (1);
  674. }
  675.