C++程序  |  68行  |  2.26 KB

/*
 * Copyright 2018, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "fork.h"

#include "log.h"

#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

bool forkAndExec(const char* argv[]) {
    pid_t pid = ::fork();
    if (pid < 0) {
        // Failed to fork
        LOGE("fork() failed: %s", strerror(errno));
        return false;
    } else if (pid == 0) {
        // Child
        char buffer[32768];
        size_t offset = 0;
        for (size_t i = 0; argv[i]; ++i) {
            offset += snprintf(buffer + offset, sizeof(buffer) - offset,
                               "%s ", argv[i]);
        }
        LOGE("Running '%s'", buffer);
        execvp(argv[0], const_cast<char* const*>(argv));
        LOGE("Failed to run '%s': %s", argv[0], strerror(errno));
        _exit(1);
    } else {
        // Parent
        int status = 0;
        do {
            ::waitpid(pid, &status, 0);
            if (WIFEXITED(status)) {
                int exitStatus = WEXITSTATUS(status);
                if (exitStatus == 0) {
                    return true;
                }
                LOGE("Error: '%s' exited with code: %d", argv[0], exitStatus);
            } else if (WIFSIGNALED(status)) {
                LOGE("Error: '%s' terminated with signal: %d",
                     argv[0], WTERMSIG(status));
            }
            // Other possibilities include being stopped and continued as part
            // of a trace but we don't really care about that. The important
            // part is that unless the process explicitly exited or was killed
            // by a signal we have to keep waiting.
        } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        return false;
    }
}