GNUnet 0.28.1-dev.5-1-gae1c02d74
 
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 if (NULL != proc->argv)
387 {
388 for (unsigned int i = 0; NULL != proc->argv[i]; i++)
389 GNUNET_free (proc->argv[i]);
390 GNUNET_free (proc->argv);
391 }
392 GNUNET_free (proc);
393}
394
395
403static int
404safe_dup2 (int oldfd,
405 int newfd)
406{
407 int ret;
408
409 while (1)
410 {
411 ret = dup2 (oldfd,
412 newfd);
413 if (-1 != ret)
414 break;
415 if ( (EBADF == errno) ||
416 (EINVAL == errno) ||
417 (EMFILE == errno) )
418 break;
419 /* should be EBUSY/EINTR, so try again */
421 "dup2");
422 }
423 return ret;
424}
425
426
436 int flags)
437{
438 int fd;
439
440 fd = open ("/dev/null",
441 flags);
442 if (-1 == fd)
443 {
445 "open",
446 "/dev/null");
447 return GNUNET_SYSERR;
448 }
449 if (fd == target_fd)
450 return GNUNET_OK;
451 if (-1 == dup2 (fd,
452 target_fd))
453 {
455 "dup2");
456 GNUNET_break (0 == close (fd));
457 return GNUNET_SYSERR;
458 }
459 GNUNET_break (0 == close (fd));
460 return GNUNET_OK;
461}
462
463
464struct GNUNET_Process *
474
475
484{
485 int flags;
486
487 flags = fcntl (fd,
488 F_GETFD);
489 if (flags == -1)
490 {
492 "fcntl(F_GETFD)");
493 return GNUNET_SYSERR;
494 }
495
496 flags &= ~FD_CLOEXEC;
497
498 if (-1 ==
499 fcntl (fd,
500 F_SETFD,
501 flags))
502 {
504 "fcntl(F_SETFD)");
505 return GNUNET_SYSERR;
506 }
507 return GNUNET_OK;
508}
509
510
523 int fd,
524 int flags)
525{
526 for (unsigned int i=0; i<proc->map_size; i++)
527 {
528 struct ProcessFileMapEntry *me = &proc->map[i];
529
530 if (fd == me->target_fd)
531 {
532 if (fd !=
533 safe_dup2 (me->parent_fd,
534 fd))
535 return GNUNET_SYSERR;
536 if (me->owned)
537 GNUNET_break (0 == close (me->parent_fd));
538 me->parent_fd = -1;
539 return GNUNET_OK;
540 }
541 }
542 return open_dev_null (fd,
543 flags);
544}
545
546
549{
550 pid_t ret;
551 int childpipe_read_fd;
552
553 if (-1 != proc->pid)
554 {
555 GNUNET_break (0);
556 return GNUNET_SYSERR;
557 }
558 if (NULL == proc->filename)
559 {
560 GNUNET_break (0);
561 return GNUNET_SYSERR;
562 }
563
565 {
566 struct GNUNET_DISK_PipeHandle *childpipe;
567 struct GNUNET_DISK_FileHandle *childpipe_read;
568 int dup_childpipe_read_fd = -1;
569
571 if (NULL == childpipe)
572 {
573 GNUNET_break (0);
574 return GNUNET_SYSERR;
575 }
576 childpipe_read =
579 proc->control_pipe =
582 GNUNET_DISK_pipe_close (childpipe);
583 if ( (NULL == childpipe_read) ||
584 (NULL == proc->control_pipe) ||
585 (GNUNET_OK !=
586 GNUNET_DISK_internal_file_handle_ (childpipe_read,
587 &childpipe_read_fd)) ||
588 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
589 {
590 GNUNET_break (0);
591 if (NULL != childpipe_read)
592 GNUNET_DISK_file_close (childpipe_read);
593 if (NULL != proc->control_pipe)
594 {
596 proc->control_pipe = NULL;
597 }
598 return GNUNET_SYSERR;
599 }
600 childpipe_read_fd = dup_childpipe_read_fd;
601 GNUNET_DISK_file_close (childpipe_read);
602 }
603 else
604 {
605 childpipe_read_fd = -1;
606 }
607
608 {
609 /* Make sure none of the parent_fds conflict with the target_fds in the client process */
610 unsigned int max_fd = 3; /* never use stdin/stdout/stderr */
611 unsigned int pos;
612
613 for (unsigned int i=0; i<proc->map_size; i++)
614 {
615 struct ProcessFileMapEntry *me = &proc->map[i];
616
617 max_fd = GNUNET_MAX (max_fd,
618 me->target_fd);
619 }
620 pos = max_fd + 1;
621 for (unsigned int i=0; i<proc->map_size; i++)
622 {
623 struct ProcessFileMapEntry *me = &proc->map[i];
624
625 if (me->parent_fd < pos)
626 {
627 if (me->target_fd == me->parent_fd)
628 {
629 /* same FD, so no conflict, but make sure FD is not closed
630 on exec() */
631 clear_cloexec (me->parent_fd);
632 }
633 else
634 {
635 int dst;
636
637 /* search for FD that is not yet open */
638 while (-1 !=
639 fcntl (pos,
640 F_GETFD))
641 pos++;
642 while (1)
643 {
644 dst = dup2 (me->parent_fd,
645 pos);
646 if (-1 != dst)
647 break;
648 if ( (EBADF == errno) ||
649 (EINVAL == errno) ||
650 (EMFILE == errno) )
651 {
652 GNUNET_break (0);
653 return GNUNET_SYSERR;
654 }
655 /* leaves interrupt/busy, try again */
656 }
657 if (me->owned)
658 GNUNET_break (0 == close (me->parent_fd));
659 me->parent_fd = dst;
660 me->owned = true;
661 }
662 }
663 }
664 }
665
666 ret = fork ();
667 if (-1 == ret)
668 {
669 int eno = errno;
670
672 "fork");
673 if (NULL != proc->control_pipe)
674 {
676 proc->control_pipe = NULL;
677 }
678 if (0 <= childpipe_read_fd)
679 GNUNET_break (0 == close (childpipe_read_fd));
680 errno = eno;
681 return GNUNET_SYSERR;
682 }
683 if (0 != ret)
684 {
685 proc->pid = ret;
686 if (0 <= childpipe_read_fd)
687 GNUNET_break (0 == close (childpipe_read_fd));
688 for (unsigned int i=0; i<proc->map_size; i++)
689 {
690 struct ProcessFileMapEntry *me = &proc->map[i];
691
692 if (! me->owned)
693 continue;
694 if (-1 != me->parent_fd)
695 {
696 GNUNET_assert (0 ==
697 close (me->parent_fd));
698 me->parent_fd = -1;
699 }
700 }
701 return GNUNET_OK;
702 }
703
704 /* in child process! */
705
706 /* deploy control pipe */
707 if (0 <= childpipe_read_fd)
708 {
709 char fdbuf[100];
710
712 snprintf (fdbuf,
713 sizeof (fdbuf),
714 "%x",
715 childpipe_read_fd);
716 GNUNET_assert (0 ==
718 fdbuf,
719 1));
720 }
721 else
722 {
723 GNUNET_assert (0 ==
724 unsetenv (GNUNET_OS_CONTROL_PIPE));
725 }
726
727 /* map stdin/stdout/stderr */
728 if (0 == (proc->std_inheritance & GNUNET_OS_INHERIT_STD_IN))
729 {
731 map_std (proc,
732 STDIN_FILENO,
733 O_RDONLY));
734 }
736 {
738 map_std (proc,
739 STDOUT_FILENO,
740 O_WRONLY));
741 }
743 {
745 map_std (proc,
746 STDERR_FILENO,
747 O_WRONLY));
748 }
749
750 /* map all other file descriptors */
751 {
752 char *fdnames = GNUNET_strdup ("");
753 unsigned int total_lfds = 0;
754
755 for (unsigned int i=0; i<proc->map_size; i++)
756 {
757 struct ProcessFileMapEntry *me = &proc->map[i];
758
759 if (-1 == me->parent_fd)
760 continue; /* already taken care of */
761 if (-1 == me->target_fd)
762 {
763 me->target_fd = dup (me->parent_fd);
764 GNUNET_assert (-1 != me->target_fd);
765 if (me->owned)
766 GNUNET_assert (0 == close (me->parent_fd));
767 }
768 else if (me->parent_fd != me->target_fd)
769 {
770 GNUNET_assert (me->target_fd ==
771 safe_dup2 (me->parent_fd,
772 me->target_fd));
773 if (me->owned)
774 GNUNET_assert (0 == close (me->parent_fd));
775 }
776 else
777 {
778 GNUNET_assert (! me->systemd_listen_socket);
779 GNUNET_assert (me->owned);
781 clear_cloexec (me->target_fd));
782 }
783 me->parent_fd = -1;
784 if (me->systemd_listen_socket)
785 {
786 char *tmp;
787
788 GNUNET_asprintf (&tmp,
789 "%s:%d",
790 fdnames,
791 me->target_fd);
792 GNUNET_free (fdnames);
793 fdnames = tmp;
794 total_lfds++;
795 }
796 }
797 if (0 != total_lfds)
798 {
799 char fds[16];
800
801 GNUNET_snprintf (fds,
802 sizeof(fds),
803 "%u",
804 total_lfds);
805 GNUNET_assert (0 ==
806 setenv ("LISTEN_FDS",
807 fds,
808 1));
809 GNUNET_assert (0 ==
810 setenv ("LISTEN_FDNAMES",
811 fdnames + 1, /* skip leading ':' */
812 1));
813 }
814 GNUNET_free (fdnames);
815 }
816
817 /* setup environment */
818 for (unsigned int i=0; i<proc->envs_size; i++)
819 {
820 struct EnviEntry *ee = &proc->envs[i];
821
822 if (NULL == ee->value)
823 GNUNET_assert (0 ==
824 unsetenv (ee->key));
825 else
826 GNUNET_assert (0 ==
827 setenv (ee->key,
828 ee->value,
829 1));
830 }
831
832 /* finally execute */
833 execvp (proc->filename,
834 proc->argv);
836 "execvp",
837 proc->filename);
838 _exit (1);
839}
840
841
844 struct GNUNET_Process *p,
845 const char *filename,
846 const char **argv)
847{
848 int argc;
849
850 if (GNUNET_SYSERR ==
852 GNUNET_NO,
853 NULL))
854 return GNUNET_SYSERR; /* not executable */
855 GNUNET_assert (NULL == p->argv);
857 argc = 0;
858 while (NULL != argv[argc])
859 argc++;
860 p->argv = GNUNET_new_array (argc + 1,
861 char *);
862 for (argc = 0; NULL != argv[argc]; argc++)
863 p->argv[argc] = GNUNET_strdup (argv[argc]);
864 return process_start (p);
865}
866
867
870 struct GNUNET_Process *p,
871 const char *filename,
872 va_list va)
873{
874 va_list ap;
875 const char *av;
876 int argc;
877
878 if (GNUNET_SYSERR ==
880 GNUNET_NO,
881 NULL))
882 return GNUNET_SYSERR; /* not executable */
883 GNUNET_assert (NULL == p->argv);
885 argc = 0;
886 va_copy (ap,
887 va);
888 while (NULL != va_arg (ap,
889 const char *))
890 argc++;
891 va_end (ap);
892 p->argv = GNUNET_new_array (argc + 1,
893 char *);
894 argc = 0;
895 va_copy (ap,
896 va);
897 while (NULL != (av = va_arg (ap,
898 const char *)))
899 p->argv[argc++] = GNUNET_strdup (av);
900 va_end (ap);
901 return process_start (p);
902}
903
904
907 const char *filename,
908 ...)
909{
911 va_list ap;
912
913 va_start (ap,
914 filename);
916 filename,
917 ap);
918 va_end (ap);
919 return ret;
920}
921
922
925 const char *command)
926{
927 char *cmd = GNUNET_strdup (command);
928 size_t len = strlen (command);
929 size_t cnt = 1;
930 size_t start = 0;
931 bool quote_on = false;
932 size_t i;
933 size_t skip = 0;
934
935 GNUNET_assert (NULL == p->argv);
936 for (i=0; i<len; i++)
937 {
938 char c = cmd[i];
939
940 switch (c)
941 {
942 case '"':
943 quote_on = ! quote_on;
944 break;
945 case '\\':
946 i++;
947 break;
948 case ' ':
949 if (! quote_on)
950 cnt++;
951 while (' ' == cmd[i + 1])
952 i++;
953 break;
954 }
955 }
956
957 p->argv = GNUNET_new_array (cnt + 1,
958 char *);
959 cnt = 0;
960 for (i=0; i<len; i++)
961 {
962 char c = cmd[i];
963
964 switch (c)
965 {
966 case '"':
967 quote_on = ! quote_on;
968 skip++;
969 break;
970 case ' ':
971 if ( (! quote_on) &&
972 (i != start) )
973 {
974 p->argv[cnt] = GNUNET_strndup (&cmd[start],
975 i - start - skip);
976 cnt++;
977 skip = 0;
978 }
979 while (' ' == cmd[i + 1])
980 i++;
981 if (! quote_on)
982 start = i + 1;
983 break;
984 case '\\':
985 i++;
986 skip++;
987 cmd[i - skip] = cmd[i];
988 break;
989 default:
990 cmd[i - skip] = c;
991 break;
992 }
993 }
994 if (i != start)
995 p->argv[cnt] = GNUNET_strndup (&cmd[start],
996 i - start);
997 if (quote_on)
998 {
1000 "Cmd `%s' has imbalanced quotes\n",
1001 cmd);
1002 }
1003 GNUNET_free (cmd);
1004 if (NULL == p->argv[0])
1005 {
1007 "Empty command specified, cannot execute\n");
1008 return GNUNET_SYSERR;
1009 }
1010 if (GNUNET_SYSERR ==
1012 GNUNET_NO,
1013 NULL))
1014 {
1016 "Specified binary `%s' is not executable\n",
1017 p->argv[0]);
1018 return GNUNET_SYSERR;
1019 }
1020 p->filename = GNUNET_strdup (p->argv[0]);
1021 return process_start (p);
1022}
1023
1024
1027 struct GNUNET_Process *proc,
1028 unsigned int num_options,
1029 const struct GNUNET_ProcessOptionValue options[])
1030{
1031 for (unsigned int i=0; i<num_options; i++)
1032 {
1033 const struct GNUNET_ProcessOptionValue *ov = &options[i];
1034
1035 switch (ov->option)
1036 {
1038 return GNUNET_OK;
1040 {
1041 struct EnviEntry ee = {
1043 };
1044
1045 if (NULL != ov->details.set_environment.value)
1048 proc->envs_size,
1049 ee);
1050 }
1051 continue;
1053 {
1054 struct ProcessFileMapEntry pme = {
1056 .parent_fd = ov->details.inherit_fd.parent_fd,
1057 .owned = true
1058 };
1059
1060 GNUNET_array_append (proc->map,
1061 proc->map_size,
1062 pme);
1063 }
1064 continue;
1066 {
1067 struct ProcessFileMapEntry pme = {
1068 .target_fd = -1, /* any */
1069 .parent_fd = ov->details.inherit_lsock,
1070 .systemd_listen_socket = true,
1071 .owned = false
1072 };
1073
1074 GNUNET_array_append (proc->map,
1075 proc->map_size,
1076 pme);
1077 }
1078 continue;
1079 }
1080 GNUNET_break (0);
1081 return GNUNET_SYSERR;
1082 }
1083 return GNUNET_OK;
1084}
1085
1086
1089 bool blocking,
1091 unsigned long *code)
1092{
1093 pid_t ret;
1094 int status;
1095
1096 if (-1 == proc->pid)
1097 {
1098 if (NULL != type)
1099 *type = proc->exit_type;
1100 if (NULL != code)
1101 *code = proc->exit_code;
1102 return GNUNET_OK;
1103 }
1104 while (proc->pid !=
1105 (ret = waitpid (proc->pid,
1106 &status,
1107 blocking ? 0 : WNOHANG)))
1108 {
1109 if ( (! blocking) &&
1110 (EINTR == errno) )
1111 {
1112 ret = 0;
1113 break;
1114 }
1115 if (EINTR != errno)
1116 break;
1117 }
1118 if (0 == ret)
1119 {
1120 if (NULL != type)
1122 if (NULL != code)
1123 *code = 0;
1124 return GNUNET_NO;
1125 }
1126#ifdef WIFCONTINUED
1127 if ( (proc->pid == ret) &&
1128 (WIFCONTINUED (status)) )
1129 {
1130 if (NULL != type)
1132 if (NULL != code)
1133 *code = 0;
1134 return GNUNET_NO;
1135 }
1136#endif
1137 if (proc->pid != ret)
1138 {
1140 "waitpid");
1141 return GNUNET_SYSERR;
1142 }
1143 /* process did exit! */
1144 proc->pid = -1;
1145 if (WIFEXITED (status))
1146 {
1148 proc->exit_code = WEXITSTATUS (status);
1149 }
1150 else if (WIFSIGNALED (status))
1151 {
1153 proc->exit_code = WTERMSIG (status);
1154 }
1155 else if (WIFSTOPPED (status))
1156 {
1158 proc->exit_code = WSTOPSIG (status);
1159 }
1160 else
1161 {
1163 proc->exit_code = 0;
1164 }
1165 if (NULL != type)
1166 *type = proc->exit_type;
1167 if (NULL != code)
1168 *code = proc->exit_code;
1169 return GNUNET_OK;
1170}
1171
1172
1173/* 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:906
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:924
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:843
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:869
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:465
@ 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:404
#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:522
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:483
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:435
static enum GNUNET_GenericReturnValue process_start(struct GNUNET_Process *proc)
Definition os_process.c:548
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