/* Guessing the program name. */ /* 3 ways to call a program: $ foo - search in PATH $ ./foo - relative filename $ /bin/foo - absolute filename */ /* See also these discussions: http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/5080/focus=5082 http://fixunix.com/unix/542990-getting-mains-argv-0-a.html */ /* ============================= glibc systems ============================= */ #if !1 /* Reference: glibc manual http://www.gnu.org/software/libc/manual/html_node/Error-Messages.html */ #define _GNU_SOURCE 1 #include /* The value of argv[0]. $ foo -> "foo" $ ./foo -> "./foo" $ /bin/foo -> "/bin/foo" */ static const char * get_program_invocation_name () { return program_invocation_name; } /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return program_invocation_short_name; } #include int main () { printf ("get_program_invocation_name() = %s\n", get_program_invocation_name ()); printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); return 0; } #endif /* ============================ uClibc systems ============================ */ /* Depending on the configuration, libc may or may not contain the variables 'program_invocation_name' and 'program_invocation_short_name', like glibc. */ /* ============================= Linux systems ============================= */ #if !1 /* The executable is accessible as /proc//exe. In newer Linux versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink to the true pathname; older Linux versions give only device and ino, enclosed in brackets, which we cannot use here. */ #define _GNU_SOURCE 1 #include #include #include /* The canonicalized file name of the program. $ foo -> "/opt/gnu/bin/foo" $ ./foo -> "/opt/gnu/bin/foo" $ /bin/foo -> "/opt/gnu/bin/foo" */ static char * get_program_canonicalized_name () { char buf[PATH_MAX]; int ret; ret = readlink ("/proc/self/exe", buf, sizeof (buf)); if (ret < 0 || buf[0] == '[') return NULL; return strndup (buf, PATH_MAX); } #include int main () { printf ("get_program_canonicalized_name() = %s\n", get_program_canonicalized_name ()); return 0; } #endif /* ============================ MacOS X systems ============================ */ #if !1 #include #include /* On MacOS X 10.2 or newer, the function int _NSGetExecutablePath (char *buf, uint32_t *bufsize); can be used to retrieve the executable's full path. Reference: */ /* The absolute name (but not canonicalized) of the value of argv[0]. $ foo -> /found_dir/foo $ ./foo -> /currdir/./foo $ symlink/foo -> /currdir/symlink/foo $ /bin/foo -> /bin/foo */ static char * get_program_absolute_name () { char location[4096]; unsigned int length = sizeof (location); if (_NSGetExecutablePath (location, &length) == 0) return strdup (location); else return NULL; } #include /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return getprogname (); } #include int main () { printf ("get_program_absolute_name() = %s\n", get_program_absolute_name ()); printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); return 0; } #endif /* ============================ FreeBSD systems ============================ */ #if !1 /* Reference: */ #include /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return getprogname (); } #include int main () { printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); return 0; } #endif /* ============================ NetBSD systems ============================ */ #if !1 #include /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return getprogname (); } #include int main () { printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); return 0; } #endif /* ============================ OpenBSD systems ============================ */ #if !1 /* The variable __progname is defined in /usr/lib/crt0.o. */ /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { extern const char *__progname; return __progname; } #include int main () { printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); return 0; } #endif /* ============================== AIX systems ============================== */ #if !1 /* Idea by Bastien ROUCARIÈS . */ /* */ /* Reference: */ #include #include #include /* The part after the last slash (if any) of the value of argv[0], truncated to at most 32 bytes. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static char * get_program_invocation_short_name_truncated () { extern int getprocs64 (struct procentry64 *, int, struct fdsinfo64 *, int, pid_t *, int); pid_t pid = getpid (); struct procentry64 procs; if (getprocs64 (&procs, sizeof (procs), NULL, 0, &pid, 1) > 0) return strdup (procs.pi_comm); return NULL; } /* The value of argv[0]. $ foo -> "foo" $ ./foo -> "./foo" $ /bin/foo -> "/bin/foo" */ static char * get_program_invocation_name () { extern int getargs (void *, int, char *, int); char arg0[PATH_MAX + 1]; struct procentry64 procs; procs.pi_pid = getpid (); if (getargs (&procs, sizeof (procs), arg0, sizeof (arg0)) == 0) /* arg0 is always NUL terminated. */ return strdup (arg0); return NULL; } #include int main () { printf ("get_program_invocation_short_name_truncated() = %s\n", get_program_invocation_short_name_truncated ()); printf ("get_program_invocation_name() = %s\n", get_program_invocation_name ()); return 0; } #endif /* ============================= HP-UX systems ============================= */ #if !1 /* Idea by Bastien ROUCARIÈS . */ /* */ /* Reference: */ #include #include #include /* The part after the last slash (if any) of the value of argv[0], truncated to at most 14 bytes. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static char * get_program_invocation_short_name_truncated () { int pid = getpid (); struct pst_status buf; if (pstat_getproc (&buf, sizeof (buf), 0, pid) > 0) return strdup (buf.pst_ucomm); return NULL; } #include int main () { printf ("get_program_invocation_short_name_truncated() = %s\n", get_program_invocation_short_name_truncated ()); return 0; } #endif /* ============================= IRIX systems ============================= */ #if !1 /* Idea by Bastien ROUCARIÈS . */ /* */ #include #include #include #include #include #include static size_t strnlen (const char *string, size_t maxlen) { const char *end = memchr (string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } static char * strndup (char const *s, size_t n) { size_t len = strnlen (s, n); char *new = malloc (len + 1); if (new == NULL) return NULL; new[len] = '\0'; return memcpy (new, s, len); } /* The part after the last slash (if any) of the value of argv[0], truncated to at most 32 bytes. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static char * get_program_invocation_short_name_truncated () { char filename[50]; int fd; sprintf (filename, "/proc/pinfo/%d", (int) getpid ()); fd = open (filename, O_RDONLY); if (fd >= 0) { prpsinfo_t buf; if (ioctl (fd, PIOCPSINFO, &buf) >= 0) { close (fd); return strndup (buf.pr_fname, sizeof (buf.pr_fname)); } close (fd); } return NULL; } int main () { printf ("get_program_invocation_short_name_truncated() = %s\n", get_program_invocation_short_name_truncated ()); return 0; } #endif /* ============================= OSF/1 systems ============================= */ #if !1 #include #include #include #include #include #include static size_t strnlen (const char *string, size_t maxlen) { const char *end = memchr (string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } static char * strndup (char const *s, size_t n) { size_t len = strnlen (s, n); char *new = malloc (len + 1); if (new == NULL) return NULL; new[len] = '\0'; return memcpy (new, s, len); } /* The part after the last slash (if any) of the value of argv[0], truncated to at most 16 bytes. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static char * get_program_invocation_short_name_truncated () { char filename[50]; int fd; sprintf (filename, "/proc/%d", (int) getpid ()); fd = open (filename, O_RDONLY); if (fd >= 0) { prpsinfo_t buf; if (ioctl (fd, PIOCPSINFO, &buf) >= 0) { close (fd); return strndup (buf.pr_fname, sizeof (buf.pr_fname)); } close (fd); } return NULL; } int main () { printf ("get_program_invocation_short_name_truncated() = %s\n", get_program_invocation_short_name_truncated ()); return 0; } #endif /* ============================ Solaris systems ============================ */ #if !1 /* Reference for getexecname: */ #include /* The value of argv[0], looked up in PATH, with symlinks resolved and "." components removed. $ foo -> "foo" or "subdir/foo" or "/bin/foo" $ ./foo -> "foo" $ subdir/foo -> "subdir/foo" $ symlink/foo -> "subdir/foo" $ /bin/foo -> "/bin/foo" */ static const char * get_resolved_program_invocation_name () { return getexecname (); } #if HAVE_GETPROGNAME /* Solaris 11 2010-11 */ /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return getprogname (); } #else static const char * get_program_invocation_short_name () { return NULL; } #endif #include int main () { printf ("get_resolved_program_invocation_name() = %s\n", get_resolved_program_invocation_name () != NULL ? get_resolved_program_invocation_name () : "(null)"); printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name () != NULL ? get_program_invocation_short_name () : "(null)"); return 0; } #endif /* ============================ Cygwin systems ============================ */ #if !1 /* References: */ #include /* The part after the last slash (if any) of the value of argv[0]. $ foo -> "foo" $ ./foo -> "foo" $ ./foo.exe -> "foo" $ /bin/foo -> "foo" */ static const char * get_program_invocation_short_name () { return getprogname (); } #define WIN32_LEAN_AND_MEAN /* avoid including junk */ #include #include /* The canonicalized file name of the program. $ foo -> "/cygdrive/c/gnu/bin/foo.exe" $ ./foo -> "/cygdrive/c/gnu/bin/foo.exe" $ /bin/foo -> "/cygdrive/c/bin/foo.exe" */ static char * get_program_canonicalized_name1 () { char location[MAX_PATH + 1]; char location_as_posix_path[2 * MAX_PATH]; int length = GetModuleFileName (NULL, location, sizeof (location) - 1); if (length < 0) return NULL; if (length == sizeof (location) - 1) location[length] = '\0'; /* On Cygwin, we need to convert paths coming from Win32 system calls to the Unix-like slashified notation. */ /* There's no error return defined for cygwin_conv_to_posix_path. See cygwin-api/func-cygwin-conv-to-posix-path.html. Does it overflow the buffer of expected size MAX_PATH or does it truncate the path? I don't know. Let's catch both. */ cygwin_conv_to_posix_path (location, location_as_posix_path); location_as_posix_path[MAX_PATH - 1] = '\0'; if (strlen (location_as_posix_path) >= MAX_PATH - 1) /* A sign of buffer overflow or path truncation. */ return NULL; return strdup (location_as_posix_path); } /* An alternative implementation, that works with cygwin-1.5.13 (2005-03-01) or newer. */ #include #include #include /* The canonicalized file name of the program. $ foo -> "/opt/gnu/bin/foo" $ ./foo -> "/opt/gnu/bin/foo" $ /bin/foo -> "/opt/gnu/bin/foo" */ static char * get_program_canonicalized_name2 () { char buf[PATH_MAX]; int ret; ret = readlink ("/proc/self/exe", buf, sizeof (buf)); if (ret < 0) return NULL; return strndup (buf, ret); } #include int main () { printf ("get_program_invocation_short_name() = %s\n", get_program_invocation_short_name ()); printf ("get_program_canonicalized_name1() = %s\n", get_program_canonicalized_name1 ()); printf ("get_program_canonicalized_name2() = %s\n", get_program_canonicalized_name2 ()); return 0; } #endif /* ============================= mingw systems ============================= */ #if !1 /* Reference: */ #define WIN32_LEAN_AND_MEAN /* avoid including junk */ #include #include /* The canonicalized file name of the program. $ foo -> "C:\\gnu\\bin\\foo.exe" $ ./foo -> "C:\\gnu\\bin\\foo.exe" $ /bin/foo -> "C:\\bin\\foo.exe" */ static char * get_program_canonicalized_name () { char location[MAX_PATH + 1]; int length = GetModuleFileName (NULL, location, sizeof (location) - 1); if (length < 0) return NULL; if (length == sizeof (location) - 1) location[length] = '\0'; return strdup (location); } #include int main () { printf ("get_program_canonicalized_name() = %s\n", get_program_canonicalized_name ()); return 0; } #endif /* ============================ Interix systems ============================ */ /* ============================= BeOS systems ============================= */