1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: kill.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
37 #pragma warning(push,1) // disable warnings within system headers
39 #define WIN32_LEAN_AND_MEAN
62 #define MAX_MODULES 1024
64 /////////////////////////////////////////////////////////////////////////////
65 // Determines if a returned handle value is valid
66 /////////////////////////////////////////////////////////////////////////////
68 static inline bool IsValidHandle( HANDLE handle
)
70 return INVALID_HANDLE_VALUE
!= handle
&& NULL
!= handle
;
74 #define elementsof( a ) (sizeof(a) / sizeof( (a)[0] ))
76 /////////////////////////////////////////////////////////////////////////////
77 // Retrieves function adress in another process
78 /////////////////////////////////////////////////////////////////////////////
81 #define GetProcAddressEx( hProcess, hModule, lpProcName ) GetProcAddress( hModule, lpProcName )
83 FARPROC WINAPI
GetProcAddressEx( HANDLE hProcess
, HMODULE hModule
, LPCSTR lpProcName
)
85 FARPROC lpfnProcAddress
= GetProcAddress( hModule
, lpProcName
);
87 if ( lpfnProcAddress
)
89 DWORD dwProcessId
= GetProcessId( hProcess
);
91 if ( GetCurrentProcessId() != dwProcessId
)
93 FARPROC lpfnRemoteProcAddress
= NULL
;
94 TCHAR szBaseName
[MAX_PATH
];
96 if ( GetModuleBaseName( GetCurrentProcess(), hModule
, szBaseName
, elementsof(szBaseName
) ) )
98 HMODULE ahModules
[MAX_MODULES
];
101 if ( EnumProcessModules( hProcess
, ahModules
, sizeof(ahModules
), &cbNeeded
) )
103 ULONG nModules
= cbNeeded
/ sizeof(ahModules
[0]);
105 for ( ULONG n
= 0; n
< nModules
; n
++ )
107 TCHAR szRemoteBaseName
[MAX_PATH
];
109 if ( GetModuleBaseName(
110 hProcess
, ahModules
[n
], szRemoteBaseName
, elementsof(szRemoteBaseName
) ) &&
111 0 == lstrcmpi( szRemoteBaseName
, szBaseName
)
114 lpfnRemoteProcAddress
= lpfnProcAddress
;
116 if ( ahModules
[n
] != hModule
)
117 *(LPBYTE
*)&lpfnRemoteProcAddress
+= (LPBYTE
)ahModules
[n
] - (LPBYTE
)hModule
;
124 lpfnProcAddress
= lpfnRemoteProcAddress
;
128 return lpfnProcAddress
;
132 /////////////////////////////////////////////////////////////////////////////
133 // Raises a signal in an other process
134 /////////////////////////////////////////////////////////////////////////////
136 static DWORD
SignalToExceptionCode( int signal
)
141 return EXCEPTION_ACCESS_VIOLATION
;
143 return EXCEPTION_FLT_INVALID_OPERATION
;
145 return EXCEPTION_ILLEGAL_INSTRUCTION
;
147 return CONTROL_C_EXIT
;
149 return CONTROL_C_EXIT
;
155 static BOOL
RaiseSignalEx( HANDLE hProcess
, int sig
)
157 DWORD dwProcessId
= GetProcessId( hProcess
);
159 HANDLE hSnapshot
= CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD
, 0 );
161 BOOL fSuccess
= FALSE
;
163 if ( IsValidHandle(hSnapshot
) )
167 te
.dwSize
= sizeof(te
);
168 fSuccess
= Thread32First( hSnapshot
, &te
);
171 if ( te
.th32OwnerProcessID
== dwProcessId
)
173 hThread
= OpenThread(
174 THREAD_SUSPEND_RESUME
| THREAD_QUERY_INFORMATION
|
175 THREAD_GET_CONTEXT
| THREAD_SET_CONTEXT
,
176 FALSE
, te
.th32ThreadID
);
177 if ( IsValidHandle(hThread
) )
181 fSuccess
= Thread32Next( hSnapshot
, &te
);
184 CloseHandle( hSnapshot
);
191 if ( SuspendThread( hThread
) != (DWORD
)-1 )
193 ZeroMemory( &aContext
, sizeof(aContext
) );
194 aContext
.ContextFlags
= CONTEXT_FULL
;
196 fSuccess
= GetThreadContext( hThread
, &aContext
);
202 DWORD dwStackBuffer
[] =
205 SignalToExceptionCode( sig
),
206 EXCEPTION_NONCONTINUABLE
,
211 aContext
.Esp
-= sizeof(dwStackBuffer
);
212 WriteProcessMemory( hProcess
, (LPVOID
)aContext
.Esp
, dwStackBuffer
, sizeof(dwStackBuffer
), NULL
);
213 aContext
.Eip
= (DWORD
)GetProcAddressEx( hProcess
, GetModuleHandleA("KERNEL32"), "RaiseException" );
217 aContext
.Ecx
= aContext
.Eax
= aContext
.Ebx
= aContext
.Edx
= aContext
.Esi
= aContext
.Edi
= 0;
220 fSuccess
= SetThreadContext( hThread
, &aContext
);
223 fSuccess
= ResumeThread( hThread
) && fSuccess
;
225 DWORD dwLastError
= GetLastError();
226 CloseHandle( hThread
);
227 SetLastError( dwLastError
);
235 /////////////////////////////////////////////////////////////////////////////
236 // Command line parameter parsing
237 /////////////////////////////////////////////////////////////////////////////
239 static void ParseCommandArgs( LPDWORD lpProcesses
, LPDWORD lpdwNumProcesses
, int *pSig
)
241 typedef struct _SignalEntry
243 LPCTSTR lpSignalName
;
247 #define SIG_ENTRY( signal ) { TEXT(#signal), SIG##signal }
249 static SignalEntry SupportedSignals
[] =
262 const int NumSupportedSignals
= elementsof(SupportedSignals
);
264 DWORD dwMaxProcesses
= *lpdwNumProcesses
;
266 TCHAR
**argv
= __targv
;
268 *lpdwNumProcesses
= 0;
270 for ( int argn
= 1; argn
< argc
; argn
++ )
272 if ( 0 == lstrcmpi( argv
[argn
], TEXT("-l") ) ||
273 0 == lstrcmpi( argv
[argn
], TEXT("/l") ) )
276 for ( int n
= 0; n
< NumSupportedSignals
; n
++ )
278 _tprintf( _T("%s "), SupportedSignals
[n
] );
280 _tprintf( _T("\n") );
283 else if ( 0 == lstrcmpi( argv
[argn
], TEXT("-?") ) ||
284 0 == lstrcmpi( argv
[argn
], TEXT("/?") ) ||
285 0 == lstrcmpi( argv
[argn
], TEXT("-h") ) ||
286 0 == lstrcmpi( argv
[argn
], TEXT("/h") ) ||
287 0 == lstrcmpi( argv
[argn
], TEXT("--help") ) )
290 _T("Terminates a process by sending a signal.\n\n")
291 _T("Usage: kill [ -l ] [ -signal ] pid ...\n\n")
292 _T("-l Lists supported signals\n")
293 _T("-signal Sends the specified signal to the given processes.\n")
294 _T(" signal can be a numeric value specifying the signal number\n")
295 _T(" or a string listed by the -l parameter. If no signal is\n")
296 _T(" given SIGTERM (-TERM) is used.\n")
297 _T("pid Process id(s) or executables names(s) of processes to \n")
298 _T(" signal or terminate.\n\n")
302 else if ( argv
[argn
] && ( *argv
[argn
] == '-' || *argv
[argn
] == '/' ) )
304 LPCTSTR argsig
= CharNext( argv
[argn
] );
307 for ( n
= 0; n
< NumSupportedSignals
; n
++ )
309 _TCHAR
*endptr
= NULL
;
311 if ( 0 == lstrcmpi( SupportedSignals
[n
].lpSignalName
, argsig
) ||
312 _tcstoul( argsig
, &endptr
, 0 ) == static_cast< unsigned >(SupportedSignals
[n
].iSignalValue
) && (!endptr
|| !*endptr
) )
314 *pSig
= SupportedSignals
[n
].iSignalValue
;
319 if ( n
>= NumSupportedSignals
)
322 _T("kill: Illegal argument %s\n")
323 _T("Type 'kill --help' to show allowed syntax.\n")
324 _T("Type 'kill -l' to show supported signals.\n"),
331 unsigned long value
= 0;
332 _TCHAR
*endptr
= NULL
;
334 value
= _tcstoul( argv
[argn
], &endptr
, 0 );
336 if ( !endptr
|| !*endptr
)
338 if ( *lpdwNumProcesses
< dwMaxProcesses
)
340 *(lpProcesses
++) = value
;
341 (*lpdwNumProcesses
)++;
346 HANDLE hSnapshot
= CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS
, 0 );
348 if ( IsValidHandle( hSnapshot
) )
352 pe
.dwSize
= sizeof(pe
);
353 BOOL fSuccess
= Process32First( hSnapshot
, &pe
);
357 if ( 0 == lstrcmpi( argv
[argn
], pe
.szExeFile
) )
359 if ( *lpdwNumProcesses
< dwMaxProcesses
)
361 *(lpProcesses
++) = pe
.th32ProcessID
;
362 (*lpdwNumProcesses
)++;
365 fSuccess
= Process32Next( hSnapshot
, &pe
);
368 CloseHandle( hSnapshot
);
374 if ( !*lpdwNumProcesses
)
377 _T("kill: No process specified.\n")
378 _T("Use kill --help to show allowed syntax.\n")
385 void OutputSystemMessage( DWORD dwErrorCode
)
389 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
390 FORMAT_MESSAGE_FROM_SYSTEM
|
391 FORMAT_MESSAGE_IGNORE_INSERTS
,
394 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
400 printf( (LPSTR
)lpMsgBuf
);
401 LocalFree( lpMsgBuf
);
406 DWORD dwProcessIds
[1024];
407 DWORD nProcesses
= elementsof(dwProcessIds
);
411 ParseCommandArgs( dwProcessIds
, &nProcesses
, &sig
);
413 for ( ULONG n
= 0; n
< nProcesses
; n
++ )
417 _tprintf( _T("Sending signal to process id %d..."), dwProcessIds
[n
] );
418 hProcess
= OpenProcess( PROCESS_TERMINATE
| PROCESS_CREATE_THREAD
| SYNCHRONIZE
|
419 PROCESS_QUERY_INFORMATION
| PROCESS_VM_OPERATION
| PROCESS_VM_WRITE
| PROCESS_VM_READ
,
420 FALSE
, dwProcessIds
[n
] );
422 if ( IsValidHandle( hProcess
) )
424 if ( SIGKILL
== sig
)
425 TerminateProcess( hProcess
, 255 );
428 if ( RaiseSignalEx( hProcess
, sig
) )
429 _tprintf( _T("OK\n") );
432 OutputSystemMessage( GetLastError() );
436 CloseHandle( hProcess
);
440 OutputSystemMessage( GetLastError() );