fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / getsysstats.c
1 /* Determine various system internal values, Linux version.
2    Copyright (C) 1996-2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <alloca.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <mntent.h>
28 #include <paths.h>
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/sysinfo.h>
35
36 #include <atomic.h>
37 #include <not-cancel.h>
38
39
40 /* How we can determine the number of available processors depends on
41    the configuration.  There is currently (as of version 2.0.21) no
42    system call to determine the number.  It is planned for the 2.1.x
43    series to add this, though.
44
45    One possibility to implement it for systems using Linux 2.0 is to
46    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
47    each processor.
48
49    But not all systems have support for the /proc filesystem.  If it
50    is not available we simply return 1 since there is no way.  */
51
52 /* Other architectures use different formats for /proc/cpuinfo.  This
53    provides a hook for alternative parsers.  */
54 #ifndef GET_NPROCS_PARSER
55 # define GET_NPROCS_PARSER(FP, BUFFER, RESULT)                          \
56   do                                                                    \
57     {                                                                   \
58       (RESULT) = 0;                                                     \
59       /* Read all lines and count the lines starting with the string    \
60          "processor".  We don't have to fear extremely long lines since \
61          the kernel will not generate them.  8192 bytes are really      \
62          enough.  */                                                    \
63       while (fgets_unlocked (BUFFER, sizeof (BUFFER), FP) != NULL)      \
64         if (strncmp (BUFFER, "processor", 9) == 0)                      \
65           ++(RESULT);                                                   \
66     }                                                                   \
67   while (0)
68 #endif
69
70
71 int
72 __get_nprocs ()
73 {
74   /* XXX Here will come a test for the new system call.  */
75
76   char buffer[8192];
77   int result = 1;
78
79   /* The /proc/stat format is more uniform, use it by default.  */
80   FILE *fp = fopen ("/proc/stat", "rc");
81   if (fp != NULL)
82     {
83       /* No threads use this stream.  */
84       __fsetlocking (fp, FSETLOCKING_BYCALLER);
85
86       result = 0;
87       while (fgets_unlocked (buffer, sizeof (buffer), fp) != NULL)
88         if (strncmp (buffer, "cpu", 3) == 0 && isdigit (buffer[3]))
89           ++result;
90
91       fclose (fp);
92     }
93   else
94     {
95       fp = fopen ("/proc/cpuinfo", "rc");
96       if (fp != NULL)
97         {
98           /* No threads use this stream.  */
99           __fsetlocking (fp, FSETLOCKING_BYCALLER);
100           GET_NPROCS_PARSER (fp, buffer, result);
101           fclose (fp);
102         }
103     }
104
105   return result;
106 }
107 weak_alias (__get_nprocs, get_nprocs)
108
109
110 /* On some architectures it is possible to distinguish between configured
111    and active cpus.  */
112 int
113 __get_nprocs_conf ()
114 {
115   /* XXX Here will come a test for the new system call.  */
116
117   /* Try to use the sysfs filesystem.  It has actual information about
118      online processors.  */
119   DIR *dir = __opendir ("/sys/devices/system/cpu");
120   if (dir != NULL)
121     {
122       int count = 0;
123       struct dirent64 *d;
124
125       while ((d = __readdir64 (dir)) != NULL)
126         /* NB: the sysfs has d_type support.  */
127         if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0)
128           {
129             char *endp;
130             unsigned long int nr = strtoul (d->d_name + 3, &endp, 10);
131             if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0')
132               ++count;
133           }
134
135       __closedir (dir);
136
137       return count;
138     }
139
140   int result = 1;
141
142 #ifdef GET_NPROCS_CONF_PARSER
143   /* If we haven't found an appropriate entry return 1.  */
144   FILE *fp = fopen ("/proc/cpuinfo", "rc");
145   if (fp != NULL)
146     {
147       char buffer[8192];
148
149       /* No threads use this stream.  */
150       __fsetlocking (fp, FSETLOCKING_BYCALLER);
151       GET_NPROCS_CONF_PARSER (fp, buffer, result);
152       fclose (fp);
153     }
154 #else
155   result = __get_nprocs ();
156 #endif
157
158   return result;
159 }
160 weak_alias (__get_nprocs_conf, get_nprocs_conf)
161
162 /* General function to get information about memory status from proc
163    filesystem.  */
164 static long int
165 internal_function
166 phys_pages_info (const char *format)
167 {
168   char buffer[8192];
169   long int result = -1;
170
171   /* If we haven't found an appropriate entry return 1.  */
172   FILE *fp = fopen ("/proc/meminfo", "rc");
173   if (fp != NULL)
174     {
175       /* No threads use this stream.  */
176       __fsetlocking (fp, FSETLOCKING_BYCALLER);
177
178       result = 0;
179       /* Read all lines and count the lines starting with the
180          string "processor".  We don't have to fear extremely long
181          lines since the kernel will not generate them.  8192
182          bytes are really enough.  */
183       while (fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
184         if (sscanf (buffer, format, &result) == 1)
185           {
186             result /= (__getpagesize () / 1024);
187             break;
188           }
189
190       fclose (fp);
191     }
192
193   if (result == -1)
194     /* We cannot get the needed value: signal an error.  */
195     __set_errno (ENOSYS);
196
197   return result;
198 }
199
200
201 /* Return the number of pages of physical memory in the system.  There
202    is currently (as of version 2.0.21) no system call to determine the
203    number.  It is planned for the 2.1.x series to add this, though.
204
205    One possibility to implement it for systems using Linux 2.0 is to
206    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
207    each processor.
208
209    But not all systems have support for the /proc filesystem.  If it
210    is not available we return -1 as an error signal.  */
211 long int
212 __get_phys_pages ()
213 {
214   /* XXX Here will come a test for the new system call.  */
215
216   return phys_pages_info ("MemTotal: %ld kB");
217 }
218 weak_alias (__get_phys_pages, get_phys_pages)
219
220
221 /* Return the number of available pages of physical memory in the
222    system.  There is currently (as of version 2.0.21) no system call
223    to determine the number.  It is planned for the 2.1.x series to add
224    this, though.
225
226    One possibility to implement it for systems using Linux 2.0 is to
227    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
228    each processor.
229
230    But not all systems have support for the /proc filesystem.  If it
231    is not available we return -1 as an error signal.  */
232 long int
233 __get_avphys_pages ()
234 {
235   /* XXX Here will come a test for the new system call.  */
236
237   return phys_pages_info ("MemFree: %ld kB");
238 }
239 weak_alias (__get_avphys_pages, get_avphys_pages)