GNUnet  0.10.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 
47  pid_t pid;
48 
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 {
83 
85  pch = NULL;
86  GNUNET_DISK_file_close(control_pipe);
87  control_pipe = NULL;
88 }
89 
90 
96 static void
98 {
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;
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  {
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);
195  spch = GNUNET_SCHEDULER_add_shutdown(&shutdown_pch, 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 
223 int
225 {
226  int ret;
227  char csig;
228 
229  csig = (char)sig;
230  if (NULL != proc->control_pipe)
231  {
233  "Sending signal %d to pid: %u via pipe\n",
234  sig,
235  proc->pid);
236  ret = GNUNET_DISK_file_write(proc->control_pipe, &csig, sizeof(csig));
237  if (sizeof(csig) == ret)
238  return 0;
239  }
240  /* pipe failed or non-existent, try other methods */
241  switch (sig)
242  {
243  case SIGHUP:
244  case SIGINT:
245  case SIGKILL:
246  case SIGTERM:
247 #if (SIGTERM != GNUNET_TERM_SIG)
248  case GNUNET_TERM_SIG:
249 #endif
251  "Sending signal %d to pid: %u via system call\n",
252  sig,
253  proc->pid);
254  return kill(proc->pid, sig);
255  default:
257  "Sending signal %d to pid: %u via system call\n",
258  sig,
259  proc->pid);
260  return kill(proc->pid, sig);
261  }
262 }
263 
264 
272 pid_t
274 {
275  return proc->pid;
276 }
277 
278 
285 void
287 {
288  if (NULL != proc->control_pipe)
290 
291  GNUNET_free(proc);
292 }
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  {
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 
343 static struct GNUNET_OS_Process *
344 start_process(int pipe_control,
345  enum GNUNET_OS_InheritStdioFlags std_inheritance,
346  struct GNUNET_DISK_PipeHandle *pipe_stdin,
347  struct GNUNET_DISK_PipeHandle *pipe_stdout,
348  struct GNUNET_DISK_PipeHandle *pipe_stderr,
349  const SOCKTYPE *lsocks,
350  const char *filename,
351  char *const argv[])
352 {
353  pid_t ret;
354  char fds[16];
355  struct GNUNET_OS_Process *gnunet_proc;
356  struct GNUNET_DISK_FileHandle *childpipe_read;
357  struct GNUNET_DISK_FileHandle *childpipe_write;
358  int childpipe_read_fd;
359  int i;
360  int j;
361  int k;
362  int tgt;
363  int flags;
364  int *lscp;
365  unsigned int ls;
366  int fd_stdout_write;
367  int fd_stdout_read;
368  int fd_stderr_write;
369  int fd_stderr_read;
370  int fd_stdin_read;
371  int fd_stdin_write;
372 
373  if (GNUNET_SYSERR ==
374  GNUNET_OS_check_helper_binary(filename, GNUNET_NO, NULL))
375  return NULL; /* not executable */
376  if (GNUNET_YES == pipe_control)
377  {
378  struct GNUNET_DISK_PipeHandle *childpipe;
379  int dup_childpipe_read_fd = -1;
380 
382  if (NULL == childpipe)
383  return NULL;
384  childpipe_read =
386  childpipe_write =
388  GNUNET_DISK_pipe_close(childpipe);
389  if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
390  (GNUNET_OK != GNUNET_DISK_internal_file_handle_(childpipe_read,
391  &childpipe_read_fd,
392  sizeof(int))) ||
393  (-1 == (dup_childpipe_read_fd = dup(childpipe_read_fd))))
394  {
395  if (NULL != childpipe_read)
396  GNUNET_DISK_file_close(childpipe_read);
397  if (NULL != childpipe_write)
398  GNUNET_DISK_file_close(childpipe_write);
399  if (0 <= dup_childpipe_read_fd)
400  close(dup_childpipe_read_fd);
401  return NULL;
402  }
403  childpipe_read_fd = dup_childpipe_read_fd;
404  GNUNET_DISK_file_close(childpipe_read);
405  }
406  else
407  {
408  childpipe_write = NULL;
409  childpipe_read_fd = -1;
410  }
411  if (NULL != pipe_stdin)
412  {
414  GNUNET_OK ==
417  &fd_stdin_read,
418  sizeof(int)));
420  GNUNET_OK ==
423  &fd_stdin_write,
424  sizeof(int)));
425  }
426  if (NULL != pipe_stdout)
427  {
429  GNUNET_OK ==
432  &fd_stdout_write,
433  sizeof(int)));
435  GNUNET_OK ==
438  &fd_stdout_read,
439  sizeof(int)));
440  }
441  if (NULL != pipe_stderr)
442  {
444  GNUNET_OK ==
447  &fd_stderr_read,
448  sizeof(int)));
450  GNUNET_OK ==
453  &fd_stderr_write,
454  sizeof(int)));
455  }
456  lscp = NULL;
457  ls = 0;
458  if (NULL != lsocks)
459  {
460  i = 0;
461  while (-1 != (k = lsocks[i++]))
462  GNUNET_array_append(lscp, ls, k);
463  GNUNET_array_append(lscp, ls, -1);
464  }
465 #if DARWIN
466  /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
467  ret = vfork();
468 #else
469  ret = fork();
470 #endif
471  if (-1 == ret)
472  {
473  int eno = errno;
475  GNUNET_array_grow(lscp, ls, 0);
476  if (NULL != childpipe_write)
477  GNUNET_DISK_file_close(childpipe_write);
478  if (0 <= childpipe_read_fd)
479  close(childpipe_read_fd);
480  errno = eno;
481  return NULL;
482  }
483  if (0 != ret)
484  {
485  unsetenv(GNUNET_OS_CONTROL_PIPE);
486  gnunet_proc = GNUNET_new(struct GNUNET_OS_Process);
487  gnunet_proc->pid = ret;
488  gnunet_proc->control_pipe = childpipe_write;
489  if (GNUNET_YES == pipe_control)
490  {
491  close(childpipe_read_fd);
492  }
493  GNUNET_array_grow(lscp, ls, 0);
494  return gnunet_proc;
495  }
496  if (0 <= childpipe_read_fd)
497  {
498  char fdbuf[100];
499 #ifndef DARWIN
500  /* due to vfork, we must NOT free memory on DARWIN! */
501  GNUNET_DISK_file_close(childpipe_write);
502 #endif
503  snprintf(fdbuf, 100, "%x", childpipe_read_fd);
504  setenv(GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
505  }
506  else
507  unsetenv(GNUNET_OS_CONTROL_PIPE);
508  if (NULL != pipe_stdin)
509  {
510  GNUNET_break(0 == close(fd_stdin_write));
511  if (-1 == dup2(fd_stdin_read, 0))
513  GNUNET_break(0 == close(fd_stdin_read));
514  }
515  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
516  {
517  GNUNET_break(0 == close(0));
518  open_dev_null(0, O_RDONLY);
519  }
520  if (NULL != pipe_stdout)
521  {
522  GNUNET_break(0 == close(fd_stdout_read));
523  if (-1 == dup2(fd_stdout_write, 1))
525  GNUNET_break(0 == close(fd_stdout_write));
526  }
527  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
528  {
529  GNUNET_break(0 == close(1));
530  open_dev_null(1, O_WRONLY);
531  }
532  if (NULL != pipe_stderr)
533  {
534  GNUNET_break(0 == close(fd_stderr_read));
535  if (-1 == dup2(fd_stderr_write, 2))
537  GNUNET_break(0 == close(fd_stderr_write));
538  }
539  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
540  {
541  GNUNET_break(0 == close(2));
542  open_dev_null(2, O_WRONLY);
543  }
544  if (NULL != lscp)
545  {
546  /* read systemd documentation... */
547  i = 0;
548  tgt = 3;
549  while (-1 != lscp[i])
550  {
551  j = i + 1;
552  while (-1 != lscp[j])
553  {
554  if (lscp[j] == tgt)
555  {
556  /* dup away */
557  k = dup(lscp[j]);
558  GNUNET_assert(-1 != k);
559  GNUNET_assert(0 == close(lscp[j]));
560  lscp[j] = k;
561  break;
562  }
563  j++;
564  }
565  if (lscp[i] != tgt)
566  {
567  /* Bury any existing FD, no matter what; they should all be closed
568  * on exec anyway and the important onces have been dup'ed away */
569  (void)close(tgt);
570  GNUNET_assert(-1 != dup2(lscp[i], tgt));
571  }
572  /* unset close-on-exec flag */
573  flags = fcntl(tgt, F_GETFD);
574  GNUNET_assert(flags >= 0);
575  flags &= ~FD_CLOEXEC;
576  fflush(stderr);
577  (void)fcntl(tgt, F_SETFD, flags);
578  tgt++;
579  i++;
580  }
581  GNUNET_snprintf(fds, sizeof(fds), "%u", i);
582  setenv("LISTEN_FDS", fds, 1);
583  }
584 #ifndef DARWIN
585  /* due to vfork, we must NOT free memory on DARWIN! */
586  GNUNET_array_grow(lscp, ls, 0);
587 #endif
588  execvp(filename, argv);
589  LOG_STRERROR_FILE(GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
590  _exit(1);
591 }
592 
593 
606 struct GNUNET_OS_Process *
608  enum GNUNET_OS_InheritStdioFlags std_inheritance,
609  struct GNUNET_DISK_PipeHandle *pipe_stdin,
610  struct GNUNET_DISK_PipeHandle *pipe_stdout,
611  struct GNUNET_DISK_PipeHandle *pipe_stderr,
612  const char *filename,
613  char *const argv[])
614 {
615  return start_process(pipe_control,
616  std_inheritance,
617  pipe_stdin,
618  pipe_stdout,
619  pipe_stderr,
620  NULL,
621  filename,
622  argv);
623 }
624 
625 
638 struct GNUNET_OS_Process *
639 GNUNET_OS_start_process_va(int pipe_control,
640  enum GNUNET_OS_InheritStdioFlags std_inheritance,
641  struct GNUNET_DISK_PipeHandle *pipe_stdin,
642  struct GNUNET_DISK_PipeHandle *pipe_stdout,
643  struct GNUNET_DISK_PipeHandle *pipe_stderr,
644  const char *filename,
645  va_list va)
646 {
647  struct GNUNET_OS_Process *ret;
648  va_list ap;
649  char **argv;
650  int argc;
651 
652  argc = 0;
653  va_copy(ap, va);
654  while (NULL != va_arg(ap, char *))
655  argc++;
656  va_end(ap);
657  argv = GNUNET_malloc(sizeof(char *) * (argc + 1));
658  argc = 0;
659  va_copy(ap, va);
660  while (NULL != (argv[argc] = va_arg(ap, char *)))
661  argc++;
662  va_end(ap);
663  ret = GNUNET_OS_start_process_vap(pipe_control,
664  std_inheritance,
665  pipe_stdin,
666  pipe_stdout,
667  pipe_stderr,
668  filename,
669  argv);
670  GNUNET_free(argv);
671  return ret;
672 }
673 
674 
686 struct GNUNET_OS_Process *
687 GNUNET_OS_start_process(int pipe_control,
688  enum GNUNET_OS_InheritStdioFlags std_inheritance,
689  struct GNUNET_DISK_PipeHandle *pipe_stdin,
690  struct GNUNET_DISK_PipeHandle *pipe_stdout,
691  struct GNUNET_DISK_PipeHandle *pipe_stderr,
692  const char *filename,
693  ...)
694 {
695  struct GNUNET_OS_Process *ret;
696  va_list ap;
697 
698  va_start(ap, filename);
699  ret = GNUNET_OS_start_process_va(pipe_control,
700  std_inheritance,
701  pipe_stdin,
702  pipe_stdout,
703  pipe_stderr,
704  filename,
705  ap);
706  va_end(ap);
707  return ret;
708 }
709 
710 
725 struct GNUNET_OS_Process *
726 GNUNET_OS_start_process_v(int pipe_control,
727  enum GNUNET_OS_InheritStdioFlags std_inheritance,
728  const SOCKTYPE *lsocks,
729  const char *filename,
730  char *const argv[])
731 {
732  return start_process(pipe_control,
733  std_inheritance,
734  NULL,
735  NULL,
736  NULL,
737  lsocks,
738  filename,
739  argv);
740 }
741 
742 
761 struct GNUNET_OS_Process *
762 GNUNET_OS_start_process_s(int pipe_control,
763  unsigned int std_inheritance,
764  const SOCKTYPE *lsocks,
765  const char *filename,
766  ...)
767 {
768  va_list ap;
769  char **argv;
770  unsigned int argv_size;
771  const char *arg;
772  const char *rpos;
773  char *pos;
774  char *cp;
775  const char *last;
776  struct GNUNET_OS_Process *proc;
777  char *binary_path;
778  int quote_on;
779  unsigned int i;
780  size_t len;
781 
782  argv_size = 1;
783  va_start(ap, filename);
784  arg = filename;
785  last = NULL;
786  do
787  {
788  rpos = arg;
789  quote_on = 0;
790  while ('\0' != *rpos)
791  {
792  if ('"' == *rpos)
793  {
794  if (1 == quote_on)
795  quote_on = 0;
796  else
797  quote_on = 1;
798  }
799  if ((' ' == *rpos) && (0 == quote_on))
800  {
801  if (NULL != last)
802  argv_size++;
803  last = NULL;
804  rpos++;
805  while (' ' == *rpos)
806  rpos++;
807  }
808  if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
809  last = rpos;
810  if ('\0' != *rpos)
811  rpos++;
812  }
813  if (NULL != last)
814  argv_size++;
815  }
816  while (NULL != (arg = (va_arg(ap, const char *))));
817  va_end(ap);
818 
819  argv = GNUNET_malloc(argv_size * sizeof(char *));
820  argv_size = 0;
821  va_start(ap, filename);
822  arg = filename;
823  last = NULL;
824  do
825  {
826  cp = GNUNET_strdup(arg);
827  quote_on = 0;
828  pos = cp;
829  while ('\0' != *pos)
830  {
831  if ('"' == *pos)
832  {
833  if (1 == quote_on)
834  quote_on = 0;
835  else
836  quote_on = 1;
837  }
838  if ((' ' == *pos) && (0 == quote_on))
839  {
840  *pos = '\0';
841  if (NULL != last)
842  argv[argv_size++] = GNUNET_strdup(last);
843  last = NULL;
844  pos++;
845  while (' ' == *pos)
846  pos++;
847  }
848  if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
849  last = pos;
850  if ('\0' != *pos)
851  pos++;
852  }
853  if (NULL != last)
854  argv[argv_size++] = GNUNET_strdup(last);
855  last = NULL;
856  GNUNET_free(cp);
857  }
858  while (NULL != (arg = (va_arg(ap, const char *))));
859  va_end(ap);
860  argv[argv_size] = NULL;
861 
862  for (i = 0; i < argv_size; i++)
863  {
864  len = strlen(argv[i]);
865  if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
866  {
867  memmove(&argv[i][0], &argv[i][1], len - 2);
868  argv[i][len - 2] = '\0';
869  }
870  }
871  binary_path = argv[0];
872  proc = GNUNET_OS_start_process_v(pipe_control,
873  std_inheritance,
874  lsocks,
875  binary_path,
876  argv);
877  while (argv_size > 0)
878  GNUNET_free(argv[--argv_size]);
879  GNUNET_free(argv);
880  return proc;
881 }
882 
883 
894 static int
897  unsigned long *code,
898  int options)
899 {
900  int status;
901  int ret;
902 
903  GNUNET_assert(0 != proc);
904  ret = waitpid(proc->pid, &status, options);
905  if (ret < 0)
906  {
908  return GNUNET_SYSERR;
909  }
910  if (0 == ret)
911  {
913  *code = 0;
914  return GNUNET_NO;
915  }
916  if (proc->pid != ret)
917  {
919  return GNUNET_SYSERR;
920  }
921  if (WIFEXITED(status))
922  {
923  *type = GNUNET_OS_PROCESS_EXITED;
924  *code = WEXITSTATUS(status);
925  }
926  else if (WIFSIGNALED(status))
927  {
929  *code = WTERMSIG(status);
930  }
931  else if (WIFSTOPPED(status))
932  {
934  *code = WSTOPSIG(status);
935  }
936 #ifdef WIFCONTINUED
937  else if (WIFCONTINUED(status))
938  {
940  *code = 0;
941  }
942 #endif
943  else
944  {
946  *code = 0;
947  }
948 
949  return GNUNET_OK;
950 }
951 
952 
962 int
965  unsigned long *code)
966 {
967  return process_status(proc, type, code, WNOHANG);
968 }
969 
970 
980 int
983  unsigned long *code)
984 {
985  return process_status(proc, type, code, 0);
986 }
987 
988 
999 int
1001 {
1002  pid_t pid = proc->pid;
1003  pid_t ret;
1004 
1005  while ((pid != (ret = waitpid(pid, NULL, 0))) && (EINTR == errno))
1006  ;
1007  if (pid != ret)
1008  {
1010  return GNUNET_SYSERR;
1011  }
1012  return GNUNET_OK;
1013 }
1014 
1015 
1024 
1029 
1033  const struct GNUNET_DISK_FileHandle *r;
1034 
1039 
1043  void *proc_cls;
1044 
1048  char buf[1024];
1049 
1054 
1059 
1063  size_t off;
1064 };
1065 
1066 
1074 void
1076 {
1077  if (NULL != cmd->proc)
1078  {
1079  GNUNET_assert(NULL != cmd->rtask);
1081  }
1082  (void)GNUNET_OS_process_kill(cmd->eip, SIGKILL);
1086  GNUNET_free(cmd);
1087 }
1088 
1089 
1095 static void
1096 cmd_read(void *cls)
1097 {
1098  struct GNUNET_OS_CommandHandle *cmd = cls;
1099  const struct GNUNET_SCHEDULER_TaskContext *tc;
1101  char *end;
1102  ssize_t ret;
1103 
1104  cmd->rtask = NULL;
1107  {
1108  /* timeout */
1109  proc = cmd->proc;
1110  cmd->proc = NULL;
1111  proc(cmd->proc_cls, NULL);
1112  return;
1113  }
1114  ret = GNUNET_DISK_file_read(cmd->r,
1115  &cmd->buf[cmd->off],
1116  sizeof(cmd->buf) - cmd->off);
1117  if (ret <= 0)
1118  {
1119  if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1120  {
1121  cmd->buf[cmd->off] = '\0';
1122  cmd->proc(cmd->proc_cls, cmd->buf);
1123  }
1124  proc = cmd->proc;
1125  cmd->proc = NULL;
1126  proc(cmd->proc_cls, NULL);
1127  return;
1128  }
1129  end = memchr(&cmd->buf[cmd->off], '\n', ret);
1130  cmd->off += ret;
1131  while (NULL != end)
1132  {
1133  *end = '\0';
1134  cmd->proc(cmd->proc_cls, cmd->buf);
1135  memmove(cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1136  cmd->off -= (end + 1 - cmd->buf);
1137  end = memchr(cmd->buf, '\n', cmd->off);
1138  }
1139  cmd->rtask =
1141  cmd->timeout),
1142  cmd->r,
1143  &cmd_read,
1144  cmd);
1145 }
1146 
1147 
1159 struct GNUNET_OS_CommandHandle *
1161  void *proc_cls,
1163  const char *binary,
1164  ...)
1165 {
1166  struct GNUNET_OS_CommandHandle *cmd;
1167  struct GNUNET_OS_Process *eip;
1168  struct GNUNET_DISK_PipeHandle *opipe;
1169  va_list ap;
1170 
1172  if (NULL == opipe)
1173  return NULL;
1174  va_start(ap, binary);
1175  /* redirect stdout, don't inherit stderr/stdin */
1176  eip =
1177  GNUNET_OS_start_process_va(GNUNET_NO, 0, NULL, opipe, NULL, binary, ap);
1178  va_end(ap);
1179  if (NULL == eip)
1180  {
1181  GNUNET_DISK_pipe_close(opipe);
1182  return NULL;
1183  }
1185  cmd = GNUNET_new(struct GNUNET_OS_CommandHandle);
1186  cmd->timeout = GNUNET_TIME_relative_to_absolute(timeout);
1187  cmd->eip = eip;
1188  cmd->opipe = opipe;
1189  cmd->proc = proc;
1190  cmd->proc_cls = proc_cls;
1192  cmd->rtask = GNUNET_SCHEDULER_add_read_file(timeout, cmd->r, &cmd_read, cmd);
1193  return cmd;
1194 }
1195 
1196 
1197 /* 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:95
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:737
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process...
Definition: gnunet_os_lib.h:68
When this flag is set, the child process will inherit stderr of the parent.
Definition: gnunet_os_lib.h:90
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:273
int GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1339
#define GNUNET_OS_CONTROL_PIPE
Definition: os_priority.c:40
char buf[1024]
Buffer for the output.
Definition: os_priority.c:1048
#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
#define SOCKTYPE
Definition: platform.h:237
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:286
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:729
int GNUNET_OS_process_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:963
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:1284
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
Definition: os_priority.c:1033
pid_t pid
PID of the process.
Definition: os_priority.c:47
size_t off
Current read offset in buf.
Definition: os_priority.c:1063
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:1028
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_OS_Process * 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,...)
Start a process.
Definition: os_priority.c:687
When this flag is set, the child process will inherit stdin of the parent.
Definition: gnunet_os_lib.h:78
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:410
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(int pipe_control, unsigned int std_inheritance, const SOCKTYPE *lsocks, const char *filename,...)
Start a process.
Definition: os_priority.c:762
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:895
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
#define GNUNET_NO
Definition: gnunet_common.h:78
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:1615
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
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.
struct GNUNET_OS_Process * 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)
Start a process.
Definition: os_priority.c:639
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
struct GNUNET_TIME_Absolute timeout
When to time out.
Definition: os_priority.c:1058
#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:1043
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:1744
struct GNUNET_OS_Process * eip
Process handle.
Definition: os_priority.c:1023
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition: os_priority.c:71
#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
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
static void cmd_read(void *cls)
Read from the process and call the line processor.
Definition: os_priority.c:1096
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:1673
#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...
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:817
When this flag is set, the child process will inherit stdout of the parent.
Definition: gnunet_os_lib.h:84
GNUNET_OS_ProcessStatusType
Process status types.
struct GNUNET_OS_Process * GNUNET_OS_process_current()
Get process structure for current process.
Definition: os_priority.c:209
struct GNUNET_OS_Process * 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, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:607
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:981
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:140
static struct GNUNET_OS_Process * 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[])
Start a process.
Definition: os_priority.c:344
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(int blocking_read, int blocking_write, int inherit_read, int inherit_write)
Creates an interprocess channel.
Definition: disk.c:1518
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
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:1769
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:1160
#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:1053
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:1196
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition: os_priority.c:66
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1706
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
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:1635
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:1000
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1369
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition: os_priority.c:54
Handle to a command.
Definition: os_priority.c:1019
Entry in list of pending tasks.
Definition: scheduler.c:131
The process is still running.
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
Definition: os_priority.c:1038
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:1075
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
static struct GNUNET_OS_Process current_process
Handle for &#39;this&#39; process.
Definition: os_priority.c:61
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:242
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:80
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
Handle used to access files (and pipes).
struct GNUNET_OS_Process * GNUNET_OS_start_process_v(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, const SOCKTYPE *lsocks, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:726
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:224
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956