GNUnet 0.26.2-114-g7c6b613e3
 
Loading...
Searching...
No Matches
os_process.c File Reference

process management More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "disk.h"
Include dependency graph for os_process.c:

Go to the source code of this file.

Data Structures

struct  ProcessFileMapEntry
 Mapping of file descriptors of the current process to (desired) file descriptors of the child process. More...
 
struct  EnviEntry
 Key-value pairs for setenv(). More...
 
struct  GNUNET_Process
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util-os-process", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)    GNUNET_log_from_strerror (kind, "util-os-process", syscall)
 
#define LOG_STRERROR_FILE(kind, syscall, filename)
 
#define GNUNET_OS_CONTROL_PIPE   "GNUNET_OS_CONTROL_PIPE"
 

Functions

static void shutdown_pch (void *cls)
 This handler is called on shutdown to remove the pch.
 
static void parent_control_handler (void *cls)
 This handler is called when there are control data to be read on the pipe.
 
void GNUNET_process_install_parent_control_handler ()
 Connects this process to its parent via pipe; essentially, the parent control handler will read signal numbers from the GNUNET_OS_CONTROL_PIPE (as given in an environment variable) and raise those signals.
 
struct GNUNET_ProcessGNUNET_process_current ()
 Get process structure for current process.
 
enum GNUNET_GenericReturnValue GNUNET_process_kill (struct GNUNET_Process *proc, int sig)
 Sends a signal to the process.
 
pid_t GNUNET_process_get_pid (const struct GNUNET_Process *proc)
 Get the pid of the process in question.
 
void GNUNET_process_destroy (struct GNUNET_Process *proc)
 Cleans up process structure contents (OS-dependent) and deallocates it.
 
static int safe_dup2 (int oldfd, int newfd)
 Call dup2() in a way that races and interrupts are safely handled.
 
static enum GNUNET_GenericReturnValue open_dev_null (int target_fd, int flags)
 Open '/dev/null' and make the result the given file descriptor.
 
struct GNUNET_ProcessGNUNET_process_create (enum GNUNET_OS_InheritStdioFlags std_inheritance)
 Create a process handle.
 
static enum GNUNET_GenericReturnValue clear_cloexec (int fd)
 Clear the close-on-exec flag of fd.
 
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.
 
static enum GNUNET_GenericReturnValue process_start (struct GNUNET_Process *proc)
 
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.
 
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.
 
enum GNUNET_GenericReturnValue GNUNET_process_run_command_va (struct GNUNET_Process *p, const char *filename,...)
 Set the command and start a process.
 
enum GNUNET_GenericReturnValue GNUNET_process_run_command (struct GNUNET_Process *p, const char *command)
 Set the command and start a process.
 
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_wait (struct GNUNET_Process *proc, bool blocking, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
 Wait for a process to terminate.
 

Variables

static struct GNUNET_Process current_process
 Handle for 'this' process.
 
static struct GNUNET_SCHEDULER_Taskpch
 Handle for the parent_control_handler() Task.
 
static struct GNUNET_SCHEDULER_Taskspch
 Handle for the shutdown_pch() Task.
 

Detailed Description

process management

Author
Nils Durner
Christian Grothoff

Definition in file os_process.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "util-os-process", __VA_ARGS__)

Definition at line 31 of file os_process.c.

◆ LOG_STRERROR

#define LOG_STRERROR (   kind,
  syscall 
)     GNUNET_log_from_strerror (kind, "util-os-process", syscall)

Definition at line 33 of file os_process.c.

47{
51 int target_fd;
52
56 int parent_fd;
57
62 bool systemd_listen_socket;
63
67 bool owned;
68};
69
70
74struct EnviEntry
75{
79 char *key;
80
84 char *value;
85};
86
87
88struct GNUNET_Process
89{
93 pid_t pid;
94
100
106
110 unsigned int map_size;
111
115 struct ProcessFileMapEntry *map;
116
120 unsigned int envs_size;
121
125 struct EnviEntry *envs;
126
130 char *filename;
131
135 char **argv;
136
141
145 unsigned long exit_code;
146};
147
148
152static struct GNUNET_Process current_process;
153
157static struct GNUNET_SCHEDULER_Task *pch;
158
162static struct GNUNET_SCHEDULER_Task *spch;
163
164
170static void
171shutdown_pch (void *cls)
172{
173 struct GNUNET_DISK_FileHandle *control_pipe = cls;
174
176 pch = NULL;
177 GNUNET_DISK_file_close (control_pipe);
178 control_pipe = NULL;
179}
180
181
187static void
188parent_control_handler (void *cls)
189{
190 struct GNUNET_DISK_FileHandle *control_pipe = cls;
191 char sig;
192 ssize_t ret;
193
194 pch = NULL;
195 ret = GNUNET_DISK_file_read (control_pipe,
196 &sig,
197 sizeof(sig));
198 if (sizeof(sig) != ret)
199 {
200 if (-1 == ret)
202 "GNUNET_DISK_file_read");
204 "Closing control pipe\n");
205 GNUNET_DISK_file_close (control_pipe);
207 spch = NULL;
208 return;
209 }
211 "Got control code %d from parent via pipe\n",
212 sig);
214 control_pipe,
216 control_pipe);
217 GNUNET_SIGNAL_raise ((int) sig);
218}
219
220
221void
223{
224 const char *env_buf;
225 char *env_buf_end;
226 struct GNUNET_DISK_FileHandle *control_pipe;
227 uint64_t pipe_fd;
228
229 if (NULL != pch)
230 {
231 /* already done, we've been called twice... */
232 GNUNET_break (0);
233 return;
234 }
235 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
236 if ( (NULL == env_buf) ||
237 (strlen (env_buf) <= 0) )
238 {
240 "Not installing a handler because $%s is empty\n",
242 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
243 return;
244 }
245 errno = 0;
246 pipe_fd = strtoull (env_buf,
247 &env_buf_end,
248 16);
249 if ( (0 != errno) ||
250 (env_buf == env_buf_end) )
251 {
253 "strtoull",
254 env_buf);
256 "",
257 1);
258 return;
259 }
260 if (pipe_fd >= FD_SETSIZE)
261 {
263 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
264 env_buf);
266 "",
267 1);
268 return;
269 }
270
271 control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
272 if (NULL == control_pipe)
273 {
275 "open",
276 env_buf);
278 "",
279 1);
280 return;
281 }
283 "Adding parent control handler pipe `%s' to the scheduler\n",
284 env_buf);
286 control_pipe,
288 control_pipe);
290 control_pipe);
292 "",
293 1);
294}
295
296
297struct GNUNET_Process *
299{
301 return &current_process;
302}
303
304
307 int sig)
308{
309 if (NULL != proc->control_pipe)
310 {
311 char csig = (char) sig;
312 ssize_t iret;
313
315 "Sending signal %d to pid: %u via pipe\n",
316 sig,
317 proc->pid);
319 &csig,
320 sizeof(csig));
321 if (sizeof(csig) == iret)
322 return GNUNET_OK;
323 }
324 /* pipe failed or non-existent, try other methods */
325 if (-1 == proc->pid)
326 {
328 "Refusing to send signal %d process `%s': not running\n",
329 sig,
330 proc->filename);
331 return GNUNET_NO; /* -1 means process is not running, refuse... */
332 }
334 "Sending signal %d to pid: %u via system call\n",
335 sig,
336 proc->pid);
337 {
338 int ret;
339
340 ret = kill (proc->pid,
341 sig);
342 if (0 != ret)
343 {
345 "kill");
346 }
347 return (0 == ret)
348 ? GNUNET_OK
350 }
351}
352
353
354pid_t
355GNUNET_process_get_pid (const struct GNUNET_Process *proc)
356{
357 return proc->pid;
358}
359
360
361void
363{
364 if (NULL != proc->control_pipe)
366 GNUNET_free (proc->filename);
367 for (unsigned int i = 0; i < proc->envs_size; i++)
368 {
369 GNUNET_free (proc->envs[i].key);
370 GNUNET_free (proc->envs[i].value);
371 }
372 GNUNET_free (proc->envs);
373 for (unsigned int i = 0; i < proc->map_size; i++)
374 {
375 struct ProcessFileMapEntry *me = &proc->map[i];
376 int pfd = me->parent_fd;
377
378 if (-1 == pfd)
379 continue;
380 if (! me->owned)
381 continue;
382 GNUNET_break (0 == close (pfd));
383 }
384 GNUNET_free (proc->map);
385 for (unsigned int i = 0; NULL != proc->argv[i]; i++)
386 GNUNET_free (proc->argv[i]);
387 GNUNET_free (proc->argv);
388 GNUNET_free (proc);
389}
390
391
399static int
400safe_dup2 (int oldfd,
401 int newfd)
402{
403 int ret;
404
405 while (1)
406 {
407 ret = dup2 (oldfd,
408 newfd);
409 if (-1 != ret)
410 break;
411 if ( (EBADF == errno) ||
412 (EINVAL == errno) ||
413 (EMFILE == errno) )
414 break;
415 /* should be EBUSY/EINTR, so try again */
417 "dup2");
418 }
419 return ret;
420}
421
422
432 int flags)
433{
434 int fd;
435
436 fd = open ("/dev/null",
437 flags);
438 if (-1 == fd)
439 {
441 "open",
442 "/dev/null");
443 return GNUNET_SYSERR;
444 }
445 if (fd == target_fd)
446 return GNUNET_OK;
447 if (-1 == dup2 (fd,
448 target_fd))
449 {
451 "dup2");
452 GNUNET_break (0 == close (fd));
453 return GNUNET_SYSERR;
454 }
455 GNUNET_break (0 == close (fd));
456 return GNUNET_OK;
457}
458
459
460struct GNUNET_Process *
462{
463 struct GNUNET_Process *p;
464
465 p = GNUNET_new (struct GNUNET_Process);
466 p->pid = -1;
468 return p;
469}
470
471
479clear_cloexec (int fd)
480{
481 int flags;
482
483 flags = fcntl (fd,
484 F_GETFD);
485 if (flags == -1)
486 {
488 "fcntl(F_GETFD)");
489 return GNUNET_SYSERR;
490 }
491
492 flags &= ~FD_CLOEXEC;
493
494 if (-1 ==
495 fcntl (fd,
496 F_SETFD,
497 flags))
498 {
500 "fcntl(F_SETFD)");
501 return GNUNET_SYSERR;
502 }
503 return GNUNET_OK;
504}
505
506
518map_std (struct GNUNET_Process *proc,
519 int fd,
520 int flags)
521{
522 for (unsigned int i=0; i<proc->map_size; i++)
523 {
524 struct ProcessFileMapEntry *me = &proc->map[i];
525
526 if (fd == me->target_fd)
527 {
528 if (fd !=
529 safe_dup2 (me->parent_fd,
530 fd))
531 return GNUNET_SYSERR;
532 if (me->owned)
533 GNUNET_break (0 == close (me->parent_fd));
534 me->parent_fd = -1;
535 return GNUNET_OK;
536 }
537 }
538 return open_dev_null (fd,
539 flags);
540}
541
542
544process_start (struct GNUNET_Process *proc)
545{
546 pid_t ret;
547 int childpipe_read_fd;
548
549 if (-1 != proc->pid)
550 {
551 GNUNET_break (0);
552 return GNUNET_SYSERR;
553 }
554 if (NULL == proc->filename)
555 {
556 GNUNET_break (0);
557 return GNUNET_SYSERR;
558 }
559
561 {
562 struct GNUNET_DISK_PipeHandle *childpipe;
563 struct GNUNET_DISK_FileHandle *childpipe_read;
564 int dup_childpipe_read_fd = -1;
565
567 if (NULL == childpipe)
568 {
569 GNUNET_break (0);
570 return GNUNET_SYSERR;
571 }
572 childpipe_read =
575 proc->control_pipe =
578 GNUNET_DISK_pipe_close (childpipe);
579 if ( (NULL == childpipe_read) ||
580 (NULL == proc->control_pipe) ||
581 (GNUNET_OK !=
582 GNUNET_DISK_internal_file_handle_ (childpipe_read,
583 &childpipe_read_fd)) ||
584 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
585 {
586 GNUNET_break (0);
587 if (NULL != childpipe_read)
588 GNUNET_DISK_file_close (childpipe_read);
589 if (NULL != proc->control_pipe)
590 {
592 proc->control_pipe = NULL;
593 }
594 return GNUNET_SYSERR;
595 }
596 childpipe_read_fd = dup_childpipe_read_fd;
597 GNUNET_DISK_file_close (childpipe_read);
598 }
599 else
600 {
601 childpipe_read_fd = -1;
602 }
603
604 {
605 /* Make sure none of the parent_fds conflict with the target_fds in the client process */
606 unsigned int max_fd = 3; /* never use stdin/stdout/stderr */
607 unsigned int pos;
608
609 for (unsigned int i=0; i<proc->map_size; i++)
610 {
611 struct ProcessFileMapEntry *me = &proc->map[i];
612
613 max_fd = GNUNET_MAX (max_fd,
614 me->target_fd);
615 }
616 pos = max_fd + 1;
617 for (unsigned int i=0; i<proc->map_size; i++)
618 {
619 struct ProcessFileMapEntry *me = &proc->map[i];
620
621 if (me->parent_fd < pos)
622 {
623 if (me->target_fd == me->parent_fd)
624 {
625 /* same FD, so no conflict, but make sure FD is not closed
626 on exec() */
627 clear_cloexec (me->parent_fd);
628 }
629 else
630 {
631 int dst;
632
633 /* search for FD that is not yet open */
634 while (-1 !=
635 fcntl (pos,
636 F_GETFD))
637 pos++;
638 while (1)
639 {
640 dst = dup2 (me->parent_fd,
641 pos);
642 if (-1 != dst)
643 break;
644 if ( (EBADF == errno) ||
645 (EINVAL == errno) ||
646 (EMFILE == errno) )
647 {
648 GNUNET_break (0);
649 return GNUNET_SYSERR;
650 }
651 /* leaves interrupt/busy, try again */
652 }
653 if (me->owned)
654 GNUNET_break (0 == close (me->parent_fd));
655 me->parent_fd = dst;
656 me->owned = true;
657 }
658 }
659 }
660 }
661
662 ret = fork ();
663 if (-1 == ret)
664 {
665 int eno = errno;
666
668 "fork");
669 if (NULL != proc->control_pipe)
670 {
672 proc->control_pipe = NULL;
673 }
674 if (0 <= childpipe_read_fd)
675 GNUNET_break (0 == close (childpipe_read_fd));
676 errno = eno;
677 return GNUNET_SYSERR;
678 }
679 if (0 != ret)
680 {
681 proc->pid = ret;
682 if (0 <= childpipe_read_fd)
683 GNUNET_break (0 == close (childpipe_read_fd));
684 for (unsigned int i=0; i<proc->map_size; i++)
685 {
686 struct ProcessFileMapEntry *me = &proc->map[i];
687
688 if (! me->owned)
689 continue;
690 if (-1 != me->parent_fd)
691 {
692 GNUNET_assert (0 ==
693 close (me->parent_fd));
694 me->parent_fd = -1;
695 }
696 }
697 return GNUNET_OK;
698 }
699
700 /* in child process! */
701
702 /* deploy control pipe */
703 if (0 <= childpipe_read_fd)
704 {
705 char fdbuf[100];
706
708 snprintf (fdbuf,
709 sizeof (fdbuf),
710 "%x",
711 childpipe_read_fd);
712 GNUNET_assert (0 ==
714 fdbuf,
715 1));
716 }
717 else
718 {
719 GNUNET_assert (0 ==
720 unsetenv (GNUNET_OS_CONTROL_PIPE));
721 }
722
723 /* map stdin/stdout/stderr */
724 if (0 == (proc->std_inheritance & GNUNET_OS_INHERIT_STD_IN))
725 {
727 map_std (proc,
728 STDIN_FILENO,
729 O_RDONLY));
730 }
732 {
734 map_std (proc,
735 STDOUT_FILENO,
736 O_WRONLY));
737 }
739 {
741 map_std (proc,
742 STDERR_FILENO,
743 O_WRONLY));
744 }
745
746 /* map all other file descriptors */
747 {
748 char *fdnames = GNUNET_strdup ("");
749 unsigned int total_lfds = 0;
750
751 for (unsigned int i=0; i<proc->map_size; i++)
752 {
753 struct ProcessFileMapEntry *me = &proc->map[i];
754
755 if (-1 == me->parent_fd)
756 continue; /* already taken care of */
757 if (-1 == me->target_fd)
758 {
759 me->target_fd = dup (me->parent_fd);
760 GNUNET_assert (-1 != me->target_fd);
761 if (me->owned)
762 GNUNET_assert (0 == close (me->parent_fd));
763 }
764 else if (me->parent_fd != me->target_fd)
765 {
766 GNUNET_assert (me->target_fd ==
767 safe_dup2 (me->parent_fd,
768 me->target_fd));
769 if (me->owned)
770 GNUNET_assert (0 == close (me->parent_fd));
771 }
772 else
773 {
774 GNUNET_assert (! me->systemd_listen_socket);
775 GNUNET_assert (me->owned);
777 clear_cloexec (me->target_fd));
778 }
779 me->parent_fd = -1;
780 if (me->systemd_listen_socket)
781 {
782 char *tmp;
783
784 GNUNET_asprintf (&tmp,
785 "%s:%d",
786 fdnames,
787 me->target_fd);
788 GNUNET_free (fdnames);
789 fdnames = tmp;
790 total_lfds++;
791 }
792 }
793 if (0 != total_lfds)
794 {
795 char fds[16];
796
797 GNUNET_snprintf (fds,
798 sizeof(fds),
799 "%u",
800 total_lfds);
801 GNUNET_assert (0 ==
802 setenv ("LISTEN_FDS",
803 fds,
804 1));
805 GNUNET_assert (0 ==
806 setenv ("LISTEN_FDNAMES",
807 fdnames + 1, /* skip leading ':' */
808 1));
809 }
810 GNUNET_free (fdnames);
811 }
812
813 /* setup environment */
814 for (unsigned int i=0; i<proc->envs_size; i++)
815 {
816 struct EnviEntry *ee = &proc->envs[i];
817
818 if (NULL == ee->value)
819 GNUNET_assert (0 ==
820 unsetenv (ee->key));
821 else
822 GNUNET_assert (0 ==
823 setenv (ee->key,
824 ee->value,
825 1));
826 }
827
828 /* finally execute */
829 execvp (proc->filename,
830 proc->argv);
832 "execvp",
833 proc->filename);
834 _exit (1);
835}
836
837
840 struct GNUNET_Process *p,
841 const char *filename,
842 const char **argv)
843{
844 int argc;
845
846 if (GNUNET_SYSERR ==
848 GNUNET_NO,
849 NULL))
850 return GNUNET_SYSERR; /* not executable */
851 GNUNET_assert (NULL == p->argv);
853 argc = 0;
854 while (NULL != argv[argc])
855 argc++;
856 p->argv = GNUNET_new_array (argc + 1,
857 char *);
858 for (argc = 0; NULL != argv[argc]; argc++)
859 p->argv[argc] = GNUNET_strdup (argv[argc]);
860 return process_start (p);
861}
862
863
866 struct GNUNET_Process *p,
867 const char *filename,
868 va_list va)
869{
870 va_list ap;
871 const char *av;
872 int argc;
873
874 if (GNUNET_SYSERR ==
876 GNUNET_NO,
877 NULL))
878 return GNUNET_SYSERR; /* not executable */
879 GNUNET_assert (NULL == p->argv);
881 argc = 0;
882 va_copy (ap,
883 va);
884 while (NULL != va_arg (ap,
885 const char *))
886 argc++;
887 va_end (ap);
888 p->argv = GNUNET_new_array (argc + 1,
889 char *);
890 argc = 0;
891 va_copy (ap,
892 va);
893 while (NULL != (av = va_arg (ap,
894 const char *)))
895 p->argv[argc++] = GNUNET_strdup (av);
896 va_end (ap);
897 return process_start (p);
898}
899
900
903 const char *filename,
904 ...)
905{
907 va_list ap;
908
909 va_start (ap,
910 filename);
912 filename,
913 ap);
914 va_end (ap);
915 return ret;
916}
917
918
921 const char *command)
922{
923 char *cmd = GNUNET_strdup (command);
924 size_t len = strlen (command);
925 size_t cnt = 1;
926 size_t start = 0;
927 bool quote_on = false;
928 size_t i;
929 size_t skip = 0;
930
931 GNUNET_assert (NULL == p->argv);
932 for (i=0; i<len; i++)
933 {
934 char c = cmd[i];
935
936 switch (c)
937 {
938 case '"':
939 quote_on = ! quote_on;
940 break;
941 case '\\':
942 i++;
943 break;
944 case ' ':
945 if (! quote_on)
946 cnt++;
947 while (' ' == cmd[i + 1])
948 i++;
949 break;
950 }
951 }
952
953 p->argv = GNUNET_new_array (cnt + 1,
954 char *);
955 cnt = 0;
956 for (i=0; i<len; i++)
957 {
958 char c = cmd[i];
959
960 switch (c)
961 {
962 case '"':
963 quote_on = ! quote_on;
964 skip++;
965 break;
966 case ' ':
967 if ( (! quote_on) &&
968 (i != start) )
969 {
970 p->argv[cnt] = GNUNET_strndup (&cmd[start],
971 i - start - skip);
972 cnt++;
973 skip = 0;
974 }
975 while (' ' == cmd[i + 1])
976 i++;
977 if (! quote_on)
978 start = i + 1;
979 break;
980 case '\\':
981 i++;
982 skip++;
983 cmd[i - skip] = cmd[i];
984 break;
985 default:
986 cmd[i - skip] = c;
987 break;
988 }
989 }
990 if (i != start)
991 p->argv[cnt] = GNUNET_strndup (&cmd[start],
992 i - start);
993 GNUNET_free (cmd);
994 if (quote_on)
995 {
997 "Cmd `%s' has imbalanced quotes\n",
998 cmd);
999 }
1000 if (NULL == p->argv[0])
1001 {
1003 "Empty command specified, cannot execute\n");
1004 return GNUNET_SYSERR;
1005 }
1006 if (GNUNET_SYSERR ==
1008 GNUNET_NO,
1009 NULL))
1010 {
1012 "Specified binary `%s' is not executable\n",
1013 p->argv[0]);
1014 return GNUNET_SYSERR;
1015 }
1016 p->filename = GNUNET_strdup (p->argv[0]);
1017 return process_start (p);
1018}
1019
1020
1023 struct GNUNET_Process *proc,
1024 unsigned int num_options,
1025 const struct GNUNET_ProcessOptionValue options[])
1026{
1027 for (unsigned int i=0; i<num_options; i++)
1028 {
1029 const struct GNUNET_ProcessOptionValue *ov = &options[i];
1030
1031 switch (ov->option)
1032 {
1034 return GNUNET_OK;
1036 {
1037 struct EnviEntry ee = {
1039 };
1040
1041 if (NULL != ov->details.set_environment.value)
1044 proc->envs_size,
1045 ee);
1046 }
1047 continue;
1049 {
1050 struct ProcessFileMapEntry pme = {
1052 .parent_fd = ov->details.inherit_fd.parent_fd,
1053 .owned = true
1054 };
1055
1056 GNUNET_array_append (proc->map,
1057 proc->map_size,
1058 pme);
1059 }
1060 continue;
1062 {
1063 struct ProcessFileMapEntry pme = {
1064 .target_fd = -1, /* any */
1065 .parent_fd = ov->details.inherit_lsock,
1066 .systemd_listen_socket = true,
1067 .owned = false
1068 };
1069
1070 GNUNET_array_append (proc->map,
1071 proc->map_size,
1072 pme);
1073 }
1074 continue;
1075 }
1076 GNUNET_break (0);
1077 return GNUNET_SYSERR;
1078 }
1079 return GNUNET_OK;
1080}
1081
1082
1085 bool blocking,
1087 unsigned long *code)
1088{
1089 pid_t ret;
1090 int status;
1091
1092 if (-1 == proc->pid)
1093 {
1094 if (NULL != type)
1095 *type = proc->exit_type;
1096 if (NULL != code)
1097 *code = proc->exit_code;
1098 return GNUNET_OK;
1099 }
1100 while (proc->pid !=
1101 (ret = waitpid (proc->pid,
1102 &status,
1103 blocking ? 0 : WNOHANG)))
1104 {
1105 if ( (! blocking) &&
1106 (EINTR == errno) )
1107 {
1108 ret = 0;
1109 break;
1110 }
1111 if (EINTR != errno)
1112 break;
1113 }
1114 if (0 == ret)
1115 {
1116 if (NULL != type)
1118 if (NULL != code)
1119 *code = 0;
1120 return GNUNET_NO;
1121 }
1122#ifdef WIFCONTINUED
1123 if ( (proc->pid == ret) &&
1124 (WIFCONTINUED (status)) )
1125 {
1126 if (NULL != type)
1128 if (NULL != code)
1129 *code = 0;
1130 return GNUNET_NO;
1131 }
1132#endif
1133 if (proc->pid != ret)
1134 {
1136 "waitpid");
1137 return GNUNET_SYSERR;
1138 }
1139 /* process did exit! */
1140 proc->pid = -1;
1141 if (WIFEXITED (status))
1142 {
1144 proc->exit_code = WEXITSTATUS (status);
1145 }
1146 else if (WIFSIGNALED (status))
1147 {
1149 proc->exit_code = WTERMSIG (status);
1150 }
1151 else if (WIFSTOPPED (status))
1152 {
1154 proc->exit_code = WSTOPSIG (status);
1155 }
1156 else
1157 {
1159 proc->exit_code = 0;
1160 }
1161 if (NULL != type)
1162 *type = proc->exit_type;
1163 if (NULL != code)
1164 *code = proc->exit_code;
1165 return GNUNET_OK;
1166}
1167
1168
1169/* 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
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 target_fd
File descriptor to be used in the target process, -1 if it does not matter.
Definition os_process.c:52

◆ LOG_STRERROR_FILE

#define LOG_STRERROR_FILE (   kind,
  syscall,
  filename 
)
Value:
GNUNET_log_from_strerror_file (kind, "util-os-process", syscall, \
#define GNUNET_log_from_strerror_file(level, component, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...

Definition at line 36 of file os_process.c.

◆ GNUNET_OS_CONTROL_PIPE

#define GNUNET_OS_CONTROL_PIPE   "GNUNET_OS_CONTROL_PIPE"

Definition at line 40 of file os_process.c.

Function Documentation

◆ shutdown_pch()

static void shutdown_pch ( void *  cls)
static

This handler is called on shutdown to remove the pch.

Parameters
clsthe struct GNUNET_DISK_FileHandle of the control pipe

Definition at line 172 of file os_process.c.

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}

References GNUNET_DISK_file_close(), GNUNET_SCHEDULER_cancel(), and pch.

Referenced by GNUNET_process_install_parent_control_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parent_control_handler()

static void parent_control_handler ( void *  cls)
static

This handler is called when there are control data to be read on the pipe.

Parameters
clsthe struct GNUNET_DISK_FileHandle of the control pipe

Definition at line 189 of file os_process.c.

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}

References GNUNET_DISK_file_close(), GNUNET_DISK_file_read(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_cancel(), GNUNET_SIGNAL_raise(), GNUNET_TIME_UNIT_FOREVER_REL, LOG, LOG_STRERROR, parent_control_handler(), pch, ret, and spch.

Referenced by GNUNET_process_install_parent_control_handler(), and parent_control_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ safe_dup2()

static int safe_dup2 ( int  oldfd,
int  newfd 
)
static

Call dup2() in a way that races and interrupts are safely handled.

Parameters
oldfdold file descriptor
newfdnew file descriptor
Returns
result of dup2()

Definition at line 401 of file os_process.c.

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}

References GNUNET_ERROR_TYPE_WARNING, GNUNET_log_strerror, and ret.

Referenced by map_std(), and process_start().

Here is the caller graph for this function:

◆ open_dev_null()

static enum GNUNET_GenericReturnValue open_dev_null ( int  target_fd,
int  flags 
)
static

Open '/dev/null' and make the result the given file descriptor.

Parameters
target_fddesired FD to point to /dev/null
flagsopen flags (O_RDONLY, O_WRONLY)
Returns
GNUNET_OK on success

Definition at line 432 of file os_process.c.

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}

References GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, GNUNET_log_strerror_file, GNUNET_OK, GNUNET_SYSERR, and ProcessFileMapEntry::target_fd.

Referenced by map_std().

Here is the caller graph for this function:

◆ clear_cloexec()

static enum GNUNET_GenericReturnValue clear_cloexec ( int  fd)
static

Clear the close-on-exec flag of fd.

Parameters
fdfile descriptor to modify
Returns
GNUNET_OK on success

Definition at line 480 of file os_process.c.

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}

References GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, GNUNET_OK, and GNUNET_SYSERR.

Referenced by process_start().

Here is the caller graph for this function:

◆ map_std()

static enum GNUNET_GenericReturnValue map_std ( struct GNUNET_Process proc,
int  fd,
int  flags 
)
static

Map the standard input/output/error file descriptor fd based on the mapping given in proc.

If fd is not explicitly mapped, use /dev/null with the given flags.

Parameters
procprocess with mapping information
fdfile descriptor to map
flagsflags to use with /dev/null
Returns
GNUNET_OK on success

Definition at line 519 of file os_process.c.

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}

References GNUNET_break, GNUNET_OK, GNUNET_SYSERR, GNUNET_Process::map, GNUNET_Process::map_size, me, open_dev_null(), and safe_dup2().

Referenced by process_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_start()

static enum GNUNET_GenericReturnValue process_start ( struct GNUNET_Process proc)
static

Definition at line 545 of file os_process.c.

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}

References GNUNET_Process::argv, clear_cloexec(), GNUNET_Process::control_pipe, GNUNET_Process::envs, GNUNET_Process::envs_size, GNUNET_Process::filename, GNUNET_asprintf(), GNUNET_assert, GNUNET_break, GNUNET_DISK_file_close(), GNUNET_DISK_internal_file_handle_(), GNUNET_DISK_PF_NONE, GNUNET_DISK_pipe(), GNUNET_DISK_pipe_close(), GNUNET_DISK_pipe_detach_end(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_PIPE_END_WRITE, GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_MAX, GNUNET_OK, GNUNET_OS_CONTROL_PIPE, GNUNET_OS_INHERIT_STD_ERR, GNUNET_OS_INHERIT_STD_IN, GNUNET_OS_INHERIT_STD_OUT, GNUNET_OS_USE_PIPE_CONTROL, GNUNET_snprintf(), GNUNET_strdup, GNUNET_SYSERR, EnviEntry::key, LOG_STRERROR, LOG_STRERROR_FILE, GNUNET_Process::map, GNUNET_Process::map_size, map_std(), me, GNUNET_Process::pid, ret, safe_dup2(), GNUNET_Process::std_inheritance, and EnviEntry::value.

Referenced by GNUNET_process_run_command(), GNUNET_process_run_command_ap(), and GNUNET_process_run_command_argv().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ current_process

struct GNUNET_Process current_process
static

Handle for 'this' process.

Definition at line 153 of file os_process.c.

Referenced by GNUNET_process_current().

◆ pch

struct GNUNET_SCHEDULER_Task* pch
static

◆ spch

struct GNUNET_SCHEDULER_Task* spch
static

Handle for the shutdown_pch() Task.

Definition at line 163 of file os_process.c.

Referenced by GNUNET_process_install_parent_control_handler(), and parent_control_handler().