text: /*@ S-nail - a mail user agent derived from Berkeley Mail.
   *@ Child process handling, direct (pipe streams are in file-streams.h).
   *
   * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
   * SPDX-License-Identifier: ISC
   *
   * Permission to use, copy, modify, and/or distribute this software for any
   * purpose with or without fee is hereby granted, provided that the above
   * copyright notice and this permission notice appear in all copies.
   *
   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   */
  #ifndef mx_CHILD_H
  #define mx_CHILD_H
  
  #include <mx/nail.h>
  
  #define mx_HEADER
  #include <su/code-in.h>
  
  struct mx_child_ctx;
  
  /* */
  #define mx_CHILD_MAXARGS 3 /* xxx vector */
  
  enum mx_child_flags{
     mx_CHILD_NONE = 0,
     /* Ensure the forked child has started running (as opposed to the default
      * success which only remarks "fork(2) has returned successfully") */
     mx_CHILD_SPAWN_CONTROL = 1u<<0,
     /* On top of SPAWN_CONTROL, wait until the child called execve */
     mx_CHILD_SPAWN_CONTROL_LINGER = 1u<<1,
     /* run(): handle all the lifetime, and wait etc., return final status */
     mx_CHILD_RUN_WAIT_LIFE = 1u<<2,
  
     /* Child uses terminal and requires termios handling */
     mx__CHILD_JOBCTL = 1u<<8
  };
  
  /* mx_child_ctx_setup() to zero out */
  struct mx_child_ctx{
     /* Output: */
     s32 cc_pid; /* Filled upon successful start (when not waited..) */
     s32 cc_exit_status; /* WEXITSTATUS(); -WEXITSTATUS() if !WIFEXITED */
     /* err_no() on failure; with SPAWN_CONTROL it could be set to errors that
      * happen in the child, too; set to ERR_CHILD when there was error and there
      * was no error */
     s32 cc_error;
     u32 cc_flags; /* child_flags */
     /* Input: the arguments are all optional */
     /* Signals must be handled by the caller.  If this is set, then it is
      * a sigset_t*: the signals to ignore in the new process.
      * SIGINT is enabled unless it is in the mask. */
     void *cc_mask; /* In fact a sigset_t XXX su_sigset! */
     s32 cc_fds[2]; /* A real FD, or _FD_PASS or _FD_NULL XXX sz[2] */
     char const *cc_cmd; /* The command to run, */
     char const *cc_args[mx_CHILD_MAXARGS]; /* and its optional arguments */
     /* NIL or NIL terminated array; Note: is modified if set! */
     char const **cc_env_addon; /* TODO su_dict */
     sz cc__cpipe[2];
  };
  
  /* Slots in .cc_fds */
  #define mx_CHILD_FD_IN 0
  #define mx_CHILD_FD_OUT 1
  
  /* Special file descriptors for .cc_fds */
  #define mx_CHILD_FD_PASS (-1)
  #define mx_CHILD_FD_NULL (-2)
  
  /* At program startup: initialize controller (panic on failure) */
  EXPORT void mx_child_controller_setup(void);
  
  /* Initialize (zero out etc.).  The .cc_fds are set to CHILD_FD_PASS */
  EXPORT void mx_child_ctx_setup(struct mx_child_ctx *ccp);
  
  /* Start and run a command, with optional arguments and splicing of stdin and
   * stdout, as defined by the ctx_setup()d ccp, return whether the process has
   * been started successfully.
   * With RUN_WAIT_LIFE the return value also indicates whether the parent has
   * child_wait()ed successfully, i.e., whether the child has terminated
   * already; .cc_exit_status etc. can be examined for more.
   * Otherwise _signal(), _forget() and _wait() can be used on ccp */
  EXPORT boole mx_child_run(struct mx_child_ctx *ccp);
  
  /* Fork a child process, "enable" the below functions upon success.
   * With SPAWN_CONTROL the parent will linger until the child has called
   * in_child_setup() or even (with SPAWN_CONTROL_LINGER) until it execve's.
   * Children can start children themselves, but we do not care about termios
   * XXX or child handling no more in recursive levels */
  EXPORT boole mx_child_fork(struct mx_child_ctx *ccp);
  
  /* Setup an image in the child; signals are still blocked before that! */
  EXPORT void mx_child_in_child_setup(struct mx_child_ctx *ccp);
  
  /* This can only be used if SPAWN_CONTROL_LINGER had been used.
   * It will pass err up to the parent, and close the control pipe.
   * It does not exit the program */
  EXPORT void mx_child_in_child_exec_failed(struct mx_child_ctx *ccp, s32 err);
  
  /* Send a signal to a managed process, return 0 on success, a negative value
   * if the process does no(t) (longer) exist, or an error constant */
  EXPORT s32 mx_child_signal(struct mx_child_ctx *ccp, s32 sig);
  
  /* Loose any knowledge we might have regarding ccp.
   * Neither waiting nor any other status report will be available.
   * This must not be used in conjunction with FD_PASS. */
  EXPORT void mx_child_forget(struct mx_child_ctx *ccp);
  
  /* Wait on the child and return whether ccp was a known child and has been
   * waited for successfully; examine ccp for error / status */
  EXPORT boole mx_child_wait(struct mx_child_ctx *ccp);
  
  #include <su/code-ou.h>
  #endif /* mx_CHILD_H */
  /* s-it-mode */
  