0

To run a command with execlp we do

execlp("ps", "ps", NULL);

A redundancy can be seen here, since we pass ps twice. This behavior is consistent across all exec variants.

Why does exec want such redundancy? Why isn't it written so that we can simply

execlp("ps", NULL);
marmistrz
  • 5,974
  • 10
  • 42
  • 94

4 Answers4

4

Other answers have explained that you may provide a different argv[0] than the name of the program, but haven't explained why you might want to do this.

Some programs behave differently depending on the name that's used to invoke them. A common example is shells, e.g. sh, bash, and csh. They check the first character of argv[0], and if this is - they operate as a login shell rather than a regular shell. So when /bin/login is invoking the user's login shell, it does something like:

execlp("/bin/bash", "-bash", (char*)NULL);

This way, bash knows that it's being run as part of a login and can behave accordingly. This could have been done using an option parameter, but then every program that might be used as a login shell would have to recognize that option (some special usernames have login shells that aren't really shells, but are other programs, and requiring them to support the same option as real shells might be problematic).

Barmar
  • 741,623
  • 53
  • 500
  • 612
2

The first argument is the path of the file to be executed (/bin/ls, /home/development/myproject/foo). The remaining arguments correspond to the argv vector passed to main. Imagine typing the following in your shell:

$ ./foo bar bletch

The executable path is ./foo - that's the first argument passed to execlp. By convention, argv[0] is supposed to be the string used to invoke the program, so the complete argv vector is {"./foo", "bar", "bletch", NULL}. Hence,

execlp( "./foo",  /* executable path */ 
        "./foo",  /* argv[0] */
        "bar",    /* argv[1] */
        "bletch", /* argv[2] */
        NULL      /* argv[3] */
      );

It's possible that you may not want argv[0] to be the same as the actual command path (say because the path is aliased or you don't want to expose the exact path), in which case you may use something like

execlp( "./secret/path/to/foo", "./foo", "bar", "bletch", NULL );
John Bode
  • 119,563
  • 19
  • 122
  • 198
1

You don't have to give your program the name of the executable as its argv[0]. You could write a program (rvw11.c compiled to rvw11 executable):

#include <unistd.h>

int main(void)
{
    execlp("sleep", "rip van winkle", "40", (char *)0);
    return 1;
}

and you would find that if you run:

$ ./rvw11 &
[1] 53034
$ ps
  PID TTY           TIME CMD
  515 ttys000    0:00.07 -bash
  534 ttys002    0:00.09 -bash
  543 ttys003    0:01.15 -bash
  558 ttys004    0:00.32 -bash
53034 ttys004    0:00.01 rip van winkle 40
$

So, the name that shows up in the ps listing is the value given as argv[0] in the argument list, not the name of the executable. (Demonstration on macOS Sierra 10.12.2, but you'd get a similar result on most Unix-like systems.)

This also demonstrates why it is not necessarily feasible to determine the name of the executable from the argument list.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

The second parameter should match the first one, but it is not required to be the same.

According to documentation,

argv is an array of argument strings passed to the new program. By convention, the first of these strings should contain the filename associated with the file being executed.

If you have a compelling reason to hide the name of the file being executed from the program that you are planning to run, you can pass any string you want for the second parameter, including an empty or a NULL string:

execlp("ps", "<hidden>", NULL);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523