GNUnet  0.11.x
os_priority.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "disk.h"
30 #include <unistr.h>
31 
32 #define LOG(kind, ...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
33 
34 #define LOG_STRERROR(kind, syscall) \
35  GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
36 
37 #define LOG_STRERROR_FILE(kind, syscall, filename) \
38  GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
39 
40 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
41 
42 
44 {
48  pid_t pid;
49 
50 
56 };
57 
58 
63 
67 static struct GNUNET_SCHEDULER_Task *pch;
68 
72 static struct GNUNET_SCHEDULER_Task *spch;
73 
74 
80 static void
81 shutdown_pch (void *cls)
82 {
84 
86  pch = NULL;
87  GNUNET_DISK_file_close (control_pipe);
88  control_pipe = NULL;
89 }
90 
91 
97 static void
99 {
100  struct GNUNET_DISK_FileHandle *control_pipe = cls;
101  char sig;
102  char *pipe_fd;
103  ssize_t ret;
104 
105  pch = NULL;
106  ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof(sig));
107  if (sizeof(sig) != ret)
108  {
109  if (-1 == ret)
110  LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
111  LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
112  GNUNET_DISK_file_close (control_pipe);
113  control_pipe = NULL;
115  spch = NULL;
116  return;
117  }
118  pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
119  GNUNET_assert ((NULL == pipe_fd) || (strlen (pipe_fd) <= 0));
121  "Got control code %d from parent via pipe %s\n",
122  sig,
123  pipe_fd);
125  control_pipe,
127  control_pipe);
128  GNUNET_SIGNAL_raise ((int) sig);
129 }
130 
131 
140 void
142 {
143  const char *env_buf;
144  char *env_buf_end;
146  uint64_t pipe_fd;
147 
148  (void) cls;
149  if (NULL != pch)
150  {
151  /* already done, we've been called twice... */
152  GNUNET_break (0);
153  return;
154  }
155  env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
156  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
157  {
159  "Not installing a handler because $%s is empty\n",
161  putenv (GNUNET_OS_CONTROL_PIPE "=");
162  return;
163  }
164  errno = 0;
165  pipe_fd = strtoull (env_buf, &env_buf_end, 16);
166  if ((0 != errno) || (env_buf == env_buf_end))
167  {
168  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
169  putenv (GNUNET_OS_CONTROL_PIPE "=");
170  return;
171  }
172  if (pipe_fd >= FD_SETSIZE)
173  {
175  "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
176  env_buf);
177  putenv (GNUNET_OS_CONTROL_PIPE "=");
178  return;
179  }
180 
181  control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
182 
183  if (NULL == control_pipe)
184  {
185  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
186  putenv (GNUNET_OS_CONTROL_PIPE "=");
187  return;
188  }
190  "Adding parent control handler pipe `%s' to the scheduler\n",
191  env_buf);
193  control_pipe,
195  control_pipe);
196  spch = GNUNET_SCHEDULER_add_shutdown (&shutdown_pch, control_pipe);
197  putenv (GNUNET_OS_CONTROL_PIPE "=");
198 }
199 
200 
209 struct GNUNET_OS_Process *
211 {
212  current_process.pid = 0;
213  return &current_process;
214 }
215 
216 
224 int
226 {
227  int ret;
228  char csig;
229 
230  csig = (char) sig;
231  if (NULL != proc->control_pipe)
232  {
234  "Sending signal %d to pid: %u via pipe\n",
235  sig,
236  proc->pid);
237  ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof(csig));
238  if (sizeof(csig) == ret)
239  return 0;
240  }
241  /* pipe failed or non-existent, try other methods */
242  switch (sig)
243  {
244  case SIGHUP:
245  case SIGINT:
246  case SIGKILL:
247  case SIGTERM:
248 #if (SIGTERM != GNUNET_TERM_SIG)
249  case GNUNET_TERM_SIG:
250 #endif
252  "Sending signal %d to pid: %u via system call\n",
253  sig,
254  proc->pid);
255  return kill (proc->pid, sig);
256  default:
258  "Sending signal %d to pid: %u via system call\n",
259  sig,
260  proc->pid);
261  return kill (proc->pid, sig);
262  }
263 }
264 
265 
273 pid_t
275 {
276  return proc->pid;
277 }
278 
279 
286 void
288 {
289  if (NULL != proc->control_pipe)
291 
292  GNUNET_free (proc);
293 }
294 
295 
303 static void
304 open_dev_null (int target_fd, int flags)
305 {
306  int fd;
307 
308  fd = open ("/dev/null", flags);
309  if (-1 == fd)
310  {
311  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
312  return;
313  }
314  if (fd == target_fd)
315  return;
316  if (-1 == dup2 (fd, target_fd))
317  {
319  (void) close (fd);
320  return;
321  }
322  GNUNET_break (0 == close (fd));
323 }
324 
325 
342 static struct GNUNET_OS_Process *
344  struct GNUNET_DISK_PipeHandle *pipe_stdin,
345  struct GNUNET_DISK_PipeHandle *pipe_stdout,
346  struct GNUNET_DISK_PipeHandle *pipe_stderr,
347  const int *lsocks,
348  const char *filename,
349  char *const argv[])
350 {
351  pid_t ret;
352  char fds[16];
353  struct GNUNET_OS_Process *gnunet_proc;
354  struct GNUNET_DISK_FileHandle *childpipe_read;
355  struct GNUNET_DISK_FileHandle *childpipe_write;
356  int childpipe_read_fd;
357  int i;
358  int j;
359  int k;
360  int tgt;
361  int flags;
362  int *lscp;
363  unsigned int ls;
364  int fd_stdout_write;
365  int fd_stdout_read;
366  int fd_stderr_write;
367  int fd_stderr_read;
368  int fd_stdin_read;
369  int fd_stdin_write;
370 
371  if (GNUNET_SYSERR ==
372  GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
373  return NULL; /* not executable */
374  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
375  {
376  struct GNUNET_DISK_PipeHandle *childpipe;
377  int dup_childpipe_read_fd = -1;
378 
380  if (NULL == childpipe)
381  return NULL;
382  childpipe_read =
384  childpipe_write =
386  GNUNET_DISK_pipe_close (childpipe);
387  if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
388  (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
389  &childpipe_read_fd,
390  sizeof(int))) ||
391  (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
392  {
393  if (NULL != childpipe_read)
394  GNUNET_DISK_file_close (childpipe_read);
395  if (NULL != childpipe_write)
396  GNUNET_DISK_file_close (childpipe_write);
397  if (0 <= dup_childpipe_read_fd)
398  close (dup_childpipe_read_fd);
399  return NULL;
400  }
401  childpipe_read_fd = dup_childpipe_read_fd;
402  GNUNET_DISK_file_close (childpipe_read);
403  }
404  else
405  {
406  childpipe_write = NULL;
407  childpipe_read_fd = -1;
408  }
409  if (NULL != pipe_stdin)
410  {
411  GNUNET_assert (
412  GNUNET_OK ==
415  &fd_stdin_read,
416  sizeof(int)));
417  GNUNET_assert (
418  GNUNET_OK ==
421  &fd_stdin_write,
422  sizeof(int)));
423  }
424  if (NULL != pipe_stdout)
425  {
426  GNUNET_assert (
427  GNUNET_OK ==
430  &fd_stdout_write,
431  sizeof(int)));
432  GNUNET_assert (
433  GNUNET_OK ==
436  &fd_stdout_read,
437  sizeof(int)));
438  }
439  if (NULL != pipe_stderr)
440  {
441  GNUNET_assert (
442  GNUNET_OK ==
445  &fd_stderr_read,
446  sizeof(int)));
447  GNUNET_assert (
448  GNUNET_OK ==
451  &fd_stderr_write,
452  sizeof(int)));
453  }
454  lscp = NULL;
455  ls = 0;
456  if (NULL != lsocks)
457  {
458  i = 0;
459  while (-1 != (k = lsocks[i++]))
460  GNUNET_array_append (lscp, ls, k);
461  GNUNET_array_append (lscp, ls, -1);
462  }
463 #if DARWIN
464  /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
465  ret = vfork ();
466 #else
467  ret = fork ();
468 #endif
469  if (-1 == ret)
470  {
471  int eno = errno;
473  GNUNET_array_grow (lscp, ls, 0);
474  if (NULL != childpipe_write)
475  GNUNET_DISK_file_close (childpipe_write);
476  if (0 <= childpipe_read_fd)
477  close (childpipe_read_fd);
478  errno = eno;
479  return NULL;
480  }
481  if (0 != ret)
482  {
483  unsetenv (GNUNET_OS_CONTROL_PIPE);
484  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
485  gnunet_proc->pid = ret;
486  gnunet_proc->control_pipe = childpipe_write;
487  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
488  {
489  close (childpipe_read_fd);
490  }
491  GNUNET_array_grow (lscp, ls, 0);
492  return gnunet_proc;
493  }
494  if (0 <= childpipe_read_fd)
495  {
496  char fdbuf[100];
497 #ifndef DARWIN
498  /* due to vfork, we must NOT free memory on DARWIN! */
499  GNUNET_DISK_file_close (childpipe_write);
500 #endif
501  snprintf (fdbuf, 100, "%x", childpipe_read_fd);
502  setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
503  }
504  else
505  unsetenv (GNUNET_OS_CONTROL_PIPE);
506  if (NULL != pipe_stdin)
507  {
508  GNUNET_break (0 == close (fd_stdin_write));
509  if (-1 == dup2 (fd_stdin_read, 0))
511  GNUNET_break (0 == close (fd_stdin_read));
512  }
513  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
514  {
515  GNUNET_break (0 == close (0));
516  open_dev_null (0, O_RDONLY);
517  }
518  if (NULL != pipe_stdout)
519  {
520  GNUNET_break (0 == close (fd_stdout_read));
521  if (-1 == dup2 (fd_stdout_write, 1))
523  GNUNET_break (0 == close (fd_stdout_write));
524  }
525  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
526  {
527  GNUNET_break (0 == close (1));
528  open_dev_null (1, O_WRONLY);
529  }
530  if (NULL != pipe_stderr)
531  {
532  GNUNET_break (0 == close (fd_stderr_read));
533  if (-1 == dup2 (fd_stderr_write, 2))
535  GNUNET_break (0 == close (fd_stderr_write));
536  }
537  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
538  {
539  GNUNET_break (0 == close (2));
540  open_dev_null (2, O_WRONLY);
541  }
542  if (NULL != lscp)
543  {
544  /* read systemd documentation... */
545  i = 0;
546  tgt = 3;
547  while (-1 != lscp[i])
548  {
549  j = i + 1;
550  while (-1 != lscp[j])
551  {
552  if (lscp[j] == tgt)
553  {
554  /* dup away */
555  k = dup (lscp[j]);
556  GNUNET_assert (-1 != k);
557  GNUNET_assert (0 == close (lscp[j]));
558  lscp[j] = k;
559  break;
560  }
561  j++;
562  }
563  if (lscp[i] != tgt)
564  {
565  /* Bury any existing FD, no matter what; they should all be closed
566  * on exec anyway and the important onces have been dup'ed away */
567  (void) close (tgt);
568  GNUNET_assert (-1 != dup2 (lscp[i], tgt));
569  }
570  /* unset close-on-exec flag */
571  flags = fcntl (tgt, F_GETFD);
572  GNUNET_assert (flags >= 0);
573  flags &= ~FD_CLOEXEC;
574  fflush (stderr);
575  (void) fcntl (tgt, F_SETFD, flags);
576  tgt++;
577  i++;
578  }
579  GNUNET_snprintf (fds, sizeof(fds), "%u", i);
580  setenv ("LISTEN_FDS", fds, 1);
581  }
582 #ifndef DARWIN
583  /* due to vfork, we must NOT free memory on DARWIN! */
584  GNUNET_array_grow (lscp, ls, 0);
585 #endif
586  execvp (filename, argv);
587  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
588  _exit (1);
589 }
590 
591 
603 struct GNUNET_OS_Process *
605  struct GNUNET_DISK_PipeHandle *pipe_stdin,
606  struct GNUNET_DISK_PipeHandle *pipe_stdout,
607  struct GNUNET_DISK_PipeHandle *pipe_stderr,
608  const char *filename,
609  char *const argv[])
610 {
611  return start_process (std_inheritance,
612  pipe_stdin,
613  pipe_stdout,
614  pipe_stderr,
615  NULL,
616  filename,
617  argv);
618 }
619 
620 
632 struct GNUNET_OS_Process *
634  struct GNUNET_DISK_PipeHandle *pipe_stdin,
635  struct GNUNET_DISK_PipeHandle *pipe_stdout,
636  struct GNUNET_DISK_PipeHandle *pipe_stderr,
637  const char *filename,
638  va_list va)
639 {
640  struct GNUNET_OS_Process *ret;
641  va_list ap;
642  char **argv;
643  int argc;
644 
645  argc = 0;
646  va_copy (ap, va);
647  while (NULL != va_arg (ap, char *))
648  argc++;
649  va_end (ap);
650  argv = GNUNET_malloc (sizeof(char *) * (argc + 1));
651  argc = 0;
652  va_copy (ap, va);
653  while (NULL != (argv[argc] = va_arg (ap, char *)))
654  argc++;
655  va_end (ap);
656  ret = GNUNET_OS_start_process_vap (std_inheritance,
657  pipe_stdin,
658  pipe_stdout,
659  pipe_stderr,
660  filename,
661  argv);
662  GNUNET_free (argv);
663  return ret;
664 }
665 
666 
677 struct GNUNET_OS_Process *
679  struct GNUNET_DISK_PipeHandle *pipe_stdin,
680  struct GNUNET_DISK_PipeHandle *pipe_stdout,
681  struct GNUNET_DISK_PipeHandle *pipe_stderr,
682  const char *filename,
683  ...)
684 {
685  struct GNUNET_OS_Process *ret;
686  va_list ap;
687 
688  va_start (ap, filename);
689  ret = GNUNET_OS_start_process_va (std_inheritance,
690  pipe_stdin,
691  pipe_stdout,
692  pipe_stderr,
693  filename,
694  ap);
695  va_end (ap);
696  return ret;
697 }
698 
699 
713 struct GNUNET_OS_Process *
715  const int *lsocks,
716  const char *filename,
717  char *const argv[])
718 {
719  return start_process (std_inheritance,
720  NULL,
721  NULL,
722  NULL,
723  lsocks,
724  filename,
725  argv);
726 }
727 
728 
746 struct GNUNET_OS_Process *
748  const int *lsocks,
749  const char *filename,
750  ...)
751 {
752  va_list ap;
753  char **argv;
754  unsigned int argv_size;
755  const char *arg;
756  const char *rpos;
757  char *pos;
758  char *cp;
759  const char *last;
760  struct GNUNET_OS_Process *proc;
761  char *binary_path;
762  int quote_on;
763  unsigned int i;
764  size_t len;
765 
766  argv_size = 1;
767  va_start (ap, filename);
768  arg = filename;
769  last = NULL;
770  do
771  {
772  rpos = arg;
773  quote_on = 0;
774  while ('\0' != *rpos)
775  {
776  if ('"' == *rpos)
777  {
778  if (1 == quote_on)
779  quote_on = 0;
780  else
781  quote_on = 1;
782  }
783  if ((' ' == *rpos) && (0 == quote_on))
784  {
785  if (NULL != last)
786  argv_size++;
787  last = NULL;
788  rpos++;
789  while (' ' == *rpos)
790  rpos++;
791  }
792  if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
793  last = rpos;
794  if ('\0' != *rpos)
795  rpos++;
796  }
797  if (NULL != last)
798  argv_size++;
799  }
800  while (NULL != (arg = (va_arg (ap, const char *))));
801  va_end (ap);
802 
803  argv = GNUNET_malloc (argv_size * sizeof(char *));
804  argv_size = 0;
805  va_start (ap, filename);
806  arg = filename;
807  last = NULL;
808  do
809  {
810  cp = GNUNET_strdup (arg);
811  quote_on = 0;
812  pos = cp;
813  while ('\0' != *pos)
814  {
815  if ('"' == *pos)
816  {
817  if (1 == quote_on)
818  quote_on = 0;
819  else
820  quote_on = 1;
821  }
822  if ((' ' == *pos) && (0 == quote_on))
823  {
824  *pos = '\0';
825  if (NULL != last)
826  argv[argv_size++] = GNUNET_strdup (last);
827  last = NULL;
828  pos++;
829  while (' ' == *pos)
830  pos++;
831  }
832  if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
833  last = pos;
834  if ('\0' != *pos)
835  pos++;
836  }
837  if (NULL != last)
838  argv[argv_size++] = GNUNET_strdup (last);
839  last = NULL;
840  GNUNET_free (cp);
841  }
842  while (NULL != (arg = (va_arg (ap, const char *))));
843  va_end (ap);
844  argv[argv_size] = NULL;
845 
846  for (i = 0; i < argv_size; i++)
847  {
848  len = strlen (argv[i]);
849  if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
850  {
851  memmove (&argv[i][0], &argv[i][1], len - 2);
852  argv[i][len - 2] = '\0';
853  }
854  }
855  binary_path = argv[0];
856  proc = GNUNET_OS_start_process_v (std_inheritance,
857  lsocks,
858  binary_path,
859  argv);
860  while (argv_size > 0)
861  GNUNET_free_nz (argv[--argv_size]);
862  GNUNET_free (argv);
863  return proc;
864 }
865 
866 
877 static int
880  unsigned long *code,
881  int options)
882 {
883  int status;
884  int ret;
885 
886  GNUNET_assert (0 != proc);
887  ret = waitpid (proc->pid, &status, options);
888  if (ret < 0)
889  {
891  return GNUNET_SYSERR;
892  }
893  if (0 == ret)
894  {
896  *code = 0;
897  return GNUNET_NO;
898  }
899  if (proc->pid != ret)
900  {
902  return GNUNET_SYSERR;
903  }
904  if (WIFEXITED (status))
905  {
906  *type = GNUNET_OS_PROCESS_EXITED;
907  *code = WEXITSTATUS (status);
908  }
909  else if (WIFSIGNALED (status))
910  {
912  *code = WTERMSIG (status);
913  }
914  else if (WIFSTOPPED (status))
915  {
917  *code = WSTOPSIG (status);
918  }
919 #ifdef WIFCONTINUED
920  else if (WIFCONTINUED (status))
921  {
923  *code = 0;
924  }
925 #endif
926  else
927  {
929  *code = 0;
930  }
931 
932  return GNUNET_OK;
933 }
934 
935 
945 int
948  unsigned long *code)
949 {
950  return process_status (proc, type, code, WNOHANG);
951 }
952 
953 
963 int
966  unsigned long *code)
967 {
968  return process_status (proc, type, code, 0);
969 }
970 
971 
982 int
984 {
985  pid_t pid = proc->pid;
986  pid_t ret;
987 
988  while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
989  ;
990  if (pid != ret)
991  {
993  return GNUNET_SYSERR;
994  }
995  return GNUNET_OK;
996 }
997 
998 
1003 {
1008 
1013 
1017  const struct GNUNET_DISK_FileHandle *r;
1018 
1023 
1027  void *proc_cls;
1028 
1032  char buf[1024];
1033 
1038 
1043 
1047  size_t off;
1048 };
1049 
1050 
1058 void
1060 {
1061  if (NULL != cmd->proc)
1062  {
1063  GNUNET_assert (NULL != cmd->rtask);
1065  }
1066  (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1070  GNUNET_free (cmd);
1071 }
1072 
1073 
1079 static void
1080 cmd_read (void *cls)
1081 {
1082  struct GNUNET_OS_CommandHandle *cmd = cls;
1083  const struct GNUNET_SCHEDULER_TaskContext *tc;
1085  char *end;
1086  ssize_t ret;
1087 
1088  cmd->rtask = NULL;
1091  {
1092  /* timeout */
1093  proc = cmd->proc;
1094  cmd->proc = NULL;
1095  proc (cmd->proc_cls, NULL);
1096  return;
1097  }
1098  ret = GNUNET_DISK_file_read (cmd->r,
1099  &cmd->buf[cmd->off],
1100  sizeof(cmd->buf) - cmd->off);
1101  if (ret <= 0)
1102  {
1103  if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1104  {
1105  cmd->buf[cmd->off] = '\0';
1106  cmd->proc (cmd->proc_cls, cmd->buf);
1107  }
1108  proc = cmd->proc;
1109  cmd->proc = NULL;
1110  proc (cmd->proc_cls, NULL);
1111  return;
1112  }
1113  end = memchr (&cmd->buf[cmd->off], '\n', ret);
1114  cmd->off += ret;
1115  while (NULL != end)
1116  {
1117  *end = '\0';
1118  cmd->proc (cmd->proc_cls, cmd->buf);
1119  memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1120  cmd->off -= (end + 1 - cmd->buf);
1121  end = memchr (cmd->buf, '\n', cmd->off);
1122  }
1123  cmd->rtask =
1125  cmd->timeout),
1126  cmd->r,
1127  &cmd_read,
1128  cmd);
1129 }
1130 
1131 
1143 struct GNUNET_OS_CommandHandle *
1145  void *proc_cls,
1147  const char *binary,
1148  ...)
1149 {
1150  struct GNUNET_OS_CommandHandle *cmd;
1151  struct GNUNET_OS_Process *eip;
1152  struct GNUNET_DISK_PipeHandle *opipe;
1153  va_list ap;
1154 
1156  if (NULL == opipe)
1157  return NULL;
1158  va_start (ap, binary);
1159  /* redirect stdout, don't inherit stderr/stdin */
1160  eip =
1162  NULL,
1163  opipe,
1164  NULL,
1165  binary,
1166  ap);
1167  va_end (ap);
1168  if (NULL == eip)
1169  {
1170  GNUNET_DISK_pipe_close (opipe);
1171  return NULL;
1172  }
1174  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1175  cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1176  cmd->eip = eip;
1177  cmd->opipe = opipe;
1178  cmd->proc = proc;
1179  cmd->proc_cls = proc_cls;
1181  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1182  return cmd;
1183 }
1184 
1185 
1186 /* end of os_priority.c */
void GNUNET_SIGNAL_raise(const int sig)
Raise the given signal by calling the installed signal handlers.
Definition: signal.c:97
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:752
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process...
Definition: gnunet_os_lib.h:68
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:747
No special options, use non-blocking read/write operations.
When this flag is set, the child process will inherit stderr of the parent.
Definition: gnunet_os_lib.h:91
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:274
struct GNUNET_OS_Process * GNUNET_OS_start_process_vap(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, char *const argv[])
Start a process.
Definition: os_priority.c:604
struct GNUNET_OS_Process * GNUNET_OS_start_process(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,...)
Start a process.
Definition: os_priority.c:678
int GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1280
#define GNUNET_OS_CONTROL_PIPE
Definition: os_priority.c:40
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
char buf[1024]
Buffer for the output.
Definition: os_priority.c:1032
#define LOG_STRERROR(kind, syscall)
Definition: os_priority.c:34
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:287
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:732
int GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
Definition: os_priority.c:946
Context information passed to each scheduler task.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1331
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
Definition: os_priority.c:1017
pid_t pid
PID of the process.
Definition: os_priority.c:48
size_t off
Current read offset in buf.
Definition: os_priority.c:1047
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:246
struct GNUNET_DISK_PipeHandle * opipe
Handle to the output pipe.
Definition: os_priority.c:1012
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
When this flag is set, the child process will inherit stdin of the parent.
Definition: gnunet_os_lib.h:79
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:423
struct GNUNET_OS_Process * GNUNET_OS_start_process_v(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:714
static int process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code, int options)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:878
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static void open_dev_null(int target_fd, int flags)
Open &#39;/dev/null&#39; and make the result the given file descriptor.
Definition: os_priority.c:304
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1667
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
struct GNUNET_TIME_Absolute timeout
When to time out.
Definition: os_priority.c:1042
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
void * proc_cls
Closure for proc.
Definition: os_priority.c:1027
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:1672
struct GNUNET_OS_Process * eip
Process handle.
Definition: os_priority.c:1007
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition: os_priority.c:72
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static void cmd_read(void *cls)
Read from the process and call the line processor.
Definition: os_priority.c:1080
static struct GNUNET_OS_Process * start_process(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 int *lsocks, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:343
struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_detach_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Detaches one of the ends from the pipe.
Definition: disk.c:1601
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
No standard streams should be inherited.
Definition: gnunet_os_lib.h:73
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:820
When this flag is set, the child process will inherit stdout of the parent.
Definition: gnunet_os_lib.h:85
GNUNET_OS_ProcessStatusType
Process status types.
struct GNUNET_OS_Process * GNUNET_OS_process_current()
Get process structure for current process.
Definition: os_priority.c:210
int GNUNET_OS_process_wait_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process, waiting on it if dead.
Definition: os_priority.c:964
uint16_t status
See PRISM_STATUS_*-constants.
static char buf[2048]
static char * filename
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
The reading-end of a pipe.
The process exited with a return code.
void GNUNET_OS_install_parent_control_handler(void *cls)
Task that connects this process to its parent via pipe; essentially, the parent control handler will ...
Definition: os_priority.c:141
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1456
#define GNUNET_free_nz(ptr)
Wrapper around free.
int GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len)
Retrieve OS file handle.
Definition: disk.c:1697
struct GNUNET_OS_Process * GNUNET_OS_start_process_va(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)
Start a process.
Definition: os_priority.c:633
char * getenv()
struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run(GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary,...)
Run the given command line and call the given function for each line of the output.
Definition: os_priority.c:1144
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: os_priority.c:37
The process was killed by a signal.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
struct GNUNET_SCHEDULER_Task * rtask
Task reading from pipe.
Definition: os_priority.c:1037
int GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h)
Check if a file handle is part of an fd set.
Definition: network.c:1208
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition: os_priority.c:67
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1634
int GNUNET_DISK_pipe_close_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Closes one half of an interprocess channel.
Definition: disk.c:1562
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:983
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1310
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition: os_priority.c:55
Handle to a command.
Definition: os_priority.c:1002
Configure both pipe ends for blocking operations if set.
Entry in list of pending tasks.
Definition: scheduler.c:134
The process is still running.
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
Definition: os_priority.c:1022
The process is not known to the OS (or at least not one of our children).
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:331
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
Definition: os_priority.c:1059
Time for absolute times used by GNUnet, in microseconds.
static struct GNUNET_OS_Process current_process
Handle for &#39;this&#39; process.
Definition: os_priority.c:62
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:246
void(* GNUNET_OS_LineProcessor)(void *cls, const char *line)
Type of a function to process a line of output.
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition: os_priority.c:81
Should a pipe be used to send signals to the child?
static void parent_control_handler(void *cls)
This handler is called when there are control data to be read on the pipe.
Definition: os_priority.c:98
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:68
#define LOG(kind,...)
Definition: os_priority.c:32
#define GNUNET_malloc(size)
Wrapper around malloc.
Internal DISK related helper functions.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:225
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972