1

I using boost 1_65_1 and try to run a process on MacOS. my main process is running as root I need to launch a sub launch as a normal user. My command line: su user_name -c "full The path to the Executable file". when I run the command line in the terminal as root it working.

When I try to run it using Boost Process the Process "su" is running but exit immediately with error 2.

My code for running the Process:

void RunProcess(std::string a_PathToExe, std::vector<std::string> a_Args, io_servicePtr a_pIoServicePtr,
                ProcessExitCallBack a_pProcessExitCallBack) {

    Error l_Error;
    std::stringstream l_ShellCommandLine;
    ProcessHandlePtr l_pProcess = NULL;
    boost::process::group l_Group;
    boost::shared_ptr<boost::process::async_pipe> l_PipeOutputStream =
        boost::shared_ptr<boost::process::async_pipe>(new boost::process::async_pipe(*(a_pIoServicePtr.get())));
    boost::shared_ptr<boost::process::async_pipe> l_PipeError =
        boost::shared_ptr<boost::process::async_pipe>(new boost::process::async_pipe(*(a_pIoServicePtr.get())));

    try {

        l_ShellCommandLine << "\"" << a_PathToExe << "\""
                           << " ";
        for (size_t i = 0; i < a_Args.size(); ++i) {
            l_ShellCommandLine << a_Args.at(i) << " ";
        }

        l_pProcess = ProcessHandlePtr(new boost::process::child(
            l_ShellCommandLine.str(), boost::process::std_in.close(),
            boost::process::std_out > *(l_PipeOutputStream.get()), boost::process::std_err > *(l_PipeError.get()),
            *(a_pIoServicePtr.get()), l_Group, boost::process::shell,
            boost::process::on_exit = [](int exit, const std::error_code &ec_in) {
                WRITE_INFO_LOG("The process exit with error %d %s", exit, ec_in.message().c_str());
            }));

        l_PID = l_pProcess->id();
        WaiteForProcessToExit(l_pProcess, l_PipeOutputStream, l_PipeError, a_pProcessExitCallBack);
    }

    catch (std::exception &e) {

    } catch (...) {
    }
    return;
}

void WaiteForProcessToExit(ProcessHandlePtr a_pProcessHandle,
                           boost::shared_ptr<boost::process::async_pipe> a_PipeOutputStream,
                           boost::shared_ptr<boost::process::async_pipe> a_PipeError,
                           ProcessExitCallBack a_pProcessExitCallBack) {

    std::array<char, 1024> buffer = std::array<char, 1024>{};
    a_PipeOutputStream->async_read_some(
        boost::process::buffer(buffer), [=](boost::system::error_code ec, size_t transferre) {
            if (transferre > 0) {
                std::string Line = std::string(buffer.data());
                WRITE_INFO_LOG("%s", Line.c_str());
            }

            if (ec != 0) {

                WRITE_INFO_LOG("The Process %d has exit with error code %d", a_pProcessHandle->id(), ec);
                if (a_pProcessExitCallBack != NULL) {
                    a_pProcessExitCallBack(a_pProcessHandle->id(), Error());
                }
            } else {
                WaiteForProcessToExit(a_pProcessHandle, a_PipeOutputStream, a_PipeError, a_pProcessExitCallBack);
            }
        });
}

why the sub prosess it not running? Thanks in advance

sehe
  • 374,641
  • 47
  • 450
  • 633
Liran Haim
  • 81
  • 1
  • 1
  • 5
  • 1
    wouldn't it be better to `fork`, `setuid` and `exec`? I don't think I've seen this functionality built into boost::process, so I imagine you might need to hand-roll it. – Richard Hodges Oct 17 '18 at 15:28

2 Answers2

2

First of all, you don't show enough code.

Second of all, if you use su, you shouldn't require bp::shell.

Third of all, that code looks like a C compiler ran away from it. Why so complicated? Why all the dynamic memory management? Why async, if all you do is wait for the completion?

Here's my simplified take, which does work for me. Perhaps you can find out a finder detail you were doing differently:

Synchronous, C++:

Live On Coliru

#include <iostream>
#include <boost/asio.hpp>
#include <boost/process.hpp>
#include <boost/process/async.hpp>

namespace bp = boost::process;

struct ProcessResult {
    std::string out, err;
    int exitcode;
};

ProcessResult RunProcess(std::string exe, std::vector<std::string> args, boost::asio::io_service& io) {
    std::future<std::string> out, err;
    bp::group group;

    bp::child child(
        bp::search_path(exe), args, bp::std_in.close(), bp::std_out > out, bp::std_err > err, io, group
    );

    child.wait();
    return { out.get(), err.get(), child.exit_code() };
}

int main() {
    boost::asio::io_service io;

    // keep work to avoid io.run to complete early
    auto work = boost::asio::make_work_guard(io);
    std::thread io_thread([&io] { io.run(); });

    auto pstree = RunProcess("su", { "sehe", "-c", "/usr/bin/free" }, io);

    std::cout << "Exitcode: " << pstree.exitcode << "\n";
    std::cout << "Output: " << pstree.out << "\n";
    std::cout << "Error: " << pstree.err << "\n";

    work.reset(); // allow service to complete
    io_thread.join();
}

Which prints (when run as root):

Exitcode: 0
Output:               total        used        free      shared  buff/cache   available
Mem:       32832516    21846896     2486924     2963636     8498696     5595284
Swap:             0           0           0

Error: 

When not run as root:

Exitcode: 1
Output: 
Error: su: must be run from a terminal

Asynchronous

You can still combine asynchrony with C++ style. See e.g.

sehe
  • 374,641
  • 47
  • 450
  • 633
0

Thank you for the replay.

my problem that after run the "su" process I see in my Xcode console output the follow error "nw_path_close_fd Failed to close guarded necp fd 4 [9: Bad file descriptor]"

in my code, I need to use async because of the rest of my app need to run.

I found that "boost::process::async_system" do the job but don't have the PID of the process.

Liran Haim
  • 81
  • 1
  • 1
  • 5