Blame sysdeps/mach/hurd/kill.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/port.h>
Packit 6c4009
#include <hurd/signal.h>
Packit 6c4009
#include <hurd/msg.h>
Packit 6c4009
Packit 6c4009
/* Send signal SIG to process number PID.  If PID is zero,
Packit 6c4009
   send SIG to all processes in the current process's process group.
Packit 6c4009
   If PID is < -1, send SIG to all processes in process group - PID.  */
Packit 6c4009
int
Packit 6c4009
__kill (pid_t pid, int sig)
Packit 6c4009
{
Packit 6c4009
  int delivered = 0;		/* Set when we deliver any signal.  */
Packit 6c4009
  error_t err;
Packit 6c4009
  mach_port_t proc;
Packit 6c4009
  struct hurd_userlink ulink;
Packit 6c4009
Packit 6c4009
  void kill_pid (pid_t pid) /* Kill one PID.  */
Packit 6c4009
    {
Packit 6c4009
      /* SIGKILL is not delivered as a normal signal.
Packit 6c4009
	 Sending SIGKILL to a process means to terminate its task.  */
Packit 6c4009
      if (sig == SIGKILL)
Packit 6c4009
	/* Fetch the process's task port and terminate the task.  We
Packit 6c4009
	   loop in case the process execs and changes its task port.
Packit 6c4009
	   If the old task port dies after we fetch it but before we
Packit 6c4009
	   send the RPC, we get MACH_SEND_INVALID_DEST; if it dies
Packit 6c4009
	   after we send the RPC request but before it is serviced, we
Packit 6c4009
	   get MIG_SERVER_DIED.  */
Packit 6c4009
	do
Packit 6c4009
	  {
Packit 6c4009
	    task_t refport;
Packit 6c4009
	    err = __proc_pid2task (proc, pid, &refport);
Packit 6c4009
	    /* Ignore zombies.  */
Packit 6c4009
	    if (!err && refport != MACH_PORT_NULL)
Packit 6c4009
	      {
Packit 6c4009
		err = __task_terminate (refport);
Packit 6c4009
		__mach_port_deallocate (__mach_task_self (), refport);
Packit 6c4009
	      }
Packit 6c4009
	  } while (err == MACH_SEND_INVALID_DEST ||
Packit 6c4009
		   err == MIG_SERVER_DIED);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  error_t taskerr;
Packit 6c4009
	  error_t kill_port (mach_port_t msgport, mach_port_t refport)
Packit 6c4009
	    {
Packit 6c4009
	      if (msgport != MACH_PORT_NULL)
Packit 6c4009
		/* Send a signal message to his message port.  */
Packit 6c4009
		return __msg_sig_post (msgport, sig, 0, refport);
Packit 6c4009
Packit 6c4009
	      /* The process has no message port.  Perhaps try direct
Packit 6c4009
		 frobnication of the task.  */
Packit 6c4009
Packit 6c4009
	      if (taskerr)
Packit 6c4009
		/* If we could not get the task port, we can do nothing.  */
Packit 6c4009
		return taskerr;
Packit 6c4009
Packit 6c4009
	      if (refport == MACH_PORT_NULL)
Packit 6c4009
		/* proc_pid2task returned success with a null task port.
Packit 6c4009
		   That means the process is a zombie.  Signals
Packit 6c4009
		   to zombies should return success and do nothing.  */
Packit 6c4009
		return 0;
Packit 6c4009
Packit 6c4009
	      /* For user convenience in the case of a task that has
Packit 6c4009
		 not registered any message port with the proc server,
Packit 6c4009
		 translate a few signals to direct task operations.  */
Packit 6c4009
	      switch (sig)
Packit 6c4009
		{
Packit 6c4009
		  /* The only signals that really make sense for an
Packit 6c4009
		     unregistered task are kill, suspend, and continue.  */
Packit 6c4009
		case SIGSTOP:
Packit 6c4009
		case SIGTSTP:
Packit 6c4009
		  return __task_suspend (refport);
Packit 6c4009
		case SIGCONT:
Packit 6c4009
		  return __task_resume (refport);
Packit 6c4009
		case SIGTERM:
Packit 6c4009
		case SIGQUIT:
Packit 6c4009
		case SIGINT:
Packit 6c4009
		  return __task_terminate (refport);
Packit 6c4009
		default:
Packit 6c4009
		  /* We have full permission to send signals, but there is
Packit 6c4009
		     no meaningful way to express this signal.  */
Packit 6c4009
		  return EPERM;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  err = HURD_MSGPORT_RPC (__proc_getmsgport (proc, pid, &msgport),
Packit 6c4009
				  (taskerr = __proc_pid2task (proc, pid,
Packit 6c4009
							      &refport)) ?
Packit 6c4009
				  __proc_getsidport (proc, &refport) : 0, 1,
Packit 6c4009
				  kill_port (msgport, refport));
Packit 6c4009
	}
Packit 6c4009
      if (! err)
Packit 6c4009
	delivered = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  proc = _hurd_port_get (&_hurd_ports[INIT_PORT_PROC], &ulink);
Packit 6c4009
Packit 6c4009
  if (pid <= 0)
Packit 6c4009
    {
Packit 6c4009
      /* Send SIG to each process in pgrp (- PID).  */
Packit 6c4009
      pid_t pidbuf[10], *pids = pidbuf;
Packit 6c4009
      mach_msg_type_number_t i, npids = sizeof (pidbuf) / sizeof (pidbuf[0]);
Packit 6c4009
Packit 6c4009
      err = __proc_getpgrppids (proc, - pid, &pids, &npids);
Packit 6c4009
      if (!err)
Packit 6c4009
	{
Packit 6c4009
	  for (i = 0; i < npids; ++i)
Packit 6c4009
	    {
Packit 6c4009
	      kill_pid (pids[i]);
Packit 6c4009
	      if (err == ESRCH)
Packit 6c4009
		/* The process died already.  Ignore it.  */
Packit 6c4009
		err = 0;
Packit 6c4009
	    }
Packit 6c4009
	  if (pids != pidbuf)
Packit 6c4009
	    __vm_deallocate (__mach_task_self (),
Packit 6c4009
			     (vm_address_t) pids, npids * sizeof (pids[0]));
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    kill_pid (pid);
Packit 6c4009
Packit 6c4009
  _hurd_port_free (&_hurd_ports[INIT_PORT_PROC], &ulink, proc);
Packit 6c4009
Packit 6c4009
  /* If we delivered no signals, but ERR is clear, this must mean that
Packit 6c4009
     every kill_pid call failed with ESRCH, meaning all the processes in
Packit 6c4009
     the pgrp died between proc_getpgrppids and kill_pid; in that case we
Packit 6c4009
     fail with ESRCH.  */
Packit 6c4009
  return delivered ? 0 : __hurd_fail (err ?: ESRCH);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
libc_hidden_def (__kill)
Packit 6c4009
weak_alias (__kill, kill)