Index: include/unistd.h =================================================================== --- include/unistd.h +++ include/unistd.h @@ -507,6 +507,7 @@ int execvP(const char *, const char *, char * const *); int feature_present(const char *); char *fflagstostr(u_long); +char *get_current_dir_name(void); int getdomainname(char *, int); int getentropy(void *, size_t); int getgrouplist(const char *, gid_t, gid_t *, int *); Index: lib/libc/Versions.def =================================================================== --- lib/libc/Versions.def +++ lib/libc/Versions.def @@ -35,6 +35,10 @@ FBSD_1.6 { } FBSD_1.5; +# This version was first added to 14.0-current. +FBSD_1.7 { +} FBSD_1.6; + # This is our private namespace. Any global interfaces that are # strictly for use only by other FreeBSD applications and libraries # are listed here. We use a separate namespace so we can write Index: lib/libc/gen/Makefile.inc =================================================================== --- lib/libc/gen/Makefile.inc +++ lib/libc/gen/Makefile.inc @@ -395,6 +395,7 @@ getcap.3 cgetset.3 \ getcap.3 cgetstr.3 \ getcap.3 cgetustr.3 +MLINKS+=getcwd.3 get_current_dir_name.3 MLINKS+=getcwd.3 getwd.3 MLINKS+=getcontext.3 getcontextx.3 MLINKS+=getcontext.3 setcontext.3 Index: lib/libc/gen/getcwd.3 =================================================================== --- lib/libc/gen/getcwd.3 +++ lib/libc/gen/getcwd.3 @@ -28,12 +28,13 @@ .\" @(#)getcwd.3 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd April 17, 2010 +.Dd March 23, 2021 .Dt GETCWD 3 .Os .Sh NAME .Nm getcwd , -.Nm getwd +.Nm getwd , +.Nm get_current_dir_name .Nd get working directory pathname .Sh LIBRARY .Lb libc @@ -43,6 +44,8 @@ .Fn getcwd "char *buf" "size_t size" .Ft char * .Fn getwd "char *buf" +.Ft char * +.Fn get_current_dir_name "void" .Sh DESCRIPTION The .Fn getcwd @@ -75,12 +78,28 @@ (as defined in the include file .In sys/param.h ) . -Obviously, .Fa buf should be at least .Dv MAXPATHLEN bytes in length. .Pp +The function +.Fn get_current_dir_name +returns the value of the environment variable +.Ev PWD +if it points to the current directory. +The value is returned verbatim. +Symbolic links will not have been resolved. +Relative paths will not have been made absolute. +If +.Ev PWD +is unset or does not point to the current +directory, +.Fn get_current_dir_name +falls back to +.Fn getcwd NULL 0 . +The return value must be freed. +.Pp These routines have traditionally been used by programs to save the name of a working directory for the purpose of returning to it. A much faster and less error-prone method of accomplishing this is to @@ -125,7 +144,9 @@ .Pp The .Fn getcwd -function +and +.Fn get_current_dir_name +functions may fail if: .Bl -tag -width Er .It Bq Er EACCES @@ -148,11 +169,17 @@ pointer and have .Fn getcwd allocate memory as necessary is an extension. +.Fn get_current_dir_name +is an extension as well. .Sh HISTORY The .Fn getwd function appeared in .Bx 4.0 . +The +.Fn get_current_dir_name +function first appeared in glibc 2.1 and was later added to +.Fx 14.0 . .Sh BUGS The .Fn getwd Index: lib/libc/stdlib/Makefile.inc =================================================================== --- lib/libc/stdlib/Makefile.inc +++ lib/libc/stdlib/Makefile.inc @@ -7,7 +7,7 @@ MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ bsearch.c \ cxa_thread_atexit.c cxa_thread_atexit_impl.c \ - div.c exit.c getenv.c getopt.c getopt_long.c \ + div.c exit.c get_current_dir_name.c getenv.c getopt.c getopt_long.c \ getsubopt.c hcreate.c hcreate_r.c hdestroy_r.c heapsort.c heapsort_b.c \ hsearch_r.c imaxabs.c imaxdiv.c \ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ Index: lib/libc/stdlib/Symbol.map =================================================================== --- lib/libc/stdlib/Symbol.map +++ lib/libc/stdlib/Symbol.map @@ -128,6 +128,10 @@ srand; }; +FBSD_1.7 { + get_current_dir_name; +}; + FBSDprivate_1.0 { __system; _system; Index: lib/libc/stdlib/get_current_dir_name.c =================================================================== --- /dev/null +++ lib/libc/stdlib/get_current_dir_name.c @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: MIT + * + * Copyright © 2005-2020 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +char * +get_current_dir_name() +{ + struct stat a, b; + char *res = getenv("PWD"); + if (res && *res && !stat(res, &a) && !stat(".", &b) + && (a.st_dev == b.st_dev) && (a.st_ino == b.st_ino)) + return (strdup(res)); + return (getcwd(NULL, 0)); +} Index: lib/libc/tests/stdlib/Makefile =================================================================== --- lib/libc/tests/stdlib/Makefile +++ lib/libc/tests/stdlib/Makefile @@ -3,6 +3,7 @@ .include ATF_TESTS_C+= dynthr_test +ATF_TESTS_C+= get_current_dir_name_test ATF_TESTS_C+= heapsort_test ATF_TESTS_C+= mergesort_test ATF_TESTS_C+= qsort_test Index: lib/libc/tests/stdlib/get_current_dir_name_test.c =================================================================== --- /dev/null +++ lib/libc/tests/stdlib/get_current_dir_name_test.c @@ -0,0 +1,65 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2021 Tobias Kortkamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test for get_current_dir_name(). + */ + +#include +#include +#include +#include + +#include + +ATF_TC_WITHOUT_HEAD(get_current_dir_name_test); +ATF_TC_BODY(get_current_dir_name_test, tc) +{ + + unsetenv("PWD"); + char *pwd = getcwd(NULL, 0); + ATF_REQUIRE_STREQ(get_current_dir_name(), pwd); + + putenv("PWD=/nonexistent"); + ATF_REQUIRE_STREQ(get_current_dir_name(), pwd); + + putenv("PWD=."); + ATF_REQUIRE_STREQ(get_current_dir_name(), "."); + + symlink("../../tests/stdlib", "foo"); + setenv("PWD", "../../tests/stdlib/foo", 1); + ATF_REQUIRE_STREQ(get_current_dir_name(), "../../tests/stdlib/foo"); + unlink("foo"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, get_current_dir_name_test); + + return (atf_no_error()); +}