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.
3 Answers
Note
- The
realpath()
function is not described in the C Standard- It is however described by POSIX 1997 and POSIX 2008.
- The
Sample Code
#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */
char *res = realpath("this_source.c", buf);
if (res) { // or: if (res != NULL)
printf("This source is at %s.\n", buf);
} else {
char* errStr = strerror(errno);
printf("error string: %s\n", errStr);
perror("realpath");
exit(EXIT_FAILURE);
}
return 0;
}
- Reference
- PATH_MAX defined in PATH_MAX from POSIX 1997
- errno
- strerror
-
5PATH_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 `
` 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 Oct 13 '09 at 22:36 -
1you should take into consideration calling `free(res);` after calling `realpath` and finishing from `res`. As `realpath` allocates the return value in the heap. Source: `man realpath` – Jalal Mostafa Mar 03 '16 at 17:44
-
@JalalMostafa: POSIX `realpath()`, as described in the link in my answer, does not allocate memory. I suspect your system is not POSIX compliant. Calling POSIX compliant `realpath()` with `NULL` for the 2nd argument invokes **UB**. – pmg Mar 03 '16 at 19:12
-
1@JalalMostafa: There is a new version of the POSIX specification ([`realpath()` in POSIX 2008](http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html)) there the 2nd argument can be NULL and then `malloc()` is called. In my example, the buffer is a local array, so no cause for calling `free()`. Thanks for the heads up. – pmg Mar 03 '16 at 19:22
One-line build command line
Minimalist but it does the job!
Build
gcc -o realpath -x c - <<< $'#include<stdlib.h>\n#include<stdio.h>\nint main(int c,char**v){puts(realpath(v[1],0));}'
Test
$> ./realpath ~/../../../usr/./bin/./awk
/bin/gawk
$> readlink -f ~/../../../usr/./bin/./awk
/bin/gawk
Requirements
Crash
My minimalist one-line command line builds an executable realpath
that produces a Segmentation fault
when the path does not exist. Instead of writing if
/else
blocs to handle that issue within my answer, I have added below some links to let you have a look on the Busybox implementation of realpath
and readlink
.
Busybox implementation
For a more complete source code, have a look on this simple implementation.
Official Git repository
GitHub mirror repository

- 51,447
- 27
- 165
- 200
-
/usr/bin/readlink -f does not require the path exist. However, realpath api does. Could you help to comment how to mimic readlink in this respect ? – SOUser Nov 11 '17 at 13:05
-
1Hi @SOUser. Thank you for your feedback. You are right, my minimalist one-line command line builds an executable `realpath` that produces a **`Segmentation fault`** when path does not exist. Instead of writing `if/else` blocs to handle that within my answer, I have added links to let you have a look on the Busybox implementation of `realpath` and `readlink`. I hope you appreciate the Busybox source code. Please let me know if I can help. Cheers – oHo Nov 17 '17 at 10:04
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).
(The extra source code is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c
, stderr.h
and errhelp.c
in the src/libsoq sub-directory.)

- 730,956
- 141
- 904
- 1,278
-
No, it *does* necessarily give you an absolute path name. [The documentation](http://pubs.opengroup.org/onlinepubs/009695399/functions/realpath.html) says "The *realpath()* function shall derive, from the pathname pointed to by *file_name*, an absolute pathname that names the same file, ..." – Adam Rosenfield Aug 20 '11 at 02:46
-
That's odd; you're right, yet...I must have gotten the wrong idea from somewhere. The difficulty almost four years after writing the code, and most of two years after writing the answer, is knowing where I got the misinformation from. It will take some investigation on obscure systems. – Jonathan Leffler Aug 20 '11 at 03:08
-
Hi there. It's 2022. Trying to understand your answer. I do `gcc -g -Wall reallink1.c stderr.c stderr.h` it won't compile. The error is `undefined reference to `err_help'` / @JonathanLeffler – jian Jul 21 '22 at 16:37
-
@Mark: Apologies — you will need `errhelp.c` too , which is available from my SOQ repository, as documented in the tail of the question. If there's another non-standard file you need, the source/header should be in the same directory of the repository. If something is missing altogether, please let me know. – Jonathan Leffler Jul 21 '22 at 18:14