views:

1842

answers:

6

In the C / Unix environment I work in, I see some developers using __progname instead of argv[0] for usage() messages. Is there some advantage to this? What's the difference between __progname and argv[0]. Is it portable?

+10  A: 

__progname isn't standard and therefore not portable, prefer argv[0]. I suppose __progname could lookup a string resource to get the name which isn't dependent on the filename you ran it as. But argv[0] will give you the name they actually ran it as which I would find more useful.

Evan Teran
Consider: execl("/bin/sh", "hot potatoes", "-c", "echo $0 - Hi", (char *)0); Works fine; argv[0] is "hot potatoes"; echoes "hot potatoes - Hi". That's nothing to do with the name of the executable that was run.
Jonathan Leffler
Despite the previous comment - I agree that argv[0] is more portable. And only a few programs mess with argv[0] like that - but any attacker can do so. Be cautious about basing critical decisions on argv[0].
Jonathan Leffler
+4  A: 

Using __progname allows you to alter the contents of the argv[] array while still maintaining the program name. Some of the common tools such as getopt() modify argv[] as they process the arguments.

For portability, you can strcopy argv[0] into your own progname buffer when your program starts.

Adam Liss
GNU getopt() messes with argv; non-GNU versions do not generally do so.
Jonathan Leffler
@Jonathan: Yes, thanks for the clarification. I GNU I'd been sticking with one platform for too long. (Sorry.)
Adam Liss
+2  A: 

It's a BSDism, and definitely not portable.

wnoise
+1  A: 

If your program was run using, for instance, a symbolic link, argv[0] will contain the name of that link.

I'm guessing that __progname will contain the name of the actual program file.

In any case, argv[0] is defined by the C standard. __progname is not.

Artelius
+2  A: 

I see at least two potential problems with argv[0].

First, argv[0] or argv itself may be NULL if execve() caller was evil or careless enough. Calling execve("foobar", NULL, NULL) is usually an easy and fun way to prove an over confident programmer his code is not sig11-proof.

It must also be noted that argv will not be defined outside of main() while __progname is usually defined as a global variable you can use from within your usage() function or even before main() is called (like non standard GCC constructors).

Krunch
But "a Strictly Conforming POSIX Application to pass at least one argument to the exec function, thus guaranteeing that argc be one or greater when invoked by such an application." Surely no one would knowingly violate POSIX! (http://www.opengroup.org/onlinepubs/000095399/functions/exec.html)
Matthew Flaschen
A: 

There is also a GNU extension for this, so that one can access the program invocation name from outside of main() without saving it manually. One might be better off doing it manually, however; thus making it portable as opposed to relying on the GNU extension. Nevertheless, I here provide an excerpt from the available documentation.

From the on-line GNU C Library manual (accessed today):

"Many programs that don't read input from the terminal are designed to exit if any system call fails. By convention, the error message from such a program should start with the program's name, sans directories. You can find that name in the variable program_invocation_short_name; the full file name is stored the variable program_invocation_name.

  • Variable: char * program_invocation_name This variable's value is the name that was used to invoke the program running in the current process. It is the same as argv[0]. Note that this is not necessarily a useful file name; often it contains no directory names.

  • Variable: char * program_invocation_short_name This variable's value is the name that was used to invoke the program running in the current process, with directory names removed. (That is to say, it is the same as program_invocation_name minus everything up to the last slash, if any.)

The library initialization code sets up both of these variables before calling main.

Portability Note: These two variables are GNU extensions. If you want your program to work with non-GNU libraries, you must save the value of argv[0] in main, and then strip off the directory names yourself. We added these extensions to make it possible to write self-contained error-reporting subroutines that require no explicit cooperation from main."

Victor