Fix confstr use of local buffer outside its extent.
[platform/upstream/glibc.git] / posix / confstr.c
1 /* Copyright (C) 1991-2012 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    <http://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 /* If BUF is not NULL and LEN > 0, fill in at most LEN - 1 bytes
26    of BUF with the value corresponding to NAME and zero-terminate BUF.
27    Return the number of bytes required to hold NAME's entire value.  */
28 size_t
29 confstr (name, buf, len)
30      int name;
31      char *buf;
32      size_t len;
33 {
34   const char *string = "";
35   size_t string_len = 1;
36   char restenvs[4 * sizeof "POSIX_V7_LPBIG_OFFBIG"];
37   char restenvs[4 * sizeof "POSIX_V6_LPBIG_OFFBIG"];
38   char restenvs[4 * sizeof "XBS5_LPBIG_OFFBIG"];
39
40   switch (name)
41     {
42     case _CS_PATH:
43       {
44         static const char cs_path[] = CS_PATH;
45         string = cs_path;
46         string_len = sizeof (cs_path);
47       }
48       break;
49
50     case _CS_V7_WIDTH_RESTRICTED_ENVS:
51       /* We have to return a newline-separated list of named of
52          programming environements in which the widths of blksize_t,
53          cc_t, mode_t, nfds_t, pid_t, ptrdiff_t, size_t, speed_t,
54          ssize_t, suseconds_t, tcflag_t, useconds_t, wchar_t, and
55          wint_t types are no greater than the width of type long.
56
57          Currently this means all environment which the system allows.  */
58       string_len = 0;
59 #ifndef _POSIX_V7_ILP32_OFF32
60       if (__sysconf (_SC_V7_ILP32_OFF32) > 0)
61 #endif
62 #if !defined _POSIX_V7_ILP32_OFF32 || _POSIX_V7_ILP32_OFF32 > 0
63         {
64           memcpy (restenvs + string_len, "POSIX_V7_ILP32_OFF32",
65                   sizeof "POSIX_V7_ILP32_OFF32" - 1);
66           string_len += sizeof "POSIX_V7_ILP32_OFF32" - 1;
67         }
68 #endif
69 #ifndef _POSIX_V7_ILP32_OFFBIG
70       if (__sysconf (_SC_V7_ILP32_OFFBIG) > 0)
71 #endif
72 #if !defined _POSIX_V7_ILP32_OFFBIG || _POSIX_V7_ILP32_OFFBIG > 0
73         {
74           if (string_len)
75             restenvs[string_len++] = '\n';
76           memcpy (restenvs + string_len, "POSIX_V7_ILP32_OFFBIG",
77                   sizeof "POSIX_V7_ILP32_OFFBIG" - 1);
78           string_len += sizeof "POSIX_V7_ILP32_OFFBIG" - 1;
79         }
80 #endif
81 #ifndef _POSIX_V7_LP64_OFF64
82       if (__sysconf (_SC_V7_LP64_OFF64) > 0)
83 #endif
84 #if !defined _POSIX_V7_LP64_OFF64 || _POSIX_V7_LP64_OFF64 > 0
85         {
86           if (string_len)
87             restenvs[string_len++] = '\n';
88           memcpy (restenvs + string_len, "POSIX_V7_LP64_OFF64",
89                   sizeof "POSIX_V7_LP64_OFF64" - 1);
90           string_len += sizeof "POSIX_V7_LP64_OFF64" - 1;
91         }
92 #endif
93 #ifndef _POSIX_V7_LPBIG_OFFBIG
94       if (__sysconf (_SC_V7_LPBIG_OFFBIG) > 0)
95 #endif
96 #if !defined _POSIX_V7_LPBIG_OFFBIG || _POSIX_V7_LPBIG_OFFBIG > 0
97         {
98           if (string_len)
99             restenvs[string_len++] = '\n';
100           memcpy (restenvs + string_len, "POSIX_V7_LPBIG_OFFBIG",
101                   sizeof "POSIX_V7_LPBIG_OFFBIG" - 1);
102           string_len += sizeof "POSIX_V7_LPBIG_OFFBIG" - 1;
103         }
104 #endif
105       restenvs[string_len++] = '\0';
106       string = restenvs;
107       break;
108
109     case _CS_V6_WIDTH_RESTRICTED_ENVS:
110       /* We have to return a newline-separated list of named of
111          programming environements in which the widths of blksize_t,
112          cc_t, mode_t, nfds_t, pid_t, ptrdiff_t, size_t, speed_t,
113          ssize_t, suseconds_t, tcflag_t, useconds_t, wchar_t, and
114          wint_t types are no greater than the width of type long.
115
116          Currently this means all environment which the system allows.  */
117       string_len = 0;
118 #ifndef _POSIX_V6_ILP32_OFF32
119       if (__sysconf (_SC_V6_ILP32_OFF32) > 0)
120 #endif
121 #if !defined _POSIX_V6_ILP32_OFF32 || _POSIX_V6_ILP32_OFF32 > 0
122         {
123           memcpy (restenvs + string_len, "POSIX_V6_ILP32_OFF32",
124                   sizeof "POSIX_V6_ILP32_OFF32" - 1);
125           string_len += sizeof "POSIX_V6_ILP32_OFF32" - 1;
126         }
127 #endif
128 #ifndef _POSIX_V6_ILP32_OFFBIG
129       if (__sysconf (_SC_V6_ILP32_OFFBIG) > 0)
130 #endif
131 #if !defined _POSIX_V6_ILP32_OFFBIG || _POSIX_V6_ILP32_OFFBIG > 0
132         {
133           if (string_len)
134             restenvs[string_len++] = '\n';
135           memcpy (restenvs + string_len, "POSIX_V6_ILP32_OFFBIG",
136                   sizeof "POSIX_V6_ILP32_OFFBIG" - 1);
137           string_len += sizeof "POSIX_V6_ILP32_OFFBIG" - 1;
138         }
139 #endif
140 #ifndef _POSIX_V6_LP64_OFF64
141       if (__sysconf (_SC_V6_LP64_OFF64) > 0)
142 #endif
143 #if !defined _POSIX_V6_LP64_OFF64 || _POSIX_V6_LP64_OFF64 > 0
144         {
145           if (string_len)
146             restenvs[string_len++] = '\n';
147           memcpy (restenvs + string_len, "POSIX_V6_LP64_OFF64",
148                   sizeof "POSIX_V6_LP64_OFF64" - 1);
149           string_len += sizeof "POSIX_V6_LP64_OFF64" - 1;
150         }
151 #endif
152 #ifndef _POSIX_V6_LPBIG_OFFBIG
153       if (__sysconf (_SC_V6_LPBIG_OFFBIG) > 0)
154 #endif
155 #if !defined _POSIX_V6_LPBIG_OFFBIG || _POSIX_V6_LPBIG_OFFBIG > 0
156         {
157           if (string_len)
158             restenvs[string_len++] = '\n';
159           memcpy (restenvs + string_len, "POSIX_V6_LPBIG_OFFBIG",
160                   sizeof "POSIX_V6_LPBIG_OFFBIG" - 1);
161           string_len += sizeof "POSIX_V6_LPBIG_OFFBIG" - 1;
162         }
163 #endif
164       restenvs[string_len++] = '\0';
165       string = restenvs;
166       break;
167
168     case _CS_V5_WIDTH_RESTRICTED_ENVS:
169       /* We have to return a newline-separated list of named of
170          programming environements in which the widths of blksize_t,
171          cc_t, mode_t, nfds_t, pid_t, ptrdiff_t, size_t, speed_t,
172          ssize_t, suseconds_t, tcflag_t, useconds_t, wchar_t, and
173          wint_t types are no greater than the width of type long.
174
175          Currently this means all environment which the system allows.  */
176       string_len = 0;
177 #ifndef _XBS5_ILP32_OFF32
178       if (__sysconf (_SC_XBS5_ILP32_OFF32) > 0)
179 #endif
180 #if !defined _XBS5_ILP32_OFF32 || _XBS5_ILP32_OFF32 > 0
181         {
182           memcpy (restenvs + string_len, "XBS5_ILP32_OFF32",
183                   sizeof "XBS5_ILP32_OFF32" - 1);
184           string_len += sizeof "XBS5_ILP32_OFF32" - 1;
185         }
186 #endif
187 #ifndef _XBS5_ILP32_OFFBIG
188       if (__sysconf (_SC_XBS5_ILP32_OFFBIG) > 0)
189 #endif
190 #if !defined _XBS5_ILP32_OFFBIG || _XBS5_ILP32_OFFBIG > 0
191         {
192           if (string_len)
193             restenvs[string_len++] = '\n';
194           memcpy (restenvs + string_len, "XBS5_ILP32_OFFBIG",
195                   sizeof "XBS5_ILP32_OFFBIG" - 1);
196           string_len += sizeof "XBS5_ILP32_OFFBIG" - 1;
197         }
198 #endif
199 #ifndef _XBS5_LP64_OFF64
200       if (__sysconf (_SC_XBS5_LP64_OFF64) > 0)
201 #endif
202 #if !defined _XBS5_LP64_OFF64 || _XBS5_LP64_OFF64 > 0
203         {
204           if (string_len)
205             restenvs[string_len++] = '\n';
206           memcpy (restenvs + string_len, "XBS5_LP64_OFF64",
207                   sizeof "XBS5_LP64_OFF64" - 1);
208           string_len += sizeof "XBS5_LP64_OFF64" - 1;
209         }
210 #endif
211 #ifndef _XBS5_LPBIG_OFFBIG
212       if (__sysconf (_SC_XBS5_LPBIG_OFFBIG) > 0)
213 #endif
214 #if !defined _XBS5_LPBIG_OFFBIG || _XBS5_LPBIG_OFFBIG > 0
215         {
216           if (string_len)
217             restenvs[string_len++] = '\n';
218           memcpy (restenvs + string_len, "XBS5_LPBIG_OFFBIG",
219                   sizeof "XBS5_LPBIG_OFFBIG" - 1);
220           string_len += sizeof "XBS5_LPBIG_OFFBIG" - 1;
221         }
222 #endif
223       restenvs[string_len++] = '\0';
224       string = restenvs;
225       break;
226
227     case _CS_XBS5_ILP32_OFF32_CFLAGS:
228     case _CS_POSIX_V6_ILP32_OFF32_CFLAGS:
229     case _CS_POSIX_V7_ILP32_OFF32_CFLAGS:
230 #ifdef __ILP32_OFF32_CFLAGS
231 # if _POSIX_V7_ILP32_OFF32 == -1
232 #  error "__ILP32_OFF32_CFLAGS should not be defined"
233 # elif !defined _POSIX_V7_ILP32_OFF32
234       if (__sysconf (_SC_V7_ILP32_OFF32) < 0)
235         break;
236 # endif
237       string = __ILP32_OFF32_CFLAGS;
238       string_len = sizeof (__ILP32_OFF32_CFLAGS);
239 #endif
240       break;
241
242     case _CS_XBS5_ILP32_OFFBIG_CFLAGS:
243     case _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS:
244     case _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS:
245 #ifdef __ILP32_OFFBIG_CFLAGS
246 # if _POSIX_V7_ILP32_OFFBIG == -1
247 #  error "__ILP32_OFFBIG_CFLAGS should not be defined"
248 # elif !defined _POSIX_V7_ILP32_OFFBIG
249       if (__sysconf (_SC_V7_ILP32_OFFBIG) < 0)
250         break;
251 # endif
252       string = __ILP32_OFFBIG_CFLAGS;
253       string_len = sizeof (__ILP32_OFFBIG_CFLAGS);
254 #endif
255       break;
256
257     case _CS_XBS5_LP64_OFF64_CFLAGS:
258     case _CS_POSIX_V6_LP64_OFF64_CFLAGS:
259     case _CS_POSIX_V7_LP64_OFF64_CFLAGS:
260 #ifdef __LP64_OFF64_CFLAGS
261 # if _POSIX_V7_LP64_OFF64 == -1
262 #  error "__LP64_OFF64_CFLAGS should not be defined"
263 # elif !defined _POSIX_V7_LP64_OFF64
264       if (__sysconf (_SC_V7_LP64_OFF64) < 0)
265         break;
266 # endif
267       string = __LP64_OFF64_CFLAGS;
268       string_len = sizeof (__LP64_OFF64_CFLAGS);
269 #endif
270       break;
271
272     case _CS_XBS5_ILP32_OFF32_LDFLAGS:
273     case _CS_POSIX_V6_ILP32_OFF32_LDFLAGS:
274     case _CS_POSIX_V7_ILP32_OFF32_LDFLAGS:
275 #ifdef __ILP32_OFF32_LDFLAGS
276 # if _POSIX_V7_ILP32_OFF32 == -1
277 #  error "__ILP32_OFF32_LDFLAGS should not be defined"
278 # elif !defined _POSIX_V7_ILP32_OFF32
279       if (__sysconf (_SC_V7_ILP32_OFF32) < 0)
280         break;
281 # endif
282       string = __ILP32_OFF32_LDFLAGS;
283       string_len = sizeof (__ILP32_OFF32_LDFLAGS);
284 #endif
285       break;
286
287     case _CS_XBS5_ILP32_OFFBIG_LDFLAGS:
288     case _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS:
289     case _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS:
290 #ifdef __ILP32_OFFBIG_LDFLAGS
291 # if _POSIX_V7_ILP32_OFFBIG == -1
292 #  error "__ILP32_OFFBIG_LDFLAGS should not be defined"
293 # elif !defined _POSIX_V7_ILP32_OFFBIG
294       if (__sysconf (_SC_V7_ILP32_OFFBIG) < 0)
295         break;
296 # endif
297       string = __ILP32_OFFBIG_LDFLAGS;
298       string_len = sizeof (__ILP32_OFFBIG_LDFLAGS);
299 #endif
300       break;
301
302     case _CS_XBS5_LP64_OFF64_LDFLAGS:
303     case _CS_POSIX_V6_LP64_OFF64_LDFLAGS:
304     case _CS_POSIX_V7_LP64_OFF64_LDFLAGS:
305 #ifdef __LP64_OFF64_LDFLAGS
306 # if _POSIX_V7_LP64_OFF64 == -1
307 #  error "__LP64_OFF64_LDFLAGS should not be defined"
308 # elif !defined _POSIX_V7_LP64_OFF64
309       if (__sysconf (_SC_V7_LP64_OFF64) < 0)
310         break;
311 # endif
312       string = __LP64_OFF64_LDFLAGS;
313       string_len = sizeof (__LP64_OFF64_LDFLAGS);
314 #endif
315       break;
316
317     case _CS_LFS_CFLAGS:
318     case _CS_LFS_LINTFLAGS:
319 #if _POSIX_V6_ILP32_OFF32 == 1 && _POSIX_V6_ILP32_OFFBIG == 1
320 # define __LFS_CFLAGS "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
321       /* Signal that we want the new ABI.  */
322       string = __LFS_CFLAGS;
323       string_len = sizeof (__LFS_CFLAGS);
324 #endif
325       break;
326
327     case _CS_LFS_LDFLAGS:
328     case _CS_LFS_LIBS:
329       /* No special libraries or linker flags needed.  */
330       break;
331
332     case _CS_LFS64_CFLAGS:
333     case _CS_LFS64_LINTFLAGS:
334 #define __LFS64_CFLAGS "-D_LARGEFILE64_SOURCE"
335       string = __LFS64_CFLAGS;
336       string_len = sizeof (__LFS64_CFLAGS);
337       break;
338
339     case _CS_LFS64_LDFLAGS:
340     case _CS_LFS64_LIBS:
341       /* No special libraries or linker flags needed.  */
342       break;
343
344     case _CS_XBS5_ILP32_OFF32_LIBS:
345     case _CS_XBS5_ILP32_OFF32_LINTFLAGS:
346     case _CS_XBS5_ILP32_OFFBIG_LIBS:
347     case _CS_XBS5_ILP32_OFFBIG_LINTFLAGS:
348     case _CS_XBS5_LP64_OFF64_LIBS:
349     case _CS_XBS5_LP64_OFF64_LINTFLAGS:
350     case _CS_XBS5_LPBIG_OFFBIG_CFLAGS:
351     case _CS_XBS5_LPBIG_OFFBIG_LDFLAGS:
352     case _CS_XBS5_LPBIG_OFFBIG_LIBS:
353     case _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS:
354
355     case _CS_POSIX_V6_ILP32_OFF32_LIBS:
356     case _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS:
357     case _CS_POSIX_V6_ILP32_OFFBIG_LIBS:
358     case _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS:
359     case _CS_POSIX_V6_LP64_OFF64_LIBS:
360     case _CS_POSIX_V6_LP64_OFF64_LINTFLAGS:
361     case _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS:
362     case _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS:
363     case _CS_POSIX_V6_LPBIG_OFFBIG_LIBS:
364     case _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS:
365
366     case _CS_POSIX_V7_ILP32_OFF32_LIBS:
367     case _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS:
368     case _CS_POSIX_V7_ILP32_OFFBIG_LIBS:
369     case _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS:
370     case _CS_POSIX_V7_LP64_OFF64_LIBS:
371     case _CS_POSIX_V7_LP64_OFF64_LINTFLAGS:
372     case _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS:
373     case _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS:
374     case _CS_POSIX_V7_LPBIG_OFFBIG_LIBS:
375     case _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS:
376       /* GNU libc does not require special actions to use LFS functions.  */
377       break;
378
379     case _CS_GNU_LIBC_VERSION:
380       string = "glibc " VERSION;
381       string_len = sizeof ("glibc " VERSION);
382       break;
383
384     case _CS_GNU_LIBPTHREAD_VERSION:
385 #ifdef LIBPTHREAD_VERSION
386       string = LIBPTHREAD_VERSION;
387       string_len = sizeof LIBPTHREAD_VERSION;
388       break;
389 #else
390       /* No thread library.  */
391       __set_errno (EINVAL);
392       return 0;
393 #endif
394
395     case _CS_V6_ENV:
396     case _CS_V7_ENV:
397       /* Maybe something else is needed in future.  */
398       string = "POSIXLY_CORRECT=1";
399       string_len = sizeof ("POSIXLY_CORRECT=1");
400       break;
401
402     default:
403       __set_errno (EINVAL);
404       return 0;
405     }
406
407   if (len > 0 && buf != NULL)
408     {
409       if (string_len <= len)
410         memcpy (buf, string, string_len);
411       else
412         {
413           memcpy (buf, string, len - 1);
414           buf[len - 1] = '\0';
415         }
416     }
417   return string_len;
418 }
419 libc_hidden_def (confstr)