» Sign in
  

The from_where/fromw.c example is a program that will find itself and report locations relative to the directory in which it is started. Note that the results would not remain correct if used in a program that has changed its own current working directory.

The program uses getcwd and getenv("PATH") most of the time, and can find itself even after a putenv("PATH") or a change to argv[0] by using the pstat and file tree walk. The file tree walk could find a different hard link to the same executable instead of the exact one it was started from. The string based answers could be fooled by changes to the file system after startup. You could add code to double check those results by stating the path and comparing with the pstat_getproc result.

There is also an alternate technique available to programs that have access to the dlgetname function. That function is present for 64-bit programs on PA-RISC and both 32-bit and 64-bit programs on Itanium®-based systems.

from_where/fromw.c

#include <sys/param.h>
#include <sys/pstat.h>
#include <mntent.h>
#include <sys/vfs.h>
#include <ftw.h>
#include <limits.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *fs_name(long fsid)
{
    FILE *mnttab;
    struct mntent *ent;
    struct statfs buf;
    int result;
    mnttab = fopen("/etc/mnttab", "r");
    ent = getmntent(mnttab);
    while (ent) {
        result = statfs(ent->mnt_dir, &buf);
        if (result == 0) {
            if (fsid == buf.f_fsid[0]) {
                printf("mount point: %s\n", ent->mnt_dir);
                fclose(mnttab);
                return(strdup(ent->mnt_dir));
            }
        } else {
            perror("statfs failed");
        }
        ent = getmntent(mnttab);
    }
    fclose(mnttab);
    return(NULL);
}
long pstat_executable(long *inode)
{
    struct pst_status pst;
    int target = getpid();
    if (pstat_getproc(&pst, sizeof(pst), (size_t)0, target) == -1) {
        perror("pstat_getproc failed");
        return (0L);
    } else {
        printf("The text for this process is inode %d of file system %u.\n",
            pst.pst_text.psf_fileid,
            pst.pst_text.psf_fsid.psfs_id);
        *inode = pst.pst_text.psf_fileid;
        return (pst.pst_text.psf_fsid.psfs_id);
    }
}
long inode;
char *executable;
int match_inode(
    const char *obj_path,
    const struct stat *obj_stat,
    int obj_flags,
    struct FTW obj_FTW)
{
    if (obj_stat->st_ino == inode) {
        executable = strdup(obj_path);
        return(1);
    }
    return(0);
}
int main(int argc, char *argv[])
{
    char cwd[PATH_MAX+1];
    char candidate[PATH_MAX+1];
    char *base_dir, *path, *dir;
    /* First handle the easiest case */
    if (argv[0][0] == '/') {
        printf("executable is '%s' (from /).\n", argv[0]);
        return 0;
    }
    /* See if argv[0] was path from cwd. */
    if (strchr(argv[0], '/') != NULL) {
        if (getcwd(cwd, PATH_MAX+1) == NULL) {
            perror("getcwd failed");
        } else {
            printf("executable is '%s/%s' (from cwd).\n", cwd, argv[0]);
            return 0;
        }
    }
    /* Try the PATH. */
    path = getenv("PATH");
    if (path != NULL) {
        path = strdup(path);
        for (dir = strtok(path, ":"); dir != NULL; dir = strtok(NULL, ":")) {
            strcpy(candidate, dir);
            strcat(candidate, "/");
            strcat(candidate, argv[0]);
            if (access(candidate, X_OK) == 0) {
                printf("executable is '%s' (from PATH).\n", candidate);
                return 0;
            }
        }
        free(path);
    }
    /* Hunt it down */
    executable = NULL;
    base_dir = fs_name(pstat_executable(&inode));
    if (base_dir) {
        nftw(base_dir, match_inode, 40, FTW_PHYS|FTW_MOUNT|FTW_SERR);
        free(base_dir);
    }
    if (executable) {
        printf("executable is '%s' (from mount point).\n", executable);
        return 0;
    }
    printf("executable is lost.\n");
    return 1;
}

Alternate program for 64-bit

#include <dlfcn.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
    struct load_module_desc desc;
    char *name;
    dlget(-2, &desc, sizeof(desc));
    name = dlgetname(&desc, sizeof(desc), NULL, NULL, NULL);
    printf("executable is '%s' (from dlgetname).\n", name);
    return 0;
}



Manage My AllianceOne Membership

 
 » Sign in
 » Join AllianceOne
 » Contact us