GNUnet  0.19.2
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 
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "disk.h"
31 #include <unistr.h>
32 
33 #define LOG(kind, ...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
34 
35 #define LOG_STRERROR(kind, syscall) \
36  GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
37 
38 #define LOG_STRERROR_FILE(kind, syscall, filename) \
39  GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
40 
41 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
42 
43 
45 {
49  pid_t pid;
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 {
83  struct GNUNET_DISK_FileHandle *control_pipe = cls;
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 
132 void
134 {
135  const char *env_buf;
136  char *env_buf_end;
137  struct GNUNET_DISK_FileHandle *control_pipe;
138  uint64_t pipe_fd;
139 
140  (void) cls;
141  if (NULL != pch)
142  {
143  /* already done, we've been called twice... */
144  GNUNET_break (0);
145  return;
146  }
147  env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
148  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
149  {
151  "Not installing a handler because $%s is empty\n",
153  putenv (GNUNET_OS_CONTROL_PIPE "=");
154  return;
155  }
156  errno = 0;
157  pipe_fd = strtoull (env_buf, &env_buf_end, 16);
158  if ((0 != errno) || (env_buf == env_buf_end))
159  {
160  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
161  putenv (GNUNET_OS_CONTROL_PIPE "=");
162  return;
163  }
164  if (pipe_fd >= FD_SETSIZE)
165  {
167  "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
168  env_buf);
169  putenv (GNUNET_OS_CONTROL_PIPE "=");
170  return;
171  }
172 
173  control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
174 
175  if (NULL == control_pipe)
176  {
177  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
178  putenv (GNUNET_OS_CONTROL_PIPE "=");
179  return;
180  }
182  "Adding parent control handler pipe `%s' to the scheduler\n",
183  env_buf);
185  control_pipe,
187  control_pipe);
189  putenv (GNUNET_OS_CONTROL_PIPE "=");
190 }
191 
192 
201 struct GNUNET_OS_Process *
203 {
204  current_process.pid = 0;
205  return &current_process;
206 }
207 
208 
209 int
211  int sig)
212 {
213  int ret;
214  char csig;
215 
216  csig = (char) sig;
217  if (NULL != proc->control_pipe)
218  {
220  "Sending signal %d to pid: %u via pipe\n",
221  sig,
222  proc->pid);
223  ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof(csig));
224  if (sizeof(csig) == ret)
225  return 0;
226  }
227  /* pipe failed or non-existent, try other methods */
228  switch (sig)
229  {
230  case SIGHUP:
231  case SIGINT:
232  case SIGKILL:
233  case SIGTERM:
234 #if (SIGTERM != GNUNET_TERM_SIG)
235  case GNUNET_TERM_SIG:
236 #endif
238  "Sending signal %d to pid: %u via system call\n",
239  sig,
240  proc->pid);
241  return kill (proc->pid, sig);
242  default:
244  "Sending signal %d to pid: %u via system call\n",
245  sig,
246  proc->pid);
247  return kill (proc->pid, sig);
248  }
249 }
250 
251 
259 pid_t
261 {
262  return proc->pid;
263 }
264 
265 
272 void
274 {
275  if (NULL != proc->control_pipe)
277 
278  GNUNET_free (proc);
279 }
280 
281 
289 static void
290 open_dev_null (int target_fd,
291  int flags)
292 {
293  int fd;
294 
295  fd = open ("/dev/null", flags);
296  if (-1 == fd)
297  {
298  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
299  return;
300  }
301  if (fd == target_fd)
302  return;
303  if (-1 == dup2 (fd, target_fd))
304  {
306  GNUNET_break (0 == close (fd));
307  return;
308  }
309  GNUNET_break (0 == close (fd));
310 }
311 
312 
329 static struct GNUNET_OS_Process *
331  struct GNUNET_DISK_PipeHandle *pipe_stdin,
332  struct GNUNET_DISK_PipeHandle *pipe_stdout,
333  struct GNUNET_DISK_PipeHandle *pipe_stderr,
334  const int *lsocks,
335  const char *filename,
336  char *const argv[])
337 {
338  pid_t ret;
339  char fds[16];
340  struct GNUNET_OS_Process *gnunet_proc;
341  struct GNUNET_DISK_FileHandle *childpipe_read;
342  struct GNUNET_DISK_FileHandle *childpipe_write;
343  int childpipe_read_fd;
344  int i;
345  int j;
346  int k;
347  int tgt;
348  int flags;
349  int *lscp;
350  unsigned int ls;
351  int fd_stdout_write;
352  int fd_stdout_read;
353  int fd_stderr_write;
354  int fd_stderr_read;
355  int fd_stdin_read;
356  int fd_stdin_write;
357 
358  if (GNUNET_SYSERR ==
360  return NULL; /* not executable */
361  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
362  {
363  struct GNUNET_DISK_PipeHandle *childpipe;
364  int dup_childpipe_read_fd = -1;
365 
367  if (NULL == childpipe)
368  return NULL;
369  childpipe_read =
371  childpipe_write =
373  GNUNET_DISK_pipe_close (childpipe);
374  if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
375  (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
376  &childpipe_read_fd,
377  sizeof(int))) ||
378  (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
379  {
380  if (NULL != childpipe_read)
381  GNUNET_DISK_file_close (childpipe_read);
382  if (NULL != childpipe_write)
383  GNUNET_DISK_file_close (childpipe_write);
384  if (0 <= dup_childpipe_read_fd)
385  GNUNET_break (0 == close (dup_childpipe_read_fd));
386  return NULL;
387  }
388  childpipe_read_fd = dup_childpipe_read_fd;
389  GNUNET_DISK_file_close (childpipe_read);
390  }
391  else
392  {
393  childpipe_write = NULL;
394  childpipe_read_fd = -1;
395  }
396  if (NULL != pipe_stdin)
397  {
398  GNUNET_assert (
399  GNUNET_OK ==
402  &fd_stdin_read,
403  sizeof(int)));
404  GNUNET_assert (
405  GNUNET_OK ==
408  &fd_stdin_write,
409  sizeof(int)));
410  }
411  if (NULL != pipe_stdout)
412  {
413  GNUNET_assert (
414  GNUNET_OK ==
417  &fd_stdout_write,
418  sizeof(int)));
419  GNUNET_assert (
420  GNUNET_OK ==
423  &fd_stdout_read,
424  sizeof(int)));
425  }
426  if (NULL != pipe_stderr)
427  {
428  GNUNET_assert (
429  GNUNET_OK ==
432  &fd_stderr_read,
433  sizeof(int)));
434  GNUNET_assert (
435  GNUNET_OK ==
438  &fd_stderr_write,
439  sizeof(int)));
440  }
441  lscp = NULL;
442  ls = 0;
443  if (NULL != lsocks)
444  {
445  i = 0;
446  while (-1 != (k = lsocks[i++]))
447  GNUNET_array_append (lscp, ls, k);
448  GNUNET_array_append (lscp, ls, -1);
449  }
450 #if DARWIN
451  /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
452  ret = vfork ();
453 #else
454  ret = fork ();
455 #endif
456  if (-1 == ret)
457  {
458  int eno = errno;
460  GNUNET_array_grow (lscp, ls, 0);
461  if (NULL != childpipe_write)
462  GNUNET_DISK_file_close (childpipe_write);
463  if (0 <= childpipe_read_fd)
464  GNUNET_break (0 == close (childpipe_read_fd));
465  errno = eno;
466  return NULL;
467  }
468  if (0 != ret)
469  {
470  unsetenv (GNUNET_OS_CONTROL_PIPE);
471  gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
472  gnunet_proc->pid = ret;
473  gnunet_proc->control_pipe = childpipe_write;
474  if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
475  {
476  GNUNET_break (0 == close (childpipe_read_fd));
477  }
478  GNUNET_array_grow (lscp, ls, 0);
479  return gnunet_proc;
480  }
481  if (0 <= childpipe_read_fd)
482  {
483  char fdbuf[100];
484 #ifndef DARWIN
485  /* due to vfork, we must NOT free memory on DARWIN! */
486  GNUNET_DISK_file_close (childpipe_write);
487 #endif
488  snprintf (fdbuf, 100, "%x", childpipe_read_fd);
489  setenv (GNUNET_OS_CONTROL_PIPE, fdbuf, 1);
490  }
491  else
492  unsetenv (GNUNET_OS_CONTROL_PIPE);
493  if (NULL != pipe_stdin)
494  {
495  GNUNET_break (0 == close (fd_stdin_write));
496  if (-1 == dup2 (fd_stdin_read, 0))
498  GNUNET_break (0 == close (fd_stdin_read));
499  }
500  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
501  {
502  GNUNET_break (0 == close (0));
503  open_dev_null (0, O_RDONLY);
504  }
505  if (NULL != pipe_stdout)
506  {
507  GNUNET_break (0 == close (fd_stdout_read));
508  if (-1 == dup2 (fd_stdout_write, 1))
510  GNUNET_break (0 == close (fd_stdout_write));
511  }
512  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
513  {
514  GNUNET_break (0 == close (1));
515  open_dev_null (1, O_WRONLY);
516  }
517  if (NULL != pipe_stderr)
518  {
519  GNUNET_break (0 == close (fd_stderr_read));
520  if (-1 == dup2 (fd_stderr_write, 2))
522  GNUNET_break (0 == close (fd_stderr_write));
523  }
524  else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
525  {
526  GNUNET_break (0 == close (2));
527  open_dev_null (2, O_WRONLY);
528  }
529  if (NULL != lscp)
530  {
531  /* read systemd documentation... */
532  i = 0;
533  tgt = 3;
534  while (-1 != lscp[i])
535  {
536  j = i + 1;
537  while (-1 != lscp[j])
538  {
539  if (lscp[j] == tgt)
540  {
541  /* dup away */
542  k = dup (lscp[j]);
543  GNUNET_assert (-1 != k);
544  GNUNET_assert (0 == close (lscp[j]));
545  lscp[j] = k;
546  break;
547  }
548  j++;
549  }
550  if (lscp[i] != tgt)
551  {
552  /* Bury any existing FD, no matter what; they should all be closed
553  * on exec anyway and the important ones have been dup'ed away */
554  GNUNET_break (0 == close (tgt));
555  GNUNET_assert (-1 != dup2 (lscp[i], tgt));
556  }
557  /* unset close-on-exec flag */
558  flags = fcntl (tgt, F_GETFD);
559  GNUNET_assert (flags >= 0);
560  flags &= ~FD_CLOEXEC;
561  fflush (stderr);
562  (void) fcntl (tgt, F_SETFD, flags);
563  tgt++;
564  i++;
565  }
566  GNUNET_snprintf (fds, sizeof(fds), "%u", i);
567  setenv ("LISTEN_FDS", fds, 1);
568  }
569 #ifndef DARWIN
570  /* due to vfork, we must NOT free memory on DARWIN! */
571  GNUNET_array_grow (lscp, ls, 0);
572 #endif
573  execvp (filename, argv);
575  _exit (1);
576 }
577 
578 
579 struct GNUNET_OS_Process *
581  struct GNUNET_DISK_PipeHandle *pipe_stdin,
582  struct GNUNET_DISK_PipeHandle *pipe_stdout,
583  struct GNUNET_DISK_PipeHandle *pipe_stderr,
584  const char *filename,
585  char *const argv[])
586 {
587  return start_process (std_inheritance,
588  pipe_stdin,
589  pipe_stdout,
590  pipe_stderr,
591  NULL,
592  filename,
593  argv);
594 }
595 
596 
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  va_list va)
604 {
605  struct GNUNET_OS_Process *ret;
606  va_list ap;
607  char **argv;
608  int argc;
609 
610  argc = 0;
611  va_copy (ap, va);
612  while (NULL != va_arg (ap, char *))
613  argc++;
614  va_end (ap);
615  argv = GNUNET_malloc (sizeof(char *) * (argc + 1));
616  argc = 0;
617  va_copy (ap, va);
618  while (NULL != (argv[argc] = va_arg (ap, char *)))
619  argc++;
620  va_end (ap);
621  ret = GNUNET_OS_start_process_vap (std_inheritance,
622  pipe_stdin,
623  pipe_stdout,
624  pipe_stderr,
625  filename,
626  argv);
627  GNUNET_free (argv);
628  return ret;
629 }
630 
631 
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  ...)
639 {
640  struct GNUNET_OS_Process *ret;
641  va_list ap;
642 
643  va_start (ap, filename);
644  ret = GNUNET_OS_start_process_va (std_inheritance,
645  pipe_stdin,
646  pipe_stdout,
647  pipe_stderr,
648  filename,
649  ap);
650  va_end (ap);
651  return ret;
652 }
653 
654 
668 struct GNUNET_OS_Process *
670  const int *lsocks,
671  const char *filename,
672  char *const argv[])
673 {
674  return start_process (std_inheritance,
675  NULL,
676  NULL,
677  NULL,
678  lsocks,
679  filename,
680  argv);
681 }
682 
683 
701 struct GNUNET_OS_Process *
703  const int *lsocks,
704  const char *filename,
705  ...)
706 {
707  va_list ap;
708  char **argv;
709  unsigned int argv_size;
710  const char *arg;
711  const char *rpos;
712  char *pos;
713  char *cp;
714  const char *last;
715  struct GNUNET_OS_Process *proc;
716  char *binary_path;
717  int quote_on;
718  unsigned int i;
719  size_t len;
720 
721  argv_size = 1;
722  va_start (ap, filename);
723  arg = filename;
724  last = NULL;
725  do
726  {
727  rpos = arg;
728  quote_on = 0;
729  while ('\0' != *rpos)
730  {
731  if ('"' == *rpos)
732  {
733  if (1 == quote_on)
734  quote_on = 0;
735  else
736  quote_on = 1;
737  }
738  if ((' ' == *rpos) && (0 == quote_on))
739  {
740  if (NULL != last)
741  argv_size++;
742  last = NULL;
743  rpos++;
744  while (' ' == *rpos)
745  rpos++;
746  }
747  if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
748  last = rpos;
749  if ('\0' != *rpos)
750  rpos++;
751  }
752  if (NULL != last)
753  argv_size++;
754  }
755  while (NULL != (arg = (va_arg (ap, const char *))));
756  va_end (ap);
757 
758  argv = GNUNET_malloc (argv_size * sizeof(char *));
759  argv_size = 0;
760  va_start (ap, filename);
761  arg = filename;
762  last = NULL;
763  do
764  {
765  cp = GNUNET_strdup (arg);
766  quote_on = 0;
767  pos = cp;
768  while ('\0' != *pos)
769  {
770  if ('"' == *pos)
771  {
772  if (1 == quote_on)
773  quote_on = 0;
774  else
775  quote_on = 1;
776  }
777  if ((' ' == *pos) && (0 == quote_on))
778  {
779  *pos = '\0';
780  if (NULL != last)
781  argv[argv_size++] = GNUNET_strdup (last);
782  last = NULL;
783  pos++;
784  while (' ' == *pos)
785  pos++;
786  }
787  if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
788  last = pos;
789  if ('\0' != *pos)
790  pos++;
791  }
792  if (NULL != last)
793  argv[argv_size++] = GNUNET_strdup (last);
794  last = NULL;
795  GNUNET_free (cp);
796  }
797  while (NULL != (arg = (va_arg (ap, const char *))));
798  va_end (ap);
799  argv[argv_size] = NULL;
800 
801  for (i = 0; i < argv_size; i++)
802  {
803  len = strlen (argv[i]);
804  if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
805  {
806  memmove (&argv[i][0], &argv[i][1], len - 2);
807  argv[i][len - 2] = '\0';
808  }
809  }
810  binary_path = argv[0];
811  proc = GNUNET_OS_start_process_v (std_inheritance,
812  lsocks,
813  binary_path,
814  argv);
815  while (argv_size > 0)
816  GNUNET_free_nz (argv[--argv_size]);
817  GNUNET_free (argv);
818  return proc;
819 }
820 
821 
832 static enum GNUNET_GenericReturnValue
833 process_status (struct GNUNET_OS_Process *proc,
835  unsigned long *code,
836  int options)
837 {
838  int status;
839  int ret;
840 
841  GNUNET_assert (0 != proc);
842  ret = waitpid (proc->pid,
843  &status,
844  options);
845  if (ret < 0)
846  {
848  "waitpid");
849  return GNUNET_SYSERR;
850  }
851  if (0 == ret)
852  {
854  *code = 0;
855  return GNUNET_NO;
856  }
857  if (proc->pid != ret)
858  {
860  "waitpid");
861  return GNUNET_SYSERR;
862  }
863  if (WIFEXITED (status))
864  {
866  *code = WEXITSTATUS (status);
867  }
868  else if (WIFSIGNALED (status))
869  {
871  *code = WTERMSIG (status);
872  }
873  else if (WIFSTOPPED (status))
874  {
876  *code = WSTOPSIG (status);
877  }
878 #ifdef WIFCONTINUED
879  else if (WIFCONTINUED (status))
880  {
882  *code = 0;
883  }
884 #endif
885  else
886  {
888  *code = 0;
889  }
890 
891  return GNUNET_OK;
892 }
893 
894 
907  unsigned long *code)
908 {
909  return process_status (proc, type, code, WNOHANG);
910 }
911 
912 
925  unsigned long *code)
926 {
927  return process_status (proc, type, code, 0);
928 }
929 
930 
941 int
943 {
944  pid_t pid = proc->pid;
945  pid_t ret;
946 
947  while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
948  ;
949  if (pid != ret)
950  {
952  return GNUNET_SYSERR;
953  }
954  return GNUNET_OK;
955 }
956 
957 
962 {
967 
972 
976  const struct GNUNET_DISK_FileHandle *r;
977 
982 
986  void *proc_cls;
987 
991  char buf[1024];
992 
997 
1002 
1006  size_t off;
1007 };
1008 
1009 
1017 void
1019 {
1020  if (NULL != cmd->proc)
1021  {
1022  GNUNET_assert (NULL != cmd->rtask);
1024  }
1025  (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1029  GNUNET_free (cmd);
1030 }
1031 
1032 
1038 static void
1039 cmd_read (void *cls)
1040 {
1041  struct GNUNET_OS_CommandHandle *cmd = cls;
1042  const struct GNUNET_SCHEDULER_TaskContext *tc;
1044  char *end;
1045  ssize_t ret;
1046 
1047  cmd->rtask = NULL;
1050  {
1051  /* timeout */
1052  proc = cmd->proc;
1053  cmd->proc = NULL;
1054  proc (cmd->proc_cls, NULL);
1055  return;
1056  }
1057  ret = GNUNET_DISK_file_read (cmd->r,
1058  &cmd->buf[cmd->off],
1059  sizeof(cmd->buf) - cmd->off);
1060  if (ret <= 0)
1061  {
1062  if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1063  {
1064  cmd->buf[cmd->off] = '\0';
1065  cmd->proc (cmd->proc_cls, cmd->buf);
1066  }
1067  proc = cmd->proc;
1068  cmd->proc = NULL;
1069  proc (cmd->proc_cls, NULL);
1070  return;
1071  }
1072  end = memchr (&cmd->buf[cmd->off], '\n', ret);
1073  cmd->off += ret;
1074  while (NULL != end)
1075  {
1076  *end = '\0';
1077  cmd->proc (cmd->proc_cls, cmd->buf);
1078  memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1079  cmd->off -= (end + 1 - cmd->buf);
1080  end = memchr (cmd->buf, '\n', cmd->off);
1081  }
1082  cmd->rtask =
1084  cmd->timeout),
1085  cmd->r,
1086  &cmd_read,
1087  cmd);
1088 }
1089 
1090 
1091 struct GNUNET_OS_CommandHandle *
1093  void *proc_cls,
1095  const char *binary,
1096  ...)
1097 {
1098  struct GNUNET_OS_CommandHandle *cmd;
1099  struct GNUNET_OS_Process *eip;
1100  struct GNUNET_DISK_PipeHandle *opipe;
1101  va_list ap;
1102 
1104  if (NULL == opipe)
1105  return NULL;
1106  va_start (ap, binary);
1107  /* redirect stdout, don't inherit stderr/stdin */
1108  eip =
1110  NULL,
1111  opipe,
1112  NULL,
1113  binary,
1114  ap);
1115  va_end (ap);
1116  if (NULL == eip)
1117  {
1118  GNUNET_DISK_pipe_close (opipe);
1119  return NULL;
1120  }
1122  cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1124  cmd->eip = eip;
1125  cmd->opipe = opipe;
1126  cmd->proc = proc;
1127  cmd->proc_cls = proc_cls;
1129  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
1130  return cmd;
1131 }
1132 
1133 
1134 /* 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:1632
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:1557
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:685
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1584
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1305
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:621
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:1615
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1327
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:1531
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1441
@ 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.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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:1128
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:1092
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:905
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:598
void GNUNET_OS_install_parent_control_handler(void *cls)
Connects this process to its parent via pipe; essentially, the parent control handler will read signa...
Definition: os_priority.c:133
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:633
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:702
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:580
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:923
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
Definition: os_priority.c:1018
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
Definition: os_priority.c:260
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:942
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:273
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:669
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:202
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:210
@ 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:1625
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:1303
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:724
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:944
void GNUNET_SIGNAL_raise(const int sig)
Raise the given signal by calling the installed signal handlers.
Definition: signal.c:98
#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:405
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:316
#define GNUNET_OS_CONTROL_PIPE
Definition: os_priority.c:41
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
static struct GNUNET_OS_Process current_process
Handle for 'this' process.
Definition: os_priority.c:62
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition: os_priority.c:67
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: os_priority.c:38
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition: os_priority.c:81
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:290
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition: os_priority.c:72
#define LOG(kind,...)
Definition: os_priority.c:33
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:330
#define LOG_STRERROR(kind, syscall)
Definition: os_priority.c:35
static void cmd_read(void *cls)
Read from the process and call the line processor.
Definition: os_priority.c:1039
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:833
#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:424
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:68
Handle to a command.
Definition: os_priority.c:962
struct GNUNET_DISK_PipeHandle * opipe
Handle to the output pipe.
Definition: os_priority.c:971
struct GNUNET_OS_Process * eip
Process handle.
Definition: os_priority.c:966
size_t off
Current read offset in buf.
Definition: os_priority.c:1006
char buf[1024]
Buffer for the output.
Definition: os_priority.c:991
struct GNUNET_SCHEDULER_Task * rtask
Task reading from pipe.
Definition: os_priority.c:996
struct GNUNET_TIME_Absolute timeout
When to time out.
Definition: os_priority.c:1001
void * proc_cls
Closure for proc.
Definition: os_priority.c:986
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
Definition: os_priority.c:981
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
Definition: os_priority.c:976
pid_t pid
PID of the process.
Definition: os_priority.c:49
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition: os_priority.c:55
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:136
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