GNUnet debian-0.24.3-28-g4f2a77692
 
Loading...
Searching...
No Matches
os_priority.c File Reference

Methods to set process priority. More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "disk.h"
#include <unistr.h>
Include dependency graph for os_priority.c:

Go to the source code of this file.

Data Structures

struct  GNUNET_OS_Process
 
struct  GNUNET_OS_CommandHandle
 Handle to a command. More...
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)    GNUNET_log_from_strerror (kind, "util-os-priority", 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_OS_install_parent_control_handler (void *cls)
 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_OS_ProcessGNUNET_OS_process_current ()
 Get process structure for current process.
 
int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 Sends a signal to the process.
 
pid_t GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc)
 Get the pid of the process in question.
 
void GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
 Cleans up process structure contents (OS-dependent) and deallocates it.
 
static void open_dev_null (int target_fd, int flags)
 Open '/dev/null' and make the result the given file descriptor.
 
static struct GNUNET_OS_Processstart_process (enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const int *lsocks, const char *filename, char *const argv[])
 Start a process.
 
struct GNUNET_OS_ProcessGNUNET_OS_start_process_vap (enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, char *const argv[])
 Start a process.
 
struct GNUNET_OS_ProcessGNUNET_OS_start_process_va (enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, va_list va)
 Start a process.
 
struct GNUNET_OS_ProcessGNUNET_OS_start_process (enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename,...)
 Start a process.
 
struct GNUNET_OS_ProcessGNUNET_OS_start_process_v (enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename, char *const argv[])
 Start a process.
 
struct GNUNET_OS_ProcessGNUNET_OS_start_process_s (enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
 Start a process.
 
static enum GNUNET_GenericReturnValue process_status (struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code, int options)
 Retrieve the status of a process, waiting on it if dead.
 
enum GNUNET_GenericReturnValue GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
 Retrieve the status of a process.
 
enum GNUNET_GenericReturnValue GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
 Retrieve the status of a process, waiting on it if dead.
 
enum GNUNET_GenericReturnValue GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 Wait for a process to terminate.
 
void GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd)
 Stop/kill a command.
 
static void cmd_read (void *cls)
 Read from the process and call the line processor.
 
struct GNUNET_OS_CommandHandleGNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary,...)
 Run the given command line and call the given function for each line of the output.
 

Variables

static struct GNUNET_OS_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

Methods to set process priority.

Author
Nils Durner

Definition in file os_priority.c.

Macro Definition Documentation

◆ LOG

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

Definition at line 33 of file os_priority.c.

◆ LOG_STRERROR

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

Definition at line 35 of file os_priority.c.

45{
49 pid_t pid;
50
55 struct GNUNET_DISK_FileHandle *control_pipe;
56};
57
58
63
67static struct GNUNET_SCHEDULER_Task *pch;
68
72static struct GNUNET_SCHEDULER_Task *spch;
73
74
80static void
81shutdown_pch (void *cls)
82{
83 struct GNUNET_DISK_FileHandle *control_pipe = cls;
84
86 pch = NULL;
87 GNUNET_DISK_file_close (control_pipe);
88 control_pipe = NULL;
89}
90
91
97static void
98parent_control_handler (void *cls)
99{
100 struct GNUNET_DISK_FileHandle *control_pipe = cls;
101 char sig;
102 char *pipe_fd;
103 ssize_t ret;
104
105 pch = NULL;
106 ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof(sig));
107 if (sizeof(sig) != ret)
108 {
109 if (-1 == ret)
110 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
111 LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
112 GNUNET_DISK_file_close (control_pipe);
113 control_pipe = NULL;
115 spch = NULL;
116 return;
117 }
118 pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
119 GNUNET_assert ((NULL == pipe_fd) || (strlen (pipe_fd) <= 0));
121 "Got control code %d from parent via pipe %s\n",
122 sig,
123 pipe_fd);
125 control_pipe,
127 control_pipe);
128 GNUNET_SIGNAL_raise ((int) sig);
129}
130
131
132void
134{
135 const char *env_buf;
136 char *env_buf_end;
137 struct GNUNET_DISK_FileHandle *control_pipe;
138 uint64_t pipe_fd;
139
140 (void) cls;
141 if (NULL != pch)
142 {
143 /* already done, we've been called twice... */
144 GNUNET_break (0);
145 return;
146 }
147 env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
148 if ((NULL == env_buf) || (strlen (env_buf) <= 0))
149 {
151 "Not installing a handler because $%s is empty\n",
153 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
154 return;
155 }
156 errno = 0;
157 pipe_fd = strtoull (env_buf, &env_buf_end, 16);
158 if ((0 != errno) || (env_buf == env_buf_end))
159 {
160 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
161 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
162 return;
163 }
164 if (pipe_fd >= FD_SETSIZE)
165 {
167 "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
168 env_buf);
169 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
170 return;
171 }
172
173 control_pipe = GNUNET_DISK_get_handle_from_int_fd ((int) pipe_fd);
174
175 if (NULL == control_pipe)
176 {
178 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
179 return;
180 }
182 "Adding parent control handler pipe `%s' to the scheduler\n",
183 env_buf);
185 control_pipe,
187 control_pipe);
189 setenv (GNUNET_OS_CONTROL_PIPE, "", 1);
190}
191
192
201struct GNUNET_OS_Process *
203{
205 return &current_process;
206}
207
208
209int
211 int sig)
212{
213 int ret;
214 char csig;
215
216 csig = (char) sig;
217 if (NULL != proc->control_pipe)
218 {
220 "Sending signal %d to pid: %u via pipe\n",
221 sig,
222 proc->pid);
223 ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof(csig));
224 if (sizeof(csig) == ret)
225 return 0;
226 }
227 /* pipe failed or non-existent, try other methods */
228 switch (sig)
229 {
230 case SIGHUP:
231 case SIGINT:
232 case SIGKILL:
233 case SIGTERM:
234#if (SIGTERM != GNUNET_TERM_SIG)
235 case GNUNET_TERM_SIG:
236#endif
238 "Sending signal %d to pid: %u via system call\n",
239 sig,
240 proc->pid);
241 return kill (proc->pid, sig);
242 default:
244 "Sending signal %d to pid: %u via system call\n",
245 sig,
246 proc->pid);
247 return kill (proc->pid, sig);
248 }
249}
250
251
252pid_t
254{
255 return proc->pid;
256}
257
258
259void
261{
262 if (NULL != proc->control_pipe)
264
265 GNUNET_free (proc);
266}
267
268
276static void
277open_dev_null (int target_fd,
278 int flags)
279{
280 int fd;
281
282 fd = open ("/dev/null", flags);
283 if (-1 == fd)
284 {
286 return;
287 }
288 if (fd == target_fd)
289 return;
290 if (-1 == dup2 (fd, target_fd))
291 {
293 GNUNET_break (0 == close (fd));
294 return;
295 }
296 GNUNET_break (0 == close (fd));
297}
298
299
316static struct GNUNET_OS_Process *
317start_process (enum GNUNET_OS_InheritStdioFlags std_inheritance,
318 struct GNUNET_DISK_PipeHandle *pipe_stdin,
319 struct GNUNET_DISK_PipeHandle *pipe_stdout,
320 struct GNUNET_DISK_PipeHandle *pipe_stderr,
321 const int *lsocks,
322 const char *filename,
323 char *const argv[])
324{
325 pid_t ret;
326 char fds[16];
327 struct GNUNET_OS_Process *gnunet_proc;
328 struct GNUNET_DISK_FileHandle *childpipe_read;
329 struct GNUNET_DISK_FileHandle *childpipe_write;
330 int childpipe_read_fd;
331 int i;
332 int j;
333 int k;
334 int tgt;
335 int flags;
336 int *lscp;
337 unsigned int ls;
338 int fd_stdout_write;
339 int fd_stdout_read;
340 int fd_stderr_write;
341 int fd_stderr_read;
342 int fd_stdin_read;
343 int fd_stdin_write;
344
345 if (GNUNET_SYSERR ==
347 return NULL; /* not executable */
348 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
349 {
350 struct GNUNET_DISK_PipeHandle *childpipe;
351 int dup_childpipe_read_fd = -1;
352
354 if (NULL == childpipe)
355 return NULL;
356 childpipe_read =
358 childpipe_write =
360 GNUNET_DISK_pipe_close (childpipe);
361 if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
363 &childpipe_read_fd)) ||
364 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
365 {
366 if (NULL != childpipe_read)
367 GNUNET_DISK_file_close (childpipe_read);
368 if (NULL != childpipe_write)
369 GNUNET_DISK_file_close (childpipe_write);
370 if (0 <= dup_childpipe_read_fd)
371 GNUNET_break (0 == close (dup_childpipe_read_fd));
372 return NULL;
373 }
374 childpipe_read_fd = dup_childpipe_read_fd;
375 GNUNET_DISK_file_close (childpipe_read);
376 }
377 else
378 {
379 childpipe_write = NULL;
380 childpipe_read_fd = -1;
381 }
382 if (NULL != pipe_stdin)
383 {
385 GNUNET_OK ==
388 &fd_stdin_read));
390 GNUNET_OK ==
393 &fd_stdin_write));
394 }
395 if (NULL != pipe_stdout)
396 {
398 GNUNET_OK ==
401 &fd_stdout_write));
403 GNUNET_OK ==
406 &fd_stdout_read));
407 }
408 if (NULL != pipe_stderr)
409 {
411 GNUNET_OK ==
414 &fd_stderr_read));
416 GNUNET_OK ==
419 &fd_stderr_write));
420 }
421 lscp = NULL;
422 ls = 0;
423 if (NULL != lsocks)
424 {
425 i = 0;
426 while (-1 != (k = lsocks[i++]))
427 GNUNET_array_append (lscp, ls, k);
428 GNUNET_array_append (lscp, ls, -1);
429 }
430#if DARWIN
431 /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
432 #pragma GCC diagnostic push
433 #pragma GCC diagnostic ignored "-Wdeprecated"
434 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
435 #pragma clang diagnostic push
436 #pragma clang diagnostic ignored "-Wdeprecated"
437 ret = vfork ();
438 #pragma clang diagnostic pop
439 #pragma GCC diagnostic pop
440#else
441 ret = fork ();
442#endif
443 if (-1 == ret)
444 {
445 int eno = errno;
446
448 "fork");
449 GNUNET_array_grow (lscp,
450 ls,
451 0);
452 if (NULL != childpipe_write)
453 GNUNET_DISK_file_close (childpipe_write);
454 if (0 <= childpipe_read_fd)
455 GNUNET_break (0 == close (childpipe_read_fd));
456 errno = eno;
457 return NULL;
458 }
459 if (0 != ret)
460 {
461 unsetenv (GNUNET_OS_CONTROL_PIPE);
462 gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
463 gnunet_proc->pid = ret;
464 gnunet_proc->control_pipe = childpipe_write;
465 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
466 {
467 GNUNET_break (0 == close (childpipe_read_fd));
468 }
469 GNUNET_array_grow (lscp, ls, 0);
470 return gnunet_proc;
471 }
472 if (0 <= childpipe_read_fd)
473 {
474 char fdbuf[100];
475#ifndef DARWIN
476 /* due to vfork, we must NOT free memory on DARWIN! */
477 GNUNET_DISK_file_close (childpipe_write);
478#endif
479 snprintf (fdbuf,
480 sizeof (fdbuf),
481 "%x",
482 childpipe_read_fd);
484 fdbuf,
485 1);
486 }
487 else
488 unsetenv (GNUNET_OS_CONTROL_PIPE);
489 if (NULL != pipe_stdin)
490 {
491 GNUNET_break (0 == close (fd_stdin_write));
492 if (-1 == dup2 (fd_stdin_read,
493 0))
495 "dup2");
496 GNUNET_break (0 == close (fd_stdin_read));
497 }
498 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
499 {
500 GNUNET_break (0 == close (0));
501 open_dev_null (0,
502 O_RDONLY);
503 }
504 if (NULL != pipe_stdout)
505 {
506 GNUNET_break (0 == close (fd_stdout_read));
507 if (-1 == dup2 (fd_stdout_write,
508 1))
510 "dup2");
511 GNUNET_break (0 ==
512 close (fd_stdout_write));
513 }
514 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
515 {
516 GNUNET_break (0 == close (1));
517 open_dev_null (1,
518 O_WRONLY);
519 }
520 if (NULL != pipe_stderr)
521 {
522 GNUNET_break (0 == close (fd_stderr_read));
523 if (-1 == dup2 (fd_stderr_write,
524 2))
526 GNUNET_break (0 == close (fd_stderr_write));
527 }
528 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
529 {
530 GNUNET_break (0 == close (2));
531 open_dev_null (2,
532 O_WRONLY);
533 }
534 if (NULL != lscp)
535 {
536 char *fdnames = GNUNET_strdup ("");
537
538 /* read systemd documentation... */
539 i = 0;
540 tgt = 3;
541 while (-1 != lscp[i])
542 {
543 j = i + 1;
544 while (-1 != lscp[j])
545 {
546 if (lscp[j] == tgt)
547 {
548 /* dup away */
549 k = dup (lscp[j]);
550 GNUNET_assert (-1 != k);
551 GNUNET_assert (0 == close (lscp[j]));
552 lscp[j] = k;
553 break;
554 }
555 j++;
556 }
557 if (lscp[i] != tgt)
558 {
559 /* Bury any existing FD, no matter what; they should all be closed
560 * on exec anyway and the important ones have been dup'ed away */
561 GNUNET_break (0 == close (tgt));
562 GNUNET_assert (-1 != dup2 (lscp[i],
563 tgt));
564 }
565 /* unset close-on-exec flag */
566 flags = fcntl (tgt,
567 F_GETFD);
568 GNUNET_assert (flags >= 0);
569 flags &= ~FD_CLOEXEC;
570 fflush (stderr);
571 (void) fcntl (tgt,
572 F_SETFD,
573 flags);
574 {
575 char *tmp;
576
577 GNUNET_asprintf (&tmp,
578 "%s:%d",
579 fdnames,
580 tgt);
581 GNUNET_free (fdnames);
582 fdnames = tmp;
583 }
584 tgt++;
585 i++;
586 }
587 GNUNET_snprintf (fds,
588 sizeof(fds),
589 "%u",
590 i);
591 setenv ("LISTEN_FDS",
592 fds,
593 1);
594 if (0 != strlen (fdnames))
595 setenv ("LISTEN_FDNAMES",
596 fdnames + 1, /* skip leading ':' */
597 1);
598 GNUNET_free (fdnames);
599 }
600#ifndef DARWIN
601 /* due to vfork, we must NOT free memory on DARWIN! */
602 GNUNET_array_grow (lscp,
603 ls,
604 0);
605#endif
606 execvp (filename,
607 argv);
609 "execvp",
610 filename);
611 _exit (1);
612}
613
614
615struct GNUNET_OS_Process *
617 struct GNUNET_DISK_PipeHandle *pipe_stdin,
618 struct GNUNET_DISK_PipeHandle *pipe_stdout,
619 struct GNUNET_DISK_PipeHandle *pipe_stderr,
620 const char *filename,
621 char *const argv[])
622{
623 return start_process (std_inheritance,
624 pipe_stdin,
625 pipe_stdout,
626 pipe_stderr,
627 NULL,
628 filename,
629 argv);
630}
631
632
633struct GNUNET_OS_Process *
635 struct GNUNET_DISK_PipeHandle *pipe_stdin,
636 struct GNUNET_DISK_PipeHandle *pipe_stdout,
637 struct GNUNET_DISK_PipeHandle *pipe_stderr,
638 const char *filename,
639 va_list va)
640{
641 struct GNUNET_OS_Process *ret;
642 va_list ap;
643 char **argv;
644 int argc;
645
646 argc = 0;
647 va_copy (ap, va);
648 while (NULL != va_arg (ap, char *))
649 argc++;
650 va_end (ap);
651 argv = GNUNET_malloc (sizeof(char *) * (argc + 1));
652 argc = 0;
653 va_copy (ap, va);
654 while (NULL != (argv[argc] = va_arg (ap, char *)))
655 argc++;
656 va_end (ap);
657 ret = GNUNET_OS_start_process_vap (std_inheritance,
658 pipe_stdin,
659 pipe_stdout,
660 pipe_stderr,
661 filename,
662 argv);
663 GNUNET_free (argv);
664 return ret;
665}
666
667
668struct GNUNET_OS_Process *
670 struct GNUNET_DISK_PipeHandle *pipe_stdin,
671 struct GNUNET_DISK_PipeHandle *pipe_stdout,
672 struct GNUNET_DISK_PipeHandle *pipe_stderr,
673 const char *filename,
674 ...)
675{
676 struct GNUNET_OS_Process *ret;
677 va_list ap;
678
679 va_start (ap, filename);
680 ret = GNUNET_OS_start_process_va (std_inheritance,
681 pipe_stdin,
682 pipe_stdout,
683 pipe_stderr,
684 filename,
685 ap);
686 va_end (ap);
687 return ret;
688}
689
690
691struct GNUNET_OS_Process *
693 const int *lsocks,
694 const char *filename,
695 char *const argv[])
696{
697 return start_process (std_inheritance,
698 NULL,
699 NULL,
700 NULL,
701 lsocks,
702 filename,
703 argv);
704}
705
706
707struct GNUNET_OS_Process *
709 const int *lsocks,
710 const char *filename,
711 ...)
712{
713 va_list ap;
714 char **argv;
715 unsigned int argv_size;
716 const char *arg;
717 const char *rpos;
718 char *pos;
719 char *cp;
720 const char *last;
721 struct GNUNET_OS_Process *proc;
722 char *binary_path;
723 int quote_on;
724 unsigned int i;
725 size_t len;
726
727 argv_size = 1;
728 va_start (ap, filename);
729 arg = filename;
730 last = NULL;
731 do
732 {
733 rpos = arg;
734 quote_on = 0;
735 while ('\0' != *rpos)
736 {
737 if ('"' == *rpos)
738 {
739 if (1 == quote_on)
740 quote_on = 0;
741 else
742 quote_on = 1;
743 }
744 if ((' ' == *rpos) && (0 == quote_on))
745 {
746 if (NULL != last)
747 argv_size++;
748 last = NULL;
749 rpos++;
750 while (' ' == *rpos)
751 rpos++;
752 }
753 if ((NULL == last) && ('\0' != *rpos)) // FIXME: == or !=?
754 last = rpos;
755 if ('\0' != *rpos)
756 rpos++;
757 }
758 if (NULL != last)
759 argv_size++;
760 }
761 while (NULL != (arg = (va_arg (ap, const char *))));
762 va_end (ap);
763
764 argv = GNUNET_malloc (argv_size * sizeof(char *));
765 argv_size = 0;
766 va_start (ap, filename);
767 arg = filename;
768 last = NULL;
769 do
770 {
771 cp = GNUNET_strdup (arg);
772 quote_on = 0;
773 pos = cp;
774 while ('\0' != *pos)
775 {
776 if ('"' == *pos)
777 {
778 if (1 == quote_on)
779 quote_on = 0;
780 else
781 quote_on = 1;
782 }
783 if ((' ' == *pos) && (0 == quote_on))
784 {
785 *pos = '\0';
786 if (NULL != last)
787 argv[argv_size++] = GNUNET_strdup (last);
788 last = NULL;
789 pos++;
790 while (' ' == *pos)
791 pos++;
792 }
793 if ((NULL == last) && ('\0' != *pos)) // FIXME: == or !=?
794 last = pos;
795 if ('\0' != *pos)
796 pos++;
797 }
798 if (NULL != last)
799 argv[argv_size++] = GNUNET_strdup (last);
800 last = NULL;
801 GNUNET_free (cp);
802 }
803 while (NULL != (arg = (va_arg (ap, const char *))));
804 va_end (ap);
805 argv[argv_size] = NULL;
806
807 for (i = 0; i < argv_size; i++)
808 {
809 len = strlen (argv[i]);
810 if ((argv[i][0] == '"') && (argv[i][len - 1] == '"'))
811 {
812 memmove (&argv[i][0], &argv[i][1], len - 2);
813 argv[i][len - 2] = '\0';
814 }
815 }
816 binary_path = argv[0];
817 proc = GNUNET_OS_start_process_v (std_inheritance,
818 lsocks,
819 binary_path,
820 argv);
821 while (argv_size > 0)
822 GNUNET_free_nz (argv[--argv_size]);
823 GNUNET_free (argv);
824 return proc;
825}
826
827
841 unsigned long *code,
842 int options)
843{
844 int status;
845 int ret;
846
847 GNUNET_assert (0 != proc);
848 ret = waitpid (proc->pid,
849 &status,
850 options);
851 if (ret < 0)
852 {
854 "waitpid");
855 return GNUNET_SYSERR;
856 }
857 if (0 == ret)
858 {
860 *code = 0;
861 return GNUNET_NO;
862 }
863 if (proc->pid != ret)
864 {
866 "waitpid");
867 return GNUNET_SYSERR;
868 }
869 if (WIFEXITED (status))
870 {
872 *code = WEXITSTATUS (status);
873 }
874 else if (WIFSIGNALED (status))
875 {
877 *code = WTERMSIG (status);
878 }
879 else if (WIFSTOPPED (status))
880 {
882 *code = WSTOPSIG (status);
883 }
884#ifdef WIFCONTINUED
885 else if (WIFCONTINUED (status))
886 {
888 *code = 0;
889 }
890#endif
891 else
892 {
894 *code = 0;
895 }
896
897 return GNUNET_OK;
898}
899
900
904 unsigned long *code)
905{
906 return process_status (proc, type, code, WNOHANG);
907}
908
909
913 unsigned long *code)
914{
915 return process_status (proc, type, code, 0);
916}
917
918
921{
922 pid_t pid = proc->pid;
923 pid_t ret;
924
925 while ((pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno))
926 ;
927 if (pid != ret)
928 {
930 "waitpid");
931 return GNUNET_SYSERR;
932 }
933 return GNUNET_OK;
934}
935
936
941{
945 struct GNUNET_OS_Process *eip;
946
951
955 const struct GNUNET_DISK_FileHandle *r;
956
961
965 void *proc_cls;
966
970 char buf[1024];
971
976
981
985 size_t off;
986};
987
988
989void
991{
992 if (NULL != cmd->proc)
993 {
994 GNUNET_assert (NULL != cmd->rtask);
996 }
997 (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL);
1001 GNUNET_free (cmd);
1002}
1003
1004
1010static void
1011cmd_read (void *cls)
1012{
1013 struct GNUNET_OS_CommandHandle *cmd = cls;
1014 const struct GNUNET_SCHEDULER_TaskContext *tc;
1016 char *end;
1017 ssize_t ret;
1018
1019 cmd->rtask = NULL;
1022 {
1023 /* timeout */
1024 proc = cmd->proc;
1025 cmd->proc = NULL;
1026 proc (cmd->proc_cls, NULL);
1027 return;
1028 }
1029 ret = GNUNET_DISK_file_read (cmd->r,
1030 &cmd->buf[cmd->off],
1031 sizeof(cmd->buf) - cmd->off);
1032 if (ret <= 0)
1033 {
1034 if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1035 {
1036 cmd->buf[cmd->off] = '\0';
1037 cmd->proc (cmd->proc_cls, cmd->buf);
1038 }
1039 proc = cmd->proc;
1040 cmd->proc = NULL;
1041 proc (cmd->proc_cls, NULL);
1042 return;
1043 }
1044 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1045 cmd->off += ret;
1046 while (NULL != end)
1047 {
1048 *end = '\0';
1049 cmd->proc (cmd->proc_cls, cmd->buf);
1050 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1051 cmd->off -= (end + 1 - cmd->buf);
1052 end = memchr (cmd->buf, '\n', cmd->off);
1053 }
1054 cmd->rtask =
1056 cmd->timeout),
1057 cmd->r,
1058 &cmd_read,
1059 cmd);
1060}
1061
1062
1065 void *proc_cls,
1067 const char *binary,
1068 ...)
1069{
1071 struct GNUNET_OS_Process *eip;
1072 struct GNUNET_DISK_PipeHandle *opipe;
1073 va_list ap;
1074
1076 if (NULL == opipe)
1077 return NULL;
1078 va_start (ap, binary);
1079 /* redirect stdout, don't inherit stderr/stdin */
1080 eip =
1082 NULL,
1083 opipe,
1084 NULL,
1085 binary,
1086 ap);
1087 va_end (ap);
1088 if (NULL == eip)
1089 {
1090 GNUNET_DISK_pipe_close (opipe);
1091 return NULL;
1092 }
1094 cmd = GNUNET_new (struct GNUNET_OS_CommandHandle);
1096 cmd->eip = eip;
1097 cmd->opipe = opipe;
1098 cmd->proc = proc;
1099 cmd->proc_cls = proc_cls;
1102 return cmd;
1103}
1104
1105
1106/* end of os_priority.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:1662
char * getenv()
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition gnunet-arm.c:118
static int end
Set if we are to shutdown all services (including ARM).
Definition gnunet-arm.c:33
static char * filename
static uint32_t type
Type string converted to DNS type value.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition gnunet-nat.c:85
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static void start_process()
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition disk.c:1645
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:1588
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:710
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1468
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1615
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition disk.c:1332
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition disk.c:1354
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:673
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Closes one half of an interprocess channel.
Definition disk.c:1562
@ GNUNET_DISK_PF_NONE
No special options, use non-blocking read/write operations.
@ GNUNET_DISK_PF_BLOCKING_RW
Configure both pipe ends for blocking operations if set.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ 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_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
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_malloc(size)
Wrapper around malloc.
#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.
#define GNUNET_free_nz(ptr)
Wrapper around free.
int GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h)
Check if a file handle is part of an fd set.
Definition network.c:1127
void(* GNUNET_OS_LineProcessor)(void *cls, const char *line)
Type of a function to process a line of output.
struct GNUNET_OS_Process * GNUNET_OS_start_process(enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename,...)
Start a process.
GNUNET_OS_InheritStdioFlags
Flags that determine which of the standard streams should be inherited by the child process.
struct GNUNET_OS_Process * GNUNET_OS_start_process_v(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename, char *const argv[])
Start a process.
struct GNUNET_OS_Process * GNUNET_OS_process_current()
Get process structure for current process.
enum GNUNET_GenericReturnValue GNUNET_OS_process_wait_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process, waiting on it if dead.
void GNUNET_OS_install_parent_control_handler(void *cls)
Connects this process to its parent via pipe; essentially, the parent control handler will read signa...
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run(GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary,...)
Run the given command line and call the given function for each line of the output.
struct GNUNET_OS_Process * GNUNET_OS_start_process_s(enum GNUNET_OS_InheritStdioFlags std_inheritance, const int *lsocks, const char *filename,...)
Start a process.
pid_t GNUNET_OS_process_get_pid(struct GNUNET_OS_Process *proc)
Get the pid of the process in question.
GNUNET_OS_ProcessStatusType
Process status types.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
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.
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
enum GNUNET_GenericReturnValue GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
enum GNUNET_GenericReturnValue GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
struct GNUNET_OS_Process * GNUNET_OS_start_process_va(enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, va_list va)
Start a process.
struct GNUNET_OS_Process * GNUNET_OS_start_process_vap(enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, char *const argv[])
Start a 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_INHERIT_STD_NONE
No standard streams should be inherited.
@ GNUNET_OS_USE_PIPE_CONTROL
Should a pipe be used to send signals to the child?
@ 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:1661
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition scheduler.c:758
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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
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".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
#define GNUNET_OS_CONTROL_PIPE
Definition os_priority.c:42
static void parent_control_handler(void *cls)
This handler is called when there are control data to be read on the pipe.
Definition os_priority.c:99
static struct GNUNET_OS_Process current_process
Handle for 'this' process.
Definition os_priority.c:63
static struct GNUNET_SCHEDULER_Task * pch
Handle for the parent_control_handler() Task.
Definition os_priority.c:68
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition os_priority.c:38
static void shutdown_pch(void *cls)
This handler is called on shutdown to remove the pch.
Definition os_priority.c:82
static void open_dev_null(int target_fd, int flags)
Open '/dev/null' and make the result the given file descriptor.
static struct GNUNET_SCHEDULER_Task * spch
Handle for the shutdown_pch() Task.
Definition os_priority.c:73
#define LOG(kind,...)
Definition os_priority.c:33
#define LOG_STRERROR(kind, syscall)
Definition os_priority.c:35
static void cmd_read(void *cls)
Read from the process and call the line processor.
static enum GNUNET_GenericReturnValue process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code, int options)
Retrieve the status of a process, waiting on it if dead.
#define GNUNET_TERM_SIG
The termination signal.
Definition platform.h:235
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition scheduler.c:431
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Handle to a command.
struct GNUNET_DISK_PipeHandle * opipe
Handle to the output pipe.
struct GNUNET_OS_Process * eip
Process handle.
size_t off
Current read offset in buf.
char buf[1024]
Buffer for the output.
struct GNUNET_SCHEDULER_Task * rtask
Task reading from pipe.
struct GNUNET_TIME_Absolute timeout
When to time out.
void * proc_cls
Closure for proc.
GNUNET_OS_LineProcessor proc
Function to call on each line of output.
const struct GNUNET_DISK_FileHandle * r
Read-end of output pipe.
pid_t pid
PID of the process.
Definition os_priority.c:50
struct GNUNET_DISK_FileHandle * control_pipe
Pipe we use to signal the process.
Definition os_priority.c:56
Context information passed to each scheduler task.
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
Entry in list of pending tasks.
Definition scheduler.c:136
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.

◆ LOG_STRERROR_FILE

#define LOG_STRERROR_FILE (   kind,
  syscall,
  filename 
)
Value:
GNUNET_log_from_strerror_file (kind, "util-os-priority", 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 38 of file os_priority.c.

◆ GNUNET_OS_CONTROL_PIPE

#define GNUNET_OS_CONTROL_PIPE   "GNUNET_OS_CONTROL_PIPE"

Definition at line 42 of file os_priority.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 82 of file os_priority.c.

83{
84 struct GNUNET_DISK_FileHandle *control_pipe = cls;
85
87 pch = NULL;
88 GNUNET_DISK_file_close (control_pipe);
89 control_pipe = NULL;
90}

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

Referenced by GNUNET_OS_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 99 of file os_priority.c.

100{
101 struct GNUNET_DISK_FileHandle *control_pipe = cls;
102 char sig;
103 char *pipe_fd;
104 ssize_t ret;
105
106 pch = NULL;
107 ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof(sig));
108 if (sizeof(sig) != ret)
109 {
110 if (-1 == ret)
111 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
112 LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
113 GNUNET_DISK_file_close (control_pipe);
114 control_pipe = NULL;
116 spch = NULL;
117 return;
118 }
119 pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
120 GNUNET_assert ((NULL == pipe_fd) || (strlen (pipe_fd) <= 0));
122 "Got control code %d from parent via pipe %s\n",
123 sig,
124 pipe_fd);
126 control_pipe,
128 control_pipe);
129 GNUNET_SIGNAL_raise ((int) sig);
130}

References getenv(), GNUNET_assert, GNUNET_DISK_file_close(), GNUNET_DISK_file_read(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_OS_CONTROL_PIPE, 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_OS_install_parent_control_handler(), and parent_control_handler().

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

◆ open_dev_null()

static void 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)

Definition at line 278 of file os_priority.c.

280{
281 int fd;
282
283 fd = open ("/dev/null", flags);
284 if (-1 == fd)
285 {
287 return;
288 }
289 if (fd == target_fd)
290 return;
291 if (-1 == dup2 (fd, target_fd))
292 {
294 GNUNET_break (0 == close (fd));
295 return;
296 }
297 GNUNET_break (0 == close (fd));
298}

References GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_log_strerror, and GNUNET_log_strerror_file.

Referenced by start_process().

Here is the caller graph for this function:

◆ start_process()

static struct GNUNET_OS_Process * start_process ( enum GNUNET_OS_InheritStdioFlags  std_inheritance,
struct GNUNET_DISK_PipeHandle pipe_stdin,
struct GNUNET_DISK_PipeHandle pipe_stdout,
struct GNUNET_DISK_PipeHandle pipe_stderr,
const int *  lsocks,
const char *  filename,
char *const  argv[] 
)
static

Start a process.

Parameters
std_inheritancea set of GNUNET_OS_INHERIT_STD_* flags controlling which std handles of the parent are inherited by the child. pipe_stdin and pipe_stdout take priority over std_inheritance (when they are non-NULL).
pipe_stdinpipe to use to send input to child process (or NULL)
pipe_stdoutpipe to use to get output from child process (or NULL)
pipe_stderrpipe to use for stderr for child process (or NULL)
lsocksarray of listen sockets to dup systemd-style (or NULL); must be NULL on platforms where dup is not supported
filenamename of the binary
argvNULL-terminated list of arguments to the process
Returns
process ID of the new process, -1 on error

Definition at line 318 of file os_priority.c.

325{
326 pid_t ret;
327 char fds[16];
328 struct GNUNET_OS_Process *gnunet_proc;
329 struct GNUNET_DISK_FileHandle *childpipe_read;
330 struct GNUNET_DISK_FileHandle *childpipe_write;
331 int childpipe_read_fd;
332 int i;
333 int j;
334 int k;
335 int tgt;
336 int flags;
337 int *lscp;
338 unsigned int ls;
339 int fd_stdout_write;
340 int fd_stdout_read;
341 int fd_stderr_write;
342 int fd_stderr_read;
343 int fd_stdin_read;
344 int fd_stdin_write;
345
346 if (GNUNET_SYSERR ==
348 return NULL; /* not executable */
349 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
350 {
351 struct GNUNET_DISK_PipeHandle *childpipe;
352 int dup_childpipe_read_fd = -1;
353
355 if (NULL == childpipe)
356 return NULL;
357 childpipe_read =
359 childpipe_write =
361 GNUNET_DISK_pipe_close (childpipe);
362 if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
364 &childpipe_read_fd)) ||
365 (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
366 {
367 if (NULL != childpipe_read)
368 GNUNET_DISK_file_close (childpipe_read);
369 if (NULL != childpipe_write)
370 GNUNET_DISK_file_close (childpipe_write);
371 if (0 <= dup_childpipe_read_fd)
372 GNUNET_break (0 == close (dup_childpipe_read_fd));
373 return NULL;
374 }
375 childpipe_read_fd = dup_childpipe_read_fd;
376 GNUNET_DISK_file_close (childpipe_read);
377 }
378 else
379 {
380 childpipe_write = NULL;
381 childpipe_read_fd = -1;
382 }
383 if (NULL != pipe_stdin)
384 {
386 GNUNET_OK ==
389 &fd_stdin_read));
391 GNUNET_OK ==
394 &fd_stdin_write));
395 }
396 if (NULL != pipe_stdout)
397 {
399 GNUNET_OK ==
402 &fd_stdout_write));
404 GNUNET_OK ==
407 &fd_stdout_read));
408 }
409 if (NULL != pipe_stderr)
410 {
412 GNUNET_OK ==
415 &fd_stderr_read));
417 GNUNET_OK ==
420 &fd_stderr_write));
421 }
422 lscp = NULL;
423 ls = 0;
424 if (NULL != lsocks)
425 {
426 i = 0;
427 while (-1 != (k = lsocks[i++]))
428 GNUNET_array_append (lscp, ls, k);
429 GNUNET_array_append (lscp, ls, -1);
430 }
431#if DARWIN
432 /* see https://web.archive.org/web/20150924082249/gnunet.org/vfork */
433 #pragma GCC diagnostic push
434 #pragma GCC diagnostic ignored "-Wdeprecated"
435 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
436 #pragma clang diagnostic push
437 #pragma clang diagnostic ignored "-Wdeprecated"
438 ret = vfork ();
439 #pragma clang diagnostic pop
440 #pragma GCC diagnostic pop
441#else
442 ret = fork ();
443#endif
444 if (-1 == ret)
445 {
446 int eno = errno;
447
449 "fork");
450 GNUNET_array_grow (lscp,
451 ls,
452 0);
453 if (NULL != childpipe_write)
454 GNUNET_DISK_file_close (childpipe_write);
455 if (0 <= childpipe_read_fd)
456 GNUNET_break (0 == close (childpipe_read_fd));
457 errno = eno;
458 return NULL;
459 }
460 if (0 != ret)
461 {
462 unsetenv (GNUNET_OS_CONTROL_PIPE);
463 gnunet_proc = GNUNET_new (struct GNUNET_OS_Process);
464 gnunet_proc->pid = ret;
465 gnunet_proc->control_pipe = childpipe_write;
466 if (0 != (std_inheritance & GNUNET_OS_USE_PIPE_CONTROL))
467 {
468 GNUNET_break (0 == close (childpipe_read_fd));
469 }
470 GNUNET_array_grow (lscp, ls, 0);
471 return gnunet_proc;
472 }
473 if (0 <= childpipe_read_fd)
474 {
475 char fdbuf[100];
476#ifndef DARWIN
477 /* due to vfork, we must NOT free memory on DARWIN! */
478 GNUNET_DISK_file_close (childpipe_write);
479#endif
480 snprintf (fdbuf,
481 sizeof (fdbuf),
482 "%x",
483 childpipe_read_fd);
485 fdbuf,
486 1);
487 }
488 else
489 unsetenv (GNUNET_OS_CONTROL_PIPE);
490 if (NULL != pipe_stdin)
491 {
492 GNUNET_break (0 == close (fd_stdin_write));
493 if (-1 == dup2 (fd_stdin_read,
494 0))
496 "dup2");
497 GNUNET_break (0 == close (fd_stdin_read));
498 }
499 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_IN))
500 {
501 GNUNET_break (0 == close (0));
502 open_dev_null (0,
503 O_RDONLY);
504 }
505 if (NULL != pipe_stdout)
506 {
507 GNUNET_break (0 == close (fd_stdout_read));
508 if (-1 == dup2 (fd_stdout_write,
509 1))
511 "dup2");
512 GNUNET_break (0 ==
513 close (fd_stdout_write));
514 }
515 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_OUT))
516 {
517 GNUNET_break (0 == close (1));
518 open_dev_null (1,
519 O_WRONLY);
520 }
521 if (NULL != pipe_stderr)
522 {
523 GNUNET_break (0 == close (fd_stderr_read));
524 if (-1 == dup2 (fd_stderr_write,
525 2))
527 GNUNET_break (0 == close (fd_stderr_write));
528 }
529 else if (0 == (std_inheritance & GNUNET_OS_INHERIT_STD_ERR))
530 {
531 GNUNET_break (0 == close (2));
532 open_dev_null (2,
533 O_WRONLY);
534 }
535 if (NULL != lscp)
536 {
537 char *fdnames = GNUNET_strdup ("");
538
539 /* read systemd documentation... */
540 i = 0;
541 tgt = 3;
542 while (-1 != lscp[i])
543 {
544 j = i + 1;
545 while (-1 != lscp[j])
546 {
547 if (lscp[j] == tgt)
548 {
549 /* dup away */
550 k = dup (lscp[j]);
551 GNUNET_assert (-1 != k);
552 GNUNET_assert (0 == close (lscp[j]));
553 lscp[j] = k;
554 break;
555 }
556 j++;
557 }
558 if (lscp[i] != tgt)
559 {
560 /* Bury any existing FD, no matter what; they should all be closed
561 * on exec anyway and the important ones have been dup'ed away */
562 GNUNET_break (0 == close (tgt));
563 GNUNET_assert (-1 != dup2 (lscp[i],
564 tgt));
565 }
566 /* unset close-on-exec flag */
567 flags = fcntl (tgt,
568 F_GETFD);
569 GNUNET_assert (flags >= 0);
570 flags &= ~FD_CLOEXEC;
571 fflush (stderr);
572 (void) fcntl (tgt,
573 F_SETFD,
574 flags);
575 {
576 char *tmp;
577
578 GNUNET_asprintf (&tmp,
579 "%s:%d",
580 fdnames,
581 tgt);
582 GNUNET_free (fdnames);
583 fdnames = tmp;
584 }
585 tgt++;
586 i++;
587 }
588 GNUNET_snprintf (fds,
589 sizeof(fds),
590 "%u",
591 i);
592 setenv ("LISTEN_FDS",
593 fds,
594 1);
595 if (0 != strlen (fdnames))
596 setenv ("LISTEN_FDNAMES",
597 fdnames + 1, /* skip leading ':' */
598 1);
599 GNUNET_free (fdnames);
600 }
601#ifndef DARWIN
602 /* due to vfork, we must NOT free memory on DARWIN! */
603 GNUNET_array_grow (lscp,
604 ls,
605 0);
606#endif
607 execvp (filename,
608 argv);
610 "execvp",
611 filename);
612 _exit (1);
613}

References GNUNET_OS_Process::control_pipe, filename, GNUNET_array_append, GNUNET_array_grow, GNUNET_asprintf(), GNUNET_assert, GNUNET_break, GNUNET_DISK_file_close(), GNUNET_DISK_internal_file_handle_(), GNUNET_DISK_PF_NONE, GNUNET_DISK_pipe(), GNUNET_DISK_pipe_close(), GNUNET_DISK_pipe_detach_end(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_PIPE_END_WRITE, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_OS_check_helper_binary(), GNUNET_OS_CONTROL_PIPE, GNUNET_OS_INHERIT_STD_ERR, GNUNET_OS_INHERIT_STD_IN, GNUNET_OS_INHERIT_STD_OUT, GNUNET_OS_USE_PIPE_CONTROL, GNUNET_snprintf(), GNUNET_strdup, GNUNET_SYSERR, LOG_STRERROR, LOG_STRERROR_FILE, ls, open_dev_null(), GNUNET_OS_Process::pid, and ret.

Here is the call graph for this function:

◆ process_status()

static enum GNUNET_GenericReturnValue process_status ( struct GNUNET_OS_Process proc,
enum GNUNET_OS_ProcessStatusType type,
unsigned long *  code,
int  options 
)
static

Retrieve the status of a process, waiting on it if dead.

Nonblocking version.

Parameters
procprocess ID
typestatus type
codereturn code/signal number
optionsWNOHANG if non-blocking is desired
Returns
GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise

Definition at line 840 of file os_priority.c.

844{
845 int status;
846 int ret;
847
848 GNUNET_assert (0 != proc);
849 ret = waitpid (proc->pid,
850 &status,
851 options);
852 if (ret < 0)
853 {
855 "waitpid");
856 return GNUNET_SYSERR;
857 }
858 if (0 == ret)
859 {
861 *code = 0;
862 return GNUNET_NO;
863 }
864 if (proc->pid != ret)
865 {
867 "waitpid");
868 return GNUNET_SYSERR;
869 }
870 if (WIFEXITED (status))
871 {
873 *code = WEXITSTATUS (status);
874 }
875 else if (WIFSIGNALED (status))
876 {
878 *code = WTERMSIG (status);
879 }
880 else if (WIFSTOPPED (status))
881 {
883 *code = WSTOPSIG (status);
884 }
885#ifdef WIFCONTINUED
886 else if (WIFCONTINUED (status))
887 {
889 *code = 0;
890 }
891#endif
892 else
893 {
895 *code = 0;
896 }
897
898 return GNUNET_OK;
899}

References GNUNET_assert, GNUNET_ERROR_TYPE_WARNING, GNUNET_NO, GNUNET_OK, GNUNET_OS_PROCESS_EXITED, GNUNET_OS_PROCESS_RUNNING, GNUNET_OS_PROCESS_SIGNALED, GNUNET_OS_PROCESS_UNKNOWN, GNUNET_SYSERR, LOG_STRERROR, options, GNUNET_OS_Process::pid, ret, status, and type.

Referenced by GNUNET_OS_process_status(), and GNUNET_OS_process_wait_status().

Here is the caller graph for this function:

◆ cmd_read()

static void cmd_read ( void *  cls)
static

Read from the process and call the line processor.

Parameters
clsthe struct GNUNET_OS_CommandHandle *

Definition at line 1012 of file os_priority.c.

1013{
1014 struct GNUNET_OS_CommandHandle *cmd = cls;
1015 const struct GNUNET_SCHEDULER_TaskContext *tc;
1017 char *end;
1018 ssize_t ret;
1019
1020 cmd->rtask = NULL;
1023 {
1024 /* timeout */
1025 proc = cmd->proc;
1026 cmd->proc = NULL;
1027 proc (cmd->proc_cls, NULL);
1028 return;
1029 }
1030 ret = GNUNET_DISK_file_read (cmd->r,
1031 &cmd->buf[cmd->off],
1032 sizeof(cmd->buf) - cmd->off);
1033 if (ret <= 0)
1034 {
1035 if ((cmd->off > 0) && (cmd->off < sizeof(cmd->buf)))
1036 {
1037 cmd->buf[cmd->off] = '\0';
1038 cmd->proc (cmd->proc_cls, cmd->buf);
1039 }
1040 proc = cmd->proc;
1041 cmd->proc = NULL;
1042 proc (cmd->proc_cls, NULL);
1043 return;
1044 }
1045 end = memchr (&cmd->buf[cmd->off], '\n', ret);
1046 cmd->off += ret;
1047 while (NULL != end)
1048 {
1049 *end = '\0';
1050 cmd->proc (cmd->proc_cls, cmd->buf);
1051 memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf));
1052 cmd->off -= (end + 1 - cmd->buf);
1053 end = memchr (cmd->buf, '\n', cmd->off);
1054 }
1055 cmd->rtask =
1057 cmd->timeout),
1058 cmd->r,
1059 &cmd_read,
1060 cmd);
1061}

References GNUNET_OS_CommandHandle::buf, cmd_read(), end, GNUNET_DISK_file_read(), GNUNET_NETWORK_fdset_handle_isset(), GNUNET_SCHEDULER_add_read_file(), GNUNET_SCHEDULER_get_task_context(), GNUNET_TIME_absolute_get_remaining(), GNUNET_YES, GNUNET_OS_CommandHandle::off, GNUNET_OS_CommandHandle::proc, GNUNET_OS_CommandHandle::proc_cls, GNUNET_OS_CommandHandle::r, GNUNET_SCHEDULER_TaskContext::read_ready, ret, GNUNET_OS_CommandHandle::rtask, tc, and GNUNET_OS_CommandHandle::timeout.

Referenced by cmd_read(), and GNUNET_OS_command_run().

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

Variable Documentation

◆ current_process

struct GNUNET_OS_Process current_process
static

Handle for 'this' process.

Definition at line 63 of file os_priority.c.

Referenced by GNUNET_OS_process_current().

◆ pch

◆ spch

struct GNUNET_SCHEDULER_Task* spch
static

Handle for the shutdown_pch() Task.

Definition at line 73 of file os_priority.c.

Referenced by GNUNET_OS_install_parent_control_handler(), and parent_control_handler().