Search code examples
c++system-callsargv

how to add a space character to trigger var args c++ execlp()


I'm writing this program on Ubuntu. If I type this command into a shell

groups root sys bin

it outputs

root : root
sys : sys
bin : bin

However I'm writing a c++ program that calls groups with execlp using

execlp("groups", "groups", args.c_str(), NULL);

where args = "root sys bin". I just get a :No such user error since groups' is obviously just looking at that entire string as argv[0] which is the equivalent of running

groups "root sys bin" 

How do i create the proper variable argument for execlp to run groups on each user, one at a time?


Solution

  • One option is to ask /bin/sh to deal with the input the way it normally would. Of course in addition to dealing with spaces, this would also deal with characters like $, #, ~, *, etc., which may or may not be what you want.

    execl("/bin/sh", "sh", "-c", ("groups " + args).c_str(), nullptr);
    

    Obviously, don't use this way if the data is user-entered and might contain nasty strings like:

    root ;rm *
    

    Otherwise, execl type functions won't work unless you know the number of command-line arguments at compile time. Assuming your args string could have varying numbers of arguments, you'll need execv type functions instead.

    std::string args = "root sys bin";
    
    std::vector<std::string> arg_vec;
    std::istringstream arg_iss(args);
    std::copy(std::istream_iterator<std::string>(arg_iss),
              std::istream_iterator<std::string>(),
              std::back_inserter(arg_vec));
    
    char groups_exec[] = "groups";
    std::vector<char*> arg_ptr_vec{ groups_exec };
    std::for_each(arg_vec.begin(), arg_vec.end(),
                  [&](std::string& arg){ arg_ptr_vec.push_back(&arg[0]); } );
    arg_ptr_vec.push_back(nullptr);
    execvp("groups", arg_ptr_vec.data());