Update to LGPL v2.1.
[jlayton/glibc.git] / hurd / hurdmsg.c
1 /* Copyright (C) 1992, 1994, 1995, 1996, 1997 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 Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the 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    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <hurd.h>
20 #include <hurd/msg_server.h>
21 #include <hurd/fd.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <string.h>
25 #include <argz.h>
26
27
28 #define AUTHCHECK \
29   if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \
30     return EPERM
31
32
33 /* Snarfing and frobbing the init ports.  */
34
35 kern_return_t
36   _S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which,
37                         mach_port_t *result, mach_msg_type_name_t *result_type)
38 {
39   AUTHCHECK;
40   *result_type = MACH_MSG_TYPE_MOVE_SEND;
41   /* This function adds a new user reference for the *RESULT it gives back.
42      Our reply message uses a move-send right that consumes this reference.  */
43   return _hurd_ports_get (which, result);
44 }
45
46 kern_return_t
47 _S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
48                       int which, mach_port_t port)
49 {
50   error_t err;
51
52   AUTHCHECK;
53
54   err = _hurd_ports_set (which, port);
55   if (err == 0)
56     __mach_port_deallocate (__mach_task_self (), port);
57
58   return 0;
59 }
60
61 kern_return_t
62 _S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
63                        mach_port_t **ports,
64                        mach_msg_type_name_t *ports_type,
65                        mach_msg_type_number_t *nports)
66 {
67   mach_msg_type_number_t i;
68   error_t err;
69
70   AUTHCHECK;
71
72   if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
73                            _hurd_nports * sizeof (mach_port_t), 1))
74     return err;
75   *nports = _hurd_nports;
76
77   for (i = 0; i < _hurd_nports; ++i)
78     /* This function adds a new user ref for the *RESULT it gives back.
79        Our reply message uses move-send rights that consumes this ref.  */
80     if (err = _hurd_ports_get (i, &(*ports)[i]))
81       {
82         /* Died part way through.  Deallocate the ports already fetched.  */
83         while (i-- > 0)
84           __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
85         __vm_deallocate (__mach_task_self (),
86                          (vm_address_t) *ports,
87                          *nports * sizeof (mach_port_t));
88         return err;
89       }
90
91   *ports_type = MACH_MSG_TYPE_MOVE_SEND;
92   return 0;
93 }
94
95 kern_return_t
96 _S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
97                        mach_port_t *ports, mach_msg_type_number_t nports)
98 {
99   mach_msg_type_number_t i;
100   error_t err;
101
102   AUTHCHECK;
103
104   for (i = 0; i < _hurd_nports; ++i)
105     {
106       if (err = _hurd_ports_set (i, ports[i]))
107         return err;
108       else
109         __mach_port_deallocate (__mach_task_self (), ports[i]);
110     }
111
112   return 0;
113 }
114 \f
115 /* Snarfing and frobbing the init ints.  */
116
117 static kern_return_t
118 get_int (int which, int *value)
119 {
120   switch (which)
121     {
122     case INIT_UMASK:
123       *value = _hurd_umask;
124       return 0;
125     case INIT_SIGMASK:
126       {
127         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
128         __spin_lock (&ss->lock);
129         *value = ss->blocked;
130         __spin_unlock (&ss->lock);
131         return 0;
132       }
133     case INIT_SIGPENDING:
134       {
135         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
136         __spin_lock (&ss->lock);
137         *value = ss->pending;
138         __spin_unlock (&ss->lock);
139         return 0;
140       }
141     case INIT_SIGIGN:
142       {
143         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
144         sigset_t ign;
145         int sig;
146         __spin_lock (&ss->lock);
147         __sigemptyset (&ign);
148         for (sig = 1; sig < NSIG; ++sig)
149           if (ss->actions[sig].sa_handler == SIG_IGN)
150             __sigaddset (&ign, sig);
151         __spin_unlock (&ss->lock);
152         *value = ign;
153         return 0;
154       }
155     default:
156       return EINVAL;
157     }
158 }
159
160 kern_return_t
161 _S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
162                      int which, int *value)
163 {
164   AUTHCHECK;
165
166   return get_int (which, value);
167 }
168
169 kern_return_t
170 _S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
171                       int **values, mach_msg_type_number_t *nvalues)
172 {
173   error_t err;
174   mach_msg_type_number_t i;
175
176   AUTHCHECK;
177
178   if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
179                            INIT_INT_MAX * sizeof (int), 1))
180     return err;
181   *nvalues = INIT_INT_MAX;
182
183   for (i = 0; i < INIT_INT_MAX; ++i)
184     switch (err = get_int (i, &(*values)[i]))
185       {
186       case 0:                   /* Success.  */
187         break;
188       case EINVAL:              /* Unknown index.  */
189         (*values)[i] = 0;
190         break;
191       default:                  /* Lossage.  */
192         __vm_deallocate (__mach_task_self (),
193                          (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
194         return err;
195       }
196
197   return 0;
198 }
199
200
201 static kern_return_t
202 set_int (int which, int value)
203 {
204   switch (which)
205     {
206     case INIT_UMASK:
207       _hurd_umask = value;
208       return 0;
209
210       /* These are pretty odd things to do.  But you asked for it.  */
211     case INIT_SIGMASK:
212       {
213         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
214         __spin_lock (&ss->lock);
215         ss->blocked = value;
216         __spin_unlock (&ss->lock);
217         return 0;
218       }
219     case INIT_SIGPENDING:
220       {
221         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
222         __spin_lock (&ss->lock);
223         ss->pending = value;
224         __spin_unlock (&ss->lock);
225         return 0;
226       }
227     case INIT_SIGIGN:
228       {
229         struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
230         int sig;
231         const sigset_t ign = value;
232         __spin_lock (&ss->lock);
233         for (sig = 1; sig < NSIG; ++sig)
234           {
235             if (__sigismember (&ign, sig))
236               ss->actions[sig].sa_handler = SIG_IGN;
237             else if (ss->actions[sig].sa_handler == SIG_IGN)
238               ss->actions[sig].sa_handler = SIG_DFL;
239           }
240         __spin_unlock (&ss->lock);
241         return 0;
242
243       case INIT_TRACEMASK:
244         _hurdsig_traced = value;
245         return 0;
246       }
247     default:
248       return EINVAL;
249     }
250 }
251
252 kern_return_t
253 _S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
254                      int which, int value)
255 {
256   AUTHCHECK;
257
258   return set_int (which, value);
259 }
260
261 kern_return_t
262 _S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
263                       int *values, mach_msg_type_number_t nvalues)
264 {
265   error_t err;
266   mach_msg_type_number_t i;
267
268   AUTHCHECK;
269
270   for (i = 0; i < INIT_INT_MAX; ++i)
271     switch (err = set_int (i, values[i]))
272       {
273       case 0:                   /* Success.  */
274         break;
275       case EINVAL:              /* Unknown index.  */
276         break;
277       default:                  /* Lossage.  */
278         return err;
279       }
280
281   return 0;
282 }
283 \f
284
285 kern_return_t
286 _S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
287                mach_port_t *result, mach_msg_type_name_t *result_type)
288 {
289   AUTHCHECK;
290
291   /* This creates a new user reference for the send right.
292      Our reply message will move that reference to the caller.  */
293   *result = __getdport (which);
294   if (*result == MACH_PORT_NULL)
295     return errno;
296   *result_type = MACH_MSG_TYPE_MOVE_SEND;
297
298   return 0;
299 }
300
301 kern_return_t
302 _S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
303                int which, mach_port_t port)
304 {
305   AUTHCHECK;
306
307   /* We consume the reference if successful.  */
308   return HURD_FD_USE (which, (_hurd_port2fd (descriptor, port, 0), 0));
309 }
310 \f
311 /* Snarfing and frobbing environment variables.  */
312
313 kern_return_t
314 _S_msg_get_env_variable (mach_port_t msgport,
315                          char *variable,
316                          char **data, mach_msg_type_number_t *datalen)
317 {
318   error_t err;
319   mach_msg_type_number_t valuelen;
320   const char *value = getenv (variable);
321
322   if (value == NULL)
323     return ENOENT;
324
325   valuelen = strlen (value);
326   if (valuelen > *datalen)
327     {
328       if (err = __vm_allocate (__mach_task_self (), 
329                                (vm_address_t *) data, valuelen, 1))
330         return err;
331     }
332
333   memcpy (*data, value, valuelen);
334   *datalen = valuelen;
335
336   return 0;
337 }
338
339
340 kern_return_t
341 _S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
342                          char *variable,
343                          char *value,
344                          int replace)
345 {
346   AUTHCHECK;
347
348   if (setenv (variable, value, replace)) /* XXX name space */
349     return errno;
350   return 0;
351 }
352
353 kern_return_t
354 _S_msg_get_environment (mach_port_t msgport,
355                         char **data, mach_msg_type_number_t *datalen)
356 {
357   /* Pack the environment into an array with nulls separating elements.  */
358   if (__environ != NULL)
359     {
360       char *ap, **p;
361       size_t envlen = 0;
362
363       for (p = __environ; *p != NULL; ++p)
364         envlen += strlen (*p) + 1;
365
366       if (envlen > *datalen)
367         {
368           if (__vm_allocate (__mach_task_self (),
369                              (vm_address_t *) data, envlen, 1))
370             return ENOMEM;
371         }
372
373       ap = *data;
374       for (p = __environ; *p != NULL; ++p)
375         ap = __memccpy (ap, *p, '\0', ULONG_MAX);
376
377       *datalen = envlen;
378     }
379   else
380     *datalen = 0;
381
382   return 0;
383 }
384
385 kern_return_t
386 _S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
387                         char *data, mach_msg_type_number_t datalen)
388 {
389   int _hurd_split_args (char *, mach_msg_type_number_t, char **);
390   int envc;
391   char **envp;
392
393   AUTHCHECK;
394
395   envc = __argz_count (data, datalen);
396   envp = malloc ((envc + 1) * sizeof (char *));
397   if (envp == NULL)
398     return errno;
399   __argz_extract (data, datalen, envp);
400   __environ = envp;             /* XXX cooperate with loadenv et al */
401   return 0;
402 }
403 \f
404
405 /* XXX */
406
407 kern_return_t
408 _S_msg_get_dtable (mach_port_t process,
409                    mach_port_t refport,
410                    portarray_t *dtable,
411                    mach_msg_type_name_t *dtablePoly,
412                    mach_msg_type_number_t *dtableCnt)
413 { return EOPNOTSUPP; }
414
415 kern_return_t
416 _S_msg_set_dtable (mach_port_t process,
417                    mach_port_t refport,
418                    portarray_t dtable,
419                    mach_msg_type_number_t dtableCnt)
420 { return EOPNOTSUPP; }