-1

I am trying to make use of execvp() to execute child processes but it gives me following error and I am unable to fix it can someone point me in direction what I am doing wrong?

My code:

#include "apue.h"
#include <sys/wait.h>

 static void    sig_int(int);       /* our signal-catching function */

int
 main(void)
{
char    buf[MAXLINE];   /* from apue.h */
pid_t   pid;
int     status;

if (signal(SIGINT, sig_int) == SIG_ERR)
    err_sys("signal error");

printf("%% ");  /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
    if (buf[strlen(buf) - 1] == '\n')
        buf[strlen(buf) - 1] = 0; /* replace newline with null */

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {      /* child */
        execlp(buf, buf); //this line is where I am not sure if I am wrong.
        err_ret("couldn't execute: %s", buf);
        exit(127);
    }

    /* parent */
    if ((pid = waitpid(pid, &status, 0)) < 0)
        err_sys("waitpid error");
    printf("%% ");
}
exit(0);
}

void
 sig_int(int signo)
 {
     printf("interrupt\n%% ");
 }

My warming/error:

  shell2.c: In function ‘main’:
shell2.c:24:16: warning: passing argument 2 of ‘execvp’ from incompatible pointer type [-Wincompatible-pointer-types]
    execvp(buf, buf);
                ^~~
In file included from ../csci3800sp22/apue.3e/include/apue.h:26:0,
                 from shell2.c:1:
/usr/include/unistd.h:578:12: note: expected ‘char * const*’ but argument is of type ‘char *’
 extern int execvp (const char *__file, char *const __argv[])

Expected result: When I run other command (execlp) it gives me following result :

[singhrav@csci-gnode-02 ~/lab1]$ ls
Makefile  shell2  shell2.c
[singhrav@csci-gnode-02 ~/lab1]$ ./shell2
% ls
Makefile  shell2  shell2.c
% ps
  PID TTY          TIME CMD
24839 pts/1    00:00:00 tcsh
25175 pts/1    00:00:00 shell2
25204 pts/1    00:00:00 ps
% ls -l
couldn't execute: ls -l: No such file or directory

Problem with execlp() is it does not execute ls -l, I wanted to be able to use ls, ps & ls -l so that's why I decided to use execvp() but when I use execvp() and run my ./shell2 command it gives me following error:

[singhrav@csci-gnode-02 ~/lab1]$ ./shell2
% ls
couldn't execute: ls: Bad address
% ps
couldn't execute: ps: Bad address
% ls -l
pppery
  • 3,731
  • 22
  • 33
  • 46

1 Answers1

3

Your problem is two-fold:

1. The original problem

The problem why your original execlp() call doesn't execute ls -l is that in your call to execlp, you don't separate the command's path from its arguments.

The man page of execlp() states:

The initial argument for these functions is the name of a file that is to be executed.

The const char *arg and subsequent ellipses in the execl(), execlp(), and execle() functions can be thought of as arg0, arg1, ..., argn. Together they describe a list of one or more pointers to null-terminated strings that represent the argument list available to the executed program. The first argument, by convention, should point to the filename associated with the file being executed. The list of arguments must be terminated by a null pointer, and, since these are variadic functions, this pointer must be cast (char *) NULL.

So, in your call execlp(buf, buf), the function would try to locate a file with literal name ls -l (including the space!) and execute it. Also, note that the argument list must be terminated with a (char *) NULL pointer, so you would need to separate the content of buf at the whitespace into individual tokens that are then fed individually to execlp(), as in

execlp("ls", "ls", "-l", (char *) NULL);

2. The problem with execvp

You don't explicitly show it, but you seem to have "blindly" switched execlp with execvp without any changes to the arguments. However, the execvp() function expects an array of null-terminated strings, which is an array of array of char as second argument. However, you simply provide a string, i.e. a simple array of char as second argument. Hence, the content of the second argument (which are characters) will be mis-interpreted as addresses to the expected strings, and access memory regions not allocated for the process, which leads to the Bad address (= EFAULT) error message.

TL;DR

You have to correct the use of the exec... functions in your program.

AdminBee
  • 137
  • 8
  • execlp(buf, buf, (char *)0); I used this for execlp() it works fine with my ls and ps commands but my execvp() I passed(buf,buf) Is this wrong? –  Feb 25 '22 at 17:22
  • @tablemesa Yes it is. As I wrote in the answer, `execvp()` expects not a `const char *`-type null-terminated string, but a `const char * []`, i.e. _an array_ of `const char *` where the individual array entries are `const char *`-type null-terminated strings. – AdminBee Feb 25 '22 at 17:27