1
2 #ifdef __INTEL_COMPILER
3 #define _BSD_SOURCE 1
4 #define _POSIX_C_SOURCE 200809L
5 #endif
6
7 #include <stdio.h>
8 #include <stdbool.h>
9 #include "windows.h"
10 #include "utils.h"
11
12 #define MIN(a,b) ((a<b)?a:b)
13 #define MAX(a,b) ((a>b)?a:b)
14
15
getppid()16 int getppid() {
17 int pid = GetCurrentProcessId();
18
19 HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
20 PROCESSENTRY32 pe;
21 // Set the size of the structure before using it.
22 pe.dwSize = sizeof(PROCESSENTRY32);
23
24 // Get info about first process.
25 if(!Process32First(hProcessSnap, &pe)) {
26 printf("Unable to get parent pid");
27 exit(1);
28 }
29
30 // Walk the snapshot of processes to find the parent.
31 do {
32 if (pe.th32ProcessID == pid) {
33 return pe.th32ParentProcessID;
34 }
35 } while(Process32Next(hProcessSnap, &pe));
36
37 CloseHandle(hProcessSnap);
38 printf("Unable to get parent pid");
39 exit(1);
40 }
41
42
open_stdin()43 HANDLE open_stdin() {
44 HANDLE h_input = GetStdHandle(STD_INPUT_HANDLE);
45
46 if (h_input == INVALID_HANDLE_VALUE) {
47 printf("Unable to get stdin handle.");
48 exit(1);
49 }
50
51 return h_input;
52 }
53
54
open_named_pipe(const char * pipe_name)55 HANDLE open_named_pipe(const char* pipe_name) {
56 HANDLE h_input = CreateFile(pipe_name,
57 GENERIC_READ,
58 0,
59 NULL,
60 OPEN_EXISTING,
61 FILE_ATTRIBUTE_NORMAL,
62 NULL
63 );
64
65 if (h_input == INVALID_HANDLE_VALUE) {
66 printf("CreateFile failed with error %u\n", (unsigned)GetLastError());
67 exit(1);
68 }
69
70 return h_input;
71 }
72
73
configure_input_handle(HANDLE h_input)74 void configure_input_handle(HANDLE h_input) {
75 DWORD handle_type = GetFileType(h_input);
76
77 if (handle_type == FILE_TYPE_CHAR) {
78
79 DWORD lpmode;
80 GetConsoleMode(h_input, &lpmode);
81
82 // Disable line input
83 lpmode = lpmode &
84 ~ENABLE_LINE_INPUT &
85 ~ENABLE_ECHO_INPUT;
86
87 // Only listen for character input events
88 if (!SetConsoleMode(h_input, lpmode)) {
89 printf("Unable to set console mode. %d", (int)GetLastError());
90 exit(1);
91 }
92
93 } else if (handle_type == FILE_TYPE_PIPE) {
94 // No need to do anything
95 } else if (handle_type == FILE_TYPE_DISK) {
96 printf("Don't know how to handle FILE_TYPE_DISK.");
97 exit(1);
98 } else {
99 printf("Unknown input type.");
100 exit(1);
101 }
102 }
103
104
105 // If there's a complete line of text, put that line in buffer, and return the
106 // number of characters. Otherwise, return NULL.
get_line_nonblock(char * buf,int max_chars,HANDLE h_input)107 char* get_line_nonblock(char* buf, int max_chars, HANDLE h_input) {
108 // Check what type of thing we're reading from
109 DWORD input_type = GetFileType(h_input);
110
111 // Debugging info
112 char* input_type_name;
113 switch(input_type) {
114 case FILE_TYPE_CHAR:
115 input_type_name = "FILE_TYPE_CHAR (console)";
116 break;
117 case FILE_TYPE_DISK:
118 input_type_name = "FILE_TYPE_DISK";
119 break;
120 case FILE_TYPE_PIPE:
121 input_type_name = "FILE_TYPE_PIPE";
122 break;
123 default:
124 input_type_name = "Unknown";
125 }
126
127
128 if (input_type == FILE_TYPE_CHAR) {
129 // Attempt to read enough to fill the buffer
130 DWORD num_peeked;
131 INPUT_RECORD in_record_buf[WIN_INPUT_BUF_LEN];
132 char input_char_buf[WIN_INPUT_BUF_LEN];
133 int input_char_buf_n = 0;
134
135 // First use PeekConsoleInput to make sure some char is available,
136 // because ReadConsoleInput will block if there's no input.
137 if (!PeekConsoleInput(h_input, in_record_buf, WIN_INPUT_BUF_LEN, &num_peeked)) {
138 printf("Error peeking at console input.\n");
139 return NULL;
140 };
141
142 if (num_peeked == 0) {
143 return NULL;
144 }
145
146 bool found_newline = false;
147
148 int i;
149 for (i=0; i<num_peeked; i++) {
150 // We're looking for key down events where the value is not 0.
151 // (Special keys like Shift will have AsciiChar value of 0.)
152 if (in_record_buf[i].EventType == KEY_EVENT &&
153 in_record_buf[i].Event.KeyEvent.bKeyDown &&
154 in_record_buf[i].Event.KeyEvent.uChar.AsciiChar != 0)
155 {
156 // Store the character in input_char_buf. If there's a \n, then
157 // copy in_record_buf (up to the \n) to buf.
158 char c = in_record_buf[i].Event.KeyEvent.uChar.AsciiChar;
159
160 if (c == '\r') {
161 found_newline = true;
162 input_char_buf[input_char_buf_n] = '\n';
163 input_char_buf_n++;
164 break;
165 } else {
166 input_char_buf[input_char_buf_n] = c;
167 input_char_buf_n++;
168 }
169 }
170 }
171
172
173 if (found_newline) {
174 // This is the number of events up to and including the '\n'
175 DWORD num_events_read = i+1;
176 DWORD num_events_read2;
177 // Clear out console buffer up to the '\n' event
178 if (!ReadConsoleInput(h_input, in_record_buf, num_events_read , &num_events_read2)) {
179 printf("Error reading console input.\n");
180 return NULL;
181 }
182
183 // Place the content in buf
184 snprintf(buf, MIN(input_char_buf_n, max_chars), "%s", input_char_buf);
185 return buf;
186
187 } else {
188 return NULL;
189 }
190
191 } else if (input_type == FILE_TYPE_PIPE) {
192 DWORD num_peeked;
193 char input_char_buf[WIN_INPUT_BUF_LEN];
194 int input_char_buf_n = 0;
195
196 if (!PeekNamedPipe(h_input, input_char_buf, WIN_INPUT_BUF_LEN, &num_peeked, NULL, NULL)) {
197 printf("Error peeking at pipe input. Error %d.\n", (unsigned)GetLastError());
198 return NULL;
199 };
200
201 bool found_newline = false;
202 for (int i=0; i<num_peeked; i++) {
203 if (input_char_buf[i] == '\r' || input_char_buf[i] == '\n') {
204 found_newline = true;
205 }
206 input_char_buf_n++;
207 }
208
209 DWORD num_read;
210 if (found_newline) {
211 // Clear out pipe
212 if (!ReadFile(h_input, input_char_buf, input_char_buf_n, &num_read, NULL)) {
213 printf("Error reading pipe input.\n");
214 return NULL;
215 }
216
217 // Place the content in buf
218 snprintf(buf, MIN(input_char_buf_n, max_chars), "%s", input_char_buf);
219 return buf;
220
221 } else {
222 return NULL;
223 }
224
225 } else {
226 printf("Unsupported input type: %s\n", input_type_name);
227 exit(1);
228 }
229
230 return buf;
231 }
232
233
234 // Send Ctrl-C to a program if it has a console.
sendCtrlC(int pid)235 void sendCtrlC(int pid) {
236 verbose_printf("Sending ctrl+c to pid %d", pid);
237 FreeConsole();
238
239 if (AttachConsole(pid)) {
240 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
241 } else {
242 verbose_printf("Error attaching to console for PID: %d\n", pid);
243 }
244 }
245
246 // Callback function that closes a window if the PID matches the value passed
247 // in to lParam.
enumCloseWindowProc(_In_ HWND hwnd,LPARAM lParam)248 BOOL CALLBACK enumCloseWindowProc(_In_ HWND hwnd, LPARAM lParam) {
249 DWORD current_pid = 0;
250
251 GetWindowThreadProcessId(hwnd, ¤t_pid);
252
253 if (current_pid == (DWORD) lParam) {
254 PostMessage(hwnd, WM_CLOSE, 0, 0);
255 }
256
257 return true;
258 }
259
sendWmClose(int pid)260 void sendWmClose(int pid) {
261 EnumWindows(enumCloseWindowProc, (LPARAM)pid);
262 }
263
264 // Terminate process by pid.
kill_pid(DWORD dwProcessId)265 BOOL kill_pid(DWORD dwProcessId) {
266 HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
267
268 if (hProcess == NULL)
269 return FALSE;
270
271 BOOL result = TerminateProcess(hProcess, 1);
272
273 CloseHandle(hProcess);
274
275 return result;
276 }
277