execvp(): no such file or directory?

CodeSammich picture CodeSammich · Nov 14, 2015 · Viewed 9.6k times · Source

For some reason, execvp() doesn't find the commands (like ls, pwd, etc.) in my PATH file, which includes /bin. Since I have a customized terminal alias with ls, I'm using pwd, etc. to test (as well as a fresh Linux machine), but I keep getting this for the output:

gcc main.c
./a.out

What would you like to do?
ls
arg[0]: ls

arg[1]: (null)
arg[2]: (null)
arg[3]: (null)
arg[4]: (null)
arg[5]: (null)
arg[6]: (null)
arg[7]: (null)
arg[8]: (null)
arg[9]: (null)
before exec
after exec
ERROR: No such file or directory

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

/* 
Write a c program that runs a command line program with exactly one command line argument. It should work as follows:
Prompts the user for a program to run via the command line.
Reads in that line (using fgets) and parses it to be used by one of the exec functions.
Runs the command using exec
You do not need to fork off a separate process and wait, the purpose of this assignment is only to parse a single line of input and run a program once.
*/

int main() {
  printf("\nWhat would you like to do?\n");

  char* input = malloc( 100 ); //100 character string for input
  fgets(input, 100, stdin); //reads from stdin (terminal input "file")

  //parses command in input (max of 8 flags)
  int number_of_args = 10;

  char *args[number_of_args];

  //puts cmd && flags in args
  int i = 0;
  for(; i < number_of_args; i++) {
    args[i] = strsep( &input, " ");
    printf("arg[%i]: %s\n", i, args[i]);
  }
  args[number_of_args - 1] = 0; //last element for execvp must be NULL;
  //  printf("nullify final index -> args[%i] = %s\n", number_of_args - 1, args[number_of_args -1]);

  printf("before exec\n");
  int e = execvp( args[0], args);
  printf("after exec\n");
  if(e < 0)
    printf("ERROR: %s\n", strerror(errno));

  return 0;
}

EDIT: Thought it'd be good to include my PATH as well:

echo $PATH
/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Answer

P.P picture P.P · Nov 14, 2015

fgets() reads in the newline character if there's space available in the buffer. So when you input ls, it's actually ls\n. Obivously, execvp() can't find such a command and it fails. So the solution is to remove the trailing newline, if any.

char *p = strchr(input, '\n');
if (p)  *p = 0;

You should also use argc for argument processing (if you read in the commands and arguments via main()'s argument) rather than assuming some fixed numbers. Or simply break the loop when strsep() returns NULL the first time. Technically, your code invokes undefined behaviour when you print all those null strings.