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 if (NULL != proc->
argv)
386 {
387 for (
unsigned int i = 0; NULL != proc->
argv[i]; i++)
390 }
392}
393
394
402static int
404 int newfd)
405{
407
408 while (1)
409 {
411 newfd);
413 break;
414 if ( (EBADF == errno) ||
415 (EINVAL == errno) ||
416 (EMFILE == errno) )
417 break;
418
420 "dup2");
421 }
423}
424
425
435 int flags)
436{
437 int fd;
438
439 fd = open ("/dev/null",
440 flags);
441 if (-1 == fd)
442 {
444 "open",
445 "/dev/null");
447 }
450 if (-1 == dup2 (fd,
452 {
454 "dup2");
457 }
460}
461
462
465{
467
472}
473
474
483{
484 int flags;
485
486 flags = fcntl (fd,
487 F_GETFD);
488 if (flags == -1)
489 {
491 "fcntl(F_GETFD)");
493 }
494
495 flags &= ~FD_CLOEXEC;
496
497 if (-1 ==
498 fcntl (fd,
499 F_SETFD,
500 flags))
501 {
503 "fcntl(F_SETFD)");
505 }
507}
508
509
522 int fd,
523 int flags)
524{
525 for (
unsigned int i=0; i<proc->
map_size; i++)
526 {
528
529 if (fd ==
me->target_fd)
530 {
531 if (fd !=
533 fd))
539 }
540 }
542 flags);
543}
544
545
548{
550 int childpipe_read_fd;
551
553 {
556 }
558 {
561 }
562
564 {
567 int dup_childpipe_read_fd = -1;
568
570 if (NULL == childpipe)
571 {
574 }
575 childpipe_read =
582 if ( (NULL == childpipe_read) ||
586 &childpipe_read_fd)) ||
587 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))) )
588 {
590 if (NULL != childpipe_read)
593 {
596 }
598 }
599 childpipe_read_fd = dup_childpipe_read_fd;
601 }
602 else
603 {
604 childpipe_read_fd = -1;
605 }
606
607 {
608
609 unsigned int max_fd = 3;
610 unsigned int pos;
611
612 for (
unsigned int i=0; i<proc->
map_size; i++)
613 {
615
618 }
619 pos = max_fd + 1;
620 for (
unsigned int i=0; i<proc->
map_size; i++)
621 {
623
624 if (
me->parent_fd < pos)
625 {
626 if (
me->target_fd ==
me->parent_fd)
627 {
628
629
631 }
632 else
633 {
634 int dst;
635
636
637 while (-1 !=
638 fcntl (pos,
639 F_GETFD))
640 pos++;
641 while (1)
642 {
643 dst = dup2 (
me->parent_fd,
644 pos);
645 if (-1 != dst)
646 break;
647 if ( (EBADF == errno) ||
648 (EINVAL == errno) ||
649 (EMFILE == errno) )
650 {
653 }
654
655 }
660 }
661 }
662 }
663 }
664
667 {
668 int eno = errno;
669
671 "fork");
673 {
676 }
677 if (0 <= childpipe_read_fd)
679 errno = eno;
681 }
683 {
685 if (0 <= childpipe_read_fd)
687 for (
unsigned int i=0; i<proc->
map_size; i++)
688 {
690
692 continue;
693 if (-1 !=
me->parent_fd)
694 {
696 close (
me->parent_fd));
698 }
699 }
701 }
702
703
704
705
706 if (0 <= childpipe_read_fd)
707 {
708 char fdbuf[100];
709
711 snprintf (fdbuf,
712 sizeof (fdbuf),
713 "%x",
714 childpipe_read_fd);
717 fdbuf,
718 1));
719 }
720 else
721 {
724 }
725
726
728 {
731 STDIN_FILENO,
732 O_RDONLY));
733 }
735 {
738 STDOUT_FILENO,
739 O_WRONLY));
740 }
742 {
745 STDERR_FILENO,
746 O_WRONLY));
747 }
748
749
750 {
752 unsigned int total_lfds = 0;
753
754 for (
unsigned int i=0; i<proc->
map_size; i++)
755 {
757
758 if (-1 ==
me->parent_fd)
759 continue;
760 if (-1 ==
me->target_fd)
761 {
762 me->target_fd = dup (
me->parent_fd);
766 }
767 else if (
me->parent_fd !=
me->target_fd)
768 {
774 }
775 else
776 {
781 }
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 int argc;
848
852 NULL))
856 argc = 0;
857 while (NULL != argv[argc])
858 argc++;
860 char *);
861 for (argc = 0; NULL != argv[argc]; argc++)
864}
865
866
871 va_list va)
872{
873 va_list ap;
874 const char *av;
875 int argc;
876
880 NULL))
884 argc = 0;
885 va_copy (ap,
886 va);
887 while (NULL != va_arg (ap,
888 const char *))
889 argc++;
890 va_end (ap);
892 char *);
893 argc = 0;
894 va_copy (ap,
895 va);
896 while (NULL != (av = va_arg (ap,
897 const char *)))
899 va_end (ap);
901}
902
903
907 ...)
908{
910 va_list ap;
911
912 va_start (ap,
916 ap);
917 va_end (ap);
919}
920
921
924 const char *command)
925{
927 size_t len = strlen (command);
928 size_t cnt = 1;
930 bool quote_on = false;
931 size_t i;
932 size_t skip = 0;
933
935 for (i=0; i<len; i++)
936 {
937 char c = cmd[i];
938
939 switch (c)
940 {
941 case '"':
942 quote_on = ! quote_on;
943 break;
944 case '\\':
945 i++;
946 break;
947 case ' ':
948 if (! quote_on)
949 cnt++;
950 while (' ' == cmd[i + 1])
951 i++;
952 break;
953 }
954 }
955
957 char *);
958 cnt = 0;
959 for (i=0; i<len; i++)
960 {
961 char c = cmd[i];
962
963 switch (c)
964 {
965 case '"':
966 quote_on = ! quote_on;
967 skip++;
968 break;
969 case ' ':
970 if ( (! quote_on) &&
972 {
975 cnt++;
976 skip = 0;
977 }
978 while (' ' == cmd[i + 1])
979 i++;
980 if (! quote_on)
982 break;
983 case '\\':
984 i++;
985 skip++;
986 cmd[i - skip] = cmd[i];
987 break;
988 default:
989 cmd[i - skip] = c;
990 break;
991 }
992 }
996 if (quote_on)
997 {
999 "Cmd `%s' has imbalanced quotes\n",
1000 cmd);
1001 }
1003 if (NULL ==
p->
argv[0])
1004 {
1006 "Empty command specified, cannot execute\n");
1008 }
1012 NULL))
1013 {
1015 "Specified binary `%s' is not executable\n",
1018 }
1021}
1022
1023
1027 unsigned int num_options,
1029{
1030 for (unsigned int i=0; i<num_options; i++)
1031 {
1033
1035 {
1039 {
1042 };
1043
1048 ee);
1049 }
1050 continue;
1052 {
1056 .owned = true
1057 };
1058
1061 pme);
1062 }
1063 continue;
1065 {
1069 .systemd_listen_socket = true,
1070 .owned = false
1071 };
1072
1075 pme);
1076 }
1077 continue;
1078 }
1081 }
1083}
1084
1085
1088 bool blocking,
1090 unsigned long *code)
1091{
1094
1095 if (-1 == proc->
pid)
1096 {
1099 if (NULL != code)
1102 }
1104 (
ret = waitpid (proc->
pid,
1106 blocking ? 0 : WNOHANG)))
1107 {
1108 if ( (! blocking) &&
1109 (EINTR == errno) )
1110 {
1112 break;
1113 }
1114 if (EINTR != errno)
1115 break;
1116 }
1118 {
1121 if (NULL != code)
1122 *code = 0;
1124 }
1125#ifdef WIFCONTINUED
1126 if ( (proc->
pid ==
ret) &&
1127 (WIFCONTINUED (
status)) )
1128 {
1131 if (NULL != code)
1132 *code = 0;
1134 }
1135#endif
1137 {
1139 "waitpid");
1141 }
1142
1145 {
1148 }
1149 else if (WIFSIGNALED (
status))
1150 {
1153 }
1154 else if (WIFSTOPPED (
status))
1155 {
1158 }
1159 else
1160 {
1163 }
1166 if (NULL != code)
1169}
1170
1171
1172
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.