[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

determining the program_invocation_name

From: Bruno Haible
Subject: determining the program_invocation_name
Date: Fri, 24 Dec 2010 22:41:40 +0100
User-agent: KMail/1.9.9


How can some library code determine the name of the running program,
for error message and display purposes, if the program's main() function
has not stored argv[0] in a particular place?

Let's be clear about two things:

  1) This question is mostly irrelevant for libposix, because library
     functions in libposix should not call exit() and should not print
     error messages. The only ways out that a library function has is
     to call abort() if there was a programming error, and to return
     an error code or error message that the caller can then handle.

  2) Even if we find an answer to this question, it does not magically
     resolve all problems with the 'error' module, because the question
     remains where the 'program_name' variable shall be allocated,
     and it is a portability problem for MacOS X, AIX, Solaris, Cygwin [1].

There was this thread [2] in 2006 where we found out that we needed some
new API [3] because we did not want to implement the BSD functions with
different semantics.

Recently, Bastien Roucari├Ęs respawned the topic in two threads [4][5],
by proposing to fetch the program invocation name (= argv[0] or a
variant of it) through the API that 'ps' and 'top' typically use.

Find attached a collection of the platform dependent code snippets.
I added code for Cygwin, mingw (from progreloc.c), and OSF/1, and
tested it on the various platforms.

The results of this investigation are:

  1) There are six different notions of "program name".

       - get_program_invocation_short_name ()
         This is what glibc calls 'program_invocation_short_name' and
         BSD calls 'getprogname ()'. It's the basename of the argv[0].

       - get_program_invocation_short_name_truncated ()
         This is like get_program_invocation_short_name (), except it
         is truncated to a certain number of bytes (14, 16, or 32).

       - get_program_invocation_name ()
         This is what glibc calls 'program_invocation_name'. It's the
         argv[0] before the search in $PATH was performed.

       - get_program_absolute_name ()
         This is like get_program_invocation_name(), except that it
         makes the result absolute by stuffing in the current directory
         if needed.

       - get_resolved_program_invocation_name ()
         This is like get_program_invocation_name(), except that it
         resolves symbolic links and removes trivial filename components.

       - get_program_canonicalized_name ()
         This is like a combination of get_program_absolute_name() and
         get_resolved_program_invocation_name(): It resolves symbolic
         links, removes trivial filename components, and stuffs in the
         current directory.

  2) Each of the functions may fail, i.e. return NULL.

  3) It's highly platform dependent. Here's the matrix of available functions:

        A  = get_program_invocation_short_name ()
        A x = get_program_invocation_short_name_truncated ()
        B = get_program_invocation_name ()
        C = get_program_absolute_name ()
        D = get_resolved_program_invocation_name ()
        E = get_program_canonicalized_name ()

                     | A | B | C | D | E |
       glibc/Linux   | X | X |   |   | X |
       glibc/other   | X | X |   |   |   |
       uClibc/Linux  |   |   |   |   | X |
       MacOS X       | X |   | X |   |   |
       FreeBSD       | X |   |   |   |   |
       NetBSD        | X |   |   |   |   |
       OpenBSD       | X |   |   |   |   |
       AIX           | x | X |   |   |   |
       HP-UX         | x |   |   |   |   |
       IRIX          | x |   |   |   |   |
       OSF/1         | x |   |   |   |   |
       Solaris       | X |   |   | X |   |
       Cygwin        | X |   |   |   | X |
       mingw         |   |   |   |   | X |
       Interix       |   |   |   |   |   |

     Given B, you can determine C, D, E, by assuming the current directory
     and $PATH have not changed since the program was launched.

     But given A only, one cannot determine B, C, D, E. And unfortunately,
     on many Unix platforms, A is the only thing you can get.

What can we reasonably do with this?

(a) We could create a new module that exports functions

    /* Returns the base name of argv[0], if known.  */
    const char *get_program_invocation_short_name ();

    /* Returns the truncated base name of argv[0], if known.  */
    const char *get_program_invocation_short_name_truncated ();
    size_t get_program_invocation_short_name_truncation_length ();

    /* Return argv[0], without resolving symlinks or current directory
       if possible.  */
    const char *get_program_invocation_name ();

    /* Return argv[0] as a canonical filename.  Assumes that the current
       directory and $PATH have not changed since the program was launched.  */
    const char *get_program_canonicalized_name ();

    Of course these functions would cache their respective result once it has
    been determined.

    And of course there are platforms, like Interix, NonStop Kernel, or Haiku,
    where all functions will return NULL.

(b) We can observe that these proposed functions would still have
    portability pitfalls:
      - truncation of the short name,
      - differences regarding relative filenames and symlinks,
      - differences regarding the ".exe" suffix on Windows.
    Decide that it is better to have no gnulib API at all than an API that
    has portability problems.

What do you think?


[1] http://lists.gnu.org/archive/html/bug-recutils/2010-12/msg00010.html
[2] http://lists.gnu.org/archive/html/bug-gnulib/2006-01/msg00005.html
[3] http://lists.gnu.org/archive/html/bug-gnulib/2006-01/msg00122.html
[4] http://lists.gnu.org/archive/html/bug-gnulib/2010-11/msg00088.html
[5] http://lists.gnu.org/archive/html/bug-gnulib/2010-12/msg00064.html

Attachment: get-program-name.c
Description: Text Data

reply via email to

[Prev in Thread] Current Thread [Next in Thread]