<commit_before>/*
 * command.c: Child command execution
 *
 * Copyright (C) 2010-2012 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>

#if HAVE_CAPNG
# include <cap-ng.h>
#endif

#include "command.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
#include "logging.h"
#include "virfile.h"
#include "virpidfile.h"
#include "buf.h"
#include "ignore-value.h"
#include "verify.h"

#define VIR_FROM_THIS VIR_FROM_NONE

#define virCommandError(code, ...)                                      \
    virReportErrorHelper(VIR_FROM_NONE, code, __FILE__,                 \
                         __FUNCTION__, __LINE__, __VA_ARGS__)

/* We have quite a bit of changes to make if this doesn't hold.  */
verify(sizeof(pid_t) <= sizeof(int));

/* Flags for virExecWithHook */
enum {
    VIR_EXEC_NONE   = 0,
    VIR_EXEC_NONBLOCK = (1 << 0),
    VIR_EXEC_DAEMON = (1 << 1),
    VIR_EXEC_CLEAR_CAPS = (1 << 2),
    VIR_EXEC_RUN_SYNC = (1 << 3),
};

struct _virCommand {
    int has_error; /* ENOMEM on allocation failure, -1 for anything else.  */

    char **args;
    size_t nargs;
    size_t maxargs;

    char **env;
    size_t nenv;
    size_t maxenv;

    char *pwd;

    int *preserve; /* FDs to pass to child. */
    int preserve_size;
    int *transfer; /* FDs to close in parent. */
    int transfer_size;

    unsigned int flags;

    char *inbuf;
    char **outbuf;
    char **errbuf;

    int infd;
    int inpipe;
    int outfd;
    int errfd;
    int *outfdptr;
    int *errfdptr;

    bool handshake;
    int handshakeWait[2];
    int handshakeNotify[2];

    virExecHook hook;
    void *opaque;

    pid_t pid;
    char *pidfile;
    bool reap;

    unsigned long long capabilities;
};

/*
 * virCommandFDIsSet:
 * @fd: FD to test
 * @set: the set
 * @set_size: actual size of @set
 *
 * Check if FD is already in @set or not.
 *
 * Returns true if @set contains @fd,
 * false otherwise.
 */
static bool
virCommandFDIsSet(int fd,
                  const int *set,
                  int set_size)
{
    int i = 0;

    while (i < set_size)
        if (set[i++] == fd)
            return true;

    return false;
}

/*
 * virCommandFDSet:
 * @fd: FD to be put into @set
 * @set: the set
 * @set_size: actual size of @set
 *
 * This is practically generalized implementation
 * of FD_SET() as we do not want to be limited
 * by FD_SETSIZE.
 *
 * Returns: 0 on success,
 *          -1 on usage error,
 *          ENOMEM on OOM
 */
static int
virCommandFDSet(int fd,
                int **set,
                int *set_size)
{
    if (fd < 0 || !set || !set_size)
        return -1;

    if (virCommandFDIsSet(fd, *set, *set_size))
        return 0;

    if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
        return ENOMEM;
    }

    (*set)[*set_size] = fd;
    (*set_size)++;

    return 0;
}

#ifndef WIN32

# if HAVE_CAPNG
static int virClearCapabilities(void) ATTRIBUTE_UNUSED;
static int virClearCapabilities(void)
{
    int ret;

    capng_clear(CAPNG_SELECT_BOTH);

    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
        virCommandError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot clear process capabilities %d"), ret);
        return -1;
    }

    return 0;
}

/**
 * virSetCapabilities:
 *  @capabilities - capability flag to set.
 *                  In case of 0, this function is identical to
 *                  virClearCapabilities()
 *
 */
static int virSetCapabilities(unsigned long long capabilities)
{
    int ret, i;

    capng_clear(CAPNG_SELECT_BOTH);

    for (i = 0; i <= CAP_LAST_CAP; i++) {
        if (capabilities & (1ULL << i))
            capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i);
    }

    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
        virCommandError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot apply process capabilities %d"), ret);
        return -1;
    }

    return 0;
}
# else
static int virClearCapabilities(void)
{
//    VIR_WARN("libcap-ng support not compiled in, unable to clear "
//             "capabilities");
    return 0;
}

static int virSetCapabilities(unsigned long long capabilities)
{
    return 0;
}
# endif

/**
 * virFork:
 * @pid - a pointer to a pid_t that will receive the return value from
 *        fork()
 *
 * fork a new process while avoiding various race/deadlock conditions
 *
 * on return from virFork(), if *pid < 0, the fork failed and there is
 * no new process. Otherwise, just like fork(), if *pid == 0, it is the
 * child process returning, and if *pid > 0, it is the parent.
 *
 * Even if *pid >= 0, if the return value from virFork() is < 0, it
 * indicates a failure that occurred in the parent or child process
 * after the fork. In this case, the child process should call
 * _exit(EXIT_FAILURE) after doing any additional error reporting.
 */
int
virFork(pid_t *pid)
{
    sigset_t oldmask, newmask;
    struct sigaction sig_action;<commit_msg>command: Fix ATTRIBUTE_UNUSED on virSetCapabilities<commit_after>/*
 * command.c: Child command execution
 *
 * Copyright (C) 2010-2012 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>

#if HAVE_CAPNG
# include <cap-ng.h>
#endif

#include "command.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
#include "logging.h"
#include "virfile.h"
#include "virpidfile.h"
#include "buf.h"
#include "ignore-value.h"
#include "verify.h"

#define VIR_FROM_THIS VIR_FROM_NONE

#define virCommandError(code, ...)                                      \
    virReportErrorHelper(VIR_FROM_NONE, code, __FILE__,                 \
                         __FUNCTION__, __LINE__, __VA_ARGS__)

/* We have quite a bit of changes to make if this doesn't hold.  */
verify(sizeof(pid_t) <= sizeof(int));

/* Flags for virExecWithHook */
enum {
    VIR_EXEC_NONE   = 0,
    VIR_EXEC_NONBLOCK = (1 << 0),
    VIR_EXEC_DAEMON = (1 << 1),
    VIR_EXEC_CLEAR_CAPS = (1 << 2),
    VIR_EXEC_RUN_SYNC = (1 << 3),
};

struct _virCommand {
    int has_error; /* ENOMEM on allocation failure, -1 for anything else.  */

    char **args;
    size_t nargs;
    size_t maxargs;

    char **env;
    size_t nenv;
    size_t maxenv;

    char *pwd;

    int *preserve; /* FDs to pass to child. */
    int preserve_size;
    int *transfer; /* FDs to close in parent. */
    int transfer_size;

    unsigned int flags;

    char *inbuf;
    char **outbuf;
    char **errbuf;

    int infd;
    int inpipe;
    int outfd;
    int errfd;
    int *outfdptr;
    int *errfdptr;

    bool handshake;
    int handshakeWait[2];
    int handshakeNotify[2];

    virExecHook hook;
    void *opaque;

    pid_t pid;
    char *pidfile;
    bool reap;

    unsigned long long capabilities;
};

/*
 * virCommandFDIsSet:
 * @fd: FD to test
 * @set: the set
 * @set_size: actual size of @set
 *
 * Check if FD is already in @set or not.
 *
 * Returns true if @set contains @fd,
 * false otherwise.
 */
static bool
virCommandFDIsSet(int fd,
                  const int *set,
                  int set_size)
{
    int i = 0;

    while (i < set_size)
        if (set[i++] == fd)
            return true;

    return false;
}

/*
 * virCommandFDSet:
 * @fd: FD to be put into @set
 * @set: the set
 * @set_size: actual size of @set
 *
 * This is practically generalized implementation
 * of FD_SET() as we do not want to be limited
 * by FD_SETSIZE.
 *
 * Returns: 0 on success,
 *          -1 on usage error,
 *          ENOMEM on OOM
 */
static int
virCommandFDSet(int fd,
                int **set,
                int *set_size)
{
    if (fd < 0 || !set || !set_size)
        return -1;

    if (virCommandFDIsSet(fd, *set, *set_size))
        return 0;

    if (VIR_REALLOC_N(*set, *set_size + 1) < 0) {
        return ENOMEM;
    }

    (*set)[*set_size] = fd;
    (*set_size)++;

    return 0;
}

#ifndef WIN32

static int virClearCapabilities(void) ATTRIBUTE_UNUSED;

# if HAVE_CAPNG
static int virClearCapabilities(void)
{
    int ret;

    capng_clear(CAPNG_SELECT_BOTH);

    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
        virCommandError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot clear process capabilities %d"), ret);
        return -1;
    }

    return 0;
}

/**
 * virSetCapabilities:
 *  @capabilities - capability flag to set.
 *                  In case of 0, this function is identical to
 *                  virClearCapabilities()
 *
 */
static int virSetCapabilities(unsigned long long capabilities)
{
    int ret, i;

    capng_clear(CAPNG_SELECT_BOTH);

    for (i = 0; i <= CAP_LAST_CAP; i++) {
        if (capabilities & (1ULL << i))
            capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i);
    }

    if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
        virCommandError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot apply process capabilities %d"), ret);
        return -1;
    }

    return 0;
}
# else
static int virClearCapabilities(void)
{
//    VIR_WARN("libcap-ng support not compiled in, unable to clear "
//             "capabilities");
    return 0;
}

static int
virSetCapabilities(unsigned long long capabilities ATTRIBUTE_UNUSED)
{
    return 0;
}
# endif

/**
 * virFork:
 * @pid - a pointer to a pid_t that will receive the return value from
 *        fork()
 *
 * fork a new process while avoiding various race/deadlock conditions
 *
 * on return from virFork(), if *pid < 0, the fork failed and there is
 * no new process. Otherwise, just like fork(), if *pid == 0, it is the
 * child process returning, and if *pid > 0, it is the parent.
 *
 * Even if *pid >= 0, if the return value from virFork() is < 0, it
 * indicates a failure that occurred in the parent or child process
 * after the fork. In this case, the child process should call
 * _exit(EXIT_FAILURE) after doing any additional error reporting.
 */
int
virFork(pid_t *pid)
{
    sigset_t oldmask, newmask;
    struct sigaction sig_action;
{'fraction_non_alphanumeric': 0.10455093949319083, 'fraction_numerical': 0.010860196517841751, 'mean_word_length': 2.6202808112324494, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4849166', 'n_tokens_mistral': 3946, 'n_tokens_neox': 3744, 'n_words': 1298}