X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fprocesses.c;h=d0501a7dbe0f9638683bdc972f12147a0acaa75f;hb=b79f8933b80036f429f8f4d5bc807326e6a3c0f9;hp=2a51da47e0cf6906ace9d61405cf3ef145a39ee8;hpb=8356150f84977016b7cb947990376096163aabdf;p=mono.git diff --git a/mono/io-layer/processes.c b/mono/io-layer/processes.c index 2a51da47e0c..d0501a7dbe0 100644 --- a/mono/io-layer/processes.c +++ b/mono/io-layer/processes.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #ifdef HAVE_SYS_MKDEV_H #include @@ -33,6 +35,29 @@ #include #endif +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) +#include +#include +# if !defined(__OpenBSD__) +# include +# endif +#endif + +#ifdef PLATFORM_SOLARIS +/* procfs.h cannot be included if this define is set, but it seems to work fine if it is undefined */ +#if _FILE_OFFSET_BITS == 64 +#undef _FILE_OFFSET_BITS +#include +#define _FILE_OFFSET_BITS 64 +#else +#include +#endif +#endif + +#ifdef __HAIKU__ +#include +#endif + #include #include #include @@ -41,15 +66,30 @@ #include #include #include +#include #include /* The process' environment strings */ +#if defined(__APPLE__) && !defined (__arm__) +/* Apple defines this in crt_externs.h but doesn't provide that header for + * arm-apple-darwin9. We'll manually define the symbol on Apple as it does + * in fact exist on all implementations (so far) + */ +gchar ***_NSGetEnviron(void); +#define environ (*_NSGetEnviron()) +#else extern char **environ; +#endif #undef DEBUG static guint32 process_wait (gpointer handle, guint32 timeout); +#if !defined(__OpenBSD__) +static FILE * +open_process_map (int pid, const char *mode); +#endif + struct _WapiHandleOps _wapi_process_ops = { NULL, /* close_shared */ NULL, /* signal */ @@ -77,6 +117,8 @@ static gboolean process_set_termination_details (gpointer handle, int status) gboolean ok; int thr_ret; + g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); + ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); if (ok == FALSE) { @@ -100,7 +142,9 @@ static gboolean process_set_termination_details (gpointer handle, int status) */ #ifdef DEBUG - g_message ("%s: Setting handle %p signalled", __func__, handle); + g_message ("%s: Setting handle %p pid %d signalled, exit status %d", + __func__, handle, process_handle->id, + process_handle->exitstatus); #endif _wapi_shared_handle_set_signal_state (handle, TRUE); @@ -126,6 +170,8 @@ static gboolean waitfor_pid (gpointer test, gpointer user_data) int status; pid_t ret; + g_assert ((GPOINTER_TO_UINT (test) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); + ok = _wapi_lookup_handle (test, WAPI_HANDLE_PROCESS, (gpointer *)&process); if (ok == FALSE) { @@ -202,6 +248,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout) pid_t pid, ret; int status; + g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); + #ifdef DEBUG g_message ("%s: Waiting for process %p", __func__, handle); #endif @@ -375,8 +423,59 @@ utf16_concat (const gunichar2 *first, ...) return ret; } +#ifdef PLATFORM_MACOSX + +/* 0 = no detection; -1 = not 10.5 or higher; 1 = 10.5 or higher */ +static int osx_10_5_or_higher; + +static void +detect_osx_10_5_or_higher (void) +{ + struct utsname u; + char *p; + int v; + + if (uname (&u) != 0){ + osx_10_5_or_higher = 1; + return; + } + + p = u.release; + v = atoi (p); + + if (v < 9) + osx_10_5_or_higher = -1; + else + osx_10_5_or_higher = 1; +} + +static gboolean +is_macos_10_5_or_higher (void) +{ + if (osx_10_5_or_higher == 0) + detect_osx_10_5_or_higher (); + + return (osx_10_5_or_higher == 1); +} +#endif + static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 }; static const gunichar2 *utf16_space = utf16_space_bytes; +static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 }; +static const gunichar2 *utf16_quote = utf16_quote_bytes; + +#ifdef DEBUG +/* Useful in gdb */ +void +print_utf16 (gunichar2 *str) +{ + gchar *res; + + res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL); + g_print ("%s\n", res); + g_free (res); +} +#endif /* Implemented as just a wrapper around CreateProcess () */ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) @@ -403,7 +502,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) * into and back out of utf8 is because there is no * g_strdup_printf () equivalent for gunichar2 :-( */ - args = utf16_concat (sei->lpFile, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); + args = utf16_concat (utf16_quote, sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); if (args == NULL){ SetLastError (ERROR_INVALID_DATA); return (FALSE); @@ -412,6 +511,9 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) CREATE_UNICODE_ENVIRONMENT, NULL, sei->lpDirectory, NULL, &process_info); g_free (args); + + if (!ret && GetLastError () == ERROR_OUTOFMEMORY) + return ret; if (!ret) { static char *handler; @@ -421,7 +523,10 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) return FALSE; #ifdef PLATFORM_MACOSX - handler = "/usr/bin/open"; + if (is_macos_10_5_or_higher ()) + handler = g_strdup ("/usr/bin/open -W"); + else + handler = g_strdup ("/usr/bin/open"); #else /* * On Linux, try: xdg-open, the FreeDesktop standard way of doing it, @@ -447,7 +552,15 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) #endif handler_utf16 = g_utf8_to_utf16 (handler, -1, NULL, NULL, NULL); g_free (handler); - args = utf16_concat (handler_utf16, utf16_space, sei->lpFile, + + /* Put quotes around the filename, in case it's a url + * that contains #'s (CreateProcess() calls + * g_shell_parse_argv(), which deliberately throws + * away anything after an unquoted #). Fixes bug + * 371567. + */ + args = utf16_concat (handler_utf16, utf16_space, utf16_quote, + sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); if (args == NULL){ @@ -588,13 +701,26 @@ gboolean CreateProcessWithLogonW (const gunichar2 *username, const gunichar2 *appname, const gunichar2 *cmdline, guint32 create_flags, - gpointer environ, + gpointer env, const gunichar2 *cwd, WapiStartupInfo *startup, WapiProcessInformation *process_info) { /* FIXME: use user information */ - return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, environ, cwd, startup, process_info); + return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, env, cwd, startup, process_info); +} + +static gboolean +is_executable (const char *prog) +{ + struct stat buf; + if (access (prog, X_OK) != 0) + return FALSE; + if (stat (prog, &buf)) + return FALSE; + if (S_ISREG (buf.st_mode)) + return TRUE; + return FALSE; } gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, @@ -652,7 +778,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, #endif SetLastError (ERROR_PATH_NOT_FOUND); - goto cleanup; + goto free_strings; } /* Turn all the slashes round the right way */ @@ -671,7 +797,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, #endif SetLastError (ERROR_PATH_NOT_FOUND); - goto cleanup; + goto free_strings; } } @@ -683,7 +809,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, #endif SetLastError (ERROR_PATH_NOT_FOUND); - goto cleanup; + goto free_strings; } /* Turn all the slashes round the right way */ @@ -713,14 +839,14 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, prog = g_strdup (unquoted); /* Executable existing ? */ - if (access (prog, X_OK) != 0) { + if (!is_executable (prog)) { #ifdef DEBUG g_message ("%s: Couldn't find executable %s", __func__, prog); #endif g_free (unquoted); SetLastError (ERROR_FILE_NOT_FOUND); - goto cleanup; + goto free_strings; } } else { /* Search for file named by cmd in the current @@ -732,14 +858,14 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, g_free (curdir); /* And make sure it's executable */ - if (access (prog, X_OK) != 0) { + if (!is_executable (prog)) { #ifdef DEBUG g_message ("%s: Couldn't find executable %s", __func__, prog); #endif g_free (unquoted); SetLastError (ERROR_FILE_NOT_FOUND); - goto cleanup; + goto free_strings; } } g_free (unquoted); @@ -748,6 +874,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } else { gchar *token = NULL; char quote; + gint token_len; /* Dig out the first token from args, taking quotation * marks into account @@ -768,10 +895,10 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, if (args[0] == '\"' || args [0] == '\'') { quote = args [0]; for (i = 1; args[i] != '\0' && args[i] != quote; i++); - if (g_ascii_isspace (args[i+1])) { + if (args [i + 1] == '\0' || g_ascii_isspace (args[i+1])) { /* We found the first token */ token = g_strndup (args+1, i-1); - args_after_prog = args + i; + args_after_prog = g_strchug (args + i + 1); } else { /* Quotation mark appeared in the * middle of the token. Just give the @@ -805,13 +932,14 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, #endif SetLastError (ERROR_PATH_NOT_FOUND); - goto cleanup; + goto free_strings; } /* Turn all the slashes round the right way. Only for * the prg. name */ - for (i = 0; i < strlen (token); i++) { + token_len = strlen (token); + for (i = 0; i < token_len; i++) { if (token[i] == '\\') { token[i] = '/'; } @@ -831,14 +959,14 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, prog = g_strdup (token); /* Executable existing ? */ - if (access (prog, X_OK) != 0) { + if (!is_executable (prog)) { #ifdef DEBUG g_message ("%s: Couldn't find executable %s", __func__, token); #endif g_free (token); SetLastError (ERROR_FILE_NOT_FOUND); - goto cleanup; + goto free_strings; } } else { @@ -856,7 +984,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* I assume X_OK is the criterion to use, * rather than F_OK */ - if (access (prog, X_OK) != 0) { + if (!is_executable (prog)) { g_free (prog); prog = g_find_program_in_path (token); if (prog == NULL) { @@ -866,7 +994,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, g_free (token); SetLastError (ERROR_FILE_NOT_FOUND); - goto cleanup; + goto free_strings; } } } @@ -882,25 +1010,36 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* Check for CLR binaries; if found, we will try to invoke * them using the same mono binary that started us. */ - if (is_managed_binary (prog) && (appname == NULL)) { + if (is_managed_binary (prog)) { + gunichar2 *newapp, *newcmd; gsize bytes_ignored; - appname = mono_unicode_from_external ("mono", &bytes_ignored); + newapp = mono_unicode_from_external ("mono", &bytes_ignored); - if (appname != NULL) { - cmdline = utf16_concat (appname, utf16_space, cmdline, NULL); + if (newapp != NULL) { + if (appname != NULL) { + newcmd = utf16_concat (newapp, utf16_space, + appname, utf16_space, + cmdline, NULL); + } else { + newcmd = utf16_concat (newapp, utf16_space, + cmdline, NULL); + } - g_free ((gunichar2 *)appname); + g_free ((gunichar2 *)newapp); - if (cmdline != NULL) { - gboolean return_value = CreateProcess ( - NULL, cmdline, process_attrs, - thread_attrs, inherit_handles, create_flags, new_environ, - cwd, startup, process_info); + if (newcmd != NULL) { + ret = CreateProcess (NULL, newcmd, + process_attrs, + thread_attrs, + inherit_handles, + create_flags, new_environ, + cwd, startup, + process_info); - g_free ((gunichar2 *)cmdline); + g_free ((gunichar2 *)newcmd); - return return_value; + goto free_strings; } } } @@ -917,8 +1056,10 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, ret = g_shell_parse_argv (full_prog, NULL, &argv, &gerr); if (ret == FALSE) { - /* FIXME: Could do something with the GError here - */ + g_message ("CreateProcess: %s\n", gerr->message); + g_error_free (gerr); + gerr = NULL; + goto free_strings; } if (startup != NULL && startup->dwFlags & STARTF_USESTDHANDLES) { @@ -940,8 +1081,9 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, if (handle == _WAPI_HANDLE_INVALID) { g_warning ("%s: error creating process handle", __func__); - SetLastError (ERROR_PATH_NOT_FOUND); - goto cleanup; + ret = FALSE; + SetLastError (ERROR_OUTOFMEMORY); + goto free_strings; } /* Hold another reference so the process has somewhere to @@ -1113,6 +1255,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, cleanup: _wapi_handle_unlock_shared_handles (); +free_strings: if (cmd != NULL) { g_free (cmd); } @@ -1276,6 +1419,11 @@ guint32 GetProcessId (gpointer handle) { struct _WapiHandle_process *process_handle; gboolean ok; + + if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + return(GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + } ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); @@ -1300,6 +1448,8 @@ static pid_t signal_process_if_gone (gpointer handle) struct _WapiHandle_process *process_handle; gboolean ok; + g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); + /* Make sure the process is signalled if it has exited - if * the parent process didn't wait for it then it won't be */ @@ -1333,6 +1483,7 @@ static pid_t signal_process_if_gone (gpointer handle) return (process_handle->id); } +#ifdef UNUSED_CODE static gboolean process_enum (gpointer handle, gpointer user_data) { GArray *processes=user_data; @@ -1368,28 +1519,142 @@ static gboolean process_enum (gpointer handle, gpointer user_data) /* Return false to keep searching */ return(FALSE); } +#endif /* UNUSED_CODE */ + +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) { - GArray *processes = g_array_new (FALSE, FALSE, sizeof(pid_t)); - guint32 fit, i, j; - + guint32 count, fit, i, j; + gint32 err; + gboolean done; + size_t proclength, size; +#if defined(__OpenBSD__) + struct kinfo_proc2 *result; + int name[6]; + name[0] = CTL_KERN; + name[1] = KERN_PROC2; + name[2] = KERN_PROC_ALL; + name[3] = 0; + name[4] = sizeof(struct kinfo_proc2); + name[5] = 0; +#else + struct kinfo_proc *result; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; +#endif + mono_once (&process_current_once, process_set_current); + + result = NULL; + done = FALSE; + + do { + proclength = 0; +#if defined(__OpenBSD__) + size = (sizeof(name) / sizeof(*name)); +#else + size = (sizeof(name) / sizeof(*name)) - 1; +#endif + err = sysctl ((int *)name, size, NULL, &proclength, NULL, 0); + + if (err == 0) { + result = malloc (proclength); + + if (result == NULL) + return FALSE; + +#if defined(__OpenBSD__) + name[5] = (int)(proclength / sizeof(struct kinfo_proc2)); +#endif + + err = sysctl ((int *) name, size, result, &proclength, NULL, 0); + + if (err == 0) + done = TRUE; + else + free (result); + } + } while (err == 0 && !done); - _wapi_search_handle (WAPI_HANDLE_PROCESS, process_enum, processes, - NULL, TRUE); + if (err != 0) { + if (result != NULL) { + free (result); + result = NULL; + } + return(FALSE); + } + +#if defined(__OpenBSD__) + count = proclength / sizeof(struct kinfo_proc2); +#else + count = proclength / sizeof(struct kinfo_proc); +#endif + fit = len / sizeof(guint32); + for (i = 0, j = 0; j< fit && i < count; i++) { +#if defined(__OpenBSD__) + pids [j++] = result [i].p_pid; +#else + if (result[i].kp_proc.p_pid > 0) /* Pid 0 not supported */ + pids [j++] = result [i].kp_proc.p_pid; +#endif + } + free (result); + result = NULL; + *needed = j * sizeof(guint32); - fit=len/sizeof(guint32); - for (i = 0, j = 0; j < fit && i < processes->len; i++) { - pids[j++] = g_array_index (processes, pid_t, i); + return(TRUE); +} +#elif defined(__HAIKU__) + +gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) +{ + guint32 fit, i = 0; + int32 cookie = 0; + team_info teamInfo; + + mono_once (&process_current_once, process_set_current); + + fit = len / sizeof (guint32); + while (get_next_team_info (&cookie, &teamInfo) == B_OK && i < fit) { + pids [i++] = teamInfo.team; } + *needed = i * sizeof (guint32); - g_array_free (processes, TRUE); + return TRUE; +} +#else +gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) +{ + guint32 fit, i; + DIR *dir; + struct dirent *entry; - *needed = j * sizeof(guint32); + mono_once (&process_current_once, process_set_current); + + dir = opendir ("/proc"); + if (dir == NULL) { + return(FALSE); + } + + i = 0; + fit = len / sizeof (guint32); + while(i < fit && (entry = readdir (dir)) != NULL) { + pid_t pid; + char *endptr; + + if (!isdigit (entry->d_name[0])) + continue; + + pid = (pid_t) strtol (entry->d_name, &endptr, 10); + if (*endptr == '\0') + pids [i++] = (guint32) pid; + } + closedir (dir); + *needed = i * sizeof(guint32); return(TRUE); } +#endif static gboolean process_open_compare (gpointer handle, gpointer user_data) { @@ -1418,10 +1683,20 @@ static gboolean process_open_compare (gpointer handle, gpointer user_data) } } -gpointer OpenProcess (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid) +gboolean CloseProcess(gpointer handle) +{ + if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + return(TRUE); + } + + return CloseHandle (handle); +} + +gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid) { /* Find the process handle that corresponds to pid */ - gpointer handle; + gpointer handle = NULL; mono_once (&process_current_once, process_set_current); @@ -1433,13 +1708,28 @@ gpointer OpenProcess (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUS process_open_compare, GUINT_TO_POINTER (pid), NULL, TRUE); if (handle == 0) { +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) + if (((kill(pid, 0) == 0) || (errno == EPERM)) && pid != 0) { +#elif defined(__HAIKU__) + team_info teamInfo; + if (get_team_info ((team_id)pid, &teamInfo) == B_OK) { +#else + gchar *dir = g_strdup_printf ("/proc/%d", pid); + if (!access (dir, F_OK)) { +#endif + /* Return a pseudo handle for processes we + * don't have handles for + */ + return GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + pid); + } else { #ifdef DEBUG - g_message ("%s: Can't find pid %d", __func__, pid); + g_message ("%s: Can't find pid %d", __func__, pid); #endif - SetLastError (ERROR_PROC_NOT_FOUND); + SetLastError (ERROR_PROC_NOT_FOUND); - return(NULL); + return(NULL); + } } _wapi_handle_ref (handle); @@ -1451,6 +1741,7 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) { struct _WapiHandle_process *process_handle; gboolean ok; + guint32 pid = -1; mono_once (&process_current_once, process_set_current); @@ -1458,6 +1749,27 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) return(FALSE); } + pid = GPOINTER_TO_UINT (process) - _WAPI_PROCESS_UNHANDLED; + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle, so we don't know what the + * exit code was, but we can check whether it's alive or not + */ +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) + if ((kill(pid, 0) == 0) || (errno == EPERM)) { +#elif defined(__HAIKU__) + team_info teamInfo; + if (get_team_info ((team_id)pid, &teamInfo) == B_OK) { +#else + gchar *dir = g_strdup_printf ("/proc/%d", pid); + if (!access (dir, F_OK)) { +#endif + *code = STILL_ACTIVE; + return TRUE; + } else { + return FALSE; + } + } + ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); if(ok==FALSE) { @@ -1470,8 +1782,13 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) /* A process handle is only signalled if the process has exited * and has been waited for */ - if (_wapi_handle_issignalled (process) == TRUE || - process_wait (process, 0) == WAIT_OBJECT_0) { + + /* Make sure any process exit has been noticed, before + * checking if the process is signalled. Fixes bug 325463. + */ + process_wait (process, 0); + + if (_wapi_handle_issignalled (process) == TRUE) { *code = process_handle->exitstatus; } else { *code = STILL_ACTIVE; @@ -1496,6 +1813,12 @@ gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time, return(FALSE); } + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle, so just fail for now + */ + return(FALSE); + } + ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); if(ok==FALSE) { @@ -1574,6 +1897,155 @@ static gint find_procmodule (gconstpointer a, gconstpointer b) } } +#ifdef PLATFORM_MACOSX +#include +#include + +static GSList *load_modules (void) +{ + GSList *ret = NULL; + WapiProcModule *mod; + uint32_t count = _dyld_image_count (); + int i = 0; + + for (i = 0; i < count; i++) { +#if SIZEOF_VOID_P == 8 + const struct mach_header_64 *hdr; + const struct section_64 *sec; +#else + const struct mach_header *hdr; + const struct section *sec; +#endif + const char *name; + intptr_t slide; + + slide = _dyld_get_image_vmaddr_slide (i); + name = _dyld_get_image_name (i); + hdr = _dyld_get_image_header (i); +#if SIZEOF_VOID_P == 8 + sec = getsectbynamefromheader_64 (hdr, SEG_DATA, SECT_DATA); +#else + sec = getsectbynamefromheader (hdr, SEG_DATA, SECT_DATA); +#endif + + /* Some dynlibs do not have data sections on osx (#533893) */ + if (sec == 0) { + continue; + } + + mod = g_new0 (WapiProcModule, 1); + mod->address_start = GINT_TO_POINTER (sec->addr); + mod->address_end = GINT_TO_POINTER (sec->addr+sec->size); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + mod->device = makedev (0, 0); + mod->inode = (ino_t) i; + mod->filename = g_strdup (name); + + if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + free_procmodule (mod); + } + } + + ret = g_slist_reverse (ret); + + return(ret); +} +#elif defined(__OpenBSD__) +#include +static int load_modules_callback (struct dl_phdr_info *info, size_t size, void *ptr) +{ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + + sizeof (info->dlpi_phnum)) + return (-1); + + struct dl_phdr_info *cpy = calloc(1, sizeof(struct dl_phdr_info)); + if (!cpy) + return (-1); + + memcpy(cpy, info, sizeof(*info)); + + g_ptr_array_add ((GPtrArray *)ptr, cpy); + + return (0); +} + +static GSList *load_modules (void) +{ + GSList *ret = NULL; + WapiProcModule *mod; + GPtrArray *dlarray = g_ptr_array_new(); + int i; + + if (dl_iterate_phdr(load_modules_callback, dlarray) < 0) + return (ret); + + for (i = 0; i < dlarray->len; i++) { + struct dl_phdr_info *info = g_ptr_array_index (dlarray, i); + + mod = g_new0 (WapiProcModule, 1); + mod->address_start = (gpointer)(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr); + mod->address_end = (gpointer)(info->dlpi_addr + + info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + mod->inode = (ino_t) i; + mod->filename = g_strdup (info->dlpi_name); + +#ifdef DEBUG + g_message ("%s: inode=%d, filename=%s, address_start=%p, address_end=%p", __func__, + mod->inode, mod->filename, mod->address_start, mod->address_end); +#endif + + free(info); + + if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + free_procmodule (mod); + } + } + + g_ptr_array_free (dlarray, TRUE); + + ret = g_slist_reverse (ret); + + return(ret); +} +#elif defined(__HAIKU__) + +static GSList *load_modules (void) +{ + GSList *ret = NULL; + WapiProcModule *mod; + int32 cookie = 0; + image_info imageInfo; + + while (get_next_image_info (B_CURRENT_TEAM, &cookie, &imageInfo) == B_OK) { + mod = g_new0 (WapiProcModule, 1); + mod->device = imageInfo.device; + mod->inode = imageInfo.node; + mod->filename = g_strdup (imageInfo.name); + mod->address_start = MIN (imageInfo.text, imageInfo.data); + mod->address_end = MAX ((uint8_t*)imageInfo.text + imageInfo.text_size, + (uint8_t*)imageInfo.data + imageInfo.data_size); + mod->perms = g_strdup ("r--p"); + mod->address_offset = 0; + + if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { + ret = g_slist_prepend (ret, mod); + } else { + free_procmodule (mod); + } + } + + ret = g_slist_reverse (ret); + + return ret; +} +#else static GSList *load_modules (FILE *fp) { GSList *ret = NULL; @@ -1692,43 +2164,110 @@ static GSList *load_modules (FILE *fp) return(ret); } +#endif + +static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename) +{ + char* lastsep = NULL; + char* pname = NULL; + char* mname = NULL; + gboolean result = FALSE; + + if (procname == NULL || modulename == NULL) + return (FALSE); + + pname = mono_path_resolve_symlinks (procname); + mname = mono_path_resolve_symlinks (modulename); + + if (!strcmp (pname, mname)) + result = TRUE; + + if (!result) { + lastsep = strrchr (mname, '/'); + if (lastsep) + if (!strcmp (lastsep+1, pname)) + result = TRUE; + } + + g_free (pname); + g_free (mname); + + return result; +} + +#if !defined(__OpenBSD__) +static FILE * +open_process_map (int pid, const char *mode) +{ + FILE *fp = NULL; + const gchar *proc_path[] = { + "/proc/%d/maps", /* GNU/Linux */ + "/proc/%d/map", /* FreeBSD */ + NULL + }; + int i; + gchar *filename; + + for (i = 0; fp == NULL && proc_path [i]; i++) { + filename = g_strdup_printf (proc_path[i], pid); + fp = fopen (filename, mode); + g_free (filename); + } + + return fp; +} +#endif gboolean EnumProcessModules (gpointer process, gpointer *modules, guint32 size, guint32 *needed) { struct _WapiHandle_process *process_handle; gboolean ok; - gchar *filename; +#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) FILE *fp; +#endif GSList *mods = NULL; WapiProcModule *module; guint32 count, avail = size / sizeof(gpointer); int i; + pid_t pid; + gchar *proc_name = NULL; /* Store modules in an array of pointers (main module as * modules[0]), using the load address for each module as a * token. (Use 'NULL' as an alternative for the main module * so that the simple implementation can just return one item * for now.) Get the info from /proc//maps on linux, - * other systems will have to implement /dev/kmem reading or - * whatever other horrid technique is needed. + * /proc//map on FreeBSD, other systems will have to + * implement /dev/kmem reading or whatever other horrid + * technique is needed. */ if (size < sizeof(gpointer)) { return(FALSE); } - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *)&process_handle); + if (ok == FALSE) { #ifdef DEBUG - g_message ("%s: Can't find process %p", __func__, process); + g_message ("%s: Can't find process %p", __func__, process); #endif - return(FALSE); + return(FALSE); + } + pid = process_handle->id; + proc_name = process_handle->proc_name; } - filename = g_strdup_printf ("/proc/%d/maps", process_handle->id); - if ((fp = fopen (filename, "r")) == NULL) { +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) + { + mods = load_modules (); +#else + if ((fp = open_process_map (pid, "r")) == NULL) { /* No /proc//maps so just return the main module * shortcut for now */ @@ -1736,6 +2275,8 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, *needed = sizeof(gpointer); } else { mods = load_modules (fp); + fclose (fp); +#endif count = g_slist_length (mods); /* count + 1 to leave slot 0 for the main module */ @@ -1743,15 +2284,20 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, /* Use the NULL shortcut, as the first line in * /proc//maps isn't the executable, and we need - * that first in the returned list. We'll probably - * have a duplicate reference to the main module later - * in the list too. FIXME if this turns out to be a - * problem. + * that first in the returned list. Check the module name + * to see if it ends with the proc name and substitute + * the first entry with it. FIXME if this turns out to + * be a problem. */ modules[0] = NULL; for (i = 0; i < (avail - 1) && i < count; i++) { module = (WapiProcModule *)g_slist_nth_data (mods, i); - modules[i + 1] = module->address_start; + if (modules[0] != NULL) + modules[i] = module->address_start; + else if (match_procname_to_modulename (proc_name, module->filename)) + modules[0] = module->address_start; + else + modules[i + 1] = module->address_start; } for (i = 0; i < count; i++) { @@ -1760,10 +2306,158 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, g_slist_free (mods); } - fclose (fp); + return(TRUE); +} + +static gchar *get_process_name_from_proc (pid_t pid) +{ +#ifdef __OpenBSD__ + int mib [6]; + size_t size; + struct kinfo_proc2 *pi; +#elif defined(PLATFORM_MACOSX) + size_t size; + struct kinfo_proc *pi; + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; +#else + FILE *fp; + gchar *filename = NULL; +#endif + gchar buf[256]; + gchar *ret = NULL; + +#if defined(PLATFORM_SOLARIS) + filename = g_strdup_printf ("/proc/%d/psinfo", pid); + if ((fp = fopen (filename, "r")) != NULL) { + struct psinfo info; + int nread; + + nread = fread (&info, sizeof (info), 1, fp); + if (nread == 1) { + ret = g_strdup (info.pr_fname); + } + + fclose (fp); + } + g_free (filename); +#elif defined(PLATFORM_MACOSX) +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) && !defined (__mono_ppc__) && !defined(__arm__) + /* No proc name on OSX < 10.5 nor ppc nor iOS */ + memset (buf, '\0', sizeof(buf)); + proc_name (pid, buf, sizeof(buf)); + if (strlen (buf) > 0) + ret = g_strdup (buf); +#else + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) + return(ret); + + if ((pi = malloc(size)) == NULL) + return(ret); + + if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { + if (errno == ENOMEM) { + free(pi); +#ifdef DEBUG + g_message ("%s: Didn't allocate enough memory for kproc info", __func__); +#endif + } + return(ret); + } + + if (strlen (pi->kp_proc.p_comm) > 0) + ret = g_strdup (pi->kp_proc.p_comm); + + free(pi); +#endif +#elif defined(__OpenBSD__) + int mib [6]; + size_t size; + struct kinfo_proc2 *pi; + + mib [0] = CTL_KERN; + mib [1] = KERN_PROC2; + mib [2] = KERN_PROC_PID; + mib [3] = pid; + mib [4] = sizeof(struct kinfo_proc2); + mib [5] = 0; + +retry: + if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) + return(ret); + + if ((pi = malloc(size)) == NULL) + return(ret); + + mib[5] = (int)(size / sizeof(struct kinfo_proc2)); + + if ((sysctl (mib, 6, pi, &size, NULL, 0) < 0) || + (size != sizeof (struct kinfo_proc2))) { + if (errno == ENOMEM) { + free(pi); + goto retry; + } + return(ret); + } + + if (strlen (pi->p_comm) > 0) + ret = g_strdup (pi->p_comm); + + free(pi); +#elif defined(__HAIKU__) + image_info imageInfo; + int32 cookie = 0; + + if (get_next_image_info ((team_id)pid, &cookie, &imageInfo) == B_OK) { + ret = g_strdup (imageInfo.name); + } +#else + memset (buf, '\0', sizeof(buf)); + filename = g_strdup_printf ("/proc/%d/exe", pid); + if (readlink (filename, buf, 255) > 0) { + ret = g_strdup (buf); + } + g_free (filename); + + if (ret != NULL) { + return(ret); + } + + filename = g_strdup_printf ("/proc/%d/cmdline", pid); + if ((fp = fopen (filename, "r")) != NULL) { + if (fgets (buf, 256, fp) != NULL) { + ret = g_strdup (buf); + } + + fclose (fp); + } g_free (filename); + + if (ret != NULL) { + return(ret); + } - return(TRUE); + filename = g_strdup_printf ("/proc/%d/stat", pid); + if ((fp = fopen (filename, "r")) != NULL) { + if (fgets (buf, 256, fp) != NULL) { + gchar *start, *end; + + start = strchr (buf, '('); + if (start != NULL) { + end = strchr (start + 1, ')'); + + if (end != NULL) { + ret = g_strndup (start + 1, + end - start - 1); + } + } + } + + fclose (fp); + } + g_free (filename); +#endif + + return ret; } static guint32 get_module_name (gpointer process, gpointer module, @@ -1777,12 +2471,14 @@ static guint32 get_module_name (gpointer process, gpointer module, gchar *procname_ext = NULL; glong len; gsize bytes; - gchar *filename; +#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) FILE *fp; +#endif GSList *mods = NULL; WapiProcModule *found_module; guint32 count; int i; + gchar *proc_name = NULL; mono_once (&process_current_once, process_set_current); @@ -1791,66 +2487,82 @@ static guint32 get_module_name (gpointer process, gpointer module, __func__, process, module); #endif + size = size*sizeof(gunichar2); /* adjust for unicode characters */ + if (basename == NULL || size == 0) { return(0); } - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + proc_name = get_process_name_from_proc (pid); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *)&process_handle); + if (ok == FALSE) { #ifdef DEBUG - g_message ("%s: Can't find process %p", __func__, process); + g_message ("%s: Can't find process %p", __func__, + process); #endif - - return(0); + + return(0); + } + pid = process_handle->id; + proc_name = g_strdup (process_handle->proc_name); } - pid = process_handle->id; - if (module == NULL) { - /* Shorthand for the main module, which has the - * process name recorded in the handle data - */ - -#ifdef DEBUG - g_message ("%s: Returning main module name", __func__); -#endif - - if (base) { - procname_ext = g_path_get_basename (process_handle->proc_name); + /* Look up the address in /proc//maps */ +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) + { + mods = load_modules (); +#else + if ((fp = open_process_map (pid, "r")) == NULL) { + if (errno == EACCES && module == NULL && base == TRUE) { + procname_ext = get_process_name_from_proc (pid); } else { - procname_ext = g_strdup (process_handle->proc_name); - } - } else { - /* Look up the address in /proc//maps */ - filename = g_strdup_printf ("/proc/%d/maps", pid); - if ((fp = fopen (filename, "r")) == NULL) { /* No /proc//maps, so just return failure * for now */ - g_free (filename); + g_free (proc_name); return(0); - } else { - mods = load_modules (fp); - fclose (fp); - count = g_slist_length (mods); - - for (i = 0; i < count; i++) { - found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (procname_ext == NULL && - found_module->address_start == module) { - if (base) { - procname_ext = g_path_get_basename (found_module->filename); - } else { - procname_ext = g_strdup (found_module->filename); - } - } + } + } else { + mods = load_modules (fp); + fclose (fp); +#endif + count = g_slist_length (mods); - free_procmodule (found_module); + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { + found_module = (WapiProcModule *)g_slist_nth_data (mods, i); + if (procname_ext == NULL && + ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || + (module != NULL && found_module->address_start == module))) { + if (base) { + procname_ext = g_path_get_basename (found_module->filename); + } else { + procname_ext = g_strdup (found_module->filename); + } } - g_slist_free (mods); - g_free (filename); + free_procmodule (found_module); + } + + if (procname_ext == NULL) + { + /* If it's *still* null, we might have hit the + * case where reading /proc/$pid/maps gives an + * empty file for this user. + */ + procname_ext = get_process_name_from_proc (pid); } + + g_slist_free (mods); + g_free (proc_name); } if (procname_ext != NULL) { @@ -1913,13 +2625,15 @@ gboolean GetModuleInformation (gpointer process, gpointer module, struct _WapiHandle_process *process_handle; gboolean ok; pid_t pid; - gchar *filename; +#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) FILE *fp; +#endif GSList *mods = NULL; WapiProcModule *found_module; guint32 count; int i; gboolean ret = FALSE; + gchar *proc_name = NULL; mono_once (&process_current_once, process_set_current); @@ -1932,56 +2646,64 @@ gboolean GetModuleInformation (gpointer process, gpointer module, return(FALSE); } - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + proc_name = get_process_name_from_proc (pid); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *)&process_handle); + if (ok == FALSE) { #ifdef DEBUG - g_message ("%s: Can't find process %p", __func__, process); + g_message ("%s: Can't find process %p", __func__, + process); #endif - - return(FALSE); + + return(FALSE); + } + pid = process_handle->id; + proc_name = g_strdup (process_handle->proc_name); } - pid = process_handle->id; - - if (module == NULL) { - /* Shorthand for the main module, which has the - * process name recorded in the handle data - * - * FIXME: try and dig through the /proc//maps - * list matching filename? + +#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) + { + mods = load_modules (); +#else + /* Look up the address in /proc//maps */ + if ((fp = open_process_map (pid, "r")) == NULL) { + /* No /proc//maps, so just return failure + * for now */ + g_free (proc_name); return(FALSE); } else { - /* Look up the address in /proc//maps */ - filename = g_strdup_printf ("/proc/%d/maps", pid); - if ((fp = fopen (filename, "r")) == NULL) { - /* No /proc//maps, so just return failure - * for now - */ - g_free (filename); - return(FALSE); - } else { - mods = load_modules (fp); - fclose (fp); - count = g_slist_length (mods); - - for (i = 0; i < count; i++) { - found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (found_module->address_start == module) { - modinfo->lpBaseOfDll = found_module->address_start; - modinfo->SizeOfImage = GPOINTER_TO_UINT(found_module->address_end) - GPOINTER_TO_UINT (found_module->address_start); - modinfo->EntryPoint = found_module->address_offset; - ret = TRUE; - } - - free_procmodule (found_module); + mods = load_modules (fp); + fclose (fp); +#endif + count = g_slist_length (mods); + + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { + found_module = (WapiProcModule *)g_slist_nth_data (mods, i); + if ( ret == FALSE && + ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || + (module != NULL && found_module->address_start == module))) { + modinfo->lpBaseOfDll = found_module->address_start; + modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start); + modinfo->EntryPoint = found_module->address_offset; + ret = TRUE; } - - g_slist_free (mods); - g_free (filename); + + free_procmodule (found_module); } + + g_slist_free (mods); + g_free (proc_name); } - + return(ret); } @@ -1997,6 +2719,12 @@ gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max) return(FALSE); } + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle, so just fail for now + */ + return(FALSE); + } + ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); if(ok==FALSE) { @@ -2019,6 +2747,12 @@ gboolean SetProcessWorkingSetSize (gpointer process, size_t min, size_t max) gboolean ok; mono_once (&process_current_once, process_set_current); + + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle, so just fail for now + */ + return(FALSE); + } ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); @@ -2044,20 +2778,28 @@ TerminateProcess (gpointer process, gint32 exitCode) gboolean ok; int signo; int ret; + pid_t pid; + + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *) &process_handle); - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (ok == FALSE) { + if (ok == FALSE) { #ifdef DEBUG - g_message ("%s: Can't find process %p", __func__, process); + g_message ("%s: Can't find process %p", __func__, + process); #endif - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; + SetLastError (ERROR_INVALID_HANDLE); + return FALSE; + } + pid = process_handle->id; } signo = (exitCode == -1) ? SIGKILL : SIGTERM; - ret = kill (process_handle->id, signo); + ret = kill (pid, signo); if (ret == -1) { switch (errno) { case EINVAL: @@ -2084,17 +2826,24 @@ GetPriorityClass (gpointer process) struct _WapiHandle_process *process_handle; gboolean ok; int ret; + pid_t pid; + + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *) &process_handle); - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (!ok) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; + if (!ok) { + SetLastError (ERROR_INVALID_HANDLE); + return FALSE; + } + pid = process_handle->id; } errno = 0; - ret = getpriority (PRIO_PROCESS, process_handle->id); + ret = getpriority (PRIO_PROCESS, pid); if (ret == -1 && errno != 0) { switch (errno) { case EPERM: @@ -2138,13 +2887,20 @@ SetPriorityClass (gpointer process, guint32 priority_class) gboolean ok; int ret; int prio; + pid_t pid; + + if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + /* This is a pseudo handle */ + pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + } else { + ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, + (gpointer *) &process_handle); - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (!ok) { - SetLastError (ERROR_INVALID_HANDLE); - return FALSE; + if (!ok) { + SetLastError (ERROR_INVALID_HANDLE); + return FALSE; + } + pid = process_handle->id; } switch (priority_class) { @@ -2171,7 +2927,7 @@ SetPriorityClass (gpointer process, guint32 priority_class) return FALSE; } - ret = setpriority (PRIO_PROCESS, process_handle->id, prio); + ret = setpriority (PRIO_PROCESS, pid, prio); if (ret == -1) { switch (errno) { case EPERM: