Formerly ../hurd/alloc-fd.c.~6~
[kopensolaris-gnu/glibc.git] / hurd / hurdsig.c
1 /* Copyright (C) 1991, 1992, 1993, 1994 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 <stdlib.h>
20 #include <stdio.h>
21 #include <gnu-stabs.h>
22 #include <hurd.h>
23 #include <hurd/signal.h>
24 #include <hurd/msg_reply.h>     /* For __sig_post_reply.  */
25
26 #ifdef noteven
27 struct mutex _hurd_siglock;
28 #endif
29 int _hurd_stopped;
30
31 /* Port that receives signals and other miscellaneous messages.  */
32 mach_port_t _hurd_msgport;
33
34 /* Thread listening on it.  */
35 thread_t _hurd_msgport_thread;
36
37 /* Thread which receives task-global signals.  */
38 thread_t _hurd_sigthread;
39
40 /* Linked-list of per-thread signal state.  */
41 struct _hurd_sigstate *_hurd_sigstates;
42
43 struct _hurd_sigstate *
44 _hurd_thread_sigstate (thread_t thread)
45 {
46   struct _hurd_sigstate *ss;
47   __mutex_lock (&_hurd_siglock);
48   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
49     if (ss->thread == thread)
50       break;
51   if (ss == NULL)
52     {
53       ss = calloc (1, sizeof (*ss)); /* Zero-initialized.  */
54       if (ss == NULL)
55         __libc_fatal ("hurd: Can't allocate thread sigstate\n");
56       ss->thread = thread;
57 #ifdef noteve
58       __mutex_init (&ss->lock);
59 #endif
60       ss->next = _hurd_sigstates;
61       _hurd_sigstates = ss;
62     }
63   __mutex_lock (&ss->lock);
64   __mutex_unlock (&_hurd_siglock);
65   return ss;
66 }
67 \f
68 #include <hurd/core.h>
69 #include <hurd/paths.h>
70 #include <setjmp.h>
71 #include <fcntl.h>
72 #include <sys/wait.h>
73 #include <thread_state.h>
74
75 jmp_buf _hurd_sigthread_fault_env;
76
77 /* Call the core server to mummify us before we die.
78    Returns nonzero if a core file was written.  */
79 static int
80 write_corefile (int signo, int sigcode)
81 {
82   error_t err;
83   volatile mach_port_t coreserver;
84   volatile file_t file;
85   char *volatile name;
86   char *volatile target;
87
88   /* XXX RLIMIT_CORE */
89
90   coreserver = MACH_PORT_NULL;
91   if (!setjmp (_hurd_sigthread_fault_env))
92     {
93       name = getenv ("CORESERVER");
94       if (name != NULL)
95         coreserver = __path_lookup (name, 0, 0);
96     }
97
98   if (coreserver == MACH_PORT_NULL)
99     coreserver = __path_lookup (_SERVERS_CORE, 0, 0);
100   if (coreserver == MACH_PORT_NULL)
101     return 0;
102
103   file = MACH_PORT_NULL;
104   name = NULL;
105   if (!setjmp (_hurd_sigthread_fault_env))
106     {
107       name = getenv ("COREFILE");
108       if (name != NULL)
109         file = __path_lookup (name, O_WRONLY|O_CREAT, 0666 & ~_hurd_umask);
110     }
111   if (name == NULL || file == MACH_PORT_NULL)
112     {
113       name = (char *) "core";
114       file = __path_lookup (name, O_WRONLY|O_CREAT, 0666 & ~_hurd_umask);
115     }
116
117   if (file == MACH_PORT_NULL)
118     return 0;
119
120   if (setjmp (_hurd_sigthread_fault_env))
121     /* We bombed in getenv.  */
122     target = NULL;
123   else
124     {
125       target = getenv ("GNUTARGET");
126       /* Fault now if TARGET is a bogus string.  */
127       (void) strlen (target);
128     }
129
130   err = __core_dump_task (coreserver,
131                           __mach_task_self (),
132                           file,
133                           signo, sigcode,
134                           target);
135   __mach_port_deallocate (__mach_task_self (), coreserver);
136   __mach_port_deallocate (__mach_task_self (), file);
137   if (err)
138     (void) remove (name);
139   return !err;
140 }
141
142
143 /* How long to give servers to respond to
144    interrupt_operation before giving up on them.  */
145 mach_msg_timeout_t _hurd_interrupt_timeout = 1000; /* One second.  */
146
147 /* SS->thread is suspended.  Fills STATE in with its registers.
148    SS->lock is held and kept.  */
149 static inline void
150 abort_rpcs (struct _hurd_sigstate *ss, int signo, void *state)
151 {
152   if (ss->intr_port != MACH_PORT_NULL)
153     {
154       /* Abort whatever the thread is doing.
155          If it is in the mach_msg syscall doing the send,
156          the syscall will return MACH_SEND_INTERRUPTED.  */
157       __thread_abort (ss->thread);
158       __thread_get_state (ss->thread, HURD_THREAD_STATE_FLAVOR,
159                           state, HURD_THREAD_STATE_COUNT);
160
161       if (_hurd_thread_state_msging_p (state))
162         {
163           /* The thread was waiting for the RPC to return.
164              Abort the operation.  The RPC will return EINTR.  */
165
166           struct
167             {
168               mach_msg_header_t header;
169               mach_msg_type_t type;
170               kern_return_t retcode;
171             } msg;
172           kern_return_t err;
173
174           msg.header.msgh_remote_port = ss->intr_port;
175           msg.header.msgh_local_port = __mach_reply_port ();
176           msg.header.msgh_seqno = 0;
177           msg.header.msgh_id = 33000; /* interrupt_operation XXX */
178           err = __mach_msg (&msg.header,
179                             MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT,
180                             sizeof (msg.header), sizeof (msg),
181                             msg.header.msgh_local_port,
182                             _hurd_interrupt_timeout,
183                             MACH_PORT_NULL);
184           if (err != MACH_MSG_SUCCESS)
185             /* The interrupt didn't work.
186                Destroy the receive right the thread is blocked on.  */
187             __mach_port_destroy (__mach_task_self (),
188                                  /* XXX */
189                                  _hurd_thread_reply_port (ss->thread));
190           else
191             /* In case the server returned something screwy.  */
192             __mach_msg_destroy (&msg.header);
193
194           /* Tell the thread whether it should restart the
195              operation or return EINTR when it wakes up.  */
196           ss->intr_restart = ss->actions[signo].sa_flags & SA_RESTART;
197         }
198
199       /* If the thread is anywhere before the system call trap,
200          it will start the operation after the signal is handled.
201          
202          If the thread is after the system call trap, but before it has
203          cleared SS->intr_port, the operation is already finished.  */
204     }
205 }
206
207 /* Abort the RPCs being run by all threads but this one;
208    all other threads should be suspended.  */
209 static inline void
210 abort_all_rpcs (int signo, void *state)
211 {
212   thread_t me = __mach_thread_self ();
213   thread_t *threads;
214   mach_msg_type_number_t nthreads, i;
215
216   __task_threads (__mach_task_self (), &threads, &nthreads);
217   for (i = 0; i < nthreads; ++i)
218     {
219       if (threads[i] != me)
220         {
221           struct _hurd_sigstate *ss = _hurd_thread_sigstate (threads[i]);
222           abort_rpcs (ss, signo, state);
223           __mutex_unlock (&ss->lock);
224         }
225       __mach_port_deallocate (__mach_task_self (), threads[i]);
226     }
227 }
228
229
230 /* Deliver a signal.
231    SS->lock is held on entry and released before return.  */
232 void
233 _hurd_internal_post_signal (struct hurd_sigstate *ss,
234                             int signo,
235                             int sigcode)
236 {
237   struct hurd_thread_state thread_state;
238   enum { stop, ignore, core, term, handle } act;
239   __sighandler_t handler = ss->actions[signo].sa_handler;
240
241   if (handler == SIG_DFL)
242     /* Figure out the default action for this signal.  */
243     switch (signo)
244       {
245       case 0:
246         /* A sig_post msg with SIGNO==0 is sent to
247            tell us to check for pending signals.  */
248         act = ignore;
249         break;
250
251       case SIGTTIN:
252       case SIGTTOU:
253       case SIGSTOP:
254       case SIGTSTP:
255         ss->pending &= ~sigmask (SIGCONT);
256         act = stop;
257         break;
258
259       case SIGCONT:
260         ss->pending &= ~(sigmask (SIGSTOP) | sigmask (SIGTSTP) |
261                          sigmask (SIGTTIN) | sigmask (SIGTTOU));
262         /* Fall through.  */
263       case SIGIO:
264       case SIGURG:
265       case SIGCHLD:
266       case SIGWINCH:
267         act = ignore;
268         break;
269
270       case SIGQUIT:
271       case SIGILL:
272       case SIGTRAP:
273       case SIGIOT:
274       case SIGEMT:
275       case SIGFPE:
276       case SIGBUS:
277       case SIGSEGV:
278       case SIGSYS:
279         act = core;
280         break;
281
282       case SIGINFO:
283         if (_hurd_pgrp == _hurd_pid)
284           {
285             /* We are the session leader.  Since there is no user-specified
286                handler for SIGINFO, we use a default one which prints
287                something interesting.  We use the normal handler mechanism
288                instead of just doing it here to avoid the signal thread
289                faulting or blocking in this potentially hairy operation.  */
290             act = handle;
291             handler = _hurd_siginfo_handler;
292           }
293         break;
294
295       default:
296         act = term;
297         break;
298       }
299   else if (handler == SIG_IGN)
300     act = ignore;
301   else
302     act = handle;
303
304   if (_hurd_orphaned && act == stop &&
305       (signo & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
306                 __sigmask (SIGTSTP))))
307     {
308       /* If we would ordinarily stop for a job control signal, but we are
309          orphaned so noone would ever notice and continue us again, we just
310          quietly die, alone and in the dark.  */
311       sigcode = signo;
312       signo = SIGKILL;
313       act = term;
314     }
315
316   /* Handle receipt of a blocked signal.  */
317   if ((__sigismember (&ss->blocked, signo) && act != ignore) ||
318       (signo != SIGKILL && _hurd_stopped))
319     {
320       __sigaddset (&ss->pending, signo);
321       /* Save the code to be given to the handler when SIGNO is unblocked.  */
322       ss->sigcodes[signo] = sigcode;
323       act = ignore;
324     }
325
326   /* Perform the chosen action for the signal.  */
327   switch (act)
328     {
329     case stop:
330       /* Stop all other threads and mark ourselves stopped.  */
331       __USEPORT (PROC,
332                  ({
333                    /* Hold the siglock while stopping other threads to be
334                       sure it is not held by another thread afterwards.  */
335                    __mutex_unlock (&ss->lock);
336                    __mutex_lock (&_hurd_siglock);
337                    __proc_dostop (port, __mach_thread_self ());
338                    __mutex_unlock (&_hurd_siglock);
339                    abort_all_rpcs (signo, &thread_state);
340                    __proc_mark_stop (port, signo);
341                  }));
342       _hurd_stopped = 1;
343
344 #ifdef noteven
345       __mutex_lock (&ss->lock);
346       if (ss->suspended)
347         /* There is a sigsuspend waiting.  Tell it to wake up.  */
348         __condition_signal (&ss->arrived);
349       else
350         __mutex_unlock (&ss->lock);
351 #endif
352
353       return;
354
355     case ignore:
356       /* Nobody cares about this signal.  */
357       break;
358
359     case term:                  /* Time to die.  */
360     case core:                  /* And leave a rotting corpse.  */
361       /* Have the proc server stop all other threads in our task.  */
362       __USEPORT (PROC, __proc_dostop (port, __mach_thread_self ()));
363       /* Abort all server operations now in progress.  */
364       abort_all_rpcs (signo, &thread_state);
365       /* Tell proc how we died and then stick the saber in the gut.  */
366       _hurd_exit (W_EXITCODE (0, signo) |
367                   /* Do a core dump if desired.  Only set the wait status
368                      bit saying we in fact dumped core if the operation was
369                      actually succesful.  */
370                   (act == core && write_corefile (signo, sigcode) ?
371                    WCOREFLAG : 0));
372       /* NOTREACHED */
373
374     case handle:
375       /* Call a handler for this signal.  */
376       {
377         struct sigcontext *scp;
378
379         /* Stop the thread and abort its pending RPC operations.  */
380         __thread_suspend (ss->thread);
381         abort_rpcs (ss, signo, &thread_state);
382
383         /* Call the machine-dependent function to set the thread up
384            to run the signal handler, and preserve its old context.  */
385         scp = _hurd_setup_sighandler (ss->actions[signo].sa_flags,
386                                       handler,
387                                       &ss->sigaltstack,
388                                       signo, sigcode,
389                                       &thread_state);
390
391         /* Set the machine-independent parts of the signal context.  */
392         scp->sc_intr_port = ss->intr_port;
393         scp->sc_mask = ss->blocked;
394
395         /* Block SIGNO and requested signals while running the handler.  */
396         ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
397
398         /* Start the thread running the handler.  */
399         __thread_set_state (ss->thread, HURD_THREAD_STATE_FLAVOR,
400                             (int *) &thread_state, HURD_THREAD_STATE_COUNT);
401         __thread_resume (ss->thread);
402         break;
403       }
404     }
405
406   /* We get here only if we are handling or ignoring the signal;
407      otherwise we are stopped or dead by now.  We still hold SS->lock.
408      Check for pending signals, and loop to post them.  */
409   for (signo = 1; signo < NSIG; ++signo)
410     if (__sigismember (&ss->pending, signo))
411       {
412         __sigdelset (&ss->pending, signo);
413         _hurd_internal_post_signal (ss, signo, ss->sigcodes[signo]);
414         return;
415       }
416
417 #ifdef noteven
418   if (ss->suspended)
419     /* There is a sigsuspend waiting.  Tell it to wake up.  */
420     __condition_signal (&ss->arrived);
421   else
422     __mutex_unlock (&ss->lock);
423 #endif
424 }
425
426 /* Implement the sig_post RPC from <hurd/msg.defs>;
427    sent when someone wants us to get a signal.  */
428 error_t
429 _S_sig_post (mach_port_t me,
430              mach_port_t reply,
431              int signo,
432              mach_port_t refport)
433 {
434   struct _hurd_sigstate *ss;
435
436   if (signo < 0 || signo >= NSIG)
437     return EINVAL;
438
439   if (refport == __mach_task_self ())
440     /* Can send any signal.  */
441     goto win;
442
443   /* Avoid needing to check for this below.  */
444   if (refport == MACH_PORT_NULL)
445     return EPERM;
446
447   switch (signo)
448     {
449     case SIGINT:
450     case SIGQUIT:
451     case SIGTSTP:
452     case SIGHUP:
453     case SIGINFO:
454       /* Job control signals can be sent by the controlling terminal.  */
455       if (__USEPORT (CTTYID, port == refport))
456         goto win;
457       break;
458
459     case SIGCONT:
460       {
461         /* A continue signal can be sent by anyone in the session.  */
462         mach_port_t sessport;
463         if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
464           { 
465             int win = refport == sessport;
466             __mach_port_deallocate (__mach_task_self (), sessport);
467             if (win)
468               goto win;
469           }
470       }
471       break;
472
473     case SIGIO:
474     case SIGURG:
475       {
476         /* Any io object a file descriptor refers to might send us
477            one of these signals using its async ID port for REFPORT.
478
479            This is pretty wide open; it is not unlikely that some random
480            process can at least open for reading something we have open,
481            get its async ID port, and send us a spurious SIGIO or SIGURG
482            signal.  But BSD is actually wider open than that!--you can set
483            the owner of an io object to any process or process group
484            whatsoever and send them gratuitous signals.
485
486            Someday we could implement some reasonable scheme for
487            authorizing SIGIO and SIGURG signals properly.  */
488
489         struct hurd_userlink dtable_ulink;
490         struct hurd_dtable dt = _hurd_dtable_get (&dtable_ulink);
491         int d;
492         for (d = 0; d >= 0 && d < dt.size; ++d)
493           {
494             struct hurd_userlink ulink;
495             io_t port;
496             mach_port_t asyncid;
497             if (dt.d[d] == NULL)
498               continue;
499             port = _hurd_port_locked_get (&dt.d[d]->port, &ulink);
500             if (! __io_get_icky_async_id (port, &asyncid))
501               {
502                 if (refport == asyncid)
503                   /* Break out of the loop on the next iteration.  */
504                   d = -1;
505                 __mach_port_deallocate (__mach_task_self (), asyncid);
506               }
507             _hurd_port_free (&dt.d[d]->port, &ulink, port);
508           }
509         _hurd_dtable_free (dt, &dtable_ulink);
510         /* If we found a lucky winner, we've set D to -1 in the loop.  */
511         if (d < 0)
512           goto win;
513       }
514     }
515
516   /* If this signal is legit, we have done `goto win' by now.
517      When we return the error, mig deallocates REFPORT.  */
518   return EPERM;
519
520  win:
521   /* Deallocate the REFPORT right; we are done with it.  */
522   __mach_port_deallocate (__mach_task_self (), refport);
523
524   /* Get a hold of the designated signal-receiving thread.  */
525   ss = _hurd_thread_sigstate (_hurd_sigthread);
526
527   /* XXX POSIX.1-1990 p56 ll605-607 says we must deliver a signal
528      before `kill' (and thus sig_post) can return.  */
529
530   /* Send a reply indicating success to the signaller.  */
531   __sig_post_reply (reply, 0);
532
533   /* Post the signal.  */
534   _hurd_internal_post_signal (ss, signo, 0);
535
536   return MIG_NO_REPLY;          /* Already replied.  */
537 }
538 \f
539 #include <mach/task_special_ports.h>
540
541 /* Initialize the message port and signal thread once.
542    Do nothing on subsequent calls.  */
543
544 void
545 _hurdsig_init (void)
546 {
547   error_t err;
548
549   if (_hurd_msgport != MACH_PORT_NULL)
550     /* We have already been run.  Return doing nothing.  */
551     return;
552
553 #ifdef noteven
554   __mutex_init (&_hurd_siglock); /* Initialize the signal lock.  */
555 #endif
556
557   if (err = __mach_port_allocate (__mach_task_self (),
558                                   MACH_PORT_RIGHT_RECEIVE,
559                                   &_hurd_msgport))
560     __libc_fatal ("hurd: Can't create message port receive right\n");
561
562   /* Make a send right to the signal port.  */
563   if (err = __mach_port_insert_right (__mach_task_self (),
564                                       _hurd_msgport,
565                                       _hurd_msgport,
566                                       MACH_MSG_TYPE_MAKE_SEND))
567     __libc_fatal ("hurd: Can't create send right to message port\n");
568
569   if (err = __thread_create (__mach_task_self (), &_hurd_msgport_thread))
570     __libc_fatal ("hurd: Can't create signal thread\n");
571
572   if (err = _hurd_start_sigthread (_hurd_msgport_thread,
573                                    _hurd_msgport_receive))
574     __libc_fatal ("hurd: Can't start signal thread\n");
575
576   /* Receive exceptions on the signal port.  */
577   __task_set_special_port (__mach_task_self (),
578                            TASK_EXCEPTION_PORT, _hurd_msgport);
579 }
580 \f
581 /* Send exceptions for the signal thread to the proc server.
582    It will forward the message on to our message port,
583    and then restore the thread's state to code which
584    does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
585
586 void
587 _hurdsig_fault_init (void)
588 {
589   error_t err;
590   mach_port_t sigexc;
591   struct hurd_thread_state state;
592
593   if (err = __mach_port_allocate (__mach_task_self (),
594                                   MACH_PORT_RIGHT_RECEIVE, &sigexc))
595     __libc_fatal ("hurd: Can't create receive right for signal thread exc\n");
596
597   /* Set up STATE with a thread state that will longjmp immediately.  */
598   _hurd_initialize_fault_recovery_state (&state);
599
600   __thread_set_special_port (_hurd_msgport_thread,
601                              THREAD_EXCEPTION_PORT, sigexc);
602
603   if (err = __USEPORT
604       (PROC,
605        __proc_handle_exceptions (port,
606                                  sigexc,
607                                  _hurd_msgport, MACH_MSG_TYPE_COPY_SEND,
608                                  HURD_THREAD_STATE_FLAVOR,
609                                  state, HURD_THREAD_STATE_COUNT)))
610     __libc_fatal ("hurd: proc won't handle signal thread exceptions\n");
611 }
612 \f                               /* XXXX */
613 static void
614 reauth_proc (mach_port_t new)
615 {
616   mach_port_t ignore;
617
618   /* Reauthenticate with the proc server.  */
619   if (! _HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
620                         __proc_reauthenticate (port, _hurd_pid) ||
621                         __auth_user_authenticate (new, port, _hurd_pid,
622                                                   &ignore))
623       && ignore != MACH_PORT_NULL)
624     __mach_port_deallocate (__mach_task_self (), ignore);
625 }
626 text_set_element (__hurd_reauth_hook, reauth_proc);