/* kill.cc 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 #include #include #include #include #include #include #include #include #include #include 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 Cygwin Authors\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 (sig, "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 (sig && 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; }