Douglas Walls' Weblog

« Special Math Functio... | Main | C99 inline function... »
20060508 Monday May 08, 2006

Finding the canonical path to an executable
Below is a coding example of how an executable can determine the canonical path to itself on the file system.  Compiler drivers, like cc, CC, f95 need to do this in order to exec the component executables that compile a program.  For example, the compiler front-end, an optimizer, and a linker.

% cat findself.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef MAXPATHLEN
#define MAXPATHLEN      1024
#endif

/* find_run_directory - find executable file in PATH
 * PARAMETERS:
 *      cmd     filename as typed by user
 *      cwd     where to return working directory
 *      dir     where to return program's directory
 *      run     where to return final resolution name
 * RETURNS:
 *      returns zero for success,
 *      -1 for error (with errno set properly).
 */
int
find_run_directory (char *cmd, char *cwd, char *dir, char **run)
{
    char                *s;

    if (!cmd || !*cmd || !cwd || !dir) {
        errno = EINVAL;         /* stupid arguments! */
        return -1;
    }

    if (*cwd != '/')
        if (getcwd (cwd, MAXPATHLEN - 1) == NULL )
            return -1;          /* cant get working directory */

    if (strchr (cmd, '/') != NULL) {
        if (realpath(cmd, dir) == NULL) {
            int lerrno = errno;
            if (chdir((const char *)cwd) == NULL)
                errno = lerrno;
            return -1;
        }
    } else {
#ifdef __linux__
        /* getexecname() not available on Linux */
        if (readlink("/proc/self/exe", dir, MAXPATHLEN) == -1) {
#else
        if (realpath(getexecname(), dir) == NULL) {
#endif
            int lerrno = errno;
            if (chdir((const char *)cwd) == NULL)
                errno = lerrno;
            return -1;
        }
    }

    s = strrchr (dir, '/');
    *s++ = 0;
    if (run)            /* user wants resolution name */
        *run = s;

    return 0;
}

char current_working_directory[MAXPATHLEN];
char run_directory[MAXPATHLEN];
char * run_exec_name = NULL;

int
main(int argc, char **argv)
{

    if ( !find_run_directory (argv[0],
                              current_working_directory,
                              run_directory, &run_exec_name) ) {
        (void)printf("argv[0] = %s\n"
                         "cwd = %s\n"
                         "run_dir = %s\n"
                         "run_exec = %s\n",
                     argv[0],
                     current_working_directory,
                     run_directory,
                     run_exec_name);
    } else {
        (void) printf("%s\n", "Unaable to find run directory.");
    }

    exit (0);
}


% cc findself.c -O -o prod/bin/findself
% ls
bin         findself.c  prod
% ls bin
findself
% ls -laF bin
total 6
drwxr-xr-x   2 me      staff        512 Mar  5 10:37 ./
drwxr-xr-x   4 me      staff        512 Mar  5 10:37 ../
lrwxrwxrwx   1 me      staff         20 Mar  5 10:37 findself -> ../prod/bin/findself*
% ls -laF prod/bin         
total 22
drwxr-xr-x   2 me      staff        512 Mar  5 10:37 ./
drwxr-xr-x   3 me      staff        512 Mar  5 10:37 ../
-rwxr-xr-x   1 me      staff       8992 Mar  5 10:37 findself*
% bin/findself
argv[0] = bin/findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
% prod/bin/findself
argv[0] = prod/bin/findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
% setenv PATH /home/me/bin:${PATH}
% findself
argv[0] = findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
%



( May 08 2006, 06:36:27 PM PDT ) Permalink Comments [0]

Trackback URL: http://blogs.sun.com/dew/entry/finding_the_canonical_path_to
Comments:

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed

Search

Calendar

Links

Navigation

Referers