47{
51 int target_fd;
52
56 int parent_fd;
57
62 bool systemd_listen_socket;
63};
64
65
70{
75
80};
81
82
84{
89
95
101
106
111
116
121
126
131
136
141};
142
143
148
153
158
159
165static void
167{
169
173 control_pipe = NULL;
174}
175
176
182static void
184{
186 char sig;
188
191 &sig,
192 sizeof(sig));
193 if (
sizeof(sig) !=
ret)
194 {
197 "GNUNET_DISK_file_read");
199 "Closing control pipe\n");
203 return;
204 }
206 "Got control code %d from parent via pipe\n",
207 sig);
209 control_pipe,
211 control_pipe);
213}
214
215
216void
218{
219 const char *env_buf;
220 char *env_buf_end;
222 uint64_t pipe_fd;
223
225 {
226
228 return;
229 }
231 if ( (NULL == env_buf) ||
232 (strlen (env_buf) <= 0) )
233 {
235 "Not installing a handler because $%s is empty\n",
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
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
294{
297}
298
299
302 int sig)
303{
305 {
306 char csig = (char) sig;
307 ssize_t iret;
308
310 "Sending signal %d to pid: %u via pipe\n",
311 sig,
314 &csig,
315 sizeof(csig));
316 if (sizeof(csig) == iret)
318 }
319
321 "Sending signal %d to pid: %u via system call\n",
322 sig,
324 {
326
328 sig);
330 {
332 "kill");
333 }
337 }
338}
339
340
341pid_t
343{
345}
346
347
348void
350{
354 for (
unsigned int i = 0; i < proc->
envs_size; i++)
355 {
358 }
360 for (
unsigned int i = 0; i < proc->
map_size; i++)
361 {
363
364 if (-1 == pfd)
365 continue;
367 }
369 for (
unsigned int i = 0; NULL != proc->
argv[i]; i++)
373}
374
375
383static int
385 int newfd)
386{
388
389 while (1)
390 {
392 newfd);
394 break;
395 if ( (EBADF == errno) ||
396 (EINVAL == errno) ||
397 (EMFILE == errno) )
398 break;
399
401 "dup2");
402 }
404}
405
406
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");
428 }
429 if (fd == target_fd)
431 if (-1 == dup2 (fd,
432 target_fd))
433 {
435 "dup2");
438 }
441}
442
443
446{
448
453}
454
455
464{
465 int flags;
466
467 flags = fcntl (fd,
468 F_GETFD);
469 if (flags == -1)
470 {
472 "fcntl(F_GETFD)");
474 }
475
476 flags &= ~FD_CLOEXEC;
477
478 if (-1 ==
479 fcntl (fd,
480 F_SETFD,
481 flags))
482 {
484 "fcntl(F_SETFD)");
486 }
488}
489
490
499{
500 int flags;
501
502 flags = fcntl (fd,
503 F_GETFD);
504 if (flags == -1)
505 {
507 "fcntl(F_GETFD)");
509 }
510
511 flags |= FD_CLOEXEC;
512
513 if (-1 ==
514 fcntl (fd,
515 F_SETFD,
516 flags))
517 {
519 "fcntl(F_SETFD)");
521 }
523}
524
525
538 int fd,
539 int flags)
540{
541 for (
unsigned int i=0; i<proc->
map_size; i++)
542 {
544
545 if (fd ==
me->target_fd)
546 {
547 if (fd !=
549 fd))
554 }
555 }
557 flags);
558}
559
560
563{
565 int childpipe_read_fd;
566
568 {
571 }
573 {
576 }
577
579 {
582 int dup_childpipe_read_fd = -1;
583
585 if (NULL == childpipe)
586 {
589 }
590 childpipe_read =
597 if ( (NULL == childpipe_read) ||
601 &childpipe_read_fd)) ||
602 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
603 {
605 if (NULL != childpipe_read)
608 {
611 }
613 }
614 childpipe_read_fd = dup_childpipe_read_fd;
616 }
617 else
618 {
619 childpipe_read_fd = -1;
620 }
621
622 {
623
624 unsigned int max_fd = 3;
625 unsigned int pos;
626
627 for (
unsigned int i=0; i<proc->
map_size; i++)
628 {
630
633 }
634 pos = max_fd + 1;
635 for (
unsigned int i=0; i<proc->
map_size; i++)
636 {
638
639 if (
me->parent_fd < pos)
640 {
641 if (
me->target_fd ==
me->parent_fd)
642 {
643
644
646 }
647 else
648 {
649 int dst;
650
651
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 {
668 }
669
670 }
673 }
674 }
675 }
676 }
677
680 {
681 int eno = errno;
682
684 "fork");
686 {
689 }
690 if (0 <= childpipe_read_fd)
692 errno = eno;
694 }
696 {
698 if (0 <= childpipe_read_fd)
700 for (
unsigned int i=0; i<proc->
map_size; i++)
701 {
703
705 close (
me->parent_fd));
707 }
709 }
710
711
712
713
714 if (0 <= childpipe_read_fd)
715 {
716 char fdbuf[100];
717
719 snprintf (fdbuf,
720 sizeof (fdbuf),
721 "%x",
722 childpipe_read_fd);
725 fdbuf,
726 1));
727 }
728 else
729 {
732 }
733
734
736 {
739 STDIN_FILENO,
740 O_RDONLY));
741 }
743 {
746 STDOUT_FILENO,
747 O_WRONLY));
748 }
750 {
753 STDERR_FILENO,
754 O_WRONLY));
755 }
756
757
758 {
760 unsigned int total_lfds = 0;
761
762 for (
unsigned int i=0; i<proc->
map_size; i++)
763 {
765
766 if (-1 ==
me->parent_fd)
767 continue;
768 if (-1 ==
me->target_fd)
769 {
770 me->target_fd = dup (
me->parent_fd);
772 }
773 else if (
me->parent_fd !=
me->target_fd)
774 {
778 }
783 if (
me->systemd_listen_socket)
784 {
785 char *tmp;
786
788 "%s:%d",
789 fdnames,
792 fdnames = tmp;
793 total_lfds++;
794 }
795 }
796 if (0 != total_lfds)
797 {
798 char fds[16];
799
801 sizeof(fds),
802 "%u",
803 total_lfds);
805 setenv ("LISTEN_FDS",
806 fds,
807 1));
809 setenv ("LISTEN_FDNAMES",
810 fdnames + 1,
811 1));
812 }
814 }
815
816
817 for (
unsigned int i=0; i<proc->
envs_size; i++)
818 {
820
821 if (NULL == ee->
value)
824 else
828 1));
829 }
830
831
835 "execvp",
837 _exit (1);
838}
839
840
845 const char **argv)
846{
847 const char *av;
848 int argc;
849
853 NULL))
857 argc = 0;
858 while (NULL != argv[argc])
859 argc++;
861 char *);
862 for (argc = 0; NULL != argv[argc]; argc++)
865}
866
867
872 va_list va)
873{
874 va_list ap;
875 const char *av;
876 int argc;
877
881 NULL))
885 argc = 0;
886 va_copy (ap,
887 va);
888 while (NULL != va_arg (ap,
889 const char *))
890 argc++;
891 va_end (ap);
893 char *);
894 argc = 0;
895 va_copy (ap,
896 va);
897 while (NULL != (av = va_arg (ap,
898 const char *)))
900 va_end (ap);
902}
903
904
908 ...)
909{
911 va_list ap;
912
913 va_start (ap,
917 ap);
918 va_end (ap);
920}
921
922
925 const char *command)
926{
928 size_t len = strlen (command);
929 size_t cnt = 1;
931 bool quote_on = false;
932 size_t i;
933 size_t skip = 0;
934
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
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) &&
973 {
976 cnt++;
977 skip = 0;
978 }
979 while (' ' == cmd[i + 1])
980 i++;
981 if (! quote_on)
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 }
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");
1009 }
1013 NULL))
1014 {
1016 "Specified binary `%s' is not executable\n",
1019 }
1022}
1023
1024
1028 unsigned int num_options,
1030{
1031 for (unsigned int i=0; i<num_options; i++)
1032 {
1034
1036 {
1041 continue;
1043 {
1046 };
1047
1052 ee);
1053 }
1054 continue;
1056 {
1060 };
1061
1064 pme);
1065 }
1066 continue;
1068 {
1072 .systemd_listen_socket = true
1073 };
1074
1077 pme);
1078 }
1079 continue;
1080 }
1083 }
1085}
1086
1087
1090 bool blocking,
1092 unsigned long *code)
1093{
1096
1097 if (-1 == proc->
pid)
1098 {
1101 if (NULL != code)
1104 }
1105 while ( (proc->
pid !=
1106 (
ret = waitpid (proc->
pid,
1108 blocking ? 0 : WNOHANG))) &&
1109 (EINTR == errno) )
1110 ;
1112 {
1115 if (NULL != code)
1116 *code = 0;
1118 }
1119#ifdef WIFCONTINUED
1120 if ( (proc->
pid ==
ret) &&
1121 (WIFCONTINUED (
status)) )
1122 {
1125 if (NULL != code)
1126 *code = 0;
1128 }
1129#endif
1131 {
1133 "waitpid");
1135 }
1136
1139 {
1142 }
1143 else if (WIFSIGNALED (
status))
1144 {
1147 }
1148 else if (WIFSTOPPED (
status))
1149 {
1152 }
1153 else
1154 {
1157 }
1160 if (NULL != code)
1163}
1164
1165
1166
struct GNUNET_GETOPT_CommandLineOption options[]
enum GNUNET_GenericReturnValue GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, int *dst)
Retrieve OS file handle.
static int start
Set if we are to start default services (including ARM).
static int ret
Final status code.
static GNUNET_NETWORK_STRUCT_END struct GNUNET_PeerIdentity me
Our own peer identity.
static uint32_t type
Type string converted to DNS type value.
static int status
The program status; 0 for success.
static struct GNUNET_Process * p
Helper process we started.
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.
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
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.
@ 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,...)
GNUNET_GenericReturnValue
Named constants for return values.
#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...
struct GNUNET_Process * GNUNET_process_create()
Create a process handle.
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_command_ap(struct GNUNET_Process *p, const char *filename, va_list va)
Set the command to start a 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.
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.
enum GNUNET_GenericReturnValue GNUNET_process_start(struct GNUNET_Process *proc)
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.
struct GNUNET_Process * GNUNET_process_current()
Get process structure for current process.
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.
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.
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
@ 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...
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,...
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
void GNUNET_SIGNAL_raise(const int sig)
Raise the given signal by calling the installed signal handlers.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_OS_CONTROL_PIPE
static void parent_control_handler(void *cls)
This handler is called when there are control data to be read on the pipe.
static enum GNUNET_GenericReturnValue set_cloexec(int fd)
Set the close-on-exec flag of fd.
static struct GNUNET_Process current_process
Handle for 'this' process.
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
static int safe_dup2(int oldfd, int newfd)
Call dup2() in a way that races and interrupts are safely handled.
#define LOG_STRERROR_FILE(kind, syscall, filename)
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 void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
#define LOG_STRERROR(kind, syscall)
static enum GNUNET_GenericReturnValue clear_cloexec(int fd)
Clear the close-on-exec flag of fd.
static enum GNUNET_GenericReturnValue open_dev_null(int target_fd, int flags)
Open '/dev/null' and make the result the given file descriptor.
Key-value pairs for setenv().
char * value
Value of the environment variable.
char * key
Environment key to use.
Handle used to access files (and pipes).
Handle used to manage a pipe.
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.
enum GNUNET_OS_ProcessStatusType exit_type
Runtime status of the process.
unsigned int envs_size
Length of the envs.
pid_t pid
PID of the process.
enum GNUNET_OS_InheritStdioFlags std_inheritance
What to do with stdin/stdout/stderr unless already specified in the file map.
struct ProcessFileMapEntry * map
Map of file descriptors to keep and dup2 for the new process.
char * filename
Name of the binary to execute.
char ** argv
Command-line arguments to pass, NULL-terminated.
unsigned long exit_code
Exit status code of the process, interpretation depends on exit_type.
unsigned int map_size
Length of the map.
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Entry in list of pending tasks.
Mapping of file descriptors of the current process to (desired) file descriptors of the child process...
int parent_fd
Original file descriptor of the parent process.
int target_fd
File descriptor to be used in the target process, -1 if it does not matter.