tags:

views:

1217

answers:

3

I'm looking for an example of how to use the realpath function in a C program. I can't seem to find one on the web or in any of my C programming books.

+4  A: 

The realpath() function is not described in the C Standard. It is however described in SUS v2 specification. If that is what you mean, here is an example:

#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    char buf[PATH_MAX + 1]; /* not sure about the "+ 1" */
    char *res = realpath("this_source.c", buf);
    if (res) {
        printf("This source is at %s.\n", buf);
    } else {
        perror("realpath");
        exit(EXIT_FAILURE);
    }
    return 0;
}

PATH_MAX is defined in <limits.h>

pmg
but what should PATH_MAX be?
Ralph
PATH_MAX is the maximum length for a path. It is a weird gizmo; there is guaranteed to be a value _POSIX_PATH_MAX which is the minimum value that PATH_MAX may be. However, many systems have a `<limits.h>` that does not set PATH_MAX, meaning there isn't a prescribed limit for the maximum length of a path on the machine. It can also be file-system dependent, anyway. So, you can look up a value with sysconf(), or with pathconf(), or you can take a guess that most sane people don't use paths longer than 1024 bytes and use that.
Jonathan Leffler
+1  A: 

Like this:

int main(int argc, char *argv[]) {
    ...
    char *symlinkpath = argv[1];
    char actualpath [PATH_MAX];
    char *ptr;
    ptr = realpath(symlinkpath, actualpath);
    ...
}

Borrowed from here

fvu
+2  A: 

What the realpath() function does is tell you the pathname of a file when all symbolic links have been resolved. It is not necessarily an absolute pathname if the value you supply is a relative name, but that depends in part on whether you traverse any symbolic links with absolute names for the link value - if you do, then the output is an absolute name after all. Also, if the relative name traverses up to the root directory (or 'beyond', as in '../../../../../..' when only three levels deep in the directory hierarchy).

You may have a 'realpath' program already on your machine. Here's the (non-standard) version I wrote.

/*
@(#)File:           $RCSfile: realpath.c,v $
@(#)Version:        $Revision: 1.3 $
@(#)Last changed:   $Date: 2007/10/23 20:23:44 $
@(#)Purpose:        Command to evaluate realpath(3) on given arguments.
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2007
@(#)Product:        :PRODUCT:
*/

/*TABSTOP=4*/

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */

#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "stderr.h"

static const char optstr[] = "hlsV";
static const char usestr[] = "[-hslV] given-path [...]";
static const char hlpstr[] =
    "  -h   Print this help message\n"
    "  -l   Long format: print given-path and real-path\n"
    "  -s   Short format: print just real-path\n"
    "  -V   Print version and exit\n"
    ;

enum { FMT_LONG, FMT_SHORT };
static int format_type = FMT_LONG;

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_realpath_c[];
const char jlss_id_realpath_c[] = "@(#)$Id: realpath.c,v 1.3 2007/10/23 20:23:44 jleffler Exp $";
#endif /* lint */

static int eval_realpath(const char *given)
{
    char realname[_POSIX_PATH_MAX];
    int rc = 0;

    if (realpath(given, realname) == 0)
    {
        rc = -1;
        err_sysrem("failed to resolve real path name for %s\n", given);
    }
    else if (format_type == FMT_SHORT)
        printf("%s\n", realname);
    else
        printf("%s %s\n", given, realname);
    return(rc);
}

int main(int argc, char **argv)
{
    int i;
    int rc = EXIT_SUCCESS;
    int opt;

    err_setarg0(argv[0]);
    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'V':
            err_version("REALPATH", &"@(#)$Revision: 1.3 $ ($Date: 2007/10/23 20:23:44 $)"[4]);
            break;
        case 'h':
            err_help(usestr, hlpstr);
            break;
        case 'l':
            format_type = FMT_LONG;
            break;
        case 's':
            format_type = FMT_SHORT;
            break;
        default:
            err_usage(usestr);
            break;
        }
    }

    for (i = optind; i < argc; i++)
    {
        if (eval_realpath(argv[i]) != 0)
            rc = EXIT_FAILURE;
    }

    return(rc);
}

I needed it to test some software that was evaluating the security of a path, and needed to be sure my code was evaluating the given path to the same resolved location as realpath() does. It would probably be sensible to extend it with a '-a' option to ensure names are mapped to absolute names (by prefixing the result of getcwd() to relative pathnames).

(Source for stderr.c, stderr.h can be found online if you know where to look. Or contact me - see my profile.)

Jonathan Leffler