1 /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <stddef.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <confstr.h>
23 #include "../version.h"
24 
25 #define NEED_SPEC_ARRAY 0
26 #include <posix-conf-vars.h>
27 
28 /* If BUF is not NULL and LEN > 0, fill in at most LEN - 1 bytes
29    of BUF with the value corresponding to NAME and zero-terminate BUF.
30    Return the number of bytes required to hold NAME's entire value.  */
31 size_t
__confstr(int name,char * buf,size_t len)32 __confstr (int name, char *buf, size_t len)
33 {
34   const char *string = "";
35   size_t string_len = 1;
36 
37   /* Note that this buffer must be large enough for the longest strings
38      used below.  */
39   char restenvs[4 * sizeof "POSIX_V7_LPBIG_OFFBIG"];
40 
41   switch (name)
42     {
43     case _CS_PATH:
44       {
45 	static const char cs_path[] = CS_PATH;
46 	string = cs_path;
47 	string_len = sizeof (cs_path);
48       }
49       break;
50 
51       /* For _CS_V7_WIDTH_RESTRICTED_ENVS, _CS_V6_WIDTH_RESTRICTED_ENVS
52 	 and _CS_V5_WIDTH_RESTRICTED_ENVS:
53 
54 	 We have to return a newline-separated list of names of
55 	 programming environments in which the widths of blksize_t,
56 	 cc_t, mode_t, nfds_t, pid_t, ptrdiff_t, size_t, speed_t,
57 	 ssize_t, suseconds_t, tcflag_t, useconds_t, wchar_t, and
58 	 wint_t types are no greater than the width of type long.
59 
60 	 Currently this means all environments that the system allows.  */
61 
62 #define START_ENV_GROUP(VERSION)		\
63     case _CS_##VERSION##_WIDTH_RESTRICTED_ENVS:	\
64       string_len = 0;
65 
66 #define END_ENV_GROUP(VERSION)			\
67       restenvs[string_len++] = '\0';		\
68       string = restenvs;			\
69       break;
70 
71 #define KNOWN_ABSENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX)	\
72       /* Empty.  */
73 
74 #define KNOWN_PRESENT_ENV_STRING(STR)		\
75       if (string_len > 0)			\
76 	restenvs[string_len++] = '\n';		\
77       memcpy (restenvs + string_len, STR,	\
78 	      sizeof STR - 1);			\
79       string_len += sizeof STR - 1;
80 
81 #define KNOWN_PRESENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX)	\
82       KNOWN_PRESENT_ENV_STRING (#ENV_PREFIX "_" #SUFFIX)
83 
84 #define UNKNOWN_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX)		\
85       if (__sysconf (_SC_##SC_PREFIX##_##SUFFIX) > 0)			\
86 	{								\
87 	  KNOWN_PRESENT_ENVIRONMENT (SC_PREFIX, ENV_PREFIX, SUFFIX)	\
88 	}
89 
90 #include "posix-envs.def"
91 
92 #undef START_ENV_GROUP
93 #undef END_ENV_GROUP
94 #undef KNOWN_ABSENT_ENVIRONMENT
95 #undef KNOWN_PRESENT_ENV_STRING
96 #undef KNOWN_PRESENT_ENVIRONMENT
97 #undef UNKNOWN_ENVIRONMENT
98 
99     case _CS_XBS5_ILP32_OFF32_CFLAGS:
100     case _CS_POSIX_V6_ILP32_OFF32_CFLAGS:
101     case _CS_POSIX_V7_ILP32_OFF32_CFLAGS:
102 #ifdef __ILP32_OFF32_CFLAGS
103 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFF32)
104 #  error "__ILP32_OFF32_CFLAGS should not be defined"
105 # elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFF32)
106       if (__sysconf (_SC_V7_ILP32_OFF32) < 0)
107 	break;
108 # endif
109       string = __ILP32_OFF32_CFLAGS;
110       string_len = sizeof (__ILP32_OFF32_CFLAGS);
111 #endif
112       break;
113 
114     case _CS_XBS5_ILP32_OFFBIG_CFLAGS:
115     case _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS:
116     case _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS:
117 #ifdef __ILP32_OFFBIG_CFLAGS
118 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFFBIG)
119 #  error "__ILP32_OFFBIG_CFLAGS should not be defined"
120 # elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFFBIG)
121       if (__sysconf (_SC_V7_ILP32_OFFBIG) < 0)
122 	break;
123 # endif
124       string = __ILP32_OFFBIG_CFLAGS;
125       string_len = sizeof (__ILP32_OFFBIG_CFLAGS);
126 #endif
127       break;
128 
129     case _CS_XBS5_LP64_OFF64_CFLAGS:
130     case _CS_POSIX_V6_LP64_OFF64_CFLAGS:
131     case _CS_POSIX_V7_LP64_OFF64_CFLAGS:
132 #ifdef __LP64_OFF64_CFLAGS
133 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_LP64_OFF64)
134 #  error "__LP64_OFF64_CFLAGS should not be defined"
135 # elif CONF_IS_UNDEFINED (_POSIX_V7_LP64_OFF64)
136       if (__sysconf (_SC_V7_LP64_OFF64) < 0)
137 	break;
138 # endif
139       string = __LP64_OFF64_CFLAGS;
140       string_len = sizeof (__LP64_OFF64_CFLAGS);
141 #endif
142       break;
143 
144     case _CS_XBS5_ILP32_OFF32_LDFLAGS:
145     case _CS_POSIX_V6_ILP32_OFF32_LDFLAGS:
146     case _CS_POSIX_V7_ILP32_OFF32_LDFLAGS:
147 #ifdef __ILP32_OFF32_LDFLAGS
148 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFF32 )
149 #  error "__ILP32_OFF32_LDFLAGS should not be defined"
150 # elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFF32)
151       if (__sysconf (_SC_V7_ILP32_OFF32) < 0)
152 	break;
153 # endif
154       string = __ILP32_OFF32_LDFLAGS;
155       string_len = sizeof (__ILP32_OFF32_LDFLAGS);
156 #endif
157       break;
158 
159     case _CS_XBS5_ILP32_OFFBIG_LDFLAGS:
160     case _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS:
161     case _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS:
162 #ifdef __ILP32_OFFBIG_LDFLAGS
163 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_ILP32_OFFBIG)
164 #  error "__ILP32_OFFBIG_LDFLAGS should not be defined"
165 # elif CONF_IS_UNDEFINED (_POSIX_V7_ILP32_OFFBIG)
166       if (__sysconf (_SC_V7_ILP32_OFFBIG) < 0)
167 	break;
168 # endif
169       string = __ILP32_OFFBIG_LDFLAGS;
170       string_len = sizeof (__ILP32_OFFBIG_LDFLAGS);
171 #endif
172       break;
173 
174     case _CS_XBS5_LP64_OFF64_LDFLAGS:
175     case _CS_POSIX_V6_LP64_OFF64_LDFLAGS:
176     case _CS_POSIX_V7_LP64_OFF64_LDFLAGS:
177 #ifdef __LP64_OFF64_LDFLAGS
178 # if CONF_IS_DEFINED_UNSET (_POSIX_V7_LP64_OFF64)
179 #  error "__LP64_OFF64_LDFLAGS should not be defined"
180 # elif CONF_IS_UNDEFINED (_POSIX_V7_LP64_OFF64)
181       if (__sysconf (_SC_V7_LP64_OFF64) < 0)
182 	break;
183 # endif
184       string = __LP64_OFF64_LDFLAGS;
185       string_len = sizeof (__LP64_OFF64_LDFLAGS);
186 #endif
187       break;
188 
189     case _CS_LFS_CFLAGS:
190     case _CS_LFS_LINTFLAGS:
191 #if (CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFF32) \
192      && CONF_IS_DEFINED_SET (_POSIX_V6_ILP32_OFFBIG))
193 # define __LFS_CFLAGS "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
194       /* Signal that we want the new ABI.  */
195       string = __LFS_CFLAGS;
196       string_len = sizeof (__LFS_CFLAGS);
197 #endif
198       break;
199 
200     case _CS_LFS_LDFLAGS:
201     case _CS_LFS_LIBS:
202       /* No special libraries or linker flags needed.  */
203       break;
204 
205     case _CS_LFS64_CFLAGS:
206     case _CS_LFS64_LINTFLAGS:
207 #define __LFS64_CFLAGS "-D_LARGEFILE64_SOURCE"
208       string = __LFS64_CFLAGS;
209       string_len = sizeof (__LFS64_CFLAGS);
210       break;
211 
212     case _CS_LFS64_LDFLAGS:
213     case _CS_LFS64_LIBS:
214       /* No special libraries or linker flags needed.  */
215       break;
216 
217     case _CS_XBS5_ILP32_OFF32_LIBS:
218     case _CS_XBS5_ILP32_OFF32_LINTFLAGS:
219     case _CS_XBS5_ILP32_OFFBIG_LIBS:
220     case _CS_XBS5_ILP32_OFFBIG_LINTFLAGS:
221     case _CS_XBS5_LP64_OFF64_LIBS:
222     case _CS_XBS5_LP64_OFF64_LINTFLAGS:
223     case _CS_XBS5_LPBIG_OFFBIG_CFLAGS:
224     case _CS_XBS5_LPBIG_OFFBIG_LDFLAGS:
225     case _CS_XBS5_LPBIG_OFFBIG_LIBS:
226     case _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS:
227 
228     case _CS_POSIX_V6_ILP32_OFF32_LIBS:
229     case _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS:
230     case _CS_POSIX_V6_ILP32_OFFBIG_LIBS:
231     case _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS:
232     case _CS_POSIX_V6_LP64_OFF64_LIBS:
233     case _CS_POSIX_V6_LP64_OFF64_LINTFLAGS:
234     case _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS:
235     case _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS:
236     case _CS_POSIX_V6_LPBIG_OFFBIG_LIBS:
237     case _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS:
238 
239     case _CS_POSIX_V7_ILP32_OFF32_LIBS:
240     case _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS:
241     case _CS_POSIX_V7_ILP32_OFFBIG_LIBS:
242     case _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS:
243     case _CS_POSIX_V7_LP64_OFF64_LIBS:
244     case _CS_POSIX_V7_LP64_OFF64_LINTFLAGS:
245     case _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS:
246     case _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS:
247     case _CS_POSIX_V7_LPBIG_OFFBIG_LIBS:
248     case _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS:
249       /* GNU libc does not require special actions to use LFS functions.  */
250       break;
251 
252     case _CS_GNU_LIBC_VERSION:
253       string = "glibc " VERSION;
254       string_len = sizeof ("glibc " VERSION);
255       break;
256 
257     case _CS_GNU_LIBPTHREAD_VERSION:
258 #ifdef LIBPTHREAD_VERSION
259       string = LIBPTHREAD_VERSION;
260       string_len = sizeof LIBPTHREAD_VERSION;
261       break;
262 #else
263       /* No thread library.  */
264       __set_errno (EINVAL);
265       return 0;
266 #endif
267 
268     case _CS_V6_ENV:
269     case _CS_V7_ENV:
270       /* Maybe something else is needed in future.  */
271       string = "POSIXLY_CORRECT=1";
272       string_len = sizeof ("POSIXLY_CORRECT=1");
273       break;
274 
275     default:
276       __set_errno (EINVAL);
277       return 0;
278     }
279 
280   if (len > 0 && buf != NULL)
281     {
282       if (string_len <= len)
283 	memcpy (buf, string, string_len);
284       else
285 	{
286 	  memcpy (buf, string, len - 1);
287 	  buf[len - 1] = '\0';
288 	}
289     }
290   return string_len;
291 }
292 libc_hidden_def (__confstr)
293 libc_hidden_def (confstr)
294 weak_alias (__confstr, confstr)
295