1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sal.hxx" 30 31 #include <tchar.h> 32 33 #ifdef _MSC_VER 34 #pragma warning(push,1) // disable warnings within system headers 35 #endif 36 #define WIN32_LEAN_AND_MEAN 37 #include <windows.h> 38 #include <tlhelp32.h> 39 #include <psapi.h> 40 #ifdef _MSC_VER 41 #pragma warning(pop) 42 #endif 43 44 #include <signal.h> 45 #include <stdarg.h> 46 #include <stdlib.h> 47 #include <stdio.h> 48 49 #ifndef SIGNULL 50 #define SIGNULL 0 51 #endif 52 53 #ifndef SIGKILL 54 #define SIGKILL 9 55 #endif 56 57 #include <signal.h> 58 59 #define MAX_MODULES 1024 60 61 ///////////////////////////////////////////////////////////////////////////// 62 // Determines if a returned handle value is valid 63 ///////////////////////////////////////////////////////////////////////////// 64 65 static inline bool IsValidHandle( HANDLE handle ) 66 { 67 return INVALID_HANDLE_VALUE != handle && NULL != handle; 68 } 69 70 71 #define elementsof( a ) (sizeof(a) / sizeof( (a)[0] )) 72 73 ///////////////////////////////////////////////////////////////////////////// 74 // Retrieves function adress in another process 75 ///////////////////////////////////////////////////////////////////////////// 76 77 #if 1 78 #define GetProcAddressEx( hProcess, hModule, lpProcName ) GetProcAddress( hModule, lpProcName ) 79 #else 80 FARPROC WINAPI GetProcAddressEx( HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName ) 81 { 82 FARPROC lpfnProcAddress = GetProcAddress( hModule, lpProcName ); 83 84 if ( lpfnProcAddress ) 85 { 86 DWORD dwProcessId = GetProcessId( hProcess ); 87 88 if ( GetCurrentProcessId() != dwProcessId ) 89 { 90 FARPROC lpfnRemoteProcAddress = NULL; 91 TCHAR szBaseName[MAX_PATH]; 92 93 if ( GetModuleBaseName( GetCurrentProcess(), hModule, szBaseName, elementsof(szBaseName) ) ) 94 { 95 HMODULE ahModules[MAX_MODULES]; 96 DWORD cbNeeded = 0; 97 98 if ( EnumProcessModules( hProcess, ahModules, sizeof(ahModules), &cbNeeded ) ) 99 { 100 ULONG nModules = cbNeeded / sizeof(ahModules[0]); 101 102 for ( ULONG n = 0; n < nModules; n++ ) 103 { 104 TCHAR szRemoteBaseName[MAX_PATH]; 105 106 if ( GetModuleBaseName( 107 hProcess, ahModules[n], szRemoteBaseName, elementsof(szRemoteBaseName) ) && 108 0 == lstrcmpi( szRemoteBaseName, szBaseName ) 109 ) 110 { 111 lpfnRemoteProcAddress = lpfnProcAddress; 112 113 if ( ahModules[n] != hModule ) 114 *(LPBYTE*)&lpfnRemoteProcAddress += (LPBYTE)ahModules[n] - (LPBYTE)hModule; 115 break; 116 } 117 } 118 } 119 } 120 121 lpfnProcAddress = lpfnRemoteProcAddress; 122 } 123 } 124 125 return lpfnProcAddress; 126 } 127 #endif 128 129 ///////////////////////////////////////////////////////////////////////////// 130 // Raises a signal in an other process 131 ///////////////////////////////////////////////////////////////////////////// 132 133 static DWORD SignalToExceptionCode( int signal ) 134 { 135 switch ( signal ) 136 { 137 case SIGSEGV: 138 return EXCEPTION_ACCESS_VIOLATION; 139 case SIGFPE: 140 return EXCEPTION_FLT_INVALID_OPERATION; 141 case SIGILL: 142 return EXCEPTION_ILLEGAL_INSTRUCTION; 143 case SIGINT: 144 return CONTROL_C_EXIT; 145 case SIGBREAK: 146 return CONTROL_C_EXIT; 147 default: 148 return 0; 149 } 150 } 151 152 static BOOL RaiseSignalEx( HANDLE hProcess, int sig ) 153 { 154 DWORD dwProcessId = GetProcessId( hProcess ); 155 156 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 157 HANDLE hThread = 0; 158 BOOL fSuccess = FALSE; 159 160 if ( IsValidHandle(hSnapshot) ) 161 { 162 THREADENTRY32 te; 163 164 te.dwSize = sizeof(te); 165 fSuccess = Thread32First( hSnapshot, &te ); 166 while ( fSuccess ) 167 { 168 if ( te.th32OwnerProcessID == dwProcessId ) 169 { 170 hThread = OpenThread( 171 THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION | 172 THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, 173 FALSE, te.th32ThreadID ); 174 if ( IsValidHandle(hThread) ) 175 break; 176 } 177 178 fSuccess = Thread32Next( hSnapshot, &te ); 179 } 180 181 CloseHandle( hSnapshot ); 182 } 183 184 if ( fSuccess ) 185 { 186 CONTEXT aContext; 187 188 if ( SuspendThread( hThread ) != (DWORD)-1 ) 189 { 190 ZeroMemory( &aContext, sizeof(aContext) ); 191 aContext.ContextFlags = CONTEXT_FULL; 192 193 fSuccess = GetThreadContext( hThread, &aContext ); 194 195 if ( fSuccess ) 196 { 197 if ( sig ) 198 { 199 DWORD dwStackBuffer[] = 200 { 201 aContext.Eip, 202 SignalToExceptionCode( sig ), 203 EXCEPTION_NONCONTINUABLE, 204 0, 205 0 206 }; 207 208 aContext.Esp -= sizeof(dwStackBuffer); 209 WriteProcessMemory( hProcess, (LPVOID)aContext.Esp, dwStackBuffer, sizeof(dwStackBuffer), NULL ); 210 aContext.Eip = (DWORD)GetProcAddressEx( hProcess, GetModuleHandleA("KERNEL32"), "RaiseException" ); 211 } 212 else 213 { 214 aContext.Ecx = aContext.Eax = aContext.Ebx = aContext.Edx = aContext.Esi = aContext.Edi = 0; 215 } 216 217 fSuccess = SetThreadContext( hThread, &aContext ); 218 } 219 220 fSuccess = ResumeThread( hThread ) && fSuccess; 221 222 DWORD dwLastError = GetLastError(); 223 CloseHandle( hThread ); 224 SetLastError( dwLastError ); 225 226 return fSuccess; 227 } 228 } 229 230 return FALSE; 231 } 232 ///////////////////////////////////////////////////////////////////////////// 233 // Command line parameter parsing 234 ///////////////////////////////////////////////////////////////////////////// 235 236 static void ParseCommandArgs( LPDWORD lpProcesses, LPDWORD lpdwNumProcesses, int *pSig ) 237 { 238 typedef struct _SignalEntry 239 { 240 LPCTSTR lpSignalName; 241 int iSignalValue; 242 } SignalEntry; 243 244 #define SIG_ENTRY( signal ) { TEXT(#signal), SIG##signal } 245 246 static SignalEntry SupportedSignals[] = 247 { 248 SIG_ENTRY( NULL ), 249 SIG_ENTRY( SEGV ), 250 SIG_ENTRY( ILL ), 251 SIG_ENTRY( FPE ), 252 SIG_ENTRY( INT ), 253 SIG_ENTRY( BREAK ), 254 SIG_ENTRY( TERM ), 255 SIG_ENTRY( ABRT ), 256 SIG_ENTRY( KILL ) 257 }; 258 259 const int NumSupportedSignals = elementsof(SupportedSignals); 260 261 DWORD dwMaxProcesses = *lpdwNumProcesses; 262 int argc = __argc; 263 TCHAR **argv = __targv; 264 265 *lpdwNumProcesses = 0; 266 267 for ( int argn = 1; argn < argc; argn++ ) 268 { 269 if ( 0 == lstrcmpi( argv[argn], TEXT("-l") ) || 270 0 == lstrcmpi( argv[argn], TEXT("/l") ) ) 271 272 { 273 for ( int n = 0; n < NumSupportedSignals; n++ ) 274 { 275 _tprintf( _T("%s "), SupportedSignals[n].lpSignalName ); 276 } 277 _tprintf( _T("\n") ); 278 ExitProcess( 0 ); 279 } 280 else if ( 0 == lstrcmpi( argv[argn], TEXT("-?") ) || 281 0 == lstrcmpi( argv[argn], TEXT("/?") ) || 282 0 == lstrcmpi( argv[argn], TEXT("-h") ) || 283 0 == lstrcmpi( argv[argn], TEXT("/h") ) || 284 0 == lstrcmpi( argv[argn], TEXT("--help") ) ) 285 { 286 _tprintf( 287 _T("Terminates a process by sending a signal.\n\n") 288 _T("Usage: kill [ -l ] [ -signal ] pid ...\n\n") 289 _T("-l Lists supported signals\n") 290 _T("-signal Sends the specified signal to the given processes.\n") 291 _T(" signal can be a numeric value specifying the signal number\n") 292 _T(" or a string listed by the -l parameter. If no signal is\n") 293 _T(" given SIGTERM (-TERM) is used.\n") 294 _T("pid Process id(s) or executables names(s) of processes to \n") 295 _T(" signal or terminate.\n\n") 296 ); 297 ExitProcess( 0 ); 298 } 299 else if ( argv[argn] && ( *argv[argn] == '-' || *argv[argn] == '/' ) ) 300 { 301 LPCTSTR argsig = CharNext( argv[argn] ); 302 303 int n; 304 for ( n = 0; n < NumSupportedSignals; n++ ) 305 { 306 _TCHAR *endptr = NULL; 307 308 if ( 0 == lstrcmpi( SupportedSignals[n].lpSignalName, argsig ) || 309 _tcstoul( argsig, &endptr, 0 ) == static_cast< unsigned >(SupportedSignals[n].iSignalValue) && (!endptr || !*endptr) ) 310 { 311 *pSig = SupportedSignals[n].iSignalValue; 312 break; 313 } 314 } 315 316 if ( n >= NumSupportedSignals ) 317 { 318 _ftprintf( stderr, 319 _T("kill: Illegal argument %s\n") 320 _T("Type 'kill --help' to show allowed syntax.\n") 321 _T("Type 'kill -l' to show supported signals.\n"), 322 argv[argn] ); 323 ExitProcess( 0 ); 324 } 325 } 326 else 327 { 328 unsigned long value = 0; 329 _TCHAR *endptr = NULL; 330 331 value = _tcstoul( argv[argn], &endptr, 0 ); 332 333 if ( !endptr || !*endptr ) 334 { 335 if ( *lpdwNumProcesses < dwMaxProcesses ) 336 { 337 *(lpProcesses++) = value; 338 (*lpdwNumProcesses)++; 339 } 340 } 341 else 342 { 343 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 344 345 if ( IsValidHandle( hSnapshot ) ) 346 { 347 PROCESSENTRY32 pe; 348 349 pe.dwSize = sizeof(pe); 350 BOOL fSuccess = Process32First( hSnapshot, &pe ); 351 352 while ( fSuccess ) 353 { 354 if ( 0 == lstrcmpi( argv[argn], pe.szExeFile ) ) 355 { 356 if ( *lpdwNumProcesses < dwMaxProcesses ) 357 { 358 *(lpProcesses++) = pe.th32ProcessID; 359 (*lpdwNumProcesses)++; 360 } 361 } 362 fSuccess = Process32Next( hSnapshot, &pe ); 363 } 364 365 CloseHandle( hSnapshot ); 366 } 367 } 368 } 369 } 370 371 if ( !*lpdwNumProcesses ) 372 { 373 _ftprintf( stderr, 374 _T("kill: No process specified.\n") 375 _T("Use kill --help to show allowed syntax.\n") 376 ); 377 ExitProcess( 0 ); 378 } 379 380 } 381 382 void OutputSystemMessage( DWORD dwErrorCode ) 383 { 384 LPVOID lpMsgBuf; 385 FormatMessageA( 386 FORMAT_MESSAGE_ALLOCATE_BUFFER | 387 FORMAT_MESSAGE_FROM_SYSTEM | 388 FORMAT_MESSAGE_IGNORE_INSERTS, 389 NULL, 390 dwErrorCode, 391 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 392 (LPSTR)&lpMsgBuf, 393 0, 394 NULL 395 ); 396 397 printf( (LPSTR)lpMsgBuf ); 398 LocalFree( lpMsgBuf ); 399 } 400 401 int _tmain() 402 { 403 DWORD dwProcessIds[1024]; 404 DWORD nProcesses = elementsof(dwProcessIds); 405 int sig = SIGTERM; 406 407 408 ParseCommandArgs( dwProcessIds, &nProcesses, &sig ); 409 410 for ( ULONG n = 0; n < nProcesses; n++ ) 411 { 412 HANDLE hProcess; 413 414 _tprintf( _T("Sending signal to process id %d..."), dwProcessIds[n] ); 415 hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_CREATE_THREAD | SYNCHRONIZE | 416 PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, 417 FALSE, dwProcessIds[n] ); 418 419 if ( IsValidHandle( hProcess ) ) 420 { 421 if ( SIGKILL == sig ) 422 TerminateProcess( hProcess, 255 ); 423 else 424 { 425 if ( RaiseSignalEx( hProcess, sig ) ) 426 _tprintf( _T("OK\n") ); 427 else 428 { 429 OutputSystemMessage( GetLastError() ); 430 } 431 } 432 433 CloseHandle( hProcess ); 434 } 435 else 436 { 437 OutputSystemMessage( GetLastError() ); 438 } 439 } 440 441 return 0; 442 } 443 444