-fix time assertion introduce in last patch
[oweals/gnunet.git] / src / util / os_priority.c
index f019bd605aa29448d9348c3102c349ea80000a3c..d3310abb175463c9e58fb3deca0651de37fa90f5 100644 (file)
  */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_os_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_strings_lib.h"
-#include "gnunet_crypto_lib.h"
+#include "gnunet_util_lib.h"
 #include "disk.h"
 #include <unistr.h>
 
@@ -84,7 +80,7 @@ parent_control_handler (void *cls,
   char sig;
   char *pipe_fd;
   ssize_t ret;
-  
+
   LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
        tc->reason);
   if (0 != (tc->reason &
@@ -111,7 +107,7 @@ parent_control_handler (void *cls,
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                  control_pipe, &parent_control_handler,
                                  control_pipe);
-  raise ((int) sig);
+  GNUNET_SIGNAL_raise ((int) sig);
 }
 
 
@@ -233,6 +229,9 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   case SIGINT:
   case SIGKILL:
   case SIGTERM:
+#if (SIGTERM != GNUNET_TERM_SIG)
+  case GNUNET_TERM_SIG:
+#endif
 #if defined(WINDOWS) && !defined(__CYGWIN__)
     {
       DWORD exitcode;
@@ -279,7 +278,7 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 #else
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
     return PLIBC_KILL (proc->pid, sig);
-#endif    
+#endif
   }
 }
 
@@ -504,6 +503,7 @@ start_process (int pipe_control,
                enum GNUNET_OS_InheritStdioFlags std_inheritance,
               struct GNUNET_DISK_PipeHandle *pipe_stdin,
               struct GNUNET_DISK_PipeHandle *pipe_stdout,
+              struct GNUNET_DISK_PipeHandle *pipe_stderr,
               const SOCKTYPE *lsocks,
               const char *filename,
               char *const argv[])
@@ -524,6 +524,8 @@ start_process (int pipe_control,
   unsigned int ls;
   int fd_stdout_write;
   int fd_stdout_read;
+  int fd_stderr_write;
+  int fd_stderr_read;
   int fd_stdin_read;
   int fd_stdin_write;
 
@@ -561,6 +563,17 @@ start_process (int pipe_control,
     childpipe_write = NULL;
     childpipe_read_fd = -1;
   }
+  if (NULL != pipe_stdin)
+  {
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
+                                                     &fd_stdin_read, sizeof (int)));
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
+                                                     &fd_stdin_write, sizeof (int)));
+  }
   if (NULL != pipe_stdout)
   {
     GNUNET_assert (GNUNET_OK ==
@@ -573,16 +586,18 @@ start_process (int pipe_control,
                                                      (pipe_stdout, GNUNET_DISK_PIPE_END_READ),
                                                      &fd_stdout_read, sizeof (int)));
   }
-  if (NULL != pipe_stdin)
+  if (NULL != pipe_stderr)
   {
     GNUNET_assert (GNUNET_OK ==
-                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_READ),
-                                                     &fd_stdin_read, sizeof (int)));
+                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                      (pipe_stderr,
+                                                       GNUNET_DISK_PIPE_END_READ),
+                                                      &fd_stderr_read, sizeof (int)));
     GNUNET_assert (GNUNET_OK ==
-                  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
-                                                     (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE),
-                                                     &fd_stdin_write, sizeof (int)));
+                   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                                      (pipe_stderr,
+                                                       GNUNET_DISK_PIPE_END_WRITE),
+                                                      &fd_stderr_write, sizeof (int)));
   }
   lscp = NULL;
   ls = 0;
@@ -660,7 +675,14 @@ start_process (int pipe_control,
     GNUNET_break (0 == close (1));
     open_dev_null (1, O_WRONLY);
   }
-  if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
+  if (NULL != pipe_stderr)
+  {
+    GNUNET_break (0 == close (fd_stderr_read));
+    if (-1 == dup2 (fd_stderr_write, 2))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    GNUNET_break (0 == close (fd_stderr_write));
+  }
+  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
   {
     GNUNET_break (0 == close (2));
     open_dev_null (2, O_WRONLY);
@@ -754,10 +776,11 @@ start_process (int pipe_control,
   DWORD stdif, stdof, stdef;
   BOOL bresult;
   DWORD error_code;
+  DWORD create_no_window;
 
   if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
     return NULL; /* not executable */
+
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
    */
@@ -906,7 +929,7 @@ start_process (int pipe_control,
     else
       SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, 0);
   }
-    
+
 
   stdoh = GetStdHandle (STD_OUTPUT_HANDLE);
   GetHandleInformation (stdoh, &stdof);
@@ -1052,13 +1075,22 @@ start_process (int pipe_control,
     return NULL;
   }
 
+  create_no_window = 0;
+  {
+    HANDLE console_input = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+    if (INVALID_HANDLE_VALUE == console_input)
+      create_no_window = CREATE_NO_WINDOW;
+    else
+      CloseHandle (console_input);
+  }
+
   bresult = CreateProcessW (wpath, wcmd, NULL, NULL, GNUNET_YES,
-       CREATE_NO_WINDOW | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
+       create_no_window | CREATE_SUSPENDED, env_block, NULL, &start, &proc);
   error_code = GetLastError ();
 
   if ((NULL == pipe_stdin) && (stdih))
     SetHandleInformation (stdih, HANDLE_FLAG_INHERIT, stdif);
-    
+
 
   if ((NULL == pipe_stdout) && (stdoh))
     SetHandleInformation (stdoh, HANDLE_FLAG_INHERIT, stdof);
@@ -1090,7 +1122,7 @@ start_process (int pipe_control,
     return NULL;
   }
 
-  gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
+  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = childpipe_write;
@@ -1120,7 +1152,7 @@ start_process (int pipe_control,
     wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
     if (sizeof (count) != wrote)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  "Failed to write %u count bytes to the child: %u\n",
                  sizeof (count), GetLastError ());
       break;
@@ -1131,8 +1163,8 @@ start_process (int pipe_control,
       /* Get a socket duplication info */
       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                   "Failed to duplicate an socket[%llu]: %u\n", i, 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to duplicate an socket[%llu]: %u\n", i,
                    GetLastError ());
         break;
       }
@@ -1148,8 +1180,8 @@ start_process (int pipe_control,
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
       if (sizeof (size) != wrote)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                   "Failed to write %u size[%llu] bytes to the child: %u\n", 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u size[%llu] bytes to the child: %u\n",
                    sizeof (size), i, GetLastError ());
         break;
       }
@@ -1157,8 +1189,8 @@ start_process (int pipe_control,
       wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
       if (sizeof (pi) != wrote)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                   "Failed to write %u socket[%llu] bytes to the child: %u\n", 
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                   "Failed to write %u socket[%llu] bytes to the child: %u\n",
                    sizeof (pi), i, GetLastError ());
         break;
       }
@@ -1193,8 +1225,6 @@ start_process (int pipe_control,
 }
 
 
-
-
 /**
  * Start a process.
  *
@@ -1202,6 +1232,7 @@ start_process (int pipe_control,
  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
  * @param pipe_stdin pipe to use to send input to child process (or NULL)
  * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param pipe_stderr pipe to use to get output from child process (or NULL)
  * @param filename name of the binary
  * @param argv NULL-terminated array of arguments to the process
  * @return pointer to process structure of the new process, NULL on error
@@ -1211,13 +1242,15 @@ GNUNET_OS_start_process_vap (int pipe_control,
                              enum GNUNET_OS_InheritStdioFlags std_inheritance,
                             struct GNUNET_DISK_PipeHandle *pipe_stdin,
                             struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                            const char *filename, 
+                             struct GNUNET_DISK_PipeHandle *pipe_stderr,
+                            const char *filename,
                             char *const argv[])
 {
   return start_process (pipe_control,
                         std_inheritance,
                        pipe_stdin,
                        pipe_stdout,
+                        pipe_stderr,
                        NULL,
                        filename,
                        argv);
@@ -1231,6 +1264,7 @@ GNUNET_OS_start_process_vap (int pipe_control,
  * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
  * @param pipe_stdin pipe to use to send input to child process (or NULL)
  * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param pipe_stderr pipe to use to get output from child process (or NULL)
  * @param filename name of the binary
  * @param va NULL-terminated list of arguments to the process
  * @return pointer to process structure of the new process, NULL on error
@@ -1240,6 +1274,7 @@ GNUNET_OS_start_process_va (int pipe_control,
                             enum GNUNET_OS_InheritStdioFlags std_inheritance,
                            struct GNUNET_DISK_PipeHandle *pipe_stdin,
                             struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                            struct GNUNET_DISK_PipeHandle *pipe_stderr,
                             const char *filename, va_list va)
 {
   struct GNUNET_OS_Process *ret;
@@ -1262,6 +1297,7 @@ GNUNET_OS_start_process_va (int pipe_control,
                                      std_inheritance,
                                     pipe_stdin,
                                     pipe_stdout,
+                                     pipe_stderr,
                                     filename,
                                     argv);
   GNUNET_free (argv);
@@ -1285,14 +1321,20 @@ GNUNET_OS_start_process (int pipe_control,
                          enum GNUNET_OS_InheritStdioFlags std_inheritance,
                         struct GNUNET_DISK_PipeHandle *pipe_stdin,
                          struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                         struct GNUNET_DISK_PipeHandle *pipe_stderr,
                          const char *filename, ...)
 {
   struct GNUNET_OS_Process *ret;
   va_list ap;
 
   va_start (ap, filename);
-  ret = GNUNET_OS_start_process_va (pipe_control, std_inheritance, pipe_stdin,
-                                   pipe_stdout, filename, ap);
+  ret = GNUNET_OS_start_process_va (pipe_control,
+                                    std_inheritance,
+                                    pipe_stdin,
+                                   pipe_stdout,
+                                    pipe_stderr,
+                                    filename,
+                                    ap);
   va_end (ap);
   return ret;
 }
@@ -1323,16 +1365,154 @@ GNUNET_OS_start_process_v (int pipe_control,
                         std_inheritance,
                        NULL,
                        NULL,
+                        NULL,
                        lsocks,
                        filename,
                        argv);
 }
 
 
+/**
+ * Start a process.  This function is similar to the GNUNET_OS_start_process_*
+ * except that the filename and arguments can have whole strings which contain
+ * the arguments.  These arguments are to be separated by spaces and are parsed
+ * in the order they appear.  Arguments containing spaces can be used by
+ * quoting them with @em ".
+ *
+ * @param pipe_control should a pipe be used to send signals to the child?
+ * @param std_inheritance a set of GNUNET_OS_INHERIT_STD_* flags
+ * @param lsocks array of listen sockets to dup systemd-style (or NULL);
+ *         must be NULL on platforms where dup is not supported
+ * @param filename name of the binary.  It is valid to have the arguments
+ *         in this string when they are separated by spaces.
+ * @param ... more arguments.  Should be of type `char *`.  It is valid
+ *         to have the arguments in these strings when they are separated by
+ *         spaces.  The last argument MUST be NULL.
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_s (int pipe_control,
+                           unsigned int std_inheritance,
+                           const SOCKTYPE * lsocks,
+                           const char *filename, ...)
+{
+  va_list ap;
+  char **argv;
+  unsigned int argv_size;
+  const char *arg;
+  const char *rpos;
+  char *pos;
+  char *cp;
+  const char *last;
+  struct GNUNET_OS_Process *proc;
+  char *binary_path;
+  int quote_on;
+  unsigned int i;
+  size_t len;
+
+  argv_size = 1;
+  va_start (ap, filename);
+  arg = filename;
+  last = NULL;
+  do
+  {
+    rpos = arg;
+    quote_on = 0;
+    while ('\0' != *rpos)
+    {
+      if ('"' == *rpos)
+      {
+       if (1 == quote_on)
+         quote_on = 0;
+       else
+         quote_on = 1;
+      }
+      if ( (' ' == *rpos) && (0 == quote_on) )
+      {
+       if (NULL != last)
+         argv_size++;
+       last = NULL;
+       rpos++;
+       while (' ' == *rpos)
+         rpos++;
+      }
+      if ( (NULL == last) && ('\0' != *rpos) ) // FIXME: == or !=?
+       last = rpos;
+      if ('\0' != *rpos)
+       rpos++;
+    }
+    if (NULL != last)
+      argv_size++;
+  }
+  while (NULL != (arg = (va_arg (ap, const char*))));
+  va_end (ap);
+
+  argv = GNUNET_malloc (argv_size * sizeof (char *));
+  argv_size = 0;
+  va_start (ap, filename);
+  arg = filename;
+  last = NULL;
+  do
+  {
+    cp = GNUNET_strdup (arg);
+    quote_on = 0;
+    pos = cp;
+    while ('\0' != *pos)
+    {
+      if ('"' == *pos)
+      {
+       if (1 == quote_on)
+         quote_on = 0;
+       else
+         quote_on = 1;
+      }
+      if ( (' ' == *pos) && (0 == quote_on) )
+      {
+       *pos = '\0';
+       if (NULL != last)
+         argv[argv_size++] = GNUNET_strdup (last);
+       last = NULL;
+       pos++;
+       while (' ' == *pos)
+         pos++;
+      }
+      if ( (NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
+       last = pos;
+      if ('\0' != *pos)
+       pos++;
+    }
+    if (NULL != last)
+      argv[argv_size++] = GNUNET_strdup (last);
+    last = NULL;
+    GNUNET_free (cp);
+  }
+  while (NULL != (arg = (va_arg (ap, const char*))));
+  va_end (ap);
+  argv[argv_size] = NULL;
+
+  for(i = 0; i < argv_size; i++)
+  {
+    len = strlen (argv[i]);
+    if ( (argv[i][0] == '"') && (argv[i][len-1] == '"'))
+    {
+      memmove (&argv[i][0], &argv[i][1], len - 2);
+      argv[i][len-2] = '\0';
+    }
+  }
+  binary_path = argv[0];
+  proc = GNUNET_OS_start_process_v (pipe_control, std_inheritance, lsocks,
+                                   binary_path, argv);
+  while (argv_size > 0)
+    GNUNET_free (argv[--argv_size]);
+  GNUNET_free (argv);
+  return proc;
+}
+
+
 /**
  * Retrieve the status of a process, waiting on him if dead.
  * Nonblocking version.
- * 
+ *
  * @param proc process ID
  * @param type status type
  * @param code return code/signal number
@@ -1445,7 +1625,7 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 
   while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
          (EINTR == errno) ) ;
-  if (pid != ret) 
+  if (pid != ret)
   {
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
     return GNUNET_SYSERR;
@@ -1630,7 +1810,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
     return NULL;
   va_start (ap, binary);
   /* redirect stdout, don't inherit stderr/stdin */
-  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, binary, ap);
+  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, NULL, binary, ap);
   va_end (ap);
   if (NULL == eip)
   {
@@ -1638,7 +1818,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
     return NULL;
   }
   GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
-  cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle));
+  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
   cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   cmd->eip = eip;
   cmd->opipe = opipe;