88483f213ba7dd872fbb347d5e1eb6cff075ceb0
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / execve.c
1 /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <stddef.h>
22 #include <unistd.h>
23 #include <hurd.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 /* Replace the current process, executing PATH with arguments ARGV and
30    environment ENVP.  ARGV and ENVP are terminated by NULL pointers.  */
31 int
32 DEFUN(__execve, (path, argv, envp),
33       CONST char *path AND char *CONST argv[] AND char *CONST envp[])
34 {
35   error_t err;
36   file_t file;
37   char *args, *env, *ap;
38   size_t argslen, envlen;
39   int ints[INIT_INT_MAX];
40   mach_port_t ports[_hurd_nports];
41   int dealloc_ports[_hurd_nports];
42   file_t *dtable;
43   int dtablesize;
44   struct _hurd_port **dtable_cells;
45   int *dealloc_dtable, *dealloc_cells;
46   int i;
47   char *const *p;
48   struct _hurd_sigstate *ss;
49
50   /* Get a port to the file we want to execute.  */
51   file = __path_lookup (path, FS_LOOKUP_EXEC, 0);
52   if (file == MACH_PORT_NULL)
53     return -1;
54
55   /* Pack the arguments into an array with nulls separating the elements.  */
56   argslen = 0;
57   p = argv;
58   while (*p != NULL)
59     argslen += strlen (*p++) + 1;
60   args = __alloca (argslen);
61   ap = args;
62   for (p = argv; *p != NULL; ++p)
63     ap = __memccpy (ap, *p, '\0', ULONG_MAX);
64
65   /* Pack the environment into an array with nulls separating the elements.  */
66   envlen = 0;
67   p = envp;
68   while (*p != NULL)
69     envlen += strlen (*p++) + 1;
70   env = __alloca (envlen);
71   ap = env;
72   for (p = envp; *p != NULL; ++p)
73     ap = __memccpy (ap, *p, '\0', ULONG_MAX);
74
75   /* Load up the ports to give to the new program.  */
76   for (i = 0; i < _hurd_nports; ++i)
77     ports[i] = _hurd_port_get (&_hurd_ports[i], &dealloc_ports[i]);
78
79   /* Load up the ints to give the new program.  */
80   for (i = 0; i < INIT_INT_MAX; ++i)
81     switch (i)
82       {
83       case INIT_UMASK:
84         ints[i] = _hurd_umask;
85         break;
86
87       case INIT_SIGMASK:
88       case INIT_SIGIGN:
89         break;
90
91       default:
92         ints[i] = 0;
93       }
94
95   ss = _hurd_thread_sigstate (__mach_thread_self ());
96   ints[INIT_SIGMASK] = ss->blocked;
97   ints[INIT_SIGPENDING] = ss->pending;
98   ints[INIT_SIGIGN] = 0;
99   for (i = 1; i < NSIG; ++i)
100     if (ss->actions[i].sa_handler == SIG_IGN)
101       ints[INIT_SIGIGN] |= __sigmask (i);
102
103   /* We hold the sigstate lock until the exec has failed so that no signal
104      can arrive between when we pack the blocked and ignored signals, and
105      when the exec actually happens.  A signal handler could change what
106      signals are blocked and ignored.  Either the change will be reflected
107      in the exec, or the signal will never be delivered.  */
108   
109   /* Pack up the descriptor table to give the new program.  */
110   __mutex_lock (&_hurd_dtable_lock);
111   if (_hurd_dtable.d != NULL)
112     {
113       dtablesize = _hurd_dtable.size;
114       dtable = __alloca (dtablesize * sizeof (dtable[0]));
115       dealloc_dtable = __alloca (dtablesize * sizeof (dealloc_dtable[0]));
116       dtable_cells = __alloca (dtablesize * sizeof (dealloc_cells[0]));
117       for (i = 0; i < dtablesize; ++i)
118         {
119           struct _hurd_fd *const d = &_hurd_dtable.d[i];
120           __spin_lock (&d->port.lock);
121           if (d->flags & FD_CLOEXEC)
122             {
123               dtable[i] = MACH_PORT_NULL;
124               __spin_unlock (&d->port.lock);
125             }
126           else
127             {
128               /* If this is a descriptor to our controlling tty,
129                  we want to give the normal port, not the foreground port.  */
130               dtable[i] = _hurd_port_get (&d->ctty, &dealloc_dtable[i]);
131               if (dtable[i] == MACH_PORT_NULL)
132                 {
133                   dtable[i] = _hurd_port_locked_get (&d->port,
134                                                      &dealloc_dtable[i]);
135                   dtable_cells[i] = &d->port;
136                 }
137               else
138                 {
139                   __spin_unlock (&d->port.lock);
140                   dtable_cells[i] = &d->ctty;
141                 }
142             }
143         }
144     }
145   else
146     {
147       dtable = _hurd_init_dtable;
148       dtablesize = _hurd_init_dtablesize;
149       dealloc_dtable = NULL;
150       dealloc_cells = NULL;
151     }
152
153   /* The information is all set up now.  Try to exec the file.  */
154
155   {
156     mach_port_t please_dealloc[_hurd_nports + dtablesize], *p = please_dealloc;
157
158     /* Request the exec server to deallocate some ports from us if the exec
159        succeeds.  The init ports and descriptor ports will arrive in the
160        new program's exec_startup message.  If we failed to deallocate
161        them, the new program would have duplicate user references for them.
162        But we cannot deallocate them ourselves, because we must still have
163        them after a failed exec call.  */
164
165     for (i = 0; i < _hurd_nports; ++i)
166       *p++ = ports[i];
167     for (i = 0; i < dtablesize; ++i)
168       *p++ = dtable[i];
169
170     err = __file_exec (file, __mach_task_self (),
171                        0,
172                        args, argslen, env, envlen,
173                        dtable, dtablesize, MACH_MSG_TYPE_COPY_SEND,
174                        ports, _hurd_nports, MACH_MSG_TYPE_COPY_SEND,
175                        ints, INIT_INT_MAX,
176                        please_dealloc, _hurd_nports + dtablesize,
177                        NULL, 0);
178   }
179
180   /* Safe to let signals happen now.  */
181   __mutex_unlock (&ss->lock);
182
183   /* Release references to the standard ports.  */
184   for (i = 0; i < _hurd_nports; ++i)
185     _hurd_port_free (&_hurd_ports[i], &dealloc_ports[i], ports[i]);
186
187   if (dealloc_dtable != NULL)
188     /* Release references to the file descriptor ports.  */
189     for (i = 0; i < dtablesize; ++i)
190       if (dtable[i] != MACH_PORT_NULL)
191         _hurd_port_free (dtable[i], &dealloc_dtable[i], dtable_cells[i]);
192
193   if (err)
194     return __hurd_fail (err);
195
196   /* That's interesting.  */
197   return 0;
198 }