How to Pass a Vector to Execvp

How to pass a vector to execvp

Not directly; you'd need to represent the vector as a NULL-terminated array of string pointers somehow. If it's a vector of strings, that is straightforward to do; if it's some other kind of data you would have to figure how to encode it as strings.

execvp() using vectorstring *

You will need to create a new array of pointers to the strings' data, instead of to the std::strings themselves. There are many ways to do this, but one simple way is to use another std::vector and a structured for loop:

assert(_arguments.size() > 0);  // else the executable will be invalid

std::vector<const char *> args;
args.reserve(_arguments.size() + 1);
for(string *sp: _arguments) {
args.push_back(sp->c_str());
}
args.push_back(nullptr); // needed to terminate the args list

execvp(args[0], args.data());

How to pass a vector of strings to execv

execv() accepts only an array of string pointers. There is no way to get it to accept anything else. It is a standard interface, callable from every hosted language, not just C++.

I have tested compiling this:

std::vector<string> vector;
const char *programname = "abc";

const char **argv = new const char* [vector.size()+2]; // extra room for program name and sentinel
argv [0] = programname; // by convention, argv[0] is program name
for (int j = 0; j < vector.size()+1; ++j) // copy args
argv [j+1] = vector[j] .c_str();

argv [vector.size()+1] = NULL; // end of arguments sentinel is NULL

execv (programname, (char **)argv);

Convert vectorstring to char** for use in execvp

I found that the answer lies with adding the NULL terminator to the end of the vector so that execvp knows where to end pvec.data(); This is thanks to Fatih above.

  std::vector<char*> pvec(tokens.size());
std::transform(tokens.begin(), tokens.end(), pvec.begin(), [](auto& str) {
return &str[0];
});
pvec.push_back(NULL);
pvec.data();

pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(pvec.data()[0], pvec.data()) == -1)
{
printf("right here officer\n");
}
exit(EXIT_FAILURE);
}```

execvp not working when converting from vectorstring to vectorchar* to char**

First, there's no point in copying the std::strings if the next thing you are going to do is call execvp.

If the execvp succeeds, then it will never return and the entire memory image will vanish into smoke (or, more accurately, be replaced by a completely new image). In the course of constructing the new image, exec* will copy the argv array (and the environment array) into it. In any event, the std::vector and std::string destructors will never be invoked.

If, on the other hand, the execvp fails, then the argument passed into it will not have been modified. (Posix: "The argv[] and envp[] arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.")

In either case, there was no need to copy the character strings. You can use std::string::c_str() to extract a pointer to the underlying C string (as a const char*, but see below).

Second, if you're using C++11 or more recent, std::vector conveniently comes with a data() member function which returns a pointer to the underlying storage. So if you have std::vector<char*> svec, then svec.data() will be the underlying char*[], which is what you want to pass into execvp.

So the problem reduces to creating a std::vector<char*> from a std::vector<std::string>, which is straightforward:

else if (kidpid == 0) {
// I am the child.
std::vector<char*> argc;
// const_cast is needed because execvp prototype wants an
// array of char*, not const char*.
for (auto const& a : args)
argc.emplace_back(const_cast<char*>(a.c_str()));
// NULL terminate
argc.push_back(nullptr);
// The first argument to execvp should be the same as the
// first element in argc, but we'll assume the caller knew
// what they were doing, and that program is a std::string.
execvp(program.c_str(), argc.data());
// It's not clear to me what is returning here, but
// if it is main(), you should return a small positive value
// to indicate an error
return 1;
}

how do i convert std::vector to char ** in a reliable way?

As Pete Becker says, the issue's probably that you haven't called it properly - and specifically that the a argument doesn't point to a sufficiently large array of char*s to write to.

Anyway, do you really need to screw around with dynamic memory allocation here? Having std::vector manage memory for you is much easier, safer, and more concise. Perhaps you can do something like below, then pass the result's .data() value to execvp? You do need to make sure the vector of strings passed as an argument is not mutated by the caller after this call and before calling execvp, otherwise the pointers you collect may be invalidated.

std::vector<const char*> getVectorOfPointersToStrings(std::vector<std::string> const& v) {
std::vector<const char*> result;
for (const auto& s : v)
result.push_back(s.c_str());
result.push_back(nullptr);
return result;
}

Execvp not executing ping command with arguments

 vector<char*> pingArgs;
pingArgs.push_back("www.google.com");
pingArgs.push_back(NULL);

The first parameter to a program, it's argv[0], is the name of the program itself.

Here, you're merely informing the ping program that it's name is www.google.com, and it has no additional parameters.

 vector<char*> pingArgs;
pingArgs.push_back("ping");
pingArgs.push_back("www.google.com");
pingArgs.push_back(NULL);

The first parameter to execvp is the executable to execute, but you still must provide all parameters separately.

However, all of the above is completely wrong anyway, for a tangential reason. In modern C++ string literals are const char *, and not char *. You must be using an ancient C++ compiler that either relaxes const-correctness when it comes to string literals or fails to implement it correctly, and I expect every modern C++ compiler to fail to compile the shown code for this unrelated reason.

Correctly doing this requires a little bit more work, in C++, but that's not directly related to the question you asked, and would be a separate question.

Is it legal to pass a null program argument vector to execve()?

The man page for the execve() system call says

The argv and envp arrays must each include a null pointer at the end of the array.

If your program doesn't conform to those requirements, there's no certainty of how well things will go from that point on. If it "works" for some programs, that's just bad luck.


The man page also says

By convention, the first of these strings (i.e., argv[0]) should contain the filename associated with the file being executed.

That convention is rather strong (mandated by POSIX), so programs that fail to do so can be considered buggy. It's probably a good idea for your main() to test it's been called correctly if you're going to rely on argv[0] so you can fail with a nice error message rather than a fault, but not all programs do.



Related Topics



Leave a reply



Submit