GNUnet 0.26.2-32-gd298f7855
 
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 ()
 Create a process handle.
 
static enum GNUNET_GenericReturnValue clear_cloexec (int fd)
 Clear the close-on-exec flag of fd.
 
static enum GNUNET_GenericReturnValue set_cloexec (int fd)
 Set 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.
 
enum GNUNET_GenericReturnValue GNUNET_process_start (struct GNUNET_Process *proc)
 Start a process.
 
enum GNUNET_GenericReturnValue GNUNET_process_set_command_argv (struct GNUNET_Process *p, const char *filename, const char **argv)
 Set the command to start a process.
 
enum GNUNET_GenericReturnValue GNUNET_process_set_command_ap (struct GNUNET_Process *p, const char *filename, va_list va)
 Set the command to start a process.
 
enum GNUNET_GenericReturnValue GNUNET_process_set_command_va (struct GNUNET_Process *p, const char *filename,...)
 Set the command to start a process.
 
enum GNUNET_GenericReturnValue GNUNET_process_set_command (struct GNUNET_Process *p, const char *command)
 Set the command to 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};
64
65
69struct EnviEntry
70{
74 char *key;
75
79 char *value;
80};
81
82
83struct GNUNET_Process
84{
88 pid_t pid;
89
95
101
105 unsigned int map_size;
106
110 struct ProcessFileMapEntry *map;
111
115 unsigned int envs_size;
116
120 struct EnviEntry *envs;
121
125 char *filename;
126
130 char **argv;
131
136
140 unsigned long exit_code;
141};
142
143
147static struct GNUNET_Process current_process;
148
152static struct GNUNET_SCHEDULER_Task *pch;
153
157static struct GNUNET_SCHEDULER_Task *spch;
158
159
165static void
166shutdown_pch (void *cls)
167{
168 struct GNUNET_DISK_FileHandle *control_pipe = cls;
169
171 pch = NULL;
172 GNUNET_DISK_file_close (control_pipe);
173 control_pipe = NULL;
174}
175
176
182static void
183parent_control_handler (void *cls)
184{
185 struct GNUNET_DISK_FileHandle *control_pipe = cls;
186 char sig;
187 ssize_t ret;
188
189 pch = NULL;
190 ret = GNUNET_DISK_file_read (control_pipe,
191 &sig,
192 sizeof(sig));
193 if (sizeof(sig) != ret)
194 {
195 if (-1 == ret)
197 "GNUNET_DISK_file_read");
199 "Closing control pipe\n");
200 GNUNET_DISK_file_close (control_pipe);
202 spch = NULL;
203 return;
204 }
206 "Got control code %d from parent via pipe\n",
207 sig);
209 control_pipe,
211 control_pipe);
212 GNUNET_SIGNAL_raise ((int) sig);
213}
214
215
216void
218{
219 const char *env_buf;
220 char *env_buf_end;
221 struct GNUNET_DISK_FileHandle *control_pipe;
222 uint64_t pipe_fd;
223
224 if (NULL != pch)
225 {
226 /* already done, we've been called twice... */
227 GNUNET_break (0);
228 return;
229 }
230 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
231 if ( (NULL == env_buf) ||
232 (strlen (env_buf) <= 0) )
233 {
235 "Not installing a handler because $%s is empty\n",
237 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
238 return;
239 }
240 errno = 0;
241 pipe_fd = strtoull (env_buf,
242 &env_buf_end,
243 16);
244 if ( (0 != errno) ||
245 (env_buf == env_buf_end) )
246 {
248 "strtoull",
249 env_buf);
251 "",
252 1);
253 return;
254 }
255 if (pipe_fd >= FD_SETSIZE)
256 {
258 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
259 env_buf);
261 "",
262 1);
263 return;
264 }
265
266 control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
267 if (NULL == control_pipe)
268 {
270 "open",
271 env_buf);
273 "",
274 1);
275 return;
276 }
278 "Adding parent control handler pipe `%s' to the scheduler\n",
279 env_buf);
281 control_pipe,
283 control_pipe);
285 control_pipe);
287 "",
288 1);
289}
290
291
292struct GNUNET_Process *
294{
296 return &current_process;
297}
298
299
302 int sig)
303{
304 if (NULL != proc->control_pipe)
305 {
306 char csig = (char) sig;
307 ssize_t iret;
308
310 "Sending signal %d to pid: %u via pipe\n",
311 sig,
312 proc->pid);
314 &csig,
315 sizeof(csig));
316 if (sizeof(csig) == iret)
317 return GNUNET_OK;
318 }
319 /* pipe failed or non-existent, try other methods */
321 "Sending signal %d to pid: %u via system call\n",
322 sig,
323 proc->pid);
324 {
325 int ret;
326
327 ret = kill (proc->pid,
328 sig);
329 if (0 != ret)
330 {
332 "kill");
333 }
334 return (0 == ret)
335 ? GNUNET_OK
337 }
338}
339
340
341pid_t
342GNUNET_process_get_pid (const struct GNUNET_Process *proc)
343{
344 return proc->pid;
345}
346
347
348void
350{
351 if (NULL != proc->control_pipe)
353 GNUNET_free (proc->filename);
354 for (unsigned int i = 0; i < proc->envs_size; i++)
355 {
356 GNUNET_free (proc->envs[i].key);
357 GNUNET_free (proc->envs[i].value);
358 }
359 GNUNET_free (proc->envs);
360 for (unsigned int i = 0; i < proc->map_size; i++)
361 {
362 int pfd = proc->map[i].parent_fd;
363
364 if (-1 == pfd)
365 continue;
366 GNUNET_break (0 == close (pfd));
367 }
368 GNUNET_free (proc->map);
369 for (unsigned int i = 0; NULL != proc->argv[i]; i++)
370 GNUNET_free (proc->argv[i]);
371 GNUNET_free (proc->argv);
372 GNUNET_free (proc);
373}
374
375
383static int
384safe_dup2 (int oldfd,
385 int newfd)
386{
387 int ret;
388
389 while (1)
390 {
391 ret = dup2 (oldfd,
392 newfd);
393 if (-1 != ret)
394 break;
395 if ( (EBADF == errno) ||
396 (EINVAL == errno) ||
397 (EMFILE == errno) )
398 break;
399 /* should be EBUSY/EINTR, so try again */
401 "dup2");
402 }
403 return ret;
404}
405
406
415open_dev_null (int target_fd,
416 int flags)
417{
418 int fd;
419
420 fd = open ("/dev/null",
421 flags);
422 if (-1 == fd)
423 {
425 "open",
426 "/dev/null");
427 return GNUNET_SYSERR;
428 }
429 if (fd == target_fd)
430 return GNUNET_OK;
431 if (-1 == dup2 (fd,
432 target_fd))
433 {
435 "dup2");
436 GNUNET_break (0 == close (fd));
437 return GNUNET_SYSERR;
438 }
439 GNUNET_break (0 == close (fd));
440 return GNUNET_OK;
441}
442
443
444struct GNUNET_Process *
446{
447 struct GNUNET_Process *p;
448
449 p = GNUNET_new (struct GNUNET_Process);
450 p->pid = -1;
452 return p;
453}
454
455
463clear_cloexec (int fd)
464{
465 int flags;
466
467 flags = fcntl (fd,
468 F_GETFD);
469 if (flags == -1)
470 {
472 "fcntl(F_GETFD)");
473 return GNUNET_SYSERR;
474 }
475
476 flags &= ~FD_CLOEXEC;
477
478 if (-1 ==
479 fcntl (fd,
480 F_SETFD,
481 flags))
482 {
484 "fcntl(F_SETFD)");
485 return GNUNET_SYSERR;
486 }
487 return GNUNET_OK;
488}
489
490
498set_cloexec (int fd)
499{
500 int flags;
501
502 flags = fcntl (fd,
503 F_GETFD);
504 if (flags == -1)
505 {
507 "fcntl(F_GETFD)");
508 return GNUNET_SYSERR;
509 }
510
511 flags |= FD_CLOEXEC;
512
513 if (-1 ==
514 fcntl (fd,
515 F_SETFD,
516 flags))
517 {
519 "fcntl(F_SETFD)");
520 return GNUNET_SYSERR;
521 }
522 return GNUNET_OK;
523}
524
525
537map_std (struct GNUNET_Process *proc,
538 int fd,
539 int flags)
540{
541 for (unsigned int i=0; i<proc->map_size; i++)
542 {
543 struct ProcessFileMapEntry *me = &proc->map[i];
544
545 if (fd == me->target_fd)
546 {
547 if (fd !=
548 safe_dup2 (me->parent_fd,
549 fd))
550 return GNUNET_SYSERR;
551 GNUNET_break (0 == close (me->parent_fd));
552 me->parent_fd = -1;
553 return GNUNET_OK;
554 }
555 }
556 return open_dev_null (fd,
557 flags);
558}
559
560
563{
564 pid_t ret;
565 int childpipe_read_fd;
566
567 if (-1 != proc->pid)
568 {
569 GNUNET_break (0);
570 return GNUNET_SYSERR;
571 }
572 if (NULL == proc->filename)
573 {
574 GNUNET_break (0);
575 return GNUNET_SYSERR;
576 }
577
579 {
580 struct GNUNET_DISK_PipeHandle *childpipe;
581 struct GNUNET_DISK_FileHandle *childpipe_read;
582 int dup_childpipe_read_fd = -1;
583
585 if (NULL == childpipe)
586 {
587 GNUNET_break (0);
588 return GNUNET_SYSERR;
589 }
590 childpipe_read =
593 proc->control_pipe =
596 GNUNET_DISK_pipe_close (childpipe);
597 if ( (NULL == childpipe_read) ||
598 (NULL == proc->control_pipe) ||
599 (GNUNET_OK !=
600 GNUNET_DISK_internal_file_handle_ (childpipe_read,
601 &childpipe_read_fd)) ||
602 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
603 {
604 GNUNET_break (0);
605 if (NULL != childpipe_read)
606 GNUNET_DISK_file_close (childpipe_read);
607 if (NULL != proc->control_pipe)
608 {
610 proc->control_pipe = NULL;
611 }
612 return GNUNET_SYSERR;
613 }
614 childpipe_read_fd = dup_childpipe_read_fd;
615 GNUNET_DISK_file_close (childpipe_read);
616 }
617 else
618 {
619 childpipe_read_fd = -1;
620 }
621
622 {
623 /* Make sure none of the parent_fds conflict with the target_fds in the client process */
624 unsigned int max_fd = 3; /* never use stdin/stdout/stderr */
625 unsigned int pos;
626
627 for (unsigned int i=0; i<proc->map_size; i++)
628 {
629 struct ProcessFileMapEntry *me = &proc->map[i];
630
631 max_fd = GNUNET_MAX (max_fd,
632 me->target_fd);
633 }
634 pos = max_fd + 1;
635 for (unsigned int i=0; i<proc->map_size; i++)
636 {
637 struct ProcessFileMapEntry *me = &proc->map[i];
638
639 if (me->parent_fd < pos)
640 {
641 if (me->target_fd == me->parent_fd)
642 {
643 /* same FD, so no conflict, but make sure FD is not closed
644 on exec() */
645 clear_cloexec (me->parent_fd);
646 }
647 else
648 {
649 int dst;
650
651 /* search for FD that is not yet open */
652 while (-1 !=
653 fcntl (pos,
654 F_GETFD))
655 pos++;
656 while (1)
657 {
658 dst = dup2 (me->parent_fd,
659 pos);
660 if (-1 != dst)
661 break;
662 if ( (EBADF == errno) ||
663 (EINVAL == errno) ||
664 (EMFILE == errno) )
665 {
666 GNUNET_break (0);
667 return GNUNET_SYSERR;
668 }
669 /* leaves interrupt/busy, try again */
670 }
671 GNUNET_break (0 == close (me->parent_fd));
672 me->parent_fd = dst;
673 }
674 }
675 }
676 }
677
678 ret = fork ();
679 if (-1 == ret)
680 {
681 int eno = errno;
682
684 "fork");
685 if (NULL != proc->control_pipe)
686 {
688 proc->control_pipe = NULL;
689 }
690 if (0 <= childpipe_read_fd)
691 GNUNET_break (0 == close (childpipe_read_fd));
692 errno = eno;
693 return GNUNET_SYSERR;
694 }
695 if (0 != ret)
696 {
697 proc->pid = ret;
698 if (0 <= childpipe_read_fd)
699 GNUNET_break (0 == close (childpipe_read_fd));
700 for (unsigned int i=0; i<proc->map_size; i++)
701 {
702 struct ProcessFileMapEntry *me = &proc->map[i];
703
704 GNUNET_break (0 ==
705 close (me->parent_fd));
706 me->parent_fd = -1;
707 }
708 return GNUNET_OK;
709 }
710
711 /* in child process! */
712
713 /* deploy control pipe */
714 if (0 <= childpipe_read_fd)
715 {
716 char fdbuf[100];
717
719 snprintf (fdbuf,
720 sizeof (fdbuf),
721 "%x",
722 childpipe_read_fd);
723 GNUNET_assert (0 ==
725 fdbuf,
726 1));
727 }
728 else
729 {
730 GNUNET_assert (0 ==
731 unsetenv (GNUNET_OS_CONTROL_PIPE));
732 }
733
734 /* map stdin/stdout/stderr */
735 if (0 == (proc->std_inheritance & GNUNET_OS_INHERIT_STD_IN))
736 {
738 map_std (proc,
739 STDIN_FILENO,
740 O_RDONLY));
741 }
743 {
745 map_std (proc,
746 STDOUT_FILENO,
747 O_WRONLY));
748 }
750 {
752 map_std (proc,
753 STDERR_FILENO,
754 O_WRONLY));
755 }
756
757 /* map all other file descriptors */
758 {
759 char *fdnames = GNUNET_strdup ("");
760 unsigned int total_lfds = 0;
761
762 for (unsigned int i=0; i<proc->map_size; i++)
763 {
764 struct ProcessFileMapEntry *me = &proc->map[i];
765
766 if (-1 == me->parent_fd)
767 continue; /* already taken care of */
768 if (-1 == me->target_fd)
769 {
770 me->target_fd = dup (me->parent_fd);
771 GNUNET_assert (-1 != me->target_fd);
772 }
773 else if (me->parent_fd != me->target_fd)
774 {
775 GNUNET_assert (me->target_fd ==
776 safe_dup2 (me->parent_fd,
777 me->target_fd));
778 }
779 GNUNET_assert (0 == close (me->parent_fd));
780 me->parent_fd = -1;
782 set_cloexec (me->target_fd));
783 if (me->systemd_listen_socket)
784 {
785 char *tmp;
786
787 GNUNET_asprintf (&tmp,
788 "%s:%d",
789 fdnames,
790 me->target_fd);
791 GNUNET_free (fdnames);
792 fdnames = tmp;
793 total_lfds++;
794 }
795 }
796 if (0 != total_lfds)
797 {
798 char fds[16];
799
800 GNUNET_snprintf (fds,
801 sizeof(fds),
802 "%u",
803 total_lfds);
804 GNUNET_assert (0 ==
805 setenv ("LISTEN_FDS",
806 fds,
807 1));
808 GNUNET_assert (0 ==
809 setenv ("LISTEN_FDNAMES",
810 fdnames + 1, /* skip leading ':' */
811 1));
812 }
813 GNUNET_free (fdnames);
814 }
815
816 /* setup environment */
817 for (unsigned int i=0; i<proc->envs_size; i++)
818 {
819 struct EnviEntry *ee = &proc->envs[i];
820
821 if (NULL == ee->value)
822 GNUNET_assert (0 ==
823 unsetenv (ee->key));
824 else
825 GNUNET_assert (0 ==
826 setenv (ee->key,
827 ee->value,
828 1));
829 }
830
831 /* finally execute */
832 execvp (proc->filename,
833 proc->argv);
835 "execvp",
836 proc->filename);
837 _exit (1);
838}
839
840
843 struct GNUNET_Process *p,
844 const char *filename,
845 const char **argv)
846{
847 const char *av;
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 GNUNET_OK;
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 GNUNET_OK;
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;
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 GNUNET_free (cmd);
998 if (quote_on)
999 {
1001 "Cmd `%s' has imbalanced quotes\n",
1002 cmd);
1003 }
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 GNUNET_OK;
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;
1041 continue;
1043 {
1044 struct EnviEntry ee = {
1046 };
1047
1048 if (NULL != ov->details.set_environment.value)
1051 proc->envs_size,
1052 ee);
1053 }
1054 continue;
1056 {
1057 struct ProcessFileMapEntry pme = {
1059 .parent_fd = ov->details.inherit_fd.parent_fd
1060 };
1061
1062 GNUNET_array_append (proc->map,
1063 proc->map_size,
1064 pme);
1065 }
1066 continue;
1068 {
1069 struct ProcessFileMapEntry pme = {
1070 .target_fd = -1, /* any */
1071 .parent_fd = ov->details.inherit_fd.parent_fd,
1072 .systemd_listen_socket = true
1073 };
1074
1075 GNUNET_array_append (proc->map,
1076 proc->map_size,
1077 pme);
1078 }
1079 continue;
1080 }
1081 GNUNET_break (0);
1082 return GNUNET_SYSERR;
1083 }
1084 return GNUNET_OK;
1085}
1086
1087
1090 bool blocking,
1092 unsigned long *code)
1093{
1094 pid_t ret;
1095 int status;
1096
1097 if (-1 == proc->pid)
1098 {
1099 if (NULL != type)
1100 *type = proc->exit_type;
1101 if (NULL != code)
1102 *code = proc->exit_code;
1103 return GNUNET_OK;
1104 }
1105 while ( (proc->pid !=
1106 (ret = waitpid (proc->pid,
1107 &status,
1108 blocking ? 0 : WNOHANG))) &&
1109 (EINTR == errno) )
1110 ;
1111 if (0 == ret)
1112 {
1113 if (NULL != type)
1115 if (NULL != code)
1116 *code = 0;
1117 return GNUNET_NO;
1118 }
1119#ifdef WIFCONTINUED
1120 if ( (proc->pid == ret) &&
1121 (WIFCONTINUED (status)) )
1122 {
1123 if (NULL != type)
1125 if (NULL != code)
1126 *code = 0;
1127 return GNUNET_NO;
1128 }
1129#endif
1130 if (proc->pid != ret)
1131 {
1133 "waitpid");
1134 return GNUNET_SYSERR;
1135 }
1136 /* process did exit! */
1137 proc->pid = -1;
1138 if (WIFEXITED (status))
1139 {
1141 proc->exit_code = WEXITSTATUS (status);
1142 }
1143 else if (WIFSIGNALED (status))
1144 {
1146 proc->exit_code = WTERMSIG (status);
1147 }
1148 else if (WIFSTOPPED (status))
1149 {
1151 proc->exit_code = WSTOPSIG (status);
1152 }
1153 else
1154 {
1156 proc->exit_code = 0;
1157 }
1158 if (NULL != type)
1159 *type = proc->exit_type;
1160 if (NULL != code)
1161 *code = proc->exit_code;
1162 return GNUNET_OK;
1163}
1164
1165
1166/* 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:1719
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:1643
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:1523
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1670
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:1409
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:218
struct GNUNET_Process * GNUNET_process_create()
Create a process handle.
Definition os_process.c:446
enum GNUNET_GenericReturnValue GNUNET_process_set_command(struct GNUNET_Process *p, const char *command)
Set the command to start a process.
Definition os_process.c:925
enum GNUNET_GenericReturnValue GNUNET_process_set_command_ap(struct GNUNET_Process *p, const char *filename, va_list va)
Set the command to start a process.
Definition os_process.c:870
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.
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:350
enum GNUNET_GenericReturnValue GNUNET_process_start(struct GNUNET_Process *proc)
Start a process.
Definition os_process.c:563
enum GNUNET_GenericReturnValue GNUNET_process_set_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command to start a process.
Definition os_process.c:907
struct GNUNET_Process * GNUNET_process_current()
Get process structure for current process.
Definition os_process.c:294
GNUNET_OS_ProcessStatusType
Process status types.
enum GNUNET_GenericReturnValue GNUNET_process_set_command_argv(struct GNUNET_Process *p, const char *filename, const char **argv)
Set the command to start a process.
Definition os_process.c:843
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:343
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:302
@ 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_PROCESS_OPTION_STD_INHERITANCE
Option to set inheritance flags.
@ 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:184
static enum GNUNET_GenericReturnValue set_cloexec(int fd)
Set the close-on-exec flag of fd.
Definition os_process.c:499
static struct GNUNET_Process current_process
Handle for 'this' process.
Definition os_process.c:148
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition os_process.c:153
static int safe_dup2(int oldfd, int newfd)
Call dup2() in a way that races and interrupts are safely handled.
Definition os_process.c:385
#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:538
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition os_process.c:167
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition os_process.c:158
#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:464
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:416
Key-value pairs for setenv().
Definition os_process.c:71
char * value
Value of the environment variable.
Definition os_process.c:80
char * key
Environment key to use.
Definition os_process.c:75
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.
enum GNUNET_OS_InheritStdioFlags std_inheritance
Value of if option is GNUNET_PROCESS_OPTION_STD_INHERITANCE.
struct EnviEntry * envs
Environment variables to set in the target process.
Definition os_process.c:121
enum GNUNET_OS_ProcessStatusType exit_type
Runtime status of the process.
Definition os_process.c:136
unsigned int envs_size
Length of the envs.
Definition os_process.c:116
pid_t pid
PID of the process.
Definition os_process.c:89
enum GNUNET_OS_InheritStdioFlags std_inheritance
What to do with stdin/stdout/stderr unless already specified in the file map.
Definition os_process.c:101
struct ProcessFileMapEntry * map
Map of file descriptors to keep and dup2 for the new process.
Definition os_process.c:111
char * filename
Name of the binary to execute.
Definition os_process.c:126
char ** argv
Command-line arguments to pass, NULL-terminated.
Definition os_process.c:131
unsigned long exit_code
Exit status code of the process, interpretation depends on exit_type.
Definition os_process.c:141
unsigned int map_size
Length of the map.
Definition os_process.c:106
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition os_process.c:95
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
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 167 of file os_process.c.

168{
169 struct GNUNET_DISK_FileHandle *control_pipe = cls;
170
172 pch = NULL;
173 GNUNET_DISK_file_close (control_pipe);
174 control_pipe = NULL;
175}

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 184 of file os_process.c.

185{
186 struct GNUNET_DISK_FileHandle *control_pipe = cls;
187 char sig;
188 ssize_t ret;
189
190 pch = NULL;
191 ret = GNUNET_DISK_file_read (control_pipe,
192 &sig,
193 sizeof(sig));
194 if (sizeof(sig) != ret)
195 {
196 if (-1 == ret)
198 "GNUNET_DISK_file_read");
200 "Closing control pipe\n");
201 GNUNET_DISK_file_close (control_pipe);
203 spch = NULL;
204 return;
205 }
207 "Got control code %d from parent via pipe\n",
208 sig);
210 control_pipe,
212 control_pipe);
213 GNUNET_SIGNAL_raise ((int) sig);
214}

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 385 of file os_process.c.

387{
388 int ret;
389
390 while (1)
391 {
392 ret = dup2 (oldfd,
393 newfd);
394 if (-1 != ret)
395 break;
396 if ( (EBADF == errno) ||
397 (EINVAL == errno) ||
398 (EMFILE == errno) )
399 break;
400 /* should be EBUSY/EINTR, so try again */
402 "dup2");
403 }
404 return ret;
405}

References GNUNET_ERROR_TYPE_WARNING, GNUNET_log_strerror, and ret.

Referenced by GNUNET_process_start(), and map_std().

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 416 of file os_process.c.

418{
419 int fd;
420
421 fd = open ("/dev/null",
422 flags);
423 if (-1 == fd)
424 {
426 "open",
427 "/dev/null");
428 return GNUNET_SYSERR;
429 }
430 if (fd == target_fd)
431 return GNUNET_OK;
432 if (-1 == dup2 (fd,
433 target_fd))
434 {
436 "dup2");
437 GNUNET_break (0 == close (fd));
438 return GNUNET_SYSERR;
439 }
440 GNUNET_break (0 == close (fd));
441 return GNUNET_OK;
442}

References GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, GNUNET_log_strerror_file, GNUNET_OK, and GNUNET_SYSERR.

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 464 of file os_process.c.

465{
466 int flags;
467
468 flags = fcntl (fd,
469 F_GETFD);
470 if (flags == -1)
471 {
473 "fcntl(F_GETFD)");
474 return GNUNET_SYSERR;
475 }
476
477 flags &= ~FD_CLOEXEC;
478
479 if (-1 ==
480 fcntl (fd,
481 F_SETFD,
482 flags))
483 {
485 "fcntl(F_SETFD)");
486 return GNUNET_SYSERR;
487 }
488 return GNUNET_OK;
489}

References GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, GNUNET_OK, and GNUNET_SYSERR.

Referenced by GNUNET_process_start().

Here is the caller graph for this function:

◆ set_cloexec()

static enum GNUNET_GenericReturnValue set_cloexec ( int  fd)
static

Set the close-on-exec flag of fd.

Parameters
fdfile descriptor to modify
Returns
GNUNET_OK on success

Definition at line 499 of file os_process.c.

500{
501 int flags;
502
503 flags = fcntl (fd,
504 F_GETFD);
505 if (flags == -1)
506 {
508 "fcntl(F_GETFD)");
509 return GNUNET_SYSERR;
510 }
511
512 flags |= FD_CLOEXEC;
513
514 if (-1 ==
515 fcntl (fd,
516 F_SETFD,
517 flags))
518 {
520 "fcntl(F_SETFD)");
521 return GNUNET_SYSERR;
522 }
523 return GNUNET_OK;
524}

References GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, GNUNET_OK, and GNUNET_SYSERR.

Referenced by GNUNET_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 538 of file os_process.c.

541{
542 for (unsigned int i=0; i<proc->map_size; i++)
543 {
544 struct ProcessFileMapEntry *me = &proc->map[i];
545
546 if (fd == me->target_fd)
547 {
548 if (fd !=
549 safe_dup2 (me->parent_fd,
550 fd))
551 return GNUNET_SYSERR;
552 GNUNET_break (0 == close (me->parent_fd));
553 me->parent_fd = -1;
554 return GNUNET_OK;
555 }
556 }
557 return open_dev_null (fd,
558 flags);
559}

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

Referenced by GNUNET_process_start().

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 148 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 158 of file os_process.c.

Referenced by GNUNET_process_install_parent_control_handler(), and parent_control_handler().