blob: d1bc952b4394a5d0ec48b6a5a32d5a02ba9704e3 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
param (
[string]$p,
[string]$batchpid,
[switch]$f,
[switch]$silent,
[switch]$help
)
#-----------------------------------------------------------------------------
Function ValidateArguments
{
if (!$p)
{
PrintUsage
}
if ($help)
{
PrintUsage
}
}
#-----------------------------------------------------------------------------
Function PrintUsage
{
echo @"
usage: stop-server.ps1 -p pidfile -f[-help]
-p pidfile tracked by server and removed on close.
-s Silent. Don't print success/failure data.
-f force kill.
"@
exit
}
#-----------------------------------------------------------------------------
Function KillProcess
{
if (-Not (Test-Path $p))
{
if (-Not ($silent))
{
echo "Error - pidfile not found. Aborting."
}
exit
}
$t = @"
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
namespace PowerStopper
{
public static class Stopper
{
delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
enum CtrlTypes : uint
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Our output gets swallowed on ms-dos as we can't re-attach our console to the output of the cmd
// running the batch file.
public static void StopProgram(int pidToKill, int consolePid, bool silent)
{
Process proc = null;
try
{
proc = Process.GetProcessById(pidToKill);
}
catch (ArgumentException)
{
if (!silent)
System.Console.WriteLine("Process " + pidToKill + " not found. Aborting.");
return;
}
if (!FreeConsole())
{
if (!silent)
System.Console.WriteLine("Failed to FreeConsole to attach to running cassandra process. Aborting.");
return;
}
if (AttachConsole((uint)pidToKill))
{
//Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(null, true);
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
// Must wait here. If we don't and re-enable Ctrl-C
// handling below too fast, we might terminate ourselves.
bool exited = proc.WaitForExit(30000);
if(!exited)
proc.Kill();
FreeConsole();
// Re-attach to current console to write output
if (consolePid >= 0)
AttachConsole((uint)consolePid);
// Re-enable Ctrl-C handling or any subsequently started
// programs will inherit the disabled state.
SetConsoleCtrlHandler(null, false);
if (!silent)
{
if(exited)
System.Console.WriteLine("Successfully sent ctrl+c to process with id: " + pidToKill + ".");
else
System.Console.WriteLine("Process with id: " + pidToKill + " did not exit after 30 seconds, killed.");
}
}
else
{
if (!silent)
{
string errorMsg = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message;
System.Console.WriteLine("Error attaching to pid: " + pidToKill + ": " + Marshal.GetLastWin32Error() + " - " + errorMsg);
}
}
}
}
}
"@
# cygwin assumes environment variables are case sensitive which causes problems when
# the type dictionary references 'tmp' or 'temp' and throws a System.ArgumentException
$oldTmp = $env:TMP
$oldTemp = $env:Temp
$env:TMP=''
$env:TEMP=''
Add-Type -TypeDefinition $t
$env:TMP = $oldTmp
$env:TEMP = $oldTemp
$pidToKill = Get-Content $p
# If run in cygwin, we don't get the TITLE / pid combo in stop-server.bat but also don't need
# to worry about reattaching console output as it gets stderr/stdout even after the C#/C++
# FreeConsole calls.
if ($batchpid -eq "No")
{
$batchpid = -1
}
if ($f)
{
taskkill /f /pid $pidToKill
}
else
{
[PowerStopper.Stopper]::StopProgram($pidToKill, $batchpid, $silent)
}
}
#-----------------------------------------------------------------------------
ValidateArguments
KillProcess