main.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "win32.hpp"
  14. #include "winprocess.hpp"
  15. #include "Tlhelp32.h"
  16. #include <list>
  17. using namespace win32;
  18. struct Param1
  19. {
  20. Param1(unsigned _ctrlC)
  21. {
  22. HMODULE kernel=::GetModuleHandle("kernel32.dll");
  23. SetErrorMode=::GetProcAddress(kernel,"SetErrorMode");
  24. GenerateConsoleCtrlEvent=::GetProcAddress(kernel,"GenerateConsoleCtrlEvent");
  25. Sleep=::GetProcAddress(kernel,"Sleep");
  26. Exit=::GetProcAddress(kernel,"ExitProcess");
  27. ctrlC=_ctrlC;
  28. }
  29. FARPROC SetErrorMode;
  30. FARPROC GenerateConsoleCtrlEvent;
  31. FARPROC Sleep;
  32. FARPROC Exit;
  33. DWORD ctrlC;
  34. };
  35. #pragma code_seg(".eclfunc")
  36. #ifndef _WIN64
  37. static DWORD _declspec(naked) WINAPI ExitProc(LPVOID param)
  38. {
  39. _asm
  40. {
  41. push ebp
  42. mov ebp, esp
  43. sub esp, __LOCAL_SIZE
  44. mov esi,[param]
  45. push SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX
  46. call [esi]Param1.SetErrorMode
  47. push 0
  48. push CTRL_BREAK_EVENT
  49. call [esi]Param1.GenerateConsoleCtrlEvent
  50. push [esi]Param1.ctrlC
  51. call [esi]Param1.Sleep
  52. push 0
  53. call [esi]Param1.Exit
  54. mov esp, ebp
  55. pop ebp
  56. ret 4
  57. }
  58. }
  59. #else
  60. static DWORD WINAPI ExitProc(LPVOID param)
  61. {
  62. return 0;
  63. }
  64. #endif
  65. #pragma code_seg()
  66. class ProcessKillList: public ProcessList
  67. {
  68. public:
  69. ProcessKillList(): ProcessList(SYNCHRONIZE|PROCESS_QUERY_INFORMATION|PROCESS_TERMINATE)
  70. {
  71. _restart=false;
  72. _other=true;
  73. _killchildren=false;
  74. ctrlC=0;
  75. timeout=1000;
  76. }
  77. bool isEmpty() const
  78. {
  79. return empty();
  80. }
  81. void kill(ProcessPid &pid,DWORD mysession)
  82. {
  83. if (_killchildren) {
  84. HANDLE hProcessSnap = hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  85. if (hProcessSnap != INVALID_HANDLE_VALUE) {
  86. PROCESSENTRY32 pe32;
  87. memset(&pe32,0,sizeof(pe32));
  88. pe32.dwSize = sizeof(PROCESSENTRY32);
  89. if (Process32First(hProcessSnap, &pe32)) {
  90. do {
  91. if (pe32.th32ParentProcessID==pid.GetPid()) {
  92. ProcessPid childpid(pe32.th32ProcessID,access);
  93. printf("child: ");
  94. kill(childpid,mysession);
  95. }
  96. } while (Process32Next(hProcessSnap, &pe32));
  97. }
  98. CloseHandle (hProcessSnap);
  99. }
  100. else
  101. printf("Could not take process snapshot, no children killed\n");
  102. }
  103. printf("%d - ",pid.GetPid());
  104. DWORD exit=0;
  105. if(::GetExitCodeProcess(pid,&exit) && exit!=STILL_ACTIVE)
  106. {
  107. printf("exited with code %d\n",exit);
  108. }
  109. else
  110. {
  111. if(pid.GetSession()!=mysession)
  112. {
  113. printf("different session (%d) - ",pid.GetSession());
  114. if(!_other)
  115. {
  116. printf(" skipped\n");
  117. return;
  118. }
  119. }
  120. if(Process(pid.GetPid(),PROCESS_TERMINATE).Terminate())
  121. {
  122. printf("terminated\n");
  123. }
  124. else
  125. {
  126. Error::perror();
  127. }
  128. }
  129. }
  130. void kill()
  131. {
  132. Param1 param(ctrlC);
  133. DWORD session=-1;
  134. ::ProcessIdToSessionId(::GetCurrentProcessId(),&session);
  135. bool empty=true;
  136. for(iterator ik=begin();ik!=end();ik++)
  137. {
  138. if(session==ik->GetSession())
  139. {
  140. RunRemote(*ik,ExitProc,4096,&param,sizeof(param));
  141. empty=false;
  142. }
  143. }
  144. if(!empty)
  145. {
  146. wait(timeout+ctrlC);
  147. }
  148. for(iterator it=begin();it!=end();it++)
  149. {
  150. kill(*it,session);
  151. }
  152. }
  153. void superuser()
  154. {
  155. ProcessToken token(TOKEN_ADJUST_PRIVILEGES);
  156. if(!token.AdjustPrivilege(SE_DEBUG_NAME,true))
  157. Error::perror();
  158. }
  159. void restart(const char* _path)
  160. {
  161. _restart=true;
  162. if(_path && *_path)
  163. {
  164. char path[MAX_PATH];
  165. _fullpath(path,_path,sizeof(path));
  166. startupDir.resize(mbstowcs(0,path,0)+1);
  167. mbstowcs(&startupDir.begin()[0],path,strlen(path));
  168. }
  169. }
  170. void setTimeout(unsigned msecs)
  171. {
  172. timeout=msecs;
  173. }
  174. void setCtrlC(unsigned msecs)
  175. {
  176. ctrlC=msecs;
  177. }
  178. void setOther(bool o)
  179. {
  180. _other=o;
  181. }
  182. void setKillChildren(bool o)
  183. {
  184. _killchildren=o;
  185. }
  186. protected:
  187. void wait(unsigned msecs)
  188. {
  189. HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  190. unsigned count=0;
  191. for(iterator ih=begin();ih!=end();ih++)
  192. {
  193. handles[count++]=*ih;
  194. if(count>=MAXIMUM_WAIT_OBJECTS)
  195. {
  196. if(::WaitForMultipleObjects(count,handles,TRUE,msecs)==WAIT_FAILED)
  197. Error::perror();
  198. count=0;
  199. }
  200. }
  201. if(count)
  202. if(::WaitForMultipleObjects(count,handles,TRUE,msecs)==WAIT_FAILED)
  203. {
  204. Error::perror();
  205. }
  206. }
  207. void RunRemote(HANDLE h, void* func,unsigned fsize,void* param, unsigned psize)
  208. {
  209. Process proc(h,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE);
  210. RemoteMemoryAsync code(proc,func,fsize,PAGE_EXECUTE_READWRITE);
  211. RemoteMemoryAsync data(proc,param,psize,PAGE_READWRITE);
  212. if(!code || !data || !RemoteThread(proc, reinterpret_cast<PTHREAD_START_ROUTINE>((void*)code), data, 0, 4096))
  213. {
  214. Error::perror();
  215. }
  216. }
  217. bool _restart;
  218. bool _other;
  219. bool _killchildren;
  220. wstring startupDir;
  221. unsigned timeout,ctrlC;
  222. };
  223. void usage()
  224. {
  225. printf("pskill pid - kills a pid\n"
  226. "pskill [-sr] [-ttimeout] [-ctimeout] filename1 filename2 ... - kills instances of named processes\n"
  227. " -t Time in seconds to wait for the process to exit, default is 2 seconds.\n"
  228. " -c Send Ctr-C signal first, the process has <timeout> seconds to exit.\n"
  229. " -s Enable SE_DEBUG privilege so the system processes can be killed.\n"
  230. " -o Terminate processes from the same terminal session only.\n"
  231. " -a Terminate child processes also.\n"
  232. " -r[dir] Restart the process with the new working directory specified.\n");
  233. exit(2);
  234. }
  235. int main(int argc, char** argv)
  236. {
  237. try
  238. {
  239. ProcessKillList procs;
  240. for(int i=1;i<argc;i++)
  241. {
  242. if(argv[i][0]=='-' || argv[i][0]=='/')
  243. {
  244. const char* arg=argv[i]+1;
  245. switch(tolower(*arg))
  246. {
  247. case 's':
  248. procs.superuser();
  249. break;
  250. case 'r':
  251. procs.restart(arg+1);
  252. break;
  253. case 't':
  254. procs.setTimeout(1000*atoi(arg+1));
  255. break;
  256. case 'c':
  257. procs.setCtrlC(1000*atoi(arg+1));
  258. break;
  259. case 'o':
  260. procs.setOther(false);
  261. break;
  262. case 'a':
  263. procs.setKillChildren(true);
  264. break;
  265. default:
  266. usage();
  267. }
  268. }
  269. else
  270. {
  271. const char* arg=argv[i];
  272. if(atoi(arg))
  273. {
  274. printf("Killing process %s\n", arg);
  275. procs.add(atoi(arg));
  276. }
  277. else
  278. {
  279. char imagepath[MAX_PATH];
  280. if(::SearchPath(NULL,arg,".exe",sizeof(imagepath),imagepath,NULL))
  281. {
  282. printf("Killing processes matching %s\n", imagepath);
  283. procs.add(imagepath);
  284. }
  285. else
  286. {
  287. printf("Can not find %s\n", arg);
  288. }
  289. }
  290. }
  291. }
  292. if(!procs.isEmpty())
  293. procs.kill();
  294. }
  295. catch(Error& e)
  296. {
  297. printf(e.GetMessage());
  298. }
  299. return 0;
  300. }