1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: dbkill.cpp,v 12.7 2008/01/08 20:58:07 bostic Exp $
7 */
8/*
9 * Kill -
10 * Simulate Unix kill on Windows/NT and Windows/9X.
11 * This good enough to support the Berkeley DB test suite,
12 * but may be missing some favorite features.
13 *
14 * Would have used MKS kill, but it didn't seem to work well
15 * on Win/9X.  Cygnus kill works within the Gnu/Cygnus environment
16 * (where processes are given small pids, with presumably a translation
17 * table between small pids and actual process handles), but our test
18 * environment, via Tcl, does not use the Cygnus environment.
19 *
20 * Compile this and install it as c:/tools/kill.exe (or as indicated
21 * by build_windows/include.tcl ).
22 */
23
24#include <windows.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <limits.h>
28
29/*
30 * Like atol, with specified base.  Would use stdlib, but
31 * strtol("0xFFFF1234", NULL, 16) returns 0x7FFFFFFF and
32 * strtol("4294712487", NULL, 16) returns 0x7FFFFFFF w/ VC++
33 */
34long
35myatol(char *s, int base)
36{
37	long result = 0;
38	char ch;
39	int sign = 1;  /* + */
40	if (base == 0)
41		base = 10;
42	if (base != 10 && base != 16)
43		return LONG_MAX;
44	while ((ch = *s++) != '\0') {
45		if (ch == '-') {
46			sign = -sign;
47		}
48		else if (ch >= '0' && ch <= '9') {
49			result = result * base + (ch - '0');
50		}
51		else if (ch == 'x' || ch == 'X') {
52			/* Allow leading 0x..., and switch to base 16 */
53			base = 16;
54		}
55		else if (base == 16 && ch >= 'a' && ch <= 'f') {
56			result = result * base + (ch - 'a' + 10);
57		}
58		else if (base == 16 && ch >= 'A' && ch <= 'F') {
59			result = result * base + (ch - 'A' + 10);
60		}
61		else {
62			if (sign > 1)
63				return LONG_MAX;
64			else
65				return LONG_MIN;
66		}
67	}
68	return sign * result;
69}
70
71void
72usage_exit()
73{
74	fprintf(stderr, "Usage: kill [ -sig ] pid\n");
75	fprintf(stderr, "       for win32, sig must be or 0, 15 (TERM)\n");
76	exit(EXIT_FAILURE);
77}
78
79int
80main(int argc, char **argv)
81{
82	HANDLE hProcess ;
83	DWORD accessflag;
84	long pid;
85	int sig = 15;
86
87	if (argc > 2) {
88		if (argv[1][0] != '-')
89			usage_exit();
90
91		if (strcmp(argv[1], "-TERM") == 0)
92			sig = 15;
93		else {
94			/* currently sig is more or less ignored,
95			 * we only care if it is zero or not
96			 */
97			sig = atoi(&argv[1][1]);
98			if (sig < 0)
99				usage_exit();
100		}
101		argc--;
102		argv++;
103	}
104	if (argc < 2)
105		usage_exit();
106
107	pid = myatol(argv[1], 10);
108	/*printf("pid = %ld (0x%lx) (command line %s)\n", pid, pid, argv[1]);*/
109	if (pid == LONG_MAX || pid == LONG_MIN)
110		usage_exit();
111
112	if (sig == 0)
113		accessflag = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
114	else
115		accessflag = STANDARD_RIGHTS_REQUIRED | PROCESS_TERMINATE;
116	hProcess = OpenProcess(accessflag, FALSE, pid);
117	if (hProcess == NULL) {
118		fprintf(stderr, "dbkill: %s: no such process\n", argv[1]);
119		exit(EXIT_FAILURE);
120	}
121	if (sig == 0)
122		exit(EXIT_SUCCESS);
123	if (!TerminateProcess(hProcess, 99)) {
124		DWORD err = GetLastError();
125		fprintf(stderr,
126		    "dbkill: cannot kill process: error %d (0x%lx)\n", err, err);
127		exit(EXIT_FAILURE);
128	}
129	return EXIT_SUCCESS;
130}
131