Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exec() any command in C

Say in C, I want to call execvp() on any string command. Command can just be:

char command[] = "ls -l";
char command[] = "rm *.txt";
char command[] = "cat makefile";

I want to put this command variable inside execvp(). So the exec() flavored function can just run with any kind of arbitrary command.

How can I do that? Thanks.

NOTE: system() is not allowed.

like image 253
JJ Liu Avatar asked Nov 11 '11 03:11

JJ Liu


2 Answers

If you have to call execvp(), then you will need to split up those strings into an executable name and an array of arguments (the first being the "name" of the program and the last being a NULL pointer).

That means something like:

char cmd1[] = "ls";  char *args1[] = {"ls", "-l", NULL};
char cmd1[] = "rm";  char *args1[] = {"rm", "*.txt", NULL}; // but see
                                                            // globbing below.
char cmd1[] = "cat"; char *args1[] = {"cat", "makefile", NULL};

This is a non-trivial exercise, especially if you want to allow for quoting, globbing, escaping and so forth.

Quoting means you'll have to be careful with commands like:

rm "file with spaces.txt"

in that you can't simply break on the spaces - you'll have to interpret items in the command much the same as the shell does. Simplistic breaking on spaces would give you a command with three arguments for that string above, rather than the correct one.

By globbing, I mean you'll almost certainly have problems with something like *.txt since it's typically the shell which expands these arguments. Passing that directly to execvp() will result in a single argument of literally *.txt rather than many arguments matching all the text files in your current directory.

Quoting means that you'll have to handle things like:

ls -l "file with spaces and \" quote in it"

which will further complicate your parser.

Don't get me wrong, it can be done, but it's probably a damn sight easier just using system().

If you're still thinking of going the execvp() route, you'll have to:

  • split the string into separate tokens (rather hard, since you have to handle quotes and escapes).
  • glob all the arguments, meaning that those with wildcards in them (and only ones that aren't escaped or protected by virtue of being inside quotes) are expanded into multiple arguments.
  • construct the argument array, with the command at the front and a NULL at the end.
  • call execvp() with the parameters being first element in that array and the address of the array.
like image 85
paxdiablo Avatar answered Oct 02 '22 00:10

paxdiablo


No, the exec family of functions does not take a single string command line like system does. Instead it uses an argv-like array of strings:

char *command = "/path/to/command";
char *arguments[] = { "command", "first argument", "second argument", NULL };
execvp(command, arguments);

Note that the first entry in the arguments array is the command itself, and that the array is terminated by NULL.

Did you check the manual page?

like image 30
Some programmer dude Avatar answered Oct 02 '22 02:10

Some programmer dude