immutable: Add tests.
[gnulib.git] / m4 / chown.m4
blobd1c083175e6b8876141d36720245705f5e3c6fc2
1 # serial 35
2 # Determine whether we need the chown wrapper.
4 dnl Copyright (C) 1997-2001, 2003-2005, 2007, 2009-2021 Free Software
5 dnl Foundation, Inc.
7 dnl This file is free software; the Free Software Foundation
8 dnl gives unlimited permission to copy and/or distribute it,
9 dnl with or without modifications, as long as this notice is preserved.
11 # chown should accept arguments of -1 for uid and gid, and it should
12 # dereference symlinks.  If it doesn't, arrange to use the replacement
13 # function.
15 # From Jim Meyering.
17 # This is taken from the following Autoconf patch:
18 # https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=7fbb553727ed7e0e689a17594b58559ecf3ea6e9
19 AC_DEFUN([AC_FUNC_CHOWN],
21   AC_REQUIRE([AC_TYPE_UID_T])dnl
22   AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
23   AC_CHECK_HEADERS([unistd.h])
24   AC_CACHE_CHECK([for working chown],
25     [ac_cv_func_chown_works],
26     [AC_RUN_IFELSE(
27        [AC_LANG_PROGRAM(
28           [AC_INCLUDES_DEFAULT
29            [#include <fcntl.h>
30           ]GL_MDA_DEFINES],
31           [[
32             char *f = "conftest.chown";
33             struct stat before, after;
35             if (creat (f, 0600) < 0)
36               return 1;
37             if (stat (f, &before) < 0)
38               return 1;
39             if (chown (f, (uid_t) -1, (gid_t) -1) == -1)
40               return 1;
41             if (stat (f, &after) < 0)
42               return 1;
43             return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid);
44           ]])
45        ],
46        [ac_cv_func_chown_works=yes],
47        [ac_cv_func_chown_works=no],
48        [case "$host_os" in # ((
49                            # Guess yes on Linux systems.
50           linux-* | linux) ac_cv_func_chown_works="guessing yes" ;;
51                            # Guess yes on glibc systems.
52           *-gnu* | gnu*)   ac_cv_func_chown_works="guessing yes" ;;
53                            # Guess no on native Windows.
54           mingw*)          ac_cv_func_chown_works="guessing no" ;;
55                            # If we don't know, obey --enable-cross-guesses.
56           *)               ac_cv_func_chown_works="$gl_cross_guess_normal" ;;
57         esac
58        ])
59      rm -f conftest.chown
60     ])
61   case "$ac_cv_func_chown_works" in
62     *yes)
63       AC_DEFINE([HAVE_CHOWN], [1],
64         [Define to 1 if your system has a working `chown' function.])
65       ;;
66   esac
67 ])# AC_FUNC_CHOWN
69 AC_DEFUN_ONCE([gl_FUNC_CHOWN],
71   AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
72   AC_REQUIRE([AC_TYPE_UID_T])
73   AC_REQUIRE([AC_FUNC_CHOWN])
74   AC_REQUIRE([gl_FUNC_CHOWN_FOLLOWS_SYMLINK])
75   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
76   AC_CHECK_FUNCS_ONCE([chown fchown])
78   dnl mingw lacks chown altogether.
79   if test $ac_cv_func_chown = no; then
80     HAVE_CHOWN=0
81   else
82     dnl Some old systems treated chown like lchown.
83     case "$gl_cv_func_chown_follows_symlink" in
84       *yes) ;;
85       *) REPLACE_CHOWN=1 ;;
86     esac
88     dnl Some old systems tried to use uid/gid -1 literally.
89     case "$ac_cv_func_chown_works" in
90       *no)
91         AC_DEFINE([CHOWN_FAILS_TO_HONOR_ID_OF_NEGATIVE_ONE], [1],
92           [Define if chown is not POSIX compliant regarding IDs of -1.])
93         REPLACE_CHOWN=1
94         ;;
95     esac
97     dnl Solaris 9 ignores trailing slash.
98     dnl FreeBSD 7.2 mishandles trailing slash on symlinks.
99     dnl Likewise for AIX 7.1.
100     AC_CACHE_CHECK([whether chown honors trailing slash],
101       [gl_cv_func_chown_slash_works],
102       [touch conftest.file && rm -f conftest.link
103        AC_RUN_IFELSE([AC_LANG_PROGRAM([[
104 #include <unistd.h>
105 #include <stdlib.h>
106 #include <errno.h>
107 ]GL_MDA_DEFINES],
108         [[if (symlink ("conftest.file", "conftest.link")) return 1;
109           if (chown ("conftest.link/", getuid (), getgid ()) == 0) return 2;
110         ]])],
111         [gl_cv_func_chown_slash_works=yes],
112         [gl_cv_func_chown_slash_works=no],
113         [case "$host_os" in
114                     # Guess yes on glibc systems.
115            *-gnu*)  gl_cv_func_chown_slash_works="guessing yes" ;;
116                     # Guess yes on musl systems.
117            *-musl*) gl_cv_func_chown_slash_works="guessing yes" ;;
118                     # If we don't know, obey --enable-cross-guesses.
119            *)       gl_cv_func_chown_slash_works="$gl_cross_guess_normal" ;;
120          esac
121         ])
122       rm -f conftest.link conftest.file])
123     case "$gl_cv_func_chown_slash_works" in
124       *yes) ;;
125       *)
126         AC_DEFINE([CHOWN_TRAILING_SLASH_BUG], [1],
127           [Define to 1 if chown mishandles trailing slash.])
128         REPLACE_CHOWN=1
129         ;;
130     esac
132     dnl OpenBSD fails to update ctime if ownership does not change.
133     AC_CACHE_CHECK([whether chown always updates ctime],
134       [gl_cv_func_chown_ctime_works],
135       [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
136 #include <unistd.h>
137 #include <stdlib.h>
138 #include <errno.h>
139 #include <fcntl.h>
140 #include <sys/stat.h>
141 ]GL_MDA_DEFINES],
142         [[struct stat st1, st2;
143           if (close (creat ("conftest.file", 0600))) return 1;
144           if (stat ("conftest.file", &st1)) return 2;
145           sleep (1);
146           if (chown ("conftest.file", st1.st_uid, st1.st_gid)) return 3;
147           if (stat ("conftest.file", &st2)) return 4;
148           if (st2.st_ctime <= st1.st_ctime) return 5;
149         ]])],
150         [gl_cv_func_chown_ctime_works=yes],
151         [gl_cv_func_chown_ctime_works=no],
152         [case "$host_os" in
153                     # Guess yes on glibc systems.
154            *-gnu*)  gl_cv_func_chown_ctime_works="guessing yes" ;;
155                     # Guess yes on musl systems.
156            *-musl*) gl_cv_func_chown_ctime_works="guessing yes" ;;
157                     # If we don't know, obey --enable-cross-guesses.
158            *)       gl_cv_func_chown_ctime_works="$gl_cross_guess_normal" ;;
159          esac
160         ])
161       rm -f conftest.file])
162     case "$gl_cv_func_chown_ctime_works" in
163       *yes) ;;
164       *)
165         AC_DEFINE([CHOWN_CHANGE_TIME_BUG], [1], [Define to 1 if chown fails
166           to change ctime when at least one argument was not -1.])
167         REPLACE_CHOWN=1
168         ;;
169     esac
170   fi
173 # Determine whether chown follows symlinks (it should).
174 AC_DEFUN_ONCE([gl_FUNC_CHOWN_FOLLOWS_SYMLINK],
176   AC_CACHE_CHECK(
177     [whether chown dereferences symlinks],
178     [gl_cv_func_chown_follows_symlink],
179     [
180       AC_RUN_IFELSE([AC_LANG_SOURCE([[
181 #include <unistd.h>
182 #include <stdlib.h>
183 #include <errno.h>
184 ]GL_MDA_DEFINES[
185         int
186         main ()
187         {
188           int result = 0;
189           char const *dangling_symlink = "conftest.dangle";
191           unlink (dangling_symlink);
192           if (symlink ("conftest.no-such", dangling_symlink))
193             abort ();
195           /* Exit successfully on a conforming system,
196              i.e., where chown must fail with ENOENT.  */
197           if (chown (dangling_symlink, getuid (), getgid ()) == 0)
198             result |= 1;
199           if (errno != ENOENT)
200             result |= 2;
201           return result;
202         }
203         ]])],
204         [gl_cv_func_chown_follows_symlink=yes],
205         [gl_cv_func_chown_follows_symlink=no],
206         [gl_cv_func_chown_follows_symlink="guessing yes"]
207       )
208     ]
209   )
211   case "$gl_cv_func_chown_follows_symlink" in
212     *yes) ;;
213     *)
214       AC_DEFINE([CHOWN_MODIFIES_SYMLINK], [1],
215         [Define if chown modifies symlinks.])
216       ;;
217   esac