1 /* Get file-specific information about a file.  Linux version.
2    Copyright (C) 2003-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sysdep.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <sys/resource.h>
27 #include <sys/param.h>
28 #include <not-cancel.h>
29 #include <ldsodefs.h>
30 #include <sysconf-sigstksz.h>
31 
32 /* Legacy value of ARG_MAX.  The macro is now not defined since the
33    actual value varies based on the stack size.  */
34 #define legacy_ARG_MAX 131072
35 
36 /* Newer kernels (4.13) limit the maximum command line arguments lengths to
37    6MiB.  */
38 #define maximum_ARG_MAX (6 * 1024 * 1024)
39 
40 static long int posix_sysconf (int name);
41 
42 
43 /* Get the value of the system variable NAME.  */
44 long int
__sysconf(int name)45 __sysconf (int name)
46 {
47   const char *procfname = NULL;
48 
49   switch (name)
50     {
51     case _SC_MONOTONIC_CLOCK:
52     case _SC_CPUTIME:
53     case _SC_THREAD_CPUTIME:
54       return _POSIX_VERSION;
55 
56     case _SC_ARG_MAX:
57       {
58         struct rlimit rlimit;
59         /* Use getrlimit to get the stack limit.  */
60         if (__getrlimit (RLIMIT_STACK, &rlimit) == 0)
61 	  {
62 	    const long int limit = MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4);
63 	    return MIN (limit, maximum_ARG_MAX);
64 	  }
65 
66         return legacy_ARG_MAX;
67       }
68 
69     case _SC_NGROUPS_MAX:
70       /* Try to read the information from the /proc/sys/kernel/ngroups_max
71 	 file.  */
72       procfname = "/proc/sys/kernel/ngroups_max";
73       break;
74 
75     case _SC_SIGQUEUE_MAX:
76       {
77         struct rlimit rlimit;
78         if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0)
79 	  return rlimit.rlim_cur;
80 
81         /* The /proc/sys/kernel/rtsig-max file contains the answer.  */
82         procfname = "/proc/sys/kernel/rtsig-max";
83       }
84       break;
85 
86     case _SC_MINSIGSTKSZ:
87       assert (GLRO(dl_minsigstacksize) != 0);
88       return GLRO(dl_minsigstacksize);
89 
90     case _SC_SIGSTKSZ:
91       return sysconf_sigstksz ();
92 
93     default:
94       break;
95     }
96 
97   if (procfname != NULL)
98     {
99       int fd = __open_nocancel (procfname, O_RDONLY | O_CLOEXEC);
100       if (fd != -1)
101 	{
102 	  /* This is more than enough, the file contains a single integer.  */
103 	  char buf[32];
104 	  ssize_t n;
105 	  n = TEMP_FAILURE_RETRY (__read_nocancel (fd, buf, sizeof (buf) - 1));
106 	  __close_nocancel_nostatus (fd);
107 
108 	  if (n > 0)
109 	    {
110 	      /* Terminate the string.  */
111 	      buf[n] = '\0';
112 
113 	      char *endp;
114 	      long int res = strtol (buf, &endp, 10);
115 	      if (endp != buf && (*endp == '\0' || *endp == '\n'))
116 		return res;
117 	    }
118 	}
119     }
120 
121   return posix_sysconf (name);
122 }
123 
124 /* Now the POSIX version.  */
125 #undef __sysconf
126 #define __sysconf static posix_sysconf
127 #include <sysdeps/posix/sysconf.c>
128