289 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* kill.cc
 | 
						|
 | 
						|
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007,
 | 
						|
   2009, 2011 Red Hat, Inc.
 | 
						|
 | 
						|
This file is part of Cygwin.
 | 
						|
 | 
						|
This software is a copyrighted work licensed under the terms of the
 | 
						|
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | 
						|
details. */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <string.h>
 | 
						|
#include <time.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <windows.h>
 | 
						|
#include <sys/cygwin.h>
 | 
						|
#include <cygwin/version.h>
 | 
						|
#include <getopt.h>
 | 
						|
#include <limits.h>
 | 
						|
 | 
						|
static char *prog_name;
 | 
						|
 | 
						|
static struct option longopts[] =
 | 
						|
{
 | 
						|
  {"help", no_argument, NULL, 'h' },
 | 
						|
  {"list", optional_argument, NULL, 'l'},
 | 
						|
  {"force", no_argument, NULL, 'f'},
 | 
						|
  {"signal", required_argument, NULL, 's'},
 | 
						|
  {"version", no_argument, NULL, 'V'},
 | 
						|
  {NULL, 0, NULL, 0}
 | 
						|
};
 | 
						|
 | 
						|
static char opts[] = "hl::fs:V";
 | 
						|
 | 
						|
static void
 | 
						|
usage (FILE *where = stderr)
 | 
						|
{
 | 
						|
  fprintf (where , ""
 | 
						|
	"Usage: %1$s [-f] [-signal] [-s signal] pid1 [pid2 ...]\n"
 | 
						|
	"       %1$s -l [signal]\n"
 | 
						|
	"\n"
 | 
						|
	"Send signals to processes\n"
 | 
						|
	"\n"
 | 
						|
	" -f, --force     force, using win32 interface if necessary\n"
 | 
						|
	" -l, --list      print a list of signal names\n"
 | 
						|
	" -s, --signal    send signal (use %1$s --list for a list)\n"
 | 
						|
	" -h, --help      output usage information and exit\n"
 | 
						|
	" -V, --version   output version information and exit\n"
 | 
						|
	"\n", prog_name);
 | 
						|
  exit (where == stderr ? 1 : 0);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
print_version ()
 | 
						|
{
 | 
						|
  printf ("kill (cygwin) %d.%d.%d\n"
 | 
						|
	  "Process Signaller\n"
 | 
						|
	  "Copyright (C) 1996 - %s Red Hat, Inc.\n"
 | 
						|
	  "This is free software; see the source for copying conditions.  There is NO\n"
 | 
						|
	  "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
 | 
						|
	  CYGWIN_VERSION_DLL_MAJOR / 1000,
 | 
						|
	  CYGWIN_VERSION_DLL_MAJOR % 1000,
 | 
						|
	  CYGWIN_VERSION_DLL_MINOR,
 | 
						|
	  strrchr (__DATE__, ' ') + 1);
 | 
						|
}
 | 
						|
 | 
						|
static const char *
 | 
						|
strsigno (int signo)
 | 
						|
{
 | 
						|
  if (signo >= 0 && signo < NSIG)
 | 
						|
    return sys_sigabbrev[signo];
 | 
						|
  static char buf[sizeof ("Unknown signal") + 32];
 | 
						|
  sprintf (buf, "Unknown signal %d", signo);
 | 
						|
  return buf;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
getsig (const char *in_sig)
 | 
						|
{
 | 
						|
  const char *sig;
 | 
						|
  char buf[80];
 | 
						|
  int intsig;
 | 
						|
 | 
						|
  if (strncmp (in_sig, "SIG", 3) == 0)
 | 
						|
    sig = in_sig;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      sprintf (buf, "SIG%-.20s", in_sig);
 | 
						|
      sig = buf;
 | 
						|
    }
 | 
						|
  intsig = strtosigno (sig) ?: atoi (in_sig);
 | 
						|
  char *p;
 | 
						|
  if (!intsig && (strcmp (buf, "SIG0") != 0 && (strtol (in_sig, &p, 10) != 0 || *p)))
 | 
						|
    intsig = -1;
 | 
						|
  return intsig;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
test_for_unknown_sig (int sig, const char *sigstr)
 | 
						|
{
 | 
						|
  if (sig < 0 || sig > NSIG)
 | 
						|
    {
 | 
						|
      fprintf (stderr, "%1$s: unknown signal: %2$s\n"
 | 
						|
		       "Try `%1$s --help' for more information.\n",
 | 
						|
	       prog_name, sigstr);
 | 
						|
      exit (1);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
listsig (const char *in_sig)
 | 
						|
{
 | 
						|
  int sig;
 | 
						|
  if (!in_sig)
 | 
						|
    for (sig = 1; sig < NSIG - 1; sig++)
 | 
						|
      printf ("%s%c", strsigno (sig) + 3, (sig < NSIG - 1) ? ' ' : '\n');
 | 
						|
  else
 | 
						|
    {
 | 
						|
      sig = getsig (in_sig);
 | 
						|
      test_for_unknown_sig (sig, in_sig);
 | 
						|
      if (atoi (in_sig) == sig)
 | 
						|
	puts (strsigno (sig) + 3);
 | 
						|
      else
 | 
						|
	printf ("%d\n", sig);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
get_debug_priv (void)
 | 
						|
{
 | 
						|
  HANDLE tok;
 | 
						|
  LUID luid;
 | 
						|
  TOKEN_PRIVILEGES tkp;
 | 
						|
 | 
						|
  if (!OpenProcessToken (GetCurrentProcess (),
 | 
						|
			 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tok))
 | 
						|
    return;
 | 
						|
 | 
						|
  if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &luid))
 | 
						|
    {
 | 
						|
      CloseHandle (tok);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  tkp.PrivilegeCount = 1;
 | 
						|
  tkp.Privileges[0].Luid = luid;
 | 
						|
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 | 
						|
 | 
						|
  AdjustTokenPrivileges (tok, FALSE, &tkp, sizeof tkp, NULL, NULL);
 | 
						|
 | 
						|
  CloseHandle (tok);
 | 
						|
}
 | 
						|
 | 
						|
static void __stdcall
 | 
						|
forcekill (int pid, int sig, int wait)
 | 
						|
{
 | 
						|
  // try to acquire SeDebugPrivilege
 | 
						|
  get_debug_priv();
 | 
						|
 | 
						|
  external_pinfo *p = NULL;
 | 
						|
  /* cygwin_internal misinterprets negative pids (Win9x pids) */
 | 
						|
  if (pid > 0)
 | 
						|
    p = (external_pinfo *) cygwin_internal (CW_GETPINFO_FULL, pid);
 | 
						|
  DWORD dwpid = p ? p->dwProcessId : (DWORD) pid;
 | 
						|
  HANDLE h = OpenProcess (PROCESS_TERMINATE, FALSE, (DWORD) dwpid);
 | 
						|
  if (!h)
 | 
						|
    {
 | 
						|
      if (!wait || GetLastError () != ERROR_INVALID_PARAMETER)
 | 
						|
	fprintf (stderr, "%s: couldn't open pid %u\n",
 | 
						|
		 prog_name, (unsigned) dwpid);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
 | 
						|
    if (sig && !TerminateProcess (h, sig << 8)
 | 
						|
	&& WaitForSingleObject (h, 200) != WAIT_OBJECT_0)
 | 
						|
      fprintf (stderr, "%s: couldn't kill pid %u, %u\n",
 | 
						|
	       prog_name, (unsigned) dwpid, (unsigned int) GetLastError ());
 | 
						|
  CloseHandle (h);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main (int argc, char **argv)
 | 
						|
{
 | 
						|
  int sig = SIGTERM;
 | 
						|
  int force = 0;
 | 
						|
  int ret = 0;
 | 
						|
  char *gotasig = NULL;
 | 
						|
 | 
						|
  prog_name = program_invocation_short_name;
 | 
						|
 | 
						|
  if (argc == 1)
 | 
						|
    usage ();
 | 
						|
 | 
						|
  opterr = 0;
 | 
						|
 | 
						|
  char *p;
 | 
						|
  long long int pid = 0;
 | 
						|
 | 
						|
  for (;;)
 | 
						|
    {
 | 
						|
      int ch;
 | 
						|
      char **av = argv + optind;
 | 
						|
      if ((ch = getopt_long (argc, argv, opts, longopts, NULL)) == EOF)
 | 
						|
	break;
 | 
						|
      switch (ch)
 | 
						|
	{
 | 
						|
	case 's':
 | 
						|
	  gotasig = optarg;
 | 
						|
	  sig = getsig (gotasig);
 | 
						|
	  break;
 | 
						|
	case 'l':
 | 
						|
	  if (!optarg)
 | 
						|
	    {
 | 
						|
	      optarg = argv[optind];
 | 
						|
	      if (optarg)
 | 
						|
		{
 | 
						|
		  optind++;
 | 
						|
		  optreset = 1;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  if (argv[optind])
 | 
						|
	    usage ();
 | 
						|
	  listsig (optarg);
 | 
						|
	  break;
 | 
						|
	case 'f':
 | 
						|
	  force = 1;
 | 
						|
	  break;
 | 
						|
	case 'h':
 | 
						|
	  usage (stdout);
 | 
						|
	  break;
 | 
						|
	case 'V':
 | 
						|
	  print_version ();
 | 
						|
	  break;
 | 
						|
	case '?':
 | 
						|
	  if (gotasig)
 | 
						|
	    {
 | 
						|
	      --optind;
 | 
						|
	      goto out;
 | 
						|
	    }
 | 
						|
	  optreset = 1;
 | 
						|
	  optind = 1 + av - argv;
 | 
						|
	  gotasig = *av + 1;
 | 
						|
	  sig = getsig (gotasig);
 | 
						|
	  break;
 | 
						|
	default:
 | 
						|
	  usage ();
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  test_for_unknown_sig (sig, gotasig);
 | 
						|
 | 
						|
  argv += optind;
 | 
						|
  while (*argv != NULL)
 | 
						|
    {
 | 
						|
      if (!pid)
 | 
						|
	pid = strtoll (*argv, &p, 10);
 | 
						|
      if (*p != '\0'
 | 
						|
	  || (!force && (pid < INT_MIN || pid > INT_MAX))
 | 
						|
	  || (force && (pid <= 0 || pid > UINT_MAX)))
 | 
						|
	{
 | 
						|
	  fprintf (stderr, "%s: illegal pid: %s\n", prog_name, *argv);
 | 
						|
	  ret = 1;
 | 
						|
	}
 | 
						|
      else if (pid <= INT_MAX && kill ((pid_t) pid, sig) == 0)
 | 
						|
	{
 | 
						|
	  if (force)
 | 
						|
	    forcekill ((pid_t) pid, sig, 1);
 | 
						|
	}
 | 
						|
      else if (force)
 | 
						|
	forcekill ((pid_t) pid, sig, 0);
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  char buf[1000];
 | 
						|
	  sprintf (buf, "%s: %lld", prog_name, pid);
 | 
						|
	  perror (buf);
 | 
						|
	  ret = 1;
 | 
						|
	}
 | 
						|
      argv++;
 | 
						|
      pid = 0;
 | 
						|
    }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 |