47{
51 int target_fd;
52
56 int parent_fd;
57
62 bool systemd_listen_socket;
63
67 bool owned;
68};
69
70
75{
80
85};
86
87
89{
94
100
106
111
116
121
126
131
136
141
146};
147
148
153
158
163
164
170static void
172{
174
178 control_pipe = NULL;
179}
180
181
187static void
189{
191 char sig;
193
196 &sig,
197 sizeof(sig));
198 if (
sizeof(sig) !=
ret)
199 {
202 "GNUNET_DISK_file_read");
204 "Closing control pipe\n");
208 return;
209 }
211 "Got control code %d from parent via pipe\n",
212 sig);
214 control_pipe,
216 control_pipe);
218}
219
220
221void
223{
224 const char *env_buf;
225 char *env_buf_end;
227 uint64_t pipe_fd;
228
230 {
231
233 return;
234 }
236 if ( (NULL == env_buf) ||
237 (strlen (env_buf) <= 0) )
238 {
240 "Not installing a handler because $%s is empty\n",
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
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
299{
302}
303
304
307 int sig)
308{
310 {
311 char csig = (char) sig;
312 ssize_t iret;
313
315 "Sending signal %d to pid: %u via pipe\n",
316 sig,
319 &csig,
320 sizeof(csig));
321 if (sizeof(csig) == iret)
323 }
324
326 {
328 "Refusing to send signal %d process `%s': not running\n",
329 sig,
332 }
334 "Sending signal %d to pid: %u via system call\n",
335 sig,
337 {
339
341 sig);
343 {
345 "kill");
346 }
350 }
351}
352
353
354pid_t
356{
358}
359
360
361void
363{
367 for (
unsigned int i = 0; i < proc->
envs_size; i++)
368 {
371 }
373 for (
unsigned int i = 0; i < proc->
map_size; i++)
374 {
376 int pfd =
me->parent_fd;
377
378 if (-1 == pfd)
379 continue;
381 continue;
383 }
385 for (
unsigned int i = 0; NULL != proc->
argv[i]; i++)
389}
390
391
399static int
401 int newfd)
402{
404
405 while (1)
406 {
408 newfd);
410 break;
411 if ( (EBADF == errno) ||
412 (EINVAL == errno) ||
413 (EMFILE == errno) )
414 break;
415
417 "dup2");
418 }
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");
444 }
447 if (-1 == dup2 (fd,
449 {
451 "dup2");
454 }
457}
458
459
462{
464
469}
470
471
480{
481 int flags;
482
483 flags = fcntl (fd,
484 F_GETFD);
485 if (flags == -1)
486 {
488 "fcntl(F_GETFD)");
490 }
491
492 flags &= ~FD_CLOEXEC;
493
494 if (-1 ==
495 fcntl (fd,
496 F_SETFD,
497 flags))
498 {
500 "fcntl(F_SETFD)");
502 }
504}
505
506
519 int fd,
520 int flags)
521{
522 for (
unsigned int i=0; i<proc->
map_size; i++)
523 {
525
526 if (fd ==
me->target_fd)
527 {
528 if (fd !=
530 fd))
536 }
537 }
539 flags);
540}
541
542
545{
547 int childpipe_read_fd;
548
550 {
553 }
555 {
558 }
559
561 {
564 int dup_childpipe_read_fd = -1;
565
567 if (NULL == childpipe)
568 {
571 }
572 childpipe_read =
579 if ( (NULL == childpipe_read) ||
583 &childpipe_read_fd)) ||
584 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
585 {
587 if (NULL != childpipe_read)
590 {
593 }
595 }
596 childpipe_read_fd = dup_childpipe_read_fd;
598 }
599 else
600 {
601 childpipe_read_fd = -1;
602 }
603
604 {
605
606 unsigned int max_fd = 3;
607 unsigned int pos;
608
609 for (
unsigned int i=0; i<proc->
map_size; i++)
610 {
612
615 }
616 pos = max_fd + 1;
617 for (
unsigned int i=0; i<proc->
map_size; i++)
618 {
620
621 if (
me->parent_fd < pos)
622 {
623 if (
me->target_fd ==
me->parent_fd)
624 {
625
626
628 }
629 else
630 {
631 int dst;
632
633
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 {
650 }
651
652 }
657 }
658 }
659 }
660 }
661
664 {
665 int eno = errno;
666
668 "fork");
670 {
673 }
674 if (0 <= childpipe_read_fd)
676 errno = eno;
678 }
680 {
682 if (0 <= childpipe_read_fd)
684 for (
unsigned int i=0; i<proc->
map_size; i++)
685 {
687
689 continue;
690 if (-1 !=
me->parent_fd)
691 {
693 close (
me->parent_fd));
695 }
696 }
698 }
699
700
701
702
703 if (0 <= childpipe_read_fd)
704 {
705 char fdbuf[100];
706
708 snprintf (fdbuf,
709 sizeof (fdbuf),
710 "%x",
711 childpipe_read_fd);
714 fdbuf,
715 1));
716 }
717 else
718 {
721 }
722
723
725 {
728 STDIN_FILENO,
729 O_RDONLY));
730 }
732 {
735 STDOUT_FILENO,
736 O_WRONLY));
737 }
739 {
742 STDERR_FILENO,
743 O_WRONLY));
744 }
745
746
747 {
749 unsigned int total_lfds = 0;
750
751 for (
unsigned int i=0; i<proc->
map_size; i++)
752 {
754
755 if (-1 ==
me->parent_fd)
756 continue;
757 if (-1 ==
me->target_fd)
758 {
759 me->target_fd = dup (
me->parent_fd);
763 }
764 else if (
me->parent_fd !=
me->target_fd)
765 {
771 }
772 else
773 {
778 }
780 if (
me->systemd_listen_socket)
781 {
782 char *tmp;
783
785 "%s:%d",
786 fdnames,
789 fdnames = tmp;
790 total_lfds++;
791 }
792 }
793 if (0 != total_lfds)
794 {
795 char fds[16];
796
798 sizeof(fds),
799 "%u",
800 total_lfds);
802 setenv ("LISTEN_FDS",
803 fds,
804 1));
806 setenv ("LISTEN_FDNAMES",
807 fdnames + 1,
808 1));
809 }
811 }
812
813
814 for (
unsigned int i=0; i<proc->
envs_size; i++)
815 {
817
818 if (NULL == ee->
value)
821 else
825 1));
826 }
827
828
832 "execvp",
834 _exit (1);
835}
836
837
842 const char **argv)
843{
844 int argc;
845
849 NULL))
853 argc = 0;
854 while (NULL != argv[argc])
855 argc++;
857 char *);
858 for (argc = 0; NULL != argv[argc]; argc++)
861}
862
863
868 va_list va)
869{
870 va_list ap;
871 const char *av;
872 int argc;
873
877 NULL))
881 argc = 0;
882 va_copy (ap,
883 va);
884 while (NULL != va_arg (ap,
885 const char *))
886 argc++;
887 va_end (ap);
889 char *);
890 argc = 0;
891 va_copy (ap,
892 va);
893 while (NULL != (av = va_arg (ap,
894 const char *)))
896 va_end (ap);
898}
899
900
904 ...)
905{
907 va_list ap;
908
909 va_start (ap,
913 ap);
914 va_end (ap);
916}
917
918
921 const char *command)
922{
924 size_t len = strlen (command);
925 size_t cnt = 1;
927 bool quote_on = false;
928 size_t i;
929 size_t skip = 0;
930
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
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) &&
969 {
972 cnt++;
973 skip = 0;
974 }
975 while (' ' == cmd[i + 1])
976 i++;
977 if (! quote_on)
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 }
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");
1005 }
1009 NULL))
1010 {
1012 "Specified binary `%s' is not executable\n",
1015 }
1018}
1019
1020
1024 unsigned int num_options,
1026{
1027 for (unsigned int i=0; i<num_options; i++)
1028 {
1030
1032 {
1036 {
1039 };
1040
1045 ee);
1046 }
1047 continue;
1049 {
1053 .owned = true
1054 };
1055
1058 pme);
1059 }
1060 continue;
1062 {
1066 .systemd_listen_socket = true,
1067 .owned = false
1068 };
1069
1072 pme);
1073 }
1074 continue;
1075 }
1078 }
1080}
1081
1082
1085 bool blocking,
1087 unsigned long *code)
1088{
1091
1092 if (-1 == proc->
pid)
1093 {
1096 if (NULL != code)
1099 }
1101 (
ret = waitpid (proc->
pid,
1103 blocking ? 0 : WNOHANG)))
1104 {
1105 if ( (! blocking) &&
1106 (EINTR == errno) )
1107 {
1109 break;
1110 }
1111 if (EINTR != errno)
1112 break;
1113 }
1115 {
1118 if (NULL != code)
1119 *code = 0;
1121 }
1122#ifdef WIFCONTINUED
1123 if ( (proc->
pid ==
ret) &&
1124 (WIFCONTINUED (
status)) )
1125 {
1128 if (NULL != code)
1129 *code = 0;
1131 }
1132#endif
1134 {
1136 "waitpid");
1138 }
1139
1142 {
1145 }
1146 else if (WIFSIGNALED (
status))
1147 {
1150 }
1151 else if (WIFSTOPPED (
status))
1152 {
1155 }
1156 else
1157 {
1160 }
1163 if (NULL != code)
1166}
1167
1168
1169
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...
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_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_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.
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
struct GNUNET_Process * GNUNET_process_current()
Get process structure for current process.
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.
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
@ 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...
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 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.
static enum GNUNET_GenericReturnValue process_start(struct GNUNET_Process *proc)
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.
int inherit_lsock
Value of if option is GNUNET_PROCESS_OPTION_INHERIT_LSOCK.
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 target_fd
File descriptor to be used in the target process, -1 if it does not matter.