GNUnet 0.26.2-114-g7c6b613e3
 
Loading...
Searching...
No Matches
os_process.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, 2026 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
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-os-process", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) \
34 GNUNET_log_from_strerror (kind, "util-os-process", syscall)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util-os-process", syscall, \
38 filename)
39
40#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
41
42
48{
53
58
64
68 bool owned;
69};
70
71
76{
80 char *key;
81
85 char *value;
86};
87
88
90{
94 pid_t pid;
95
101
107
111 unsigned int map_size;
112
117
121 unsigned int envs_size;
122
127
131 char *filename;
132
136 char **argv;
137
142
146 unsigned long exit_code;
147};
148
149
154
159
164
165
171static void
172shutdown_pch (void *cls)
173{
174 struct GNUNET_DISK_FileHandle *control_pipe = cls;
175
177 pch = NULL;
178 GNUNET_DISK_file_close (control_pipe);
179 control_pipe = NULL;
180}
181
182
188static void
190{
191 struct GNUNET_DISK_FileHandle *control_pipe = cls;
192 char sig;
193 ssize_t ret;
194
195 pch = NULL;
196 ret = GNUNET_DISK_file_read (control_pipe,
197 &sig,
198 sizeof(sig));
199 if (sizeof(sig) != ret)
200 {
201 if (-1 == ret)
203 "GNUNET_DISK_file_read");
205 "Closing control pipe\n");
206 GNUNET_DISK_file_close (control_pipe);
208 spch = NULL;
209 return;
210 }
212 "Got control code %d from parent via pipe\n",
213 sig);
215 control_pipe,
217 control_pipe);
218 GNUNET_SIGNAL_raise ((int) sig);
219}
220
221
222void
224{
225 const char *env_buf;
226 char *env_buf_end;
227 struct GNUNET_DISK_FileHandle *control_pipe;
228 uint64_t pipe_fd;
229
230 if (NULL != pch)
231 {
232 /* already done, we've been called twice... */
233 GNUNET_break (0);
234 return;
235 }
236 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
237 if ( (NULL == env_buf) ||
238 (strlen (env_buf) <= 0) )
239 {
241 "Not installing a handler because $%s is empty\n",
243 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
244 return;
245 }
246 errno = 0;
247 pipe_fd = strtoull (env_buf,
248 &env_buf_end,
249 16);
250 if ( (0 != errno) ||
251 (env_buf == env_buf_end) )
252 {
254 "strtoull",
255 env_buf);
257 "",
258 1);
259 return;
260 }
261 if (pipe_fd >= FD_SETSIZE)
262 {
264 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
265 env_buf);
267 "",
268 1);
269 return;
270 }
271
272 control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
273 if (NULL == control_pipe)
274 {
276 "open",
277 env_buf);
279 "",
280 1);
281 return;
282 }
284 "Adding parent control handler pipe `%s' to the scheduler\n",
285 env_buf);
287 control_pipe,
289 control_pipe);
291 control_pipe);
293 "",
294 1);
295}
296
297
298struct GNUNET_Process *
304
305
308 int sig)
309{
310 if (NULL != proc->control_pipe)
311 {
312 char csig = (char) sig;
313 ssize_t iret;
314
316 "Sending signal %d to pid: %u via pipe\n",
317 sig,
318 proc->pid);
320 &csig,
321 sizeof(csig));
322 if (sizeof(csig) == iret)
323 return GNUNET_OK;
324 }
325 /* pipe failed or non-existent, try other methods */
326 if (-1 == proc->pid)
327 {
329 "Refusing to send signal %d process `%s': not running\n",
330 sig,
331 proc->filename);
332 return GNUNET_NO; /* -1 means process is not running, refuse... */
333 }
335 "Sending signal %d to pid: %u via system call\n",
336 sig,
337 proc->pid);
338 {
339 int ret;
340
341 ret = kill (proc->pid,
342 sig);
343 if (0 != ret)
344 {
346 "kill");
347 }
348 return (0 == ret)
349 ? GNUNET_OK
351 }
352}
353
354
355pid_t
357{
358 return proc->pid;
359}
360
361
362void
364{
365 if (NULL != proc->control_pipe)
367 GNUNET_free (proc->filename);
368 for (unsigned int i = 0; i < proc->envs_size; i++)
369 {
370 GNUNET_free (proc->envs[i].key);
371 GNUNET_free (proc->envs[i].value);
372 }
373 GNUNET_free (proc->envs);
374 for (unsigned int i = 0; i < proc->map_size; i++)
375 {
376 struct ProcessFileMapEntry *me = &proc->map[i];
377 int pfd = me->parent_fd;
378
379 if (-1 == pfd)
380 continue;
381 if (! me->owned)
382 continue;
383 GNUNET_break (0 == close (pfd));
384 }
385 GNUNET_free (proc->map);
386 for (unsigned int i = 0; NULL != proc->argv[i]; i++)
387 GNUNET_free (proc->argv[i]);
388 GNUNET_free (proc->argv);
389 GNUNET_free (proc);
390}
391
392
400static int
401safe_dup2 (int oldfd,
402 int newfd)
403{
404 int ret;
405
406 while (1)
407 {
408 ret = dup2 (oldfd,
409 newfd);
410 if (-1 != ret)
411 break;
412 if ( (EBADF == errno) ||
413 (EINVAL == errno) ||
414 (EMFILE == errno) )
415 break;
416 /* should be EBUSY/EINTR, so try again */
418 "dup2");
419 }
420 return ret;
421}
422
423
433 int flags)
434{
435 int fd;
436
437 fd = open ("/dev/null",
438 flags);
439 if (-1 == fd)
440 {
442 "open",
443 "/dev/null");
444 return GNUNET_SYSERR;
445 }
446 if (fd == target_fd)
447 return GNUNET_OK;
448 if (-1 == dup2 (fd,
449 target_fd))
450 {
452 "dup2");
453 GNUNET_break (0 == close (fd));
454 return GNUNET_SYSERR;
455 }
456 GNUNET_break (0 == close (fd));
457 return GNUNET_OK;
458}
459
460
461struct GNUNET_Process *
471
472
481{
482 int flags;
483
484 flags = fcntl (fd,
485 F_GETFD);
486 if (flags == -1)
487 {
489 "fcntl(F_GETFD)");
490 return GNUNET_SYSERR;
491 }
492
493 flags &= ~FD_CLOEXEC;
494
495 if (-1 ==
496 fcntl (fd,
497 F_SETFD,
498 flags))
499 {
501 "fcntl(F_SETFD)");
502 return GNUNET_SYSERR;
503 }
504 return GNUNET_OK;
505}
506
507
520 int fd,
521 int flags)
522{
523 for (unsigned int i=0; i<proc->map_size; i++)
524 {
525 struct ProcessFileMapEntry *me = &proc->map[i];
526
527 if (fd == me->target_fd)
528 {
529 if (fd !=
530 safe_dup2 (me->parent_fd,
531 fd))
532 return GNUNET_SYSERR;
533 if (me->owned)
534 GNUNET_break (0 == close (me->parent_fd));
535 me->parent_fd = -1;
536 return GNUNET_OK;
537 }
538 }
539 return open_dev_null (fd,
540 flags);
541}
542
543
546{
547 pid_t ret;
548 int childpipe_read_fd;
549
550 if (-1 != proc->pid)
551 {
552 GNUNET_break (0);
553 return GNUNET_SYSERR;
554 }
555 if (NULL == proc->filename)
556 {
557 GNUNET_break (0);
558 return GNUNET_SYSERR;
559 }
560
562 {
563 struct GNUNET_DISK_PipeHandle *childpipe;
564 struct GNUNET_DISK_FileHandle *childpipe_read;
565 int dup_childpipe_read_fd = -1;
566
568 if (NULL == childpipe)
569 {
570 GNUNET_break (0);
571 return GNUNET_SYSERR;
572 }
573 childpipe_read =
576 proc->control_pipe =
579 GNUNET_DISK_pipe_close (childpipe);
580 if ( (NULL == childpipe_read) ||
581 (NULL == proc->control_pipe) ||
582 (GNUNET_OK !=
583 GNUNET_DISK_internal_file_handle_ (childpipe_read,
584 &childpipe_read_fd)) ||
585 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
586 {
587 GNUNET_break (0);
588 if (NULL != childpipe_read)
589 GNUNET_DISK_file_close (childpipe_read);
590 if (NULL != proc->control_pipe)
591 {
593 proc->control_pipe = NULL;
594 }
595 return GNUNET_SYSERR;
596 }
597 childpipe_read_fd = dup_childpipe_read_fd;
598 GNUNET_DISK_file_close (childpipe_read);
599 }
600 else
601 {
602 childpipe_read_fd = -1;
603 }
604
605 {
606 /* Make sure none of the parent_fds conflict with the target_fds in the client process */
607 unsigned int max_fd = 3; /* never use stdin/stdout/stderr */
608 unsigned int pos;
609
610 for (unsigned int i=0; i<proc->map_size; i++)
611 {
612 struct ProcessFileMapEntry *me = &proc->map[i];
613
614 max_fd = GNUNET_MAX (max_fd,
615 me->target_fd);
616 }
617 pos = max_fd + 1;
618 for (unsigned int i=0; i<proc->map_size; i++)
619 {
620 struct ProcessFileMapEntry *me = &proc->map[i];
621
622 if (me->parent_fd < pos)
623 {
624 if (me->target_fd == me->parent_fd)
625 {
626 /* same FD, so no conflict, but make sure FD is not closed
627 on exec() */
628 clear_cloexec (me->parent_fd);
629 }
630 else
631 {
632 int dst;
633
634 /* search for FD that is not yet open */
635 while (-1 !=
636 fcntl (pos,
637 F_GETFD))
638 pos++;
639 while (1)
640 {
641 dst = dup2 (me->parent_fd,
642 pos);
643 if (-1 != dst)
644 break;
645 if ( (EBADF == errno) ||
646 (EINVAL == errno) ||
647 (EMFILE == errno) )
648 {
649 GNUNET_break (0);
650 return GNUNET_SYSERR;
651 }
652 /* leaves interrupt/busy, try again */
653 }
654 if (me->owned)
655 GNUNET_break (0 == close (me->parent_fd));
656 me->parent_fd = dst;
657 me->owned = true;
658 }
659 }
660 }
661 }
662
663 ret = fork ();
664 if (-1 == ret)
665 {
666 int eno = errno;
667
669 "fork");
670 if (NULL != proc->control_pipe)
671 {
673 proc->control_pipe = NULL;
674 }
675 if (0 <= childpipe_read_fd)
676 GNUNET_break (0 == close (childpipe_read_fd));
677 errno = eno;
678 return GNUNET_SYSERR;
679 }
680 if (0 != ret)
681 {
682 proc->pid = ret;
683 if (0 <= childpipe_read_fd)
684 GNUNET_break (0 == close (childpipe_read_fd));
685 for (unsigned int i=0; i<proc->map_size; i++)
686 {
687 struct ProcessFileMapEntry *me = &proc->map[i];
688
689 if (! me->owned)
690 continue;
691 if (-1 != me->parent_fd)
692 {
693 GNUNET_assert (0 ==
694 close (me->parent_fd));
695 me->parent_fd = -1;
696 }
697 }
698 return GNUNET_OK;
699 }
700
701 /* in child process! */
702
703 /* deploy control pipe */
704 if (0 <= childpipe_read_fd)
705 {
706 char fdbuf[100];
707
709 snprintf (fdbuf,
710 sizeof (fdbuf),
711 "%x",
712 childpipe_read_fd);
713 GNUNET_assert (0 ==
715 fdbuf,
716 1));
717 }
718 else
719 {
720 GNUNET_assert (0 ==
721 unsetenv (GNUNET_OS_CONTROL_PIPE));
722 }
723
724 /* map stdin/stdout/stderr */
725 if (0 == (proc->std_inheritance & GNUNET_OS_INHERIT_STD_IN))
726 {
728 map_std (proc,
729 STDIN_FILENO,
730 O_RDONLY));
731 }
733 {
735 map_std (proc,
736 STDOUT_FILENO,
737 O_WRONLY));
738 }
740 {
742 map_std (proc,
743 STDERR_FILENO,
744 O_WRONLY));
745 }
746
747 /* map all other file descriptors */
748 {
749 char *fdnames = GNUNET_strdup ("");
750 unsigned int total_lfds = 0;
751
752 for (unsigned int i=0; i<proc->map_size; i++)
753 {
754 struct ProcessFileMapEntry *me = &proc->map[i];
755
756 if (-1 == me->parent_fd)
757 continue; /* already taken care of */
758 if (-1 == me->target_fd)
759 {
760 me->target_fd = dup (me->parent_fd);
761 GNUNET_assert (-1 != me->target_fd);
762 if (me->owned)
763 GNUNET_assert (0 == close (me->parent_fd));
764 }
765 else if (me->parent_fd != me->target_fd)
766 {
767 GNUNET_assert (me->target_fd ==
768 safe_dup2 (me->parent_fd,
769 me->target_fd));
770 if (me->owned)
771 GNUNET_assert (0 == close (me->parent_fd));
772 }
773 else
774 {
775 GNUNET_assert (! me->systemd_listen_socket);
776 GNUNET_assert (me->owned);
778 clear_cloexec (me->target_fd));
779 }
780 me->parent_fd = -1;
781 if (me->systemd_listen_socket)
782 {
783 char *tmp;
784
785 GNUNET_asprintf (&tmp,
786 "%s:%d",
787 fdnames,
788 me->target_fd);
789 GNUNET_free (fdnames);
790 fdnames = tmp;
791 total_lfds++;
792 }
793 }
794 if (0 != total_lfds)
795 {
796 char fds[16];
797
798 GNUNET_snprintf (fds,
799 sizeof(fds),
800 "%u",
801 total_lfds);
802 GNUNET_assert (0 ==
803 setenv ("LISTEN_FDS",
804 fds,
805 1));
806 GNUNET_assert (0 ==
807 setenv ("LISTEN_FDNAMES",
808 fdnames + 1, /* skip leading ':' */
809 1));
810 }
811 GNUNET_free (fdnames);
812 }
813
814 /* setup environment */
815 for (unsigned int i=0; i<proc->envs_size; i++)
816 {
817 struct EnviEntry *ee = &proc->envs[i];
818
819 if (NULL == ee->value)
820 GNUNET_assert (0 ==
821 unsetenv (ee->key));
822 else
823 GNUNET_assert (0 ==
824 setenv (ee->key,
825 ee->value,
826 1));
827 }
828
829 /* finally execute */
830 execvp (proc->filename,
831 proc->argv);
833 "execvp",
834 proc->filename);
835 _exit (1);
836}
837
838
841 struct GNUNET_Process *p,
842 const char *filename,
843 const char **argv)
844{
845 int argc;
846
847 if (GNUNET_SYSERR ==
849 GNUNET_NO,
850 NULL))
851 return GNUNET_SYSERR; /* not executable */
852 GNUNET_assert (NULL == p->argv);
854 argc = 0;
855 while (NULL != argv[argc])
856 argc++;
857 p->argv = GNUNET_new_array (argc + 1,
858 char *);
859 for (argc = 0; NULL != argv[argc]; argc++)
860 p->argv[argc] = GNUNET_strdup (argv[argc]);
861 return process_start (p);
862}
863
864
867 struct GNUNET_Process *p,
868 const char *filename,
869 va_list va)
870{
871 va_list ap;
872 const char *av;
873 int argc;
874
875 if (GNUNET_SYSERR ==
877 GNUNET_NO,
878 NULL))
879 return GNUNET_SYSERR; /* not executable */
880 GNUNET_assert (NULL == p->argv);
882 argc = 0;
883 va_copy (ap,
884 va);
885 while (NULL != va_arg (ap,
886 const char *))
887 argc++;
888 va_end (ap);
889 p->argv = GNUNET_new_array (argc + 1,
890 char *);
891 argc = 0;
892 va_copy (ap,
893 va);
894 while (NULL != (av = va_arg (ap,
895 const char *)))
896 p->argv[argc++] = GNUNET_strdup (av);
897 va_end (ap);
898 return process_start (p);
899}
900
901
904 const char *filename,
905 ...)
906{
908 va_list ap;
909
910 va_start (ap,
911 filename);
913 filename,
914 ap);
915 va_end (ap);
916 return ret;
917}
918
919
922 const char *command)
923{
924 char *cmd = GNUNET_strdup (command);
925 size_t len = strlen (command);
926 size_t cnt = 1;
927 size_t start = 0;
928 bool quote_on = false;
929 size_t i;
930 size_t skip = 0;
931
932 GNUNET_assert (NULL == p->argv);
933 for (i=0; i<len; i++)
934 {
935 char c = cmd[i];
936
937 switch (c)
938 {
939 case '"':
940 quote_on = ! quote_on;
941 break;
942 case '\\':
943 i++;
944 break;
945 case ' ':
946 if (! quote_on)
947 cnt++;
948 while (' ' == cmd[i + 1])
949 i++;
950 break;
951 }
952 }
953
954 p->argv = GNUNET_new_array (cnt + 1,
955 char *);
956 cnt = 0;
957 for (i=0; i<len; i++)
958 {
959 char c = cmd[i];
960
961 switch (c)
962 {
963 case '"':
964 quote_on = ! quote_on;
965 skip++;
966 break;
967 case ' ':
968 if ( (! quote_on) &&
969 (i != start) )
970 {
971 p->argv[cnt] = GNUNET_strndup (&cmd[start],
972 i - start - skip);
973 cnt++;
974 skip = 0;
975 }
976 while (' ' == cmd[i + 1])
977 i++;
978 if (! quote_on)
979 start = i + 1;
980 break;
981 case '\\':
982 i++;
983 skip++;
984 cmd[i - skip] = cmd[i];
985 break;
986 default:
987 cmd[i - skip] = c;
988 break;
989 }
990 }
991 if (i != start)
992 p->argv[cnt] = GNUNET_strndup (&cmd[start],
993 i - start);
994 GNUNET_free (cmd);
995 if (quote_on)
996 {
998 "Cmd `%s' has imbalanced quotes\n",
999 cmd);
1000 }
1001 if (NULL == p->argv[0])
1002 {
1004 "Empty command specified, cannot execute\n");
1005 return GNUNET_SYSERR;
1006 }
1007 if (GNUNET_SYSERR ==
1009 GNUNET_NO,
1010 NULL))
1011 {
1013 "Specified binary `%s' is not executable\n",
1014 p->argv[0]);
1015 return GNUNET_SYSERR;
1016 }
1017 p->filename = GNUNET_strdup (p->argv[0]);
1018 return process_start (p);
1019}
1020
1021
1024 struct GNUNET_Process *proc,
1025 unsigned int num_options,
1026 const struct GNUNET_ProcessOptionValue options[])
1027{
1028 for (unsigned int i=0; i<num_options; i++)
1029 {
1030 const struct GNUNET_ProcessOptionValue *ov = &options[i];
1031
1032 switch (ov->option)
1033 {
1035 return GNUNET_OK;
1037 {
1038 struct EnviEntry ee = {
1040 };
1041
1042 if (NULL != ov->details.set_environment.value)
1045 proc->envs_size,
1046 ee);
1047 }
1048 continue;
1050 {
1051 struct ProcessFileMapEntry pme = {
1053 .parent_fd = ov->details.inherit_fd.parent_fd,
1054 .owned = true
1055 };
1056
1057 GNUNET_array_append (proc->map,
1058 proc->map_size,
1059 pme);
1060 }
1061 continue;
1063 {
1064 struct ProcessFileMapEntry pme = {
1065 .target_fd = -1, /* any */
1066 .parent_fd = ov->details.inherit_lsock,
1067 .systemd_listen_socket = true,
1068 .owned = false
1069 };
1070
1071 GNUNET_array_append (proc->map,
1072 proc->map_size,
1073 pme);
1074 }
1075 continue;
1076 }
1077 GNUNET_break (0);
1078 return GNUNET_SYSERR;
1079 }
1080 return GNUNET_OK;
1081}
1082
1083
1086 bool blocking,
1088 unsigned long *code)
1089{
1090 pid_t ret;
1091 int status;
1092
1093 if (-1 == proc->pid)
1094 {
1095 if (NULL != type)
1096 *type = proc->exit_type;
1097 if (NULL != code)
1098 *code = proc->exit_code;
1099 return GNUNET_OK;
1100 }
1101 while (proc->pid !=
1102 (ret = waitpid (proc->pid,
1103 &status,
1104 blocking ? 0 : WNOHANG)))
1105 {
1106 if ( (! blocking) &&
1107 (EINTR == errno) )
1108 {
1109 ret = 0;
1110 break;
1111 }
1112 if (EINTR != errno)
1113 break;
1114 }
1115 if (0 == ret)
1116 {
1117 if (NULL != type)
1119 if (NULL != code)
1120 *code = 0;
1121 return GNUNET_NO;
1122 }
1123#ifdef WIFCONTINUED
1124 if ( (proc->pid == ret) &&
1125 (WIFCONTINUED (status)) )
1126 {
1127 if (NULL != type)
1129 if (NULL != code)
1130 *code = 0;
1131 return GNUNET_NO;
1132 }
1133#endif
1134 if (proc->pid != ret)
1135 {
1137 "waitpid");
1138 return GNUNET_SYSERR;
1139 }
1140 /* process did exit! */
1141 proc->pid = -1;
1142 if (WIFEXITED (status))
1143 {
1145 proc->exit_code = WEXITSTATUS (status);
1146 }
1147 else if (WIFSIGNALED (status))
1148 {
1150 proc->exit_code = WTERMSIG (status);
1151 }
1152 else if (WIFSTOPPED (status))
1153 {
1155 proc->exit_code = WSTOPSIG (status);
1156 }
1157 else
1158 {
1160 proc->exit_code = 0;
1161 }
1162 if (NULL != type)
1163 *type = proc->exit_type;
1164 if (NULL != code)
1165 *code = proc->exit_code;
1166 return GNUNET_OK;
1167}
1168
1169
1170/* end of os_process.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
enum GNUNET_GenericReturnValue GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, int *dst)
Retrieve OS file handle.
Definition disk.c:1720
Internal DISK related helper functions.
char * getenv()
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int ret
Final status code.
Definition gnunet-arm.c:93
static GNUNET_NETWORK_STRUCT_END struct GNUNET_PeerIdentity me
Our own peer identity.
static char * filename
static uint32_t type
Type string converted to DNS type value.
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static struct GNUNET_Process * p
Helper process we started.
Definition gnunet-uri.c:38
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:1644
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:745
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1524
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1671
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition disk.c:1386
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition disk.c:1410
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:704
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ 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
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
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_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#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.
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process.
void GNUNET_process_install_parent_control_handler()
Connects this process to its parent via pipe; essentially, the parent control handler will read signa...
Definition os_process.c:223
enum GNUNET_GenericReturnValue GNUNET_process_run_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command and start a process.
Definition os_process.c:903
enum GNUNET_GenericReturnValue GNUNET_process_run_command(struct GNUNET_Process *p, const char *command)
Set the command and start a process.
Definition os_process.c:921
enum GNUNET_GenericReturnValue GNUNET_process_run_command_argv(struct GNUNET_Process *p, const char *filename, const char **argv)
Set the command and start a process.
Definition os_process.c:840
enum GNUNET_GenericReturnValue GNUNET_process_wait(struct GNUNET_Process *proc, bool blocking, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Wait for a process to terminate.
enum GNUNET_GenericReturnValue GNUNET_process_set_options_(struct GNUNET_Process *proc, unsigned int num_options, const struct GNUNET_ProcessOptionValue options[])
Set the requested options for the process.
enum GNUNET_GenericReturnValue GNUNET_process_run_command_ap(struct GNUNET_Process *p, const char *filename, va_list va)
Set the command and start a process.
Definition os_process.c:866
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:363
struct GNUNET_Process * GNUNET_process_current()
Get process structure for current process.
Definition os_process.c:299
GNUNET_OS_ProcessStatusType
Process status types.
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.
pid_t GNUNET_process_get_pid(const struct GNUNET_Process *proc)
Get the pid of the process in question.
Definition os_process.c:356
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:307
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
Definition os_process.c:462
@ GNUNET_OS_INHERIT_STD_IN
When this flag is set, the child process will inherit stdin of the parent.
@ GNUNET_OS_INHERIT_STD_OUT
When this flag is set, the child process will inherit stdout of the parent.
@ GNUNET_OS_INHERIT_STD_ERR
When this flag is set, the child process will inherit stderr of the parent.
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
@ GNUNET_PROCESS_OPTION_INHERIT_FD
Option to inherit file descriptors.
@ GNUNET_PROCESS_OPTION_END
End of list of options.
@ GNUNET_PROCESS_OPTION_INHERIT_LSOCK
Option to inherit a listen socket systemd-style.
@ GNUNET_PROCESS_OPTION_SET_ENVIRONMENT
Option to set environment variables.
@ 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:1667
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:1345
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
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".
#define GNUNET_OS_CONTROL_PIPE
Definition os_process.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_process.c:189
static struct GNUNET_Process current_process
Handle for 'this' process.
Definition os_process.c:153
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition os_process.c:158
static int safe_dup2(int oldfd, int newfd)
Call dup2() in a way that races and interrupts are safely handled.
Definition os_process.c:401
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition os_process.c:36
static enum GNUNET_GenericReturnValue map_std(struct GNUNET_Process *proc, int fd, int flags)
Map the standard input/output/error file descriptor fd based on the mapping given in proc.
Definition os_process.c:519
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition os_process.c:172
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition os_process.c:163
#define LOG(kind,...)
Definition os_process.c:31
#define LOG_STRERROR(kind, syscall)
Definition os_process.c:33
static enum GNUNET_GenericReturnValue clear_cloexec(int fd)
Clear the close-on-exec flag of fd.
Definition os_process.c:480
static enum GNUNET_GenericReturnValue open_dev_null(int target_fd, int flags)
Open '/dev/null' and make the result the given file descriptor.
Definition os_process.c:432
static enum GNUNET_GenericReturnValue process_start(struct GNUNET_Process *proc)
Definition os_process.c:545
Key-value pairs for setenv().
Definition os_process.c:76
char * value
Value of the environment variable.
Definition os_process.c:85
char * key
Environment key to use.
Definition os_process.c:80
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Possible options we can set for a process.
struct GNUNET_ProcessOptionValue::@34::@35 set_environment
Value of if option is GNUNET_PROCESS_OPTION_SET_ENVIRONMENT.
int target_fd
File descriptor in the target process.
const char * key
Name of the environment variable to set.
struct GNUNET_ProcessOptionValue::@34::@36 inherit_fd
Value of if option is GNUNET_PROCESS_OPTION_INHERIT_FD.
int parent_fd
File descriptor in the parent process (must be open!).
enum GNUNET_ProcessOption option
Type of the option being set.
const char * value
Value to set, NULL to clear.
union GNUNET_ProcessOptionValue::@34 details
Specific option value.
int inherit_lsock
Value of if option is GNUNET_PROCESS_OPTION_INHERIT_LSOCK.
struct EnviEntry * envs
Environment variables to set in the target process.
Definition os_process.c:126
enum GNUNET_OS_ProcessStatusType exit_type
Runtime status of the process.
Definition os_process.c:141
unsigned int envs_size
Length of the envs.
Definition os_process.c:121
pid_t pid
PID of the process.
Definition os_process.c:94
enum GNUNET_OS_InheritStdioFlags std_inheritance
What to do with stdin/stdout/stderr unless already specified in the file map.
Definition os_process.c:106
struct ProcessFileMapEntry * map
Map of file descriptors to keep and dup2 for the new process.
Definition os_process.c:116
char * filename
Name of the binary to execute.
Definition os_process.c:131
char ** argv
Command-line arguments to pass, NULL-terminated.
Definition os_process.c:136
unsigned long exit_code
Exit status code of the process, interpretation depends on exit_type.
Definition os_process.c:146
unsigned int map_size
Length of the map.
Definition os_process.c:111
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition os_process.c:100
Entry in list of pending tasks.
Definition scheduler.c:141
Mapping of file descriptors of the current process to (desired) file descriptors of the child process...
Definition os_process.c:48
int parent_fd
Original file descriptor of the parent process.
Definition os_process.c:57
bool systemd_listen_socket
True if this descriptor should be passed in the style of a systemd listen socket with the respective ...
Definition os_process.c:63
int target_fd
File descriptor to be used in the target process, -1 if it does not matter.
Definition os_process.c:52
bool owned
True if we own this socket (and thus should also close it).
Definition os_process.c:68