| /* Test program for returning the canonical absolute name of a given file. | 
 |    Copyright (C) 1996-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |    Contributed by David Mosberger <davidm@azstarnet.com>. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | /* This file must be run from within a directory called "stdlib".  */ | 
 |  | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <sys/param.h> | 
 |  | 
 | /* Prototype for our test function.  */ | 
 | extern int do_test (int argc, char *argv[]); | 
 | #include <test-skeleton.c> | 
 |  | 
 | #ifndef PATH_MAX | 
 | # define PATH_MAX 4096 | 
 | #endif | 
 | static char	cwd[PATH_MAX]; | 
 | static size_t	cwd_len; | 
 |  | 
 | struct { | 
 |   const char *	name; | 
 |   const char *	value; | 
 | } symlinks[] = { | 
 |   {"SYMLINK_LOOP",	"SYMLINK_LOOP"}, | 
 |   {"SYMLINK_1",		"."}, | 
 |   {"SYMLINK_2",		"//////./../../etc"}, | 
 |   {"SYMLINK_3",		"SYMLINK_1"}, | 
 |   {"SYMLINK_4",		"SYMLINK_2"}, | 
 |   {"SYMLINK_5",		"doesNotExist"}, | 
 | }; | 
 |  | 
 | struct { | 
 |   const char * in, * out, * resolved; | 
 |   int error; | 
 | } tests[] = { | 
 |   /*  0 */ | 
 |   {"/",					"/"}, | 
 |   {"/////////////////////////////////",	"/"}, | 
 |   {"/.././.././.././..///",		"/"}, | 
 |   {"/etc",				"/etc"}, | 
 |   {"/etc/../etc",			"/etc"}, | 
 |   /*  5 */ | 
 |   {"/doesNotExist/../etc",		0, "/doesNotExist", ENOENT}, | 
 |   {"./././././././././.",		"."}, | 
 |   {"/etc/.//doesNotExist",		0, "/etc/doesNotExist", ENOENT}, | 
 |   {"./doesExist",			"./doesExist"}, | 
 |   {"./doesExist/",			"./doesExist"}, | 
 |   /* 10 */ | 
 |   {"./doesExist/../doesExist",		"./doesExist"}, | 
 |   {"foobar",				0, "./foobar", ENOENT}, | 
 |   {".",					"."}, | 
 |   {"./foobar",				0, "./foobar", ENOENT}, | 
 |   {"SYMLINK_LOOP",			0, "./SYMLINK_LOOP", ELOOP}, | 
 |   /* 15 */ | 
 |   {"./SYMLINK_LOOP",			0, "./SYMLINK_LOOP", ELOOP}, | 
 |   {"SYMLINK_1",				"."}, | 
 |   {"SYMLINK_1/foobar",			0, "./foobar", ENOENT}, | 
 |   {"SYMLINK_2",				"/etc"}, | 
 |   {"SYMLINK_3",				"."}, | 
 |   /* 20 */ | 
 |   {"SYMLINK_4",				"/etc"}, | 
 |   {"../stdlib/SYMLINK_1",		"."}, | 
 |   {"../stdlib/SYMLINK_2",		"/etc"}, | 
 |   {"../stdlib/SYMLINK_3",		"."}, | 
 |   {"../stdlib/SYMLINK_4",		"/etc"}, | 
 |   /* 25 */ | 
 |   {"./SYMLINK_5",			0, "./doesNotExist", ENOENT}, | 
 |   {"SYMLINK_5",				0, "./doesNotExist", ENOENT}, | 
 |   {"SYMLINK_5/foobar",			0, "./doesNotExist", ENOENT}, | 
 |   {"doesExist/../../stdlib/doesExist",	"./doesExist"}, | 
 |   {"doesExist/.././../stdlib/.",	"."}, | 
 |   /* 30 */ | 
 |   {"./doesExist/someFile/",		0, "./doesExist/someFile", ENOTDIR}, | 
 |   {"./doesExist/someFile/..",		0, "./doesExist/someFile", ENOTDIR}, | 
 | }; | 
 |  | 
 |  | 
 | static int | 
 | check_path (const char * result, const char * expected) | 
 | { | 
 |   int good; | 
 |  | 
 |   if (!result) | 
 |     return (expected == NULL); | 
 |  | 
 |   if (!expected) | 
 |     return 0; | 
 |  | 
 |   if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0')) | 
 |     good = (strncmp (result, cwd, cwd_len) == 0 | 
 | 	    && strcmp (result + cwd_len, expected + 1) == 0); | 
 |   else | 
 |     good = (strcmp (expected, result) == 0); | 
 |  | 
 |   return good; | 
 | } | 
 |  | 
 |  | 
 | int | 
 | do_test (int argc, char ** argv) | 
 | { | 
 |   char * result; | 
 |   int i, errors = 0; | 
 |   char buf[PATH_MAX]; | 
 |  | 
 |   getcwd (cwd, sizeof(buf)); | 
 |   cwd_len = strlen (cwd); | 
 |  | 
 |   errno = 0; | 
 |   if (realpath (NULL, buf) != NULL || errno != EINVAL) | 
 |     { | 
 |       printf ("%s: expected return value NULL and errno set to EINVAL" | 
 | 	      " for realpath(NULL,...)\n", argv[0]); | 
 |       ++errors; | 
 |     } | 
 |  | 
 | #if 0 | 
 |   /* This is now allowed.  The test is invalid.  */ | 
 |   errno = 0; | 
 |   if (realpath ("/", NULL) != NULL || errno != EINVAL) | 
 |     { | 
 |       printf ("%s: expected return value NULL and errno set to EINVAL" | 
 | 	      " for realpath(...,NULL)\n", argv[0]); | 
 |       ++errors; | 
 |     } | 
 | #endif | 
 |  | 
 |   errno = 0; | 
 |   if (realpath ("", buf) != NULL || errno != ENOENT) | 
 |     { | 
 |       printf ("%s: expected return value NULL and set errno to ENOENT" | 
 | 	      " for realpath(\"\",...)\n", argv[0]); | 
 |       ++errors; | 
 |     } | 
 |  | 
 |   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i) | 
 |     symlink (symlinks[i].value, symlinks[i].name); | 
 |  | 
 |   int has_dir = mkdir ("doesExist", 0777) == 0; | 
 |  | 
 |   int fd = has_dir ? creat ("doesExist/someFile", 0777) : -1; | 
 |  | 
 |   for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i) | 
 |     { | 
 |       buf[0] = '\0'; | 
 |       result = realpath (tests[i].in, buf); | 
 |  | 
 |       if (!check_path (result, tests[i].out)) | 
 | 	{ | 
 | 	  printf ("%s: flunked test %d (expected `%s', got `%s')\n", | 
 | 		  argv[0], i, tests[i].out ? tests[i].out : "NULL", | 
 | 		  result ? result : "NULL"); | 
 | 	  ++errors; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       if (!check_path (buf, tests[i].out ? tests[i].out : tests[i].resolved)) | 
 | 	{ | 
 | 	  printf ("%s: flunked test %d (expected resolved `%s', got `%s')\n", | 
 | 		  argv[0], i, tests[i].out ? tests[i].out : tests[i].resolved, | 
 | 		  buf); | 
 | 	  ++errors; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       if (!tests[i].out && errno != tests[i].error) | 
 | 	{ | 
 | 	  printf ("%s: flunked test %d (expected errno %d, got %d)\n", | 
 | 		  argv[0], i, tests[i].error, errno); | 
 | 	  ++errors; | 
 | 	  continue; | 
 | 	} | 
 |  | 
 |       char *result2 = realpath (tests[i].in, NULL); | 
 |       if ((result2 == NULL && result != NULL) | 
 | 	  || (result2 != NULL && strcmp (result, result2) != 0)) | 
 | 	{ | 
 | 	  printf ("\ | 
 | %s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n", | 
 | 		  argv[0], result2, result); | 
 | 	  ++errors; | 
 | 	} | 
 |       free (result2); | 
 |     } | 
 |  | 
 |   getcwd (buf, sizeof(buf)); | 
 |   if (strcmp (buf, cwd)) | 
 |     { | 
 |       printf ("%s: current working directory changed from %s to %s\n", | 
 | 	      argv[0], cwd, buf); | 
 |       ++errors; | 
 |     } | 
 |  | 
 |   if (fd >= 0) | 
 |     { | 
 |       close (fd); | 
 |       unlink ("doesExist/someFile"); | 
 |     } | 
 |  | 
 |   if (has_dir) | 
 |     rmdir ("doesExist"); | 
 |  | 
 |   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i) | 
 |     unlink (symlinks[i].name); | 
 |  | 
 |   if (errors != 0) | 
 |     { | 
 |       printf ("%d errors.\n", errors); | 
 |       return EXIT_FAILURE; | 
 |     } | 
 |  | 
 |   puts ("No errors."); | 
 |   return EXIT_SUCCESS; | 
 | } |