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?
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());