GNUnet  0.17.5
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 
55 };
56 
57 
62 
66 static struct GNUNET_SCHEDULER_Task *pch;
67 
71 static struct GNUNET_SCHEDULER_Task *spch;
72 
73 
79 static void
80 shutdown_pch (void *cls)
81 {
82  struct GNUNET_DISK_FileHandle *control_pipe = cls;
83 
85  pch = NULL;
86  GNUNET_DISK_file_close (control_pipe);
87  control_pipe = NULL;
88 }
89 
90 
96 static void
98 {
99  struct GNUNET_DISK_FileHandle *control_pipe = cls;
100  char sig;
101  char *pipe_fd;
102  ssize_t ret;
103 
104  pch = NULL;
105  ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof(sig));
106  if (sizeof(sig) != ret)
107  {
108  if (-1 == ret)
109  LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
110  LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
111  GNUNET_DISK_file_close (control_pipe);
112  control_pipe = NULL;
114  spch = NULL;
115  return;
116  }
117  pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
118  GNUNET_assert ((NULL == pipe_fd) || (strlen (pipe_fd) <= 0));
120  "Got control code %d from parent via pipe %s\n",
121  sig,
122  pipe_fd);
124  control_pipe,
126  control_pipe);
127  GNUNET_SIGNAL_raise ((int) sig);
128 }
129 
130 
139 void
141 {
142  const char *env_buf;
143  char *env_buf_end;
144  struct GNUNET_DISK_FileHandle *control_pipe;
145  uint64_t pipe_fd;
146 
147  (void) cls;
148  if (NULL != pch)
149  {
150  /* already done, we've been called twice... */
151  GNUNET_break (0);
152  return;
153  }
154  env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
155  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
156  {
158  "Not installing a handler because $%s is empty\n",
160  putenv (GNUNET_OS_CONTROL_PIPE "=");
161  return;
162  }
163  errno = 0;
164  pipe_fd = strtoull (env_buf, &env_buf_end, 16);
165  if ((0 != errno) || (env_buf == env_buf_end))
166  {
167  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
168  putenv (GNUNET_OS_CONTROL_PIPE "=");
169  return;
170  }
171  if (pipe_fd >= FD_SETSIZE)
172  {
174  "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
175  env_buf);
176  putenv (GNUNET_OS_CONTROL_PIPE "=");
177  return;
178  }
179 
180  control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
181 
182  if (NULL == control_pipe)
183  {
184  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
185  putenv (GNUNET_OS_CONTROL_PIPE "=");
186  return;
187  }
189  "Adding parent control handler pipe `%s' to the scheduler\n",
190  env_buf);
192  control_pipe,
194  control_pipe);
196  putenv (GNUNET_OS_CONTROL_PIPE "=");
197 }
198 
199 
208 struct GNUNET_OS_Process *
210 {
211  current_process.pid = 0;
212  return &current_process;
213 }
214 
215 
216 int
218  int sig)
219 {
220  int ret;
221  char csig;
222 
223  csig = (char) sig;
224  if (NULL != proc->control_pipe)
225  {
227  "Sending signal %d to pid: %u via pipe\n",
228  sig,
229  proc->pid);
230  ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof(csig));
231  if (sizeof(csig) == ret)
232  return 0;
233  }
234  /* pipe failed or non-existent, try other methods */
235  switch (sig)
236  {
237  case SIGHUP:
238  case SIGINT:
239  case SIGKILL:
240  case SIGTERM:
241 #if (SIGTERM != GNUNET_TERM_SIG)
242  case GNUNET_TERM_SIG:
243 #endif
245  "Sending signal %d to pid: %u via system call\n",
246  sig,
247  proc->pid);
248  return kill (proc->pid, sig);
249  default:
251  "Sending signal %d to pid: %u via system call\n",
252  sig,
253  proc->pid);
254  return kill (proc->pid, sig);
255  }
256 }
257 
258 
266 pid_t
268 {
269  return proc->pid;
270 }
271 
272 
279 void
281 {
282  if (NULL != proc->control_pipe)
284 
285  GNUNET_free (proc);
286 }
287 
288 
296 static void
297 open_dev_null (int target_fd,
298  int flags)
299 {
300  int fd;
301 
302  fd = open ("/dev/null", flags);
303  if (-1 == fd)
304  {
305  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
306  return;
307  }
308  if (fd == target_fd)
309  return;
310  if (-1 == dup2 (fd, target_fd))
311  {
313  GNUNET_break (0 == close (fd));
314  return;
315  }
316  GNUNET_break (0 == close (fd));
317 }
318 
319 
336 static struct GNUNET_OS_Process *
338  struct GNUNET_DISK_PipeHandle *pipe_stdin,
339  struct GNUNET_DISK_PipeHandle *pipe_stdout,
340  struct GNUNET_DISK_PipeHandle *pipe_stderr,
341  const int *lsocks,
342  const char *filename,
343  char *const argv[])
344 {
345  pid_t ret;
346  char fds[16];
347  struct GNUNET_OS_Process *gnunet_proc;
348  struct GNUNET_DISK_FileHandle *childpipe_read;
349  struct GNUNET_DISK_FileHandle *childpipe_write;
350  int childpipe_read_fd;
351  int i;
352  int j;
353  int k;
354  int tgt;
355  int flags;
356  int *lscp;
357  unsigned int ls;
358  int fd_stdout_write;
359  int fd_stdout_read;
360  int fd_stderr_write;
361  int fd_stderr_read;
362  int fd_stdin_read;
363  int fd_stdin_write;
364 
365  if (GNUNET_SYSERR ==
367  return NULL; /* not executable */
368  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
369  {
370  struct GNUNET_DISK_PipeHandle *childpipe;
371  int dup_childpipe_read_fd = -1;
372 
374  if (NULL == childpipe)
375  return NULL;
376  childpipe_read =
378  childpipe_write =
380  GNUNET_DISK_pipe_close (childpipe);
381  if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
382  (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
383  &childpipe_read_fd,
384  sizeof(int))) ||
385  (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
386  {
387  if (NULL != childpipe_read)
388  GNUNET_DISK_file_close (childpipe_read);
389  if (NULL != childpipe_write)
390  GNUNET_DISK_file_close (childpipe_write);
391  if (0 <= dup_childpipe_read_fd)
392  GNUNET_break (0 == close (dup_childpipe_read_fd));
393  return NULL;
394  }
395  childpipe_read_fd = dup_childpipe_read_fd;
396  GNUNET_DISK_file_close (childpipe_read);
397  }
398  else
399  {
400  childpipe_write = NULL;
401  childpipe_read_fd = -1;
402  }
403  if (NULL != pipe_stdin)
404  {
405  GNUNET_assert (
406  GNUNET_OK ==
409  &fd_stdin_read,
410  sizeof(int)));
411  GNUNET_assert (
412  GNUNET_OK ==
415  &fd_stdin_write,
416  sizeof(int)));
417  }
418  if (NULL != pipe_stdout)
419  {
420  GNUNET_assert (
421  GNUNET_OK ==
424  &fd_stdout_write,
425  sizeof(int)));
426  GNUNET_assert (
427  GNUNET_OK ==
430  &fd_stdout_read,
431  sizeof(int)));
432  }
433  if (NULL != pipe_stderr)
434  {
435  GNUNET_assert (
436  GNUNET_OK ==
439  &fd_stderr_read,
440  sizeof(int)));
441  GNUNET_assert (
442  GNUNET_OK ==
445  &fd_stderr_write,
446  sizeof(int)));
447  }
448  lscp = NULL;
449  ls = 0;
450  if (NULL != lsocks)
451  {
452  i = 0;
453  while (-1 != (k = lsocks[i++]))
454  GNUNET_array_append (lscp, ls, k);
455  GNUNET_array_append (lscp, ls, -1);
456  }
457 #if DARWIN
458  /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
459  ret = vfork ();
460 #else
461  ret = fork ();
462 #endif
463  if (-1 == ret)
464  {
465  int eno = errno;
467  GNUNET_array_grow (lscp, ls, 0);
468  if (NULL != childpipe_write)
469  GNUNET_DISK_file_close (childpipe_write);
470  if (0 <= childpipe_read_fd)
471  GNUNET_break (0 == close (childpipe_read_fd));
472  errno = eno;
473  return NULL;
474  }
475  if (0 != ret)
476  {
477  unsetenv (GNUNET_OS_CONTROL_PIPE);
478  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
479  gnunet_proc->pid = ret;
480  gnunet_proc->control_pipe = childpipe_write;
481  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
482  {
483  GNUNET_break (0 == close (childpipe_read_fd));
484  }
485  GNUNET_array_grow (lscp, ls, 0);
486  return gnunet_proc;
487  }
488  if (0 <= childpipe_read_fd)
489  {
490  char fdbuf[100];
491 #ifndef DARWIN
492  /* due to vfork, we must NOT free memory on DARWIN! */
493  GNUNET_DISK_file_close (childpipe_write);
494 #endif
495  snprintf (fdbuf, 100, "%x", childpipe_read_fd);
496  setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
497  }
498  else
499  unsetenv (GNUNET_OS_CONTROL_PIPE);
500  if (NULL != pipe_stdin)
501  {
502  GNUNET_break (0 == close (fd_stdin_write));
503  if (-1 == dup2 (fd_stdin_read, 0))
505  GNUNET_break (0 == close (fd_stdin_read));
506  }
507  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
508  {
509  GNUNET_break (0 == close (0));
510  open_dev_null (0, O_RDONLY);
511  }
512  if (NULL != pipe_stdout)
513  {
514  GNUNET_break (0 == close (fd_stdout_read));
515  if (-1 == dup2 (fd_stdout_write, 1))
517  GNUNET_break (0 == close (fd_stdout_write));
518  }
519  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
520  {
521  GNUNET_break (0 == close (1));
522  open_dev_null (1, O_WRONLY);
523  }
524  if (NULL != pipe_stderr)
525  {
526  GNUNET_break (0 == close (fd_stderr_read));
527  if (-1 == dup2 (fd_stderr_write, 2))
529  GNUNET_break (0 == close (fd_stderr_write));
530  }
531  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
532  {
533  GNUNET_break (0 == close (2));
534  open_dev_null (2, O_WRONLY);
535  }
536  if (NULL != lscp)
537  {
538  /* read systemd documentation... */
539  i = 0;
540  tgt = 3;
541  while (-1 != lscp[i])
542  {
543  j = i + 1;
544  while (-1 != lscp[j])
545  {
546  if (lscp[j] == tgt)
547  {
548  /* dup away */
549  k = dup (lscp[j]);
550  GNUNET_assert (-1 != k);
551  GNUNET_assert (0 == close (lscp[j]));
552  lscp[j] = k;
553  break;
554  }
555  j++;
556  }
557  if (lscp[i] != tgt)
558  {
559  /* Bury any existing FD, no matter what; they should all be closed
560  * on exec anyway and the important ones have been dup'ed away */
561  GNUNET_break (0 == close (tgt));
562  GNUNET_assert (-1 != dup2 (lscp[i], tgt));
563  }
564  /* unset close-on-exec flag */
565  flags = fcntl (tgt, F_GETFD);
566  GNUNET_assert (flags >= 0);
567  flags &= ~FD_CLOEXEC;
568  fflush (stderr);
569  (void) fcntl (tgt, F_SETFD, flags);
570  tgt++;
571  i++;
572  }
573  GNUNET_snprintf (fds, sizeof(fds), "%u", i);
574  setenv ("LISTEN_FDS", fds, 1);
575  }
576 #ifndef DARWIN
577  /* due to vfork, we must NOT free memory on DARWIN! */
578  GNUNET_array_grow (lscp, ls, 0);
579 #endif
580  execvp (filename, argv);
582  _exit (1);
583 }
584 
585 
597 struct GNUNET_OS_Process *
599  struct GNUNET_DISK_PipeHandle *pipe_stdin,
600  struct GNUNET_DISK_PipeHandle *pipe_stdout,
601  struct GNUNET_DISK_PipeHandle *pipe_stderr,
602  const char *filename,
603  char *const argv[])
604 {
605  return start_process (std_inheritance,
606  pipe_stdin,
607  pipe_stdout,
608  pipe_stderr,
609  NULL,
610  filename,
611  argv);
612 }
613 
614 
626 struct GNUNET_OS_Process *
628  struct GNUNET_DISK_PipeHandle *pipe_stdin,
629  struct GNUNET_DISK_PipeHandle *pipe_stdout,
630  struct GNUNET_DISK_PipeHandle *pipe_stderr,
631  const char *filename,
632  va_list va)
633 {
634  struct GNUNET_OS_Process *ret;
635  va_list ap;
636  char **argv;
637  int argc;
638 
639  argc = 0;
640  va_copy (ap, va);
641  while (NULL != va_arg (ap, char *))
642  argc++;
643  va_end (ap);
644  argv = GNUNET_malloc (sizeof(char *) * (argc + 1));
645  argc = 0;
646  va_copy (ap, va);
647  while (NULL != (argv[argc] = va_arg (ap, char *)))
648  argc++;
649  va_end (ap);
650  ret = GNUNET_OS_start_process_vap (std_inheritance,
651  pipe_stdin,
652  pipe_stdout,
653  pipe_stderr,
654  filename,
655  argv);
656  GNUNET_free (argv);
657  return ret;
658 }
659 
660 
671 struct GNUNET_OS_Process *
673  struct GNUNET_DISK_PipeHandle *pipe_stdin,
674  struct GNUNET_DISK_PipeHandle *pipe_stdout,
675  struct GNUNET_DISK_PipeHandle *pipe_stderr,
676  const char *filename,
677  ...)
678 {
679  struct GNUNET_OS_Process *ret;
680  va_list ap;
681 
682  va_start (ap, filename);
683  ret = GNUNET_OS_start_process_va (std_inheritance,
684  pipe_stdin,
685  pipe_stdout,
686  pipe_stderr,
687  filename,
688  ap);
689  va_end (ap);
690  return ret;
691 }
692 
693 
707 struct GNUNET_OS_Process *
709  const int *lsocks,
710  const char *filename,
711  char *const argv[])
712 {
713  return start_process (std_inheritance,
714  NULL,
715  NULL,
716  NULL,
717  lsocks,
718  filename,
719  argv);
720 }
721 
722 
740 struct GNUNET_OS_Process *
742  const int *lsocks,
743  const char *filename,
744  ...)
745 {
746  va_list ap;
747  char **argv;
748  unsigned int argv_size;
749  const char *arg;
750  const char *rpos;
751  char *pos;
752  char *cp;
753  const char *last;
754  struct GNUNET_OS_Process *proc;
755  char *binary_path;
756  int quote_on;
757  unsigned int i;
758  size_t len;
759 
760  argv_size = 1;
761  va_start (ap, filename);
762  arg = filename;
763  last = NULL;
764  do
765  {
766  rpos = arg;
767  quote_on = 0;
768  while ('\0' != *rpos)
769  {
770  if ('"' == *rpos)
771  {
772  if (1 == quote_on)
773  quote_on = 0;
774  else
775  quote_on = 1;
776  }
777  if ((' ' == *rpos) && (0 == quote_on))
778  {
779  if (NULL != last)
780  argv_size++;
781  last = NULL;
782  rpos++;
783  while (' ' == *rpos)
784  rpos++;
785  }
786  if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
787  last = rpos;
788  if ('\0' != *rpos)
789  rpos++;
790  }
791  if (NULL != last)
792  argv_size++;
793  }
794  while (NULL != (arg = (va_arg (ap, const char *))));
795  va_end (ap);
796 
797  argv = GNUNET_malloc (argv_size * sizeof(char *));
798  argv_size = 0;
799  va_start (ap, filename);
800  arg = filename;
801  last = NULL;
802  do
803  {
804  cp = GNUNET_strdup (arg);
805  quote_on = 0;
806  pos = cp;
807  while ('\0' != *pos)
808  {
809  if ('"' == *pos)
810  {
811  if (1 == quote_on)
812  quote_on = 0;
813  else
814  quote_on = 1;
815  }
816  if ((' ' == *pos) && (0 == quote_on))
817  {
818  *pos = '\0';
819  if (NULL != last)
820  argv[argv_size++] = GNUNET_strdup (last);
821  last = NULL;
822  pos++;
823  while (' ' == *pos)
824  pos++;
825  }
826  if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
827  last = pos;
828  if ('\0' != *pos)
829  pos++;
830  }
831  if (NULL != last)
832  argv[argv_size++] = GNUNET_strdup (last);
833  last = NULL;
834  GNUNET_free (cp);
835  }
836  while (NULL != (arg = (va_arg (ap, const char *))));
837  va_end (ap);
838  argv[argv_size] = NULL;
839 
840  for (i = 0; i < argv_size; i++)
841  {
842  len = strlen (argv[i]);
843  if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
844  {
845  memmove (&argv[i][0], &argv[i][1], len - 2);
846  argv[i][len - 2] = '\0';
847  }
848  }
849  binary_path = argv[0];
850  proc = GNUNET_OS_start_process_v (std_inheritance,
851  lsocks,
852  binary_path,
853  argv);
854  while (argv_size > 0)
855  GNUNET_free_nz (argv[--argv_size]);
856  GNUNET_free (argv);
857  return proc;
858 }
859 
860 
871 static enum GNUNET_GenericReturnValue
872 process_status (struct GNUNET_OS_Process *proc,
874  unsigned long *code,
875  int options)
876 {
877  int status;
878  int ret;
879 
880  GNUNET_assert (0 != proc);
881  ret = waitpid (proc->pid,
882  &status,
883  options);
884  if (ret < 0)
885  {
887  "waitpid");
888  return GNUNET_SYSERR;
889  }
890  if (0 == ret)
891  {
893  *code = 0;
894  return GNUNET_NO;
895  }
896  if (proc->pid != ret)
897  {
899  "waitpid");
900  return GNUNET_SYSERR;
901  }
902  if (WIFEXITED (status))
903  {
905  *code = WEXITSTATUS (status);
906  }
907  else if (WIFSIGNALED (status))
908  {
910  *code = WTERMSIG (status);
911  }
912  else if (WIFSTOPPED (status))
913  {
915  *code = WSTOPSIG (status);
916  }
917 #ifdef WIFCONTINUED
918  else if (WIFCONTINUED (status))
919  {
921  *code = 0;
922  }
923 #endif
924  else
925  {
927  *code = 0;
928  }
929 
930  return GNUNET_OK;
931 }
932 
933 
946  unsigned long *code)
947 {
948  return process_status (proc, type, code, WNOHANG);
949 }
950 
951 
964  unsigned long *code)
965 {
966  return process_status (proc, type, code, 0);
967 }
968 
969 
980 int
982 {
983  pid_t pid = proc->pid;
984  pid_t ret;
985 
986  while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
987  ;
988  if (pid != ret)
989  {
991  return GNUNET_SYSERR;
992  }
993  return GNUNET_OK;
994 }
995 
996 
1001 {
1006 
1011 
1015  const struct GNUNET_DISK_FileHandle *r;
1016 
1021 
1025  void *proc_cls;
1026 
1030  char buf[1024];
1031 
1036 
1041 
1045  size_t off;
1046 };
1047 
1048 
1056 void
1058 {
1059  if (NULL != cmd->proc)
1060  {
1061  GNUNET_assert (NULL != cmd->rtask);
1063  }
1064  (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1068  GNUNET_free (cmd);
1069 }
1070 
1071 
1077 static void
1078 cmd_read (void *cls)
1079 {
1080  struct GNUNET_OS_CommandHandle *cmd = cls;
1081  const struct GNUNET_SCHEDULER_TaskContext *tc;
1083  char *end;
1084  ssize_t ret;
1085 
1086  cmd->rtask = NULL;
1089  {
1090  /* timeout */
1091  proc = cmd->proc;
1092  cmd->proc = NULL;
1093  proc (cmd->proc_cls, NULL);
1094  return;
1095  }
1096  ret = GNUNET_DISK_file_read (cmd->r,
1097  &cmd->buf[cmd->off],
1098  sizeof(cmd->buf) - cmd->off);
1099  if (ret <= 0)
1100  {
1101  if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1102  {
1103  cmd->buf[cmd->off] = '\0';
1104  cmd->proc (cmd->proc_cls, cmd->buf);
1105  }
1106  proc = cmd->proc;
1107  cmd->proc = NULL;
1108  proc (cmd->proc_cls, NULL);
1109  return;
1110  }
1111  end = memchr (&cmd->buf[cmd->off], '\n', ret);
1112  cmd->off += ret;
1113  while (NULL != end)
1114  {
1115  *end = '\0';
1116  cmd->proc (cmd->proc_cls, cmd->buf);
1117  memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1118  cmd->off -= (end + 1 - cmd->buf);
1119  end = memchr (cmd->buf, '\n', cmd->off);
1120  }
1121  cmd->rtask =
1123  cmd->timeout),
1124  cmd->r,
1125  &cmd_read,
1126  cmd);
1127 }
1128 
1129 
1141 struct GNUNET_OS_CommandHandle *
1143  void *proc_cls,
1145  const char *binary,
1146  ...)
1147 {
1148  struct GNUNET_OS_CommandHandle *cmd;
1149  struct GNUNET_OS_Process *eip;
1150  struct GNUNET_DISK_PipeHandle *opipe;
1151  va_list ap;
1152 
1154  if (NULL == opipe)
1155  return NULL;
1156  va_start (ap, binary);
1157  /* redirect stdout, don't inherit stderr/stdin */
1158  eip =
1160  NULL,
1161  opipe,
1162  NULL,
1163  binary,
1164  ap);
1165  va_end (ap);
1166  if (NULL == eip)
1167  {
1168  GNUNET_DISK_pipe_close (opipe);
1169  return NULL;
1170  }
1172  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1174  cmd->eip = eip;
1175  cmd->opipe = opipe;
1176  cmd->proc = proc;
1177  cmd->proc_cls = proc_cls;
1179  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1180  return cmd;
1181 }
1182 
1183 
1184 /* end of os_priority.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
enum GNUNET_GenericReturnValue GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len)
Retrieve OS file handle.
Definition: disk.c:1633
Internal DISK related helper functions.
char * getenv()
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
static char * filename
uint16_t status
See PRISM_STATUS_*-constants.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
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:1558
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:686
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1585
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1306
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:622
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:1616
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1328
enum GNUNET_GenericReturnValue 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:1532
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1442
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PF_BLOCKING_RW
Configure both pipe ends for blocking operations if set.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:96
@ GNUNET_OK
Definition: gnunet_common.h:99
@ GNUNET_YES
@ GNUNET_NO
Definition: gnunet_common.h:98
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
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:1151
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:1142
enum GNUNET_GenericReturnValue 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:944
void(* GNUNET_OS_LineProcessor)(void *cls, const char *line)
Type of a function to process a line of output.
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process.
Definition: gnunet_os_lib.h:73
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:627
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:140
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:672
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:741
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:598
enum GNUNET_GenericReturnValue 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:962
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
Definition: os_priority.c:1057
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:267
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:981
GNUNET_OS_ProcessStatusType
Process status types.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:280
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:708
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
struct GNUNET_OS_Process * GNUNET_OS_process_current()
Get process structure for current process.
Definition: os_priority.c:209
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:217
@ GNUNET_OS_INHERIT_STD_IN
When this flag is set, the child process will inherit stdin of the parent.
Definition: gnunet_os_lib.h:83
@ GNUNET_OS_INHERIT_STD_OUT
When this flag is set, the child process will inherit stdout of the parent.
Definition: gnunet_os_lib.h:89
@ GNUNET_OS_INHERIT_STD_ERR
When this flag is set, the child process will inherit stderr of the parent.
Definition: gnunet_os_lib.h:95
@ GNUNET_OS_INHERIT_STD_NONE
No standard streams should be inherited.
Definition: gnunet_os_lib.h:77
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
@ GNUNET_OS_PROCESS_SIGNALED
The process was killed by a signal.
@ GNUNET_OS_PROCESS_EXITED
The process exited with a return code.
@ GNUNET_OS_PROCESS_UNKNOWN
The process is not known to the OS (or at least not one of our children).
@ GNUNET_OS_PROCESS_RUNNING
The process is still running.
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:1652
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,...
Definition: scheduler.c:1316
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:737
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:957
void GNUNET_SIGNAL_raise(const int sig)
Raise the given signal by calling the installed signal handlers.
Definition: signal.c:97
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
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:404
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:315
#define GNUNET_OS_CONTROL_PIPE
Definition: os_priority.c:40
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:97
static struct GNUNET_OS_Process current_process
Handle for 'this' process.
Definition: os_priority.c:61
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition: os_priority.c:66
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: os_priority.c:37
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition: os_priority.c:80
static void open_dev_null(int target_fd, int flags)
Open '/dev/null' and make the result the given file descriptor.
Definition: os_priority.c:297
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition: os_priority.c:71
#define LOG(kind,...)
Definition: os_priority.c:32
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:337
#define LOG_STRERROR(kind, syscall)
Definition: os_priority.c:34
static void cmd_read(void *cls)
Read from the process and call the line processor.
Definition: os_priority.c:1078
static enum GNUNET_GenericReturnValue 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:872
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:233
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:423
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:69
Handle to a command.
Definition: os_priority.c:1001
struct GNUNET_DISK_PipeHandle * opipe
Handle to the output pipe.
Definition: os_priority.c:1010
struct GNUNET_OS_Process * eip
Process handle.
Definition: os_priority.c:1005
size_t off
Current read offset in buf.
Definition: os_priority.c:1045
char buf[1024]
Buffer for the output.
Definition: os_priority.c:1030
struct GNUNET_SCHEDULER_Task * rtask
Task reading from pipe.
Definition: os_priority.c:1035
struct GNUNET_TIME_Absolute timeout
When to time out.
Definition: os_priority.c:1040
void * proc_cls
Closure for proc.
Definition: os_priority.c:1025
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
Definition: os_priority.c:1020
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
Definition: os_priority.c:1015
pid_t pid
PID of the process.
Definition: os_priority.c:48
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition: os_priority.c:54
Context information passed to each scheduler task.
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 ...
Entry in list of pending tasks.
Definition: scheduler.c:135
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model