Merge pull request #2338 from BogdanovKirill/httpwritefix3
[mono.git] / mono / io-layer / processes.c
index a57d8aaeb7ad287a7eebf321b6ddf9e2b5c648ad..851ffaffb6eb1b6f2712a38daca9cec9d7c59cea 100644 (file)
@@ -83,7 +83,6 @@
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 #include <mono/io-layer/handles-private.h>
-#include <mono/io-layer/misc-private.h>
 #include <mono/io-layer/process-private.h>
 #include <mono/io-layer/threads.h>
 #include <mono/utils/strenc.h>
 #include <mono/io-layer/timefuncs-private.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-membar.h>
-#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-os-mutex.h>
 #include <mono/utils/mono-signal-handler.h>
 #include <mono/utils/mono-proclib.h>
+#include <mono/utils/mono-once.h>
 
 /* The process' environment strings */
-#if defined(__APPLE__) && !defined (__arm__) && !defined (__aarch64__)
+#if defined(__APPLE__)
+#if defined (TARGET_OSX)
 /* 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) 
  */
-char ***_NSGetEnviron(void);
+gchar ***_NSGetEnviron(void);
 #define environ (*_NSGetEnviron())
 #else
+static char *mono_environ[1] = { NULL };
+#define environ mono_environ
+#endif /* defined (TARGET_OSX) */
+#else
 extern char **environ;
 #endif
 
@@ -178,7 +183,9 @@ is_pid_valid (pid_t pid)
 {
        gboolean result = FALSE;
 
-#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#if defined(HOST_WATCHOS)
+       result = TRUE; // TODO: Rewrite using sysctl
+#elif defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__)
        if (((kill(pid, 0) == 0) || (errno == EPERM)) && pid != 0)
                result = TRUE;
 #elif defined(__HAIKU__)
@@ -552,6 +559,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
                        WapiStartupInfo *startup,
                        WapiProcessInformation *process_info)
 {
+#if defined (HAVE_FORK) && defined (HAVE_EXECVE)
        char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL;
        char *dir = NULL, **env_strings = NULL, **argv = NULL;
        guint32 i, env_count = 0;
@@ -815,11 +823,11 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
 
                if (newapp != NULL) {
                        if (appname != NULL) {
-                               newcmd = utf16_concat (newapp, utf16_space,
+                               newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space,
                                                       appname, utf16_space,
                                                       cmdline, NULL);
                        } else {
-                               newcmd = utf16_concat (newapp, utf16_space,
+                               newcmd = utf16_concat (utf16_quote, newapp, utf16_quote, utf16_space,
                                                       cmdline, NULL);
                        }
                        
@@ -1029,7 +1037,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
        mono_process = (struct MonoProcess *) g_malloc0 (sizeof (struct MonoProcess));
        mono_process->pid = pid;
        mono_process->handle_count = 1;
-       if (MONO_SEM_INIT (&mono_process->exit_sem, 0) != 0) {
+       if (mono_os_sem_init (&mono_process->exit_sem, 0) != 0) {
                /* If we can't create the exit semaphore, we just don't add anything
                 * to our list of mono processes. Waiting on the process will return 
                 * immediately. */
@@ -1043,10 +1051,10 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
 
                process_handle_data->mono_process = mono_process;
 
-               mono_mutex_lock (&mono_processes_mutex);
+               mono_os_mutex_lock (&mono_processes_mutex);
                mono_process->next = mono_processes;
                mono_processes = mono_process;
-               mono_mutex_unlock (&mono_processes_mutex);
+               mono_os_mutex_unlock (&mono_processes_mutex);
        }
        
        if (process_info != NULL) {
@@ -1096,6 +1104,10 @@ free_strings:
        mono_processes_cleanup ();
        
        return ret;
+#else
+       SetLastError (ERROR_NOT_SUPPORTED);
+       return FALSE;
+#endif // defined (HAVE_FORK) && defined (HAVE_EXECVE)
 }
                
 static void
@@ -1125,8 +1137,7 @@ wapi_processes_init (void)
        WapiHandle_process process_handle = {0};
 
        _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
-                                           WAPI_HANDLE_CAP_WAIT |
-                                           WAPI_HANDLE_CAP_SPECIAL_WAIT);
+               (WapiHandleCapability)(WAPI_HANDLE_CAP_WAIT | WAPI_HANDLE_CAP_SPECIAL_WAIT));
        
        process_handle.id = pid;
 
@@ -1136,6 +1147,8 @@ wapi_processes_init (void)
        current_process = _wapi_handle_new (WAPI_HANDLE_PROCESS,
                                            &process_handle);
        g_assert (current_process);
+
+       mono_os_mutex_init (&mono_processes_mutex);
 }
 
 gpointer
@@ -1768,7 +1781,7 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules,
                        return FALSE;
                }
                pid = process_handle->id;
-               proc_name = process_handle->proc_name;
+               proc_name = g_strdup (process_handle->proc_name);
        }
        
 #if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__)
@@ -1786,6 +1799,7 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules,
                 */
                modules[0] = NULL;
                *needed = sizeof(gpointer);
+               g_free (proc_name);
                return TRUE;
        }
        mods = load_modules (fp);
@@ -1816,10 +1830,11 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules,
        }
                
        for (i = 0; i < count; i++) {
-               free_procmodule (g_slist_nth_data (mods, i));
+               free_procmodule ((WapiProcModule *)g_slist_nth_data (mods, i));
        }
        g_slist_free (mods);
-
+       g_free (proc_name);
+       
        return TRUE;
 }
 
@@ -1862,7 +1877,31 @@ get_process_name_from_proc (pid_t pid)
        /* 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)
+
+       // Fixes proc_name triming values to 15 characters #32539
+       if (strlen (buf) >= MAXCOMLEN - 1) {
+               char path_buf [PROC_PIDPATHINFO_MAXSIZE];
+               char *name_buf;
+               int path_len;
+
+               memset (path_buf, '\0', sizeof(path_buf));
+               path_len = proc_pidpath (pid, path_buf, sizeof(path_buf));
+
+               if (path_len > 0 && path_len < sizeof(path_buf)) {
+                       name_buf = path_buf + path_len;
+                       for(;name_buf > path_buf; name_buf--) {
+                               if (name_buf [0] == '/') {
+                                       name_buf++;
+                                       break;
+                               }
+                       }
+
+                       if (memcmp (buf, name_buf, MAXCOMLEN - 1) == 0)
+                               ret = g_strdup (name_buf);
+               }
+       }
+
+       if (ret == NULL && strlen (buf) > 0)
                ret = g_strdup (buf);
 #else
        if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0)
@@ -2169,6 +2208,53 @@ get_module_name (gpointer process, gpointer module,
        return 0;
 }
 
+static guint32
+get_module_filename (gpointer process, gpointer module,
+                                        gunichar2 *basename, guint32 size)
+{
+       int pid, len;
+       gsize bytes;
+       char *path;
+       gunichar2 *proc_path;
+       
+       size *= sizeof (gunichar2); /* adjust for unicode characters */
+
+       if (basename == NULL || size == 0)
+               return 0;
+
+       pid = GetProcessId (process);
+
+       path = wapi_process_get_path (pid);
+       if (path == NULL)
+               return 0;
+
+       proc_path = mono_unicode_from_external (path, &bytes);
+       g_free (path);
+
+       if (proc_path == NULL)
+               return 0;
+
+       len = (bytes / 2);
+       
+       /* Add the terminator */
+       bytes += 2;
+
+       if (size < bytes) {
+               DEBUG ("%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes);
+
+               memcpy (basename, proc_path, size);
+       } else {
+               DEBUG ("%s: Size %d larger than needed (%ld)",
+                          __func__, size, bytes);
+
+               memcpy (basename, proc_path, bytes);
+       }
+
+       g_free (proc_path);
+
+       return len;
+}
+
 guint32
 GetModuleBaseName (gpointer process, gpointer module,
                                   gunichar2 *basename, guint32 size)
@@ -2180,7 +2266,7 @@ guint32
 GetModuleFileNameEx (gpointer process, gpointer module,
                                         gunichar2 *filename, guint32 size)
 {
-       return get_module_name (process, module, filename, size, FALSE);
+       return get_module_filename (process, module, filename, size);
 }
 
 gboolean
@@ -2313,6 +2399,7 @@ SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
 gboolean
 TerminateProcess (gpointer process, gint32 exitCode)
 {
+#if defined(HAVE_KILL)
        WapiHandle_process *process_handle;
        int signo;
        int ret;
@@ -2350,6 +2437,10 @@ TerminateProcess (gpointer process, gint32 exitCode)
        }
        
        return (ret == 0);
+#else
+       g_error ("kill() is not supported by this platform");
+       return FALSE;
+#endif
 }
 
 guint32
@@ -2495,10 +2586,10 @@ mono_processes_cleanup (void)
                if (mp->pid == 0 && mp->handle) {
                        /* This process has exited and we need to remove the artifical ref
                         * on the handle */
-                       mono_mutex_lock (&mono_processes_mutex);
+                       mono_os_mutex_lock (&mono_processes_mutex);
                        unref_handle = mp->handle;
                        mp->handle = NULL;
-                       mono_mutex_unlock (&mono_processes_mutex);
+                       mono_os_mutex_unlock (&mono_processes_mutex);
                        if (unref_handle)
                                _wapi_handle_unref (unref_handle);
                }
@@ -2510,7 +2601,7 @@ mono_processes_cleanup (void)
         * asynchronously. The handler requires that the mono_processes list
         * remain valid.
         */
-       mono_mutex_lock (&mono_processes_mutex);
+       mono_os_mutex_lock (&mono_processes_mutex);
 
        mp = mono_processes;
        while (mp) {
@@ -2541,13 +2632,13 @@ mono_processes_cleanup (void)
                 * they have the 'finished' flag set, which means the sigchld handler is done
                 * accessing them.
                 */
-               mp = l->data;
-               MONO_SEM_DESTROY (&mp->exit_sem);
+               mp = (MonoProcess *)l->data;
+               mono_os_sem_destroy (&mp->exit_sem);
                g_free (mp);
        }
        g_slist_free (finished);
 
-       mono_mutex_unlock (&mono_processes_mutex);
+       mono_os_mutex_unlock (&mono_processes_mutex);
 
        DEBUG ("%s done", __func__);
 
@@ -2599,7 +2690,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
                if (p) {
                        p->pid = 0; /* this pid doesn't exist anymore, clear it */
                        p->status = status;
-                       MONO_SEM_POST (&p->exit_sem);
+                       mono_os_sem_post (&p->exit_sem);
                        mono_memory_barrier ();
                        /* Mark this as freeable, the pointer becomes invalid afterwards */
                        p->freeable = TRUE;
@@ -2669,12 +2760,11 @@ process_wait (gpointer handle, guint32 timeout, gboolean alertable)
                if (timeout != INFINITE) {
                        DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...", 
                                   __func__, handle, timeout, (timeout - (now - start)));
-
-                       ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable);
+                       ret = mono_os_sem_timedwait (&mp->exit_sem, (timeout - (now - start)), alertable ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
                } else {
                        DEBUG ("%s (%p, %u): waiting on semaphore forever...", 
                                   __func__, handle, timeout);
-                       ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable);
+                       ret = mono_os_sem_wait (&mp->exit_sem, alertable ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
                }
 
                if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) {
@@ -2685,7 +2775,7 @@ process_wait (gpointer handle, guint32 timeout, gboolean alertable)
 
                if (ret == 0) {
                        /* Success, process has exited */
-                       MONO_SEM_POST (&mp->exit_sem);
+                       mono_os_sem_post (&mp->exit_sem);
                        break;
                }