/* FIXME Argument processing does not match behavior observed on Windows. * Stringent argument counting and processing is performed, and unrecognized * options are detected as parameters when placed after options that accept one. */ static BOOL process_arguments(int argc, WCHAR *argv[]) { static const WCHAR slashForceTerminate[] = {'/','f',0}; static const WCHAR slashImage[] = {'/','i','m',0}; static const WCHAR slashPID[] = {'/','p','i','d',0}; static const WCHAR slashHelp[] = {'/','?',0}; if (argc > 1) { int i; BOOL has_im = 0, has_pid = 0; /* Only the lone help option is recognized. */ if (argc == 2 && !strcmpW(slashHelp, argv[1])) { taskkill_message(STRING_USAGE); exit(0); } for (i = 1; i < argc; i++) { int got_im = 0, got_pid = 0; if (!strcmpiW(slashForceTerminate, argv[i])) force_termination = 1; /* Options /IM and /PID appear to behave identically, except for * the fact that they cannot be specified at the same time. */ else if ((got_im = !strcmpiW(slashImage, argv[i])) || (got_pid = !strcmpiW(slashPID, argv[i]))) { if (!argv[i + 1]) { taskkill_message_printfW(STRING_MISSING_PARAM, argv[i]); taskkill_message(STRING_USAGE); return FALSE; } if (got_im) has_im = 1; if (got_pid) has_pid = 1; if (has_im && has_pid) { taskkill_message(STRING_MUTUAL_EXCLUSIVE); taskkill_message(STRING_USAGE); return FALSE; } if (!add_to_task_list(argv[i + 1])) return FALSE; i++; } else { taskkill_message(STRING_INVALID_OPTION); taskkill_message(STRING_USAGE); return FALSE; } } } else { taskkill_message(STRING_MISSING_OPTION); taskkill_message(STRING_USAGE); return FALSE; } return TRUE; }
/* The implemented task enumeration and termination behavior does not * exactly match native behavior. On Windows: * * In the case of terminating by process name, specifying a particular * process name more times than the number of running instances causes * all instances to be terminated, but termination failure messages to * be printed as many times as the difference between the specification * quantity and the number of running instances. * * Successful terminations are all listed first in order, with failing * terminations being listed at the end. * * A PID of zero causes taskkill to warn about the inability to terminate * system processes. */ static int send_close_messages(void) { DWORD *pid_list, pid_list_size; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; pid_list = enumerate_processes(&pid_list_size); if (!pid_list) { taskkill_message(STRING_ENUM_FAILED); return 1; } for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; BOOL is_numeric = TRUE; /* Determine whether the string is not numeric. */ while (*p) { if (!isdigitW(*p++)) { is_numeric = FALSE; break; } } if (is_numeric) { DWORD pid = atoiW(task_list[i]); struct pid_close_info info = { pid }; if (pid == self_pid) { taskkill_message(STRING_SELF_TERMINATION); status_code = 1; continue; } EnumWindows(pid_enum_proc, (LPARAM)&info); if (info.found) taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, pid); else { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; } } else { DWORD index; BOOL found_process = FALSE; for (index = 0; index < pid_list_size; index++) { WCHAR process_name[MAX_PATH]; if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) && !strcmpiW(process_name, task_list[i])) { struct pid_close_info info = { pid_list[index] }; found_process = TRUE; if (pid_list[index] == self_pid) { taskkill_message(STRING_SELF_TERMINATION); status_code = 1; continue; } EnumWindows(pid_enum_proc, (LPARAM)&info); taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]); } } if (!found_process) { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; } } } HeapFree(GetProcessHeap(), 0, pid_list); return status_code; }
static int terminate_processes(void) { DWORD *pid_list, pid_list_size; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; pid_list = enumerate_processes(&pid_list_size); if (!pid_list) { taskkill_message(STRING_ENUM_FAILED); return 1; } for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; BOOL is_numeric = TRUE; /* Determine whether the string is not numeric. */ while (*p) { if (!isdigitW(*p++)) { is_numeric = FALSE; break; } } if (is_numeric) { DWORD pid = atoiW(task_list[i]); HANDLE process; if (pid == self_pid) { taskkill_message(STRING_SELF_TERMINATION); status_code = 1; continue; } process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (!process) { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; continue; } if (!TerminateProcess(process, 0)) { taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); status_code = 1; CloseHandle(process); continue; } taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); CloseHandle(process); } else { DWORD index; BOOL found_process = FALSE; for (index = 0; index < pid_list_size; index++) { WCHAR process_name[MAX_PATH]; if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) && !strcmpiW(process_name, task_list[i])) { HANDLE process; if (pid_list[index] == self_pid) { taskkill_message(STRING_SELF_TERMINATION); status_code = 1; continue; } process = OpenProcess(PROCESS_TERMINATE, FALSE, pid_list[index]); if (!process) { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; continue; } if (!TerminateProcess(process, 0)) { taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); status_code = 1; CloseHandle(process); continue; } found_process = TRUE; taskkill_message_printfW(STRING_TERM_PROC_SEARCH, task_list[i], pid_list[index]); CloseHandle(process); } } if (!found_process) { taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); status_code = 128; } } } HeapFree(GetProcessHeap(), 0, pid_list); return status_code; }
/* FIXME Argument processing does not match behavior observed on Windows. * Stringent argument counting and processing is performed, and unrecognized * options are detected as parameters when placed after options that accept one. */ static BOOL process_arguments(int argc, WCHAR *argv[]) { static const WCHAR opForceTerminate[] = {'f',0}; static const WCHAR opImage[] = {'i','m',0}; static const WCHAR opPID[] = {'p','i','d',0}; static const WCHAR opHelp[] = {'?',0}; static const WCHAR opTerminateChildren[] = {'t',0}; if (argc > 1) { int i; WCHAR *argdata; BOOL has_im = FALSE, has_pid = FALSE; /* Only the lone help option is recognized. */ if (argc == 2) { argdata = argv[1]; if ((*argdata == '/' || *argdata == '-') && !strcmpW(opHelp, argdata + 1)) { taskkill_message(STRING_USAGE); exit(0); } } for (i = 1; i < argc; i++) { BOOL got_im = FALSE, got_pid = FALSE; argdata = argv[i]; if (*argdata != '/' && *argdata != '-') goto invalid; argdata++; if (!strcmpiW(opTerminateChildren, argdata)) WINE_FIXME("argument T not supported\n"); if (!strcmpiW(opForceTerminate, argdata)) force_termination = TRUE; /* Options /IM and /PID appear to behave identically, except for * the fact that they cannot be specified at the same time. */ else if ((got_im = !strcmpiW(opImage, argdata)) || (got_pid = !strcmpiW(opPID, argdata))) { if (!argv[i + 1]) { taskkill_message_printfW(STRING_MISSING_PARAM, argv[i]); taskkill_message(STRING_USAGE); return FALSE; } if (got_im) has_im = TRUE; if (got_pid) has_pid = TRUE; if (has_im && has_pid) { taskkill_message(STRING_MUTUAL_EXCLUSIVE); taskkill_message(STRING_USAGE); return FALSE; } if (!add_to_task_list(argv[i + 1])) return FALSE; i++; } else { invalid: taskkill_message(STRING_INVALID_OPTION); taskkill_message(STRING_USAGE); return FALSE; } } } else { taskkill_message(STRING_MISSING_OPTION); taskkill_message(STRING_USAGE); return FALSE; } return TRUE; }