aboutsummaryrefslogtreecommitdiffstats
path: root/libexec.h
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
committerMattias Andrée <maandree@kth.se>2024-05-05 10:24:40 +0200
commit3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e (patch)
treeb7717583b99f29028c85c3423cf43b104dfa8943 /libexec.h
downloadlibexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.gz
libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.bz2
libexec-3dfd6c11ed5599ab8baf4a6114f4ccb34150de6e.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libexec.h')
-rw-r--r--libexec.h1633
1 files changed, 1633 insertions, 0 deletions
diff --git a/libexec.h b/libexec.h
new file mode 100644
index 0000000..5f7b2d0
--- /dev/null
+++ b/libexec.h
@@ -0,0 +1,1633 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBEXEC_H
+#define LIBEXEC_H
+
+
+#if defined(__linux__)
+# include <linux/openat2.h>
+#endif
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+
+
+/* For internal use only { */
+#if defined(__GNUC__)
+# define LIBEXEC_PURE__ __attribute__((__pure__))
+# define LIBEXEC_CONST__ __attribute__((__const__))
+# define LIBEXEC_PRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), (FMTIDX) + 1)))
+# define LIBEXEC_VPRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), 0)))
+#else
+# define LIBEXEC_PURE__
+# define LIBEXEC_CONST__
+# define LIBEXEC_PRINTF__(FMTIDX)
+# define LIBEXEC_VPRINTF__(FMTIDX)
+#endif
+/* } */
+
+
+#define LIBEXEC_VERSION 0U
+
+
+enum libexec_insert_mode {
+ LIBEXEC_REPLACE, /* replace existing definition if any */
+ LIBEXEC_NOREPLACE, /* do nothing if definition already exists */
+ LIBEXEC_NOCLOBBER, /* fail if definition already exists an differs */
+ LIBEXEC_APPEND, /* add, to end of list, even if definition already exists, but also keep old */
+ LIBEXEC_PREPEND /* add, to beginning of list, even if definition already exists, but also keep old */
+ /* Either LIBEXEC_APPEND or LIBEXEC_PREPEND is required to put something missing '=' in the environment */
+#define LIBEXEC_INSERT_MODE__COUNT__ 5
+};
+
+enum libexec_pluming_type {
+ LIBEXEC_PLUMING_OPENAT,
+ LIBEXEC_PLUMING_OPENAT2,
+ LIBEXEC_PLUMING_CLOSE,
+ LIBEXEC_PLUMING_DUP2,
+ LIBEXEC_PLUMING_DOCUMENT,
+ LIBEXEC_PLUMING_PIPE
+#define LIBEXEC_PLUMING_TYPE__COUNT__ 6
+};
+
+enum libexec_pipe {
+ LIBEXEC_PIPE = 0,
+ LIBEXEC_SOCK_STREAM = 1,
+ LIBEXEC_SOCK_SEQPACKET = 2,
+ LIBEXEC_SOCK_DGRAM = 3,
+ LIBEXEC_DIRECT_PIPE = 4,
+ LIBEXEC_PIPE_CIRCULARLY = 0x8000
+#define LIBEXEC_PIPE__COUNT__ 5
+};
+
+enum libexec_locate_method {
+ LIBEXEC_ALLOW_NAME,
+ LIBEXEC_REQUIRE_PATH,
+ LIBEXEC_EXEC_FD,
+ LIBEXEC_EXEC_AT
+#define LIBEXEC_LOCATE_METHOD__COUNT__ 4
+};
+
+enum libexec_run_instruction {
+ LIBEXEC_RUN_END, /* required to mark end if arguments for libexec_run */
+ LIBEXEC_RUN_END_CIRCULAR_PIPE, /* alternative to LIBEXEC_RUN_END */
+ LIBEXEC_RUN_PIPE,
+ LIBEXEC_RUN_SET_EXECUTABLE,
+ LIBEXEC_RUN_SET_REQUIRE_PATH,
+ LIBEXEC_RUN_SET_EXEC_FD,
+ LIBEXEC_RUN_SET_EXEC_PATH,
+ LIBEXEC_RUN_COPY_ENVIRON,
+ LIBEXEC_RUN_SET_ENVIRON,
+ LIBEXEC_RUN_CLEAR_ENVIRON,
+ LIBEXEC_RUN_UNSETENV,
+ LIBEXEC_RUN_PUTENV,
+ LIBEXEC_RUN_SETENV,
+ LIBEXEC_RUN_PUTENVF,
+ LIBEXEC_RUN_SETENVF,
+ LIBEXEC_RUN_OPEN,
+ LIBEXEC_RUN_OPENAT,
+ LIBEXEC_RUN_OPENAT2, /* generates ENOSYS unless running on Linux */
+ LIBEXEC_RUN_DUP,
+ LIBEXEC_RUN_CLOSE,
+ LIBEXEC_RUN_RENUMBER_FD,
+ LIBEXEC_RUN_INPUT_COPY,
+ LIBEXEC_RUN_INPUT_GIFT,
+ LIBEXEC_RUN_ADD_OUTPUT_FD, /* use LIBEXEC_RUN_SET_FD_CALLBACK first */
+ LIBEXEC_RUN_ADD_OUTPUT,
+ LIBEXEC_RUN_SET_SIGMASK, /* use once to configure how libexec_run_pipeline is invoked behind the scenes */
+ LIBEXEC_RUN_SET_FD_CALLBACK, /* ditto */
+ LIBEXEC_RUN_SET_REAPER, /* ditto */
+ LIBEXEC_RUN_SET_ATFORK, /* ditto */
+ LIBEXEC_RUN_SET_MUTEX, /* ditto */
+ LIBEXEC_RUN_SET_INTERRUPT_CALLBACK /* ditto */
+#define LIBEXEC_RUN_INSTRUCTION__COUNT__ 31
+};
+#define LIBEXEC_RUN_END() LIBEXEC_RUN_END
+#define LIBEXEC_RUN_END_CIRCULAR_PIPE(TYPE) LIBEXEC_RUN_END_CIRCULAR_PIPE, TYPE
+#define LIBEXEC_RUN_PIPE(TYPE) LIBEXEC_RUN_PIPE, TYPE
+#define LIBEXEC_RUN_SET_EXECUTABLE(FILE) LIBEXEC_RUN_SET_EXECUTABLE, FILE
+#define LIBEXEC_RUN_SET_REQUIRE_PATH(REQUIRE) LIBEXEC_RUN_SET_REQUIRE_PATH, REQUIRE
+#define LIBEXEC_RUN_SET_EXEC_FD(FD) LIBEXEC_RUN_SET_EXEC_FD, FD
+#define LIBEXEC_RUN_SET_EXEC_PATH(DIRFD, PATH) LIBEXEC_RUN_SET_EXEC_PATH, DIRFD, PATH
+#define LIBEXEC_RUN_COPY_ENVIRON(ENVIRON) LIBEXEC_RUN_COPY_ENVIRON, ENVIRON
+#define LIBEXEC_RUN_SET_ENVIRON(ENVIRON) LIBEXEC_RUN_SET_ENVIRON, ENVIRON
+#define LIBEXEC_RUN_CLEAR_ENVIRON(ENVIRON) LIBEXEC_RUN_CLEAR_ENVIRON
+#define LIBEXEC_RUN_UNSETENV(ENV) LIBEXEC_RUN_UNSETENV, ENV
+#define LIBEXEC_RUN_PUTENV(... /* STR, [HOW] */) LIBEXEC_RUN_PUTENV__(__VA_ARGS__, LIBEXEC_REPLACE,)
+#define LIBEXEC_RUN_SETENV(... /* ENV, VAL, [HOW] */) LIBEXEC_RUN_PUTENV__(__VA_ARGS__, LIBEXEC_REPLACE,)
+#define LIBEXEC_RUN_PUTENV_SAFE(HOW, STR) LIBEXEC_RUN_PUTENV, HOW, STR
+#define LIBEXEC_RUN_SETENV_SAFE(HOW, ENV, VAL) LIBEXEC_RUN_SETENV, HOW, ENV, VAL
+#define LIBEXEC_RUN_PUTENVF_SAFE(HOW, ...) LIBEXEC_RUN_PUTENV, HOW, __VA_ARGS__
+#define LIBEXEC_RUN_SETENVF_SAFE(HOW, ENV, ...) LIBEXEC_RUN_SETENV, HOW, ENV, __VA_ARGS__
+#define LIBEXEC_RUN_PUTENVF(...) LIBEXEC_RUN_PUTENVF_SAFE(LIBEXEC_REPLACE, __VA_ARGS__)
+#define LIBEXEC_RUN_SETENVF(ENV, ...) LIBEXEC_RUN_SETENVF_SAFE(LIBEXEC_REPLACE, ENV, __VA_ARGS__)
+#define LIBEXEC_RUN_OPEN(FD, FILE, ... /* FLAGS, [MODE] */) LIBEXEC_RUN_OPEN__(FD, FILE, __VA_ARGS__, 0666,)
+#define LIBEXEC_RUN_OPENAT(FD, DIRFD, FILE, ... /* FLAGS, [MODE] */) LIBEXEC_RUN_OPENAT__(FD, DIRFD, FILE, __VA_ARGS__, 0666,)
+#define LIBEXEC_RUN_OPENAT2(FD, DIRFD, FILE, ... /* HOW, [SIZE] */)\
+ LIBEXEC_RUN_OPENAT2__(FD, DIRFD, FILE, __VA_ARGS__, sizeof(LIBEXEC__FIRST__(__VA_ARGS__,)),)
+#define LIBEXEC_RUN_DUP(NEW_FD, OLD_FD) LIBEXEC_RUN_DUP, NEW_FD, OLD_FD
+#define LIBEXEC_RUN_CLOSE(FD) LIBEXEC_RUN_CLOSE, FD
+#define LIBEXEC_RUN_RENUMBER_FD(NEW_FD, OLD_FD) LIBEXEC_RUN_RENUMBER_FD, NEW_FD, OLD_FD
+#define LIBEXEC_RUN_INPUT_COPY(FD, ... /* DATA, [LEN] */)\
+ LIBEXEC_RUN_INPUT__(COPY, FD, __VA_ARGS__, strlen(LIBEXEC__FIRST__(__VA_ARGS__)),)
+#define LIBEXEC_RUN_INPUT_GIFT(FD, ... /* DATA, [LEN] */)\
+ LIBEXEC_RUN_INPUT__(GIFT, FD, __VA_ARGS__, strlen(LIBEXEC__FIRST__(__VA_ARGS__)),)
+#define LIBEXEC_RUN_ADD_OUTPUT_FD(FD, WR_FD) LIBEXEC_RUN_ADD_OUTPUT_FD, FD, WR_FD
+#define LIBEXEC_RUN_ADD_OUTPUT(FD, OUT) LIBEXEC_RUN_ADD_OUTPUT, FD, OUT
+#define LIBEXEC_RUN_SET_SIGMASK(SIGMASK) LIBEXEC_RUN_SET_SIGMASK, SIGMASK
+#define LIBEXEC_RUN_SET_FD_CALLBACK(CB, USER) LIBEXEC_RUN_SET_FD_CALLBACK, CB, USER
+#define LIBEXEC_RUN_SET_REAPER(CB, USER) LIBEXEC_RUN_SET_REAPER, CB, USER
+#define LIBEXEC_RUN_SET_ATFORK(CB, USER) LIBEXEC_RUN_SET_ATFORK, CB, USER
+#define LIBEXEC_RUN_SET_MUTEX(CB, USER) LIBEXEC_RUN_SET_MUTEX, CB, USER
+#define LIBEXEC_RUN_SET_INTERRUPT_CALLBACK(CB, USER) LIBEXEC_RUN_SET_INTERRUPT_CALLBACK, CB, USER
+
+#define LIBEXEC__FIRST__(X, ...) X
+#define LIBEXEC_RUN_PUTENV__(STR, HOW, ...) LIBEXEC_RUN_PUTENV, HOW, STR
+#define LIBEXEC_RUN_SETENV__(ENV, VAL, HOW, ...) LIBEXEC_RUN_SETENV, HOW, ENV, VAL
+#define LIBEXEC_RUN_OPEN__(FD, FILE, FLAGS, MODE, ...) LIBEXEC_RUN_OPEN, FD, FILE, FLAGS, MODE
+#define LIBEXEC_RUN_OPENAT__(FD, DIRFD, FILE, FLAGS, MODE, ...) LIBEXEC_RUN_OPENAT, FD, DIRFD, FILE, FLAGS, MODE
+#define LIBEXEC_RUN_INPUT__(INSTR, FD, DATA, LEN, ...) LIBEXEC_RUN_INPUT_##INSTR, FD, DATA, LEN
+
+struct libexec_pluming {
+ int fd;
+ enum libexec_pluming_type type;
+ union {
+ int fd;
+ struct {
+ char *file;
+ int dirfd;
+ union {
+ struct {
+ mode_t mode;
+ int flags;
+ };
+#if defined(__linux__)
+ struct {
+ struct open_how *how;
+ size_t how_size;
+ };
+#endif
+ };
+ };
+ struct {
+ char *text;
+ size_t len;
+ };
+ } target;
+};
+
+#define LIBEXEC_COMMAND_INIT\
+ ((struct libexec_command){LIBEXEC_VERSION, LIBEXEC_ALLOW_NAME, -1, NULL, NULL, 0, NULL, 0, NULL})
+struct libexec_command {
+ unsigned library_version;
+ enum libexec_locate_method exec_how;
+ int exec_fd;
+ char *executable;
+ char **arguments;
+ size_t narguments;
+ struct libexec_pluming *plumings;
+ size_t nplumings;
+ char **environ;
+};
+
+struct libexec_document {
+ unsigned long long int user;
+ int fd;
+ char *text;
+ size_t length;
+ union {
+ size_t offset; /* when used for input */
+ size_t alloc_size; /* when used for output */
+ };
+};
+
+struct libexec_result {
+ int *exit_statuses;
+ size_t proc_count;
+ int all_successful;
+};
+
+
+void libexec_init_command(struct libexec_command *cmd);
+void libexec_destroy_command(struct libexec_command *cmd);
+void libexec_destroy_pluming(struct libexec_pluming *pluming);
+int libexec_destroy_document(struct libexec_document *doc);
+void libexec_destroy_result(struct libexec_result *result);
+
+int libexec_vconstruct_command(struct libexec_command *cmd, const char *fmt, va_list args);
+int libexec_construct_command(struct libexec_command *cmd, const char *fmt, ...);
+int libexec_put_argumentsn(struct libexec_command *cmd, const char *const *args, size_t nargs);
+int libexec_put_arguments(struct libexec_command *cmd, const char *const *args);
+int libexec_set_executable(struct libexec_command *cmd, const char *executable /* NULL = use first argument in command */);
+void libexec_set_require_path(struct libexec_command *cmd, int require);
+int libexec_set_exec_fd(struct libexec_command *cmd, int fd);
+int libexec_set_exec_path(struct libexec_command *cmd, int dirfd, const char *path /* NULL = use first argument in command */);
+
+int libexec_add_pluming(struct libexec_command *cmd, const struct libexec_pluming *pluming);
+int libexec_open(struct libexec_command *cmd, int fd, const char *file, int flags, mode_t mode);
+int libexec_openat(struct libexec_command *cmd, int fd, int dirfd, const char *file, int flags, mode_t mode);
+#if defined(__linux__)
+int libexec_openat2(struct libexec_command *cmd, int fd, int dirfd, const char *file, struct open_how *how, size_t size);
+#endif
+int libexec_dup(struct libexec_command *cmd, int fd, int old_fd);
+int libexec_close(struct libexec_command *cmd, int fd);
+int libexec_renumber_fd(struct libexec_command *cmd, int fd, int old_fd);
+int libexec_input_data_copy(struct libexec_command *cmd, int fd, const char *data, size_t len);
+int libexec_input_data_gift(struct libexec_command *cmd, int fd, char *data, size_t len);
+int libexec_input_text_copy(struct libexec_command *cmd, int fd, const char *text);
+int libexec_input_text_gift(struct libexec_command *cmd, int fd, char *text);
+int libexec_add_output_fd(struct libexec_command *cmd, int fd, int wr_fd);
+int libexec_add_output_document(struct libexec_command *cmd, int fd, struct libexec_document *doc /* .fd will be set */, int flags);
+
+
+/**
+ * The the value of an environment variable in a command
+ *
+ * If command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment is inspected
+ *
+ * In the event that the environment contains multiple
+ * definitions of the same variable, the first definition
+ * is used
+ *
+ * @param cmd The command whose environment shall be inspected
+ * @param name The name of the environment variable to read
+ * @return The value of the environment variable, or NULL
+ * on failure or if the environment variable was
+ * not found
+ *
+ * @throws (unmodified) The environment variable does not exist
+ * @throws EINVAL Invalid argument input
+ */
+LIBEXEC_PURE__ const char *libexec_getenv(struct libexec_command *, const char *);
+
+/**
+ * The the value of an environment variable in a command
+ *
+ * If command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment is inspected
+ *
+ * In the event that the environment contains multiple
+ * definitions of the same variable, the last definition
+ * is used
+ *
+ * @param cmd The command whose environment shall be inspected
+ * @param name The name of the environment variable to read
+ * @return The value of the environment variable, or NULL
+ * on failure or if the environment variable was
+ * not found
+ *
+ * @throws (unmodified) The environment variable does not exist
+ * @throws EINVAL Invalid argument input
+ */
+LIBEXEC_PURE__ const char *libexec_getenv_last(struct libexec_command *, const char *);
+
+
+/**
+ * Copy a list of environment variables and used it for a command
+ *
+ * @param cmd The command whose environment shall be set
+ * @param env The environment (will be copied), if NULL, the
+ * calling process's environment will be (copied
+ * and) used for the command
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_copy_environ(struct libexec_command *, const char *const *);
+
+/**
+ * Set the command's environment to a prebuilt list of
+ * environment variables
+ *
+ * @param cmd The command whose environment shall be set
+ * @param env The environment; the ownership of the input
+ * pointer and all pointers stored in it will be
+ * transfered to `cmd`, meaning that they will be
+ * deallocated using free(3) when they are removed
+ * or when `cmd` is destructed. If NULL, the
+ * commands environment will be reset to its default
+ * state, meaning that the calling process's environment
+ * (it will not be copied into `cmd`) will be used
+ * when running the command
+ */
+void libexec_set_environ(struct libexec_command *, char **);
+
+/**
+ * Clear a command's environment, removing all it's environment variables
+ *
+ * Even if the command's environment is in its default state (to
+ * use the calling process's environment), and calling process's
+ * environment is void of variables, the command's environment
+ * will be put in a non-default state, meaning that future changes
+ * to the calling process's environments variable will not affect
+ * the command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_clear_environ(struct libexec_command *);
+
+/**
+ * Remove all occurences of an environment variable
+ * in a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will be copied and set as the
+ * command's environment once the variable is found; however
+ * if the variable is not found within the environment, the
+ * command's environment will remain in its default state
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the variable to remove from the environment
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_unsetenv(struct libexec_command *, const char *);
+
+/**
+ * Remove the first occurence of an environment variable
+ * in a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will be copied and set as the
+ * command's environment once the variable is found; however
+ * if the variable is not found within the environment, the
+ * command's environment will remain in its default state
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the variable to remove from the environment
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_unsetenv_first(struct libexec_command *, const char *);
+
+/**
+ * Remove the last occurence of an environment variable
+ * in a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will be copied and set as the
+ * command's environment once the variable is found; however
+ * if the variable is not found within the environment, the
+ * command's environment will remain in its default state
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the variable to remove from the environment
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_unsetenv_last(struct libexec_command *, const char *);
+
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param string The environment variable that should be put into
+ * the environment, unless `how` is `LIBEXEC_APPEND`
+ * or `LIBEXEC_PREPEND`, it must be in the form
+ * `"%s=%s", name, value` (where `name` does not
+ * contain an equal sign)
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv(struct libexec_command *, enum libexec_insert_mode, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, unless `how` is `LIBEXEC_APPEND`
+ * or `LIBEXEC_PREPEND`, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vputenvf(struct libexec_command *, enum libexec_insert_mode, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, unless `how` is `LIBEXEC_APPEND`
+ * or `LIBEXEC_PREPEND`, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_putenvf(struct libexec_command *, enum libexec_insert_mode, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv(struct libexec_command *, enum libexec_insert_mode, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(4) int libexec_vsetenvf(struct libexec_command *, enum libexec_insert_mode, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param how Must be one of the following values:
+ * - LIBEXEC_REPLACE:
+ * If the environment already contains the
+ * variable, replace its first definition in
+ * the environment
+ * - LIBEXEC_NOREPLACE:
+ * Do not replacing already existing definition
+ * of the environment variable
+ * - LIBEXEC_NOCLOBBER:
+ * Fail if the environment already contains the
+ * variable, but has a different value
+ * - LIBEXEC_APPEND:
+ * Always the string to the end of the environment
+ * - LIBEXEC_PREPEND:
+ * Always the string to the beginning of the environment
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * (Only if `how` is `LIBEXEC_NOCLOBBER`)
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(4) int libexec_setenvf(struct libexec_command *, enum libexec_insert_mode, const char *, const char *, ...);
+
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenv(cmd, LIBEXEC_REPLACE, string)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param string The environment variable that should be put into the
+ * environment, it must be in the form `"%s=%s", name, value`
+ * (where `name` does not contain an equal sign)
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv_replace(struct libexec_command *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vputenvf(cmd, LIBEXEC_REPLACE, fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(2) int libexec_vputenvf_replace(struct libexec_command *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenvf(cmd, LIBEXEC_REPLACE, fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(2) int libexec_putenvf_replace(struct libexec_command *, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenv(cmd, LIBEXEC_REPLACE, name, value)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv_replace(struct libexec_command *, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vsetenvf(cmd, LIBEXEC_REPLACE, name, value_fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vsetenvf_replace(struct libexec_command *, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * replacing the first already existing definition of the
+ * variable if there is one
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenvf(cmd, LIBEXEC_REPLACE, name, value_fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_setenvf_replace(struct libexec_command *, const char *, const char *, ...);
+
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_putenv(cmd, LIBEXEC_NOREPLACE, string)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param string The environment variable that should be put into the
+ * environment, it must be in the form `"%s=%s", name, value`
+ * (where `name` does not contain an equal sign)
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv_noreplace(struct libexec_command *, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_vputenvf(cmd, LIBEXEC_NOREPLACE, fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(2) int libexec_vputenvf_noreplace(struct libexec_command *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_putenvf(cmd, LIBEXEC_NOREPLACE, fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(2) int libexec_putenvf_noreplace(struct libexec_command *, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_setenv(cmd, LIBEXEC_NOREPLACE, name, value)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv_noreplace(struct libexec_command *, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_vsetenvf(cmd, LIBEXEC_NOREPLACE, name, value_fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vsetenvf_noreplace(struct libexec_command *, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, the command's environment variable will not
+ * be modified, except that initialisation from default state
+ * as describe above will take place
+ *
+ * Equivalent to `libexec_setenvf(cmd, LIBEXEC_NOREPLACE, name, value_fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_setenvf_noreplace(struct libexec_command *, const char *, const char *, ...);
+
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_putenv(cmd, LIBEXEC_NOCLOBBER, string)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param string The environment variable that should be put into the
+ * environment, it must be in the form `"%s=%s", name, value`
+ * (where `name` does not contain an equal sign)
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv_noclobber(struct libexec_command *, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_vputenvf(cmd, LIBEXEC_NOCLOBBER, fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(2) int libexec_vputenvf_noclobber(struct libexec_command *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_putenvf(cmd, LIBEXEC_NOCLOBBER, fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment, the resulting string must
+ * be in the form `"%s=%s", name, value` (where `name`
+ * does not contain an equal sign)
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(2) int libexec_putenvf_noclobber(struct libexec_command *, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_setenv(cmd, LIBEXEC_NOCLOBBER, name, value)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv_noclobber(struct libexec_command *, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_vsetenvf(cmd, LIBEXEC_NOCLOBBER, name, value_fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vsetenvf_noclobber(struct libexec_command *, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * If the environment variable already exists in the command's
+ * environment, but has a different value, the function will
+ * fail without side effects
+ *
+ * Equivalent to `libexec_setenvf(cmd, LIBEXEC_NOCLOBBER, name, value_fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws (unmodified) The environment variable already exists
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_setenvf_noclobber(struct libexec_command *, const char *, const char *, ...);
+
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenv(cmd, LIBEXEC_APPEND, string)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param string The environment variable that should be put into the
+ * environment; there is no requirement that it contains
+ * an equal sign
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv_append(struct libexec_command *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vputenvf(cmd, LIBEXEC_APPEND, fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment; there is no requirement that
+ * the resulting string contains an equal sign
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(2) int libexec_vputenvf_append(struct libexec_command *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenvf(cmd, LIBEXEC_APPEND, fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment; there is no requirement that
+ * the resulting string contains an equal sign
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(2) int libexec_putenvf_append(struct libexec_command *, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenv(cmd, LIBEXEC_APPEND, name, value)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv_append(struct libexec_command *, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vsetenvf(cmd, LIBEXEC_APPEND, name, value_fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vsetenvf_append(struct libexec_command *, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the end of the environment regardless of
+ * whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenvf(cmd, LIBEXEC_APPEND, name, value_fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_setenvf_append(struct libexec_command *, const char *, const char *, ...);
+
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenv(cmd, LIBEXEC_PREPEND, string)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param string The environment variable that should be put into the
+ * environment; there is no requirement that it contains
+ * an equal sign
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_putenv_prepend(struct libexec_command *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vputenvf(cmd, LIBEXEC_PREPEND, fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment; there is no requirement that
+ * the resulting string contains an equal sign
+ * @param args Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(2) int libexec_vputenvf_prepend(struct libexec_command *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_putenvf(cmd, LIBEXEC_PREPEND, fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param fmt Formatting string, following the rules of printf(3),
+ * for the environment variable that should be put
+ * into the environment; there is no requirement that
+ * the resulting string contains an equal sign
+ * @param ... Arguments for `fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(2) int libexec_putenvf_prepend(struct libexec_command *, const char *, ...);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenv(cmd, LIBEXEC_PREPEND, name, value)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value The value that shall be associated with the
+ * environment variable
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ */
+int libexec_setenv_prepend(struct libexec_command *, const char *, const char *);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_vsetenvf(cmd, LIBEXEC_PREPEND, name, value_fmt, args)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param args Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_VPRINTF__(3) int libexec_vsetenvf_prepend(struct libexec_command *, const char *, const char *, va_list);
+
+/**
+ * Put an environment variable into a command's environment,
+ * adding it to the beginning of the environment regardless
+ * of whether the variable already exists
+ *
+ * If the command's environment is in its default state (to
+ * use the calling process's environment), the calling
+ * process's environment will first be copied and set as the
+ * command's environment
+ *
+ * Equivalent to `libexec_setenvf(cmd, LIBEXEC_PREPEND, name, value_fmt, ...)`
+ *
+ * @param cmd The command whose environment shall be modified
+ * @param name The name of the environment variable, must not
+ * contain an equal sign
+ * @param value_fmt Formatting string, following the rules of printf(3),
+ * for the environment variable's value
+ * @param ... Arguments for `value_fmt`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory to modify the command's environment
+ * @throws EILSEQ According to printf(3)
+ * @throws EOVERFLOW According to printf(3)
+ */
+LIBEXEC_PRINTF__(3) int libexec_setenvf_prepend(struct libexec_command *, const char *, const char *, ...);
+
+
+/**
+ * Put a series of commands in a pipeline, piping each's
+ * standard output to the next's (when there is one)
+ * standard input
+ *
+ * Pluming data added to the commands will prefix any
+ * already existing pluming information
+ *
+ * @param how Which type of file should be used to pipe
+ * together commands, and additional options.
+ * Must be one of the following values:
+ * - LIBEXEC_PIPE:
+ * Use a normal pipe(7)
+ * - LIBEXEC_SOCK_STREAM
+ * Use a unix(7) socketpair(3) with the type SOCK_STREAM
+ * - LIBEXEC_SOCK_SEQPACKET
+ * Use a unix(7) socketpair(3) with the type SOCK_SEQPACKET
+ * - LIBEXEC_SOCK_DGRAM
+ * Use a unix(7) socketpair(3) with the type SOCK_DGRAM
+ * - LIBEXEC_DIRECT_PIPE
+ * Use an O_DIRECT pipe(7) (see pipe2(2))
+ * Optionally, the file type may be OR'ed with
+ * LIBEXEC_PIPE_CIRCULARLY to pipe the last
+ * command's standard output to the first command's
+ * standard input.
+ * @param cmds List of commands to put in a pipeline
+ * @param n The number of elements in `cmds`
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory
+ */
+int libexec_pipe_commandsvn(enum libexec_pipe how, struct libexec_command *const *cmds, size_t n);
+
+/**
+ * Put a series of commands in a pipeline, piping each's
+ * standard output to the next's (when there is one)
+ * standard input
+ *
+ * Pluming data added to the commands will prefix any
+ * already existing pluming information
+ *
+ * @param how Which type of file should be used to pipe
+ * together commands, and additional options.
+ * Must be one of the following values:
+ * - LIBEXEC_PIPE:
+ * Use a normal pipe(7)
+ * - LIBEXEC_SOCK_STREAM
+ * Use a unix(7) socketpair(3) with the type SOCK_STREAM
+ * - LIBEXEC_SOCK_SEQPACKET
+ * Use a unix(7) socketpair(3) with the type SOCK_SEQPACKET
+ * - LIBEXEC_SOCK_DGRAM
+ * Use a unix(7) socketpair(3) with the type SOCK_DGRAM
+ * - LIBEXEC_DIRECT_PIPE
+ * Use an O_DIRECT pipe(7) (see pipe2(2))
+ * Optionally, the file type may be OR'ed with
+ * LIBEXEC_PIPE_CIRCULARLY to pipe the last
+ * command's standard output to the first command's
+ * standard input.
+ * @param cmds `NULL` terminated list of commands to put in a pipeline
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory
+ */
+int libexec_pipe_commandsv(enum libexec_pipe how, struct libexec_command *const *cmds);
+
+/**
+ * Put a series of commands in a pipeline, piping each's
+ * standard output to the next's (when there is one)
+ * standard input
+ *
+ * Pluming data added to the commands will prefix any
+ * already existing pluming information
+ *
+ * @param how Which type of file should be used to pipe
+ * together commands, and additional options.
+ * Must be one of the following values:
+ * - LIBEXEC_PIPE:
+ * Use a normal pipe(7)
+ * - LIBEXEC_SOCK_STREAM
+ * Use a unix(7) socketpair(3) with the type SOCK_STREAM
+ * - LIBEXEC_SOCK_SEQPACKET
+ * Use a unix(7) socketpair(3) with the type SOCK_SEQPACKET
+ * - LIBEXEC_SOCK_DGRAM
+ * Use a unix(7) socketpair(3) with the type SOCK_DGRAM
+ * - LIBEXEC_DIRECT_PIPE
+ * Use an O_DIRECT pipe(7) (see pipe2(2))
+ * Optionally, the file type may be OR'ed with
+ * LIBEXEC_PIPE_CIRCULARLY to pipe the last
+ * command's standard output to the first command's
+ * standard input.
+ * @param args `NULL` terminated list of commands to put in a pipeline
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory
+ */
+int libexec_vpipe_commands(enum libexec_pipe how, va_list args);
+
+/**
+ * Put a series of commands in a pipeline, piping each's
+ * standard output to the next's (when there is one)
+ * standard input
+ *
+ * Pluming data added to the commands will prefix any
+ * already existing pluming information
+ *
+ * @param how Which type of file should be used to pipe
+ * together commands, and additional options.
+ * Must be one of the following values:
+ * - LIBEXEC_PIPE:
+ * Use a normal pipe(7)
+ * - LIBEXEC_SOCK_STREAM
+ * Use a unix(7) socketpair(3) with the type SOCK_STREAM
+ * - LIBEXEC_SOCK_SEQPACKET
+ * Use a unix(7) socketpair(3) with the type SOCK_SEQPACKET
+ * - LIBEXEC_SOCK_DGRAM
+ * Use a unix(7) socketpair(3) with the type SOCK_DGRAM
+ * - LIBEXEC_DIRECT_PIPE
+ * Use an O_DIRECT pipe(7) (see pipe2(2))
+ * Optionally, the file type may be OR'ed with
+ * LIBEXEC_PIPE_CIRCULARLY to pipe the last
+ * command's standard output to the first command's
+ * standard input.
+ * @param ... `NULL` terminated list of commands to put in a pipeline
+ * @return 0 on success, -1 on failure
+ *
+ * @throws EINVAL Invalid argument input
+ * @throws ENOMEM Failed to allocate enough memory
+ */
+int libexec_pipe_commands(enum libexec_pipe how, ...);
+
+
+int libexec_get_documents(struct libexec_command *cmd, struct libexec_document **docsp, size_t *ndocsp, int flags);
+int libexec_exec(struct libexec_command *cmd);
+int libexec_spawn(pid_t *out, struct libexec_command *cmd,
+ int (*after_fork)(struct libexec_command *cmd, int new_fd, void *user),
+ void *user, struct libexec_document **docsp, size_t *ndocsp, int doc_fd_flags);
+int libexec_send_document(struct libexec_document *doc);
+int libexec_recv_document(struct libexec_document *doc);
+
+/* TODO maybe its better to have `struct libexec_run_how` */
+int libexec_run_pipeline(int (*on_alien_epoll)(int alien_epoll, uint32_t events, void *user1), int alien_epoll, void *user1,
+ int (*on_alien_child_death)(pid_t pid, void *user2), void *user2,
+ int (*after_fork)(struct libexec_command *cmd, int new_fd, void *user3), void *user3,
+ int (*reap_mutex_control)(int action /* -1 = acquire, +1 = release */, void *user4), void *user4,
+ int (*on_interrupt)(void *user5), void *user5,
+ const sigset_t *sigmask /* nullable */,
+ struct libexec_document *const *docs, size_t ndocs, int docs_1_level,
+ struct libexec_command *const *cmds, int *exit_statuses_out /* nullable */, size_t ncmds);
+#define LIBEXEC_RUN_PIPELINE_NO_EPOLL NULL, -1, NULL
+#define LIBEXEC_RUN_PIPELINE_NO_CHILDREN NULL, NULL
+#define LIBEXEC_RUN_PIPELINE_NO_AFTER_FORK NULL, NULL
+#define LIBEXEC_RUN_PIPELINE_NO_THREADING NULL, NULL
+#define LIBEXEC_RUN_PIPELINE_NO_INTERRUPT NULL, NULL
+#define LIBEXEC_RUN_PIPELINE_NO_SIGMASK NULL
+#define LIBEXEC_RUN_PIPELINE_NO_OUTPUT NULL, 0, 0
+#define LIBEXEC_RUN_PIPELINE_ONLY_OUTPUT\
+ LIBEXEC_RUN_PIPELINE_NO_EPOLL,\
+ LIBEXEC_RUN_PIPELINE_NO_CHILDREN,\
+ LIBEXEC_RUN_PIPELINE_NO_AFTER_FORK,\
+ LIBEXEC_RUN_PIPELINE_NO_THREADING,\
+ LIBEXEC_RUN_PIPELINE_NO_INTERRUPT
+#define LIBEXEC_RUN_PIPELINE_NOTHING\
+ LIBEXEC_RUN_PIPELINE_ONLY_OUTPUT,\
+ LIBEXEC_RUN_PIPELINE_NO_OUTPUT
+
+int libexec_vrun(struct libexec_result *out, va_list args);
+int libexec_run(struct libexec_result *out, ...);
+
+
+#endif