1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #include <unistd.h> 29 #include <sys/sysconf.h> 30 #include <limits.h> 31 #include <bionic_tls.h> 32 #include <asm/page.h> 33 #include <stdio.h> /* for FOPEN_MAX */ 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <ctype.h> 38 39 /* seems to be the default on Linux, per the GLibc sources and my own digging */ 40 41 #define SYSTEM_CLK_TCK 100 42 #define SYSTEM_IOV_MAX 1024 43 #define SYSTEM_DELAYTIMER_MAX 2147483647 44 #define SYSTEM_MQ_OPEN_MAX 8 45 #define SYSTEM_MQ_PRIO_MAX 32768 46 #define SYSTEM_SEM_NSEMS_MAX 256 47 #define SYSTEM_SEM_VALUE_MAX 0x3fffffff /* see bionic/semaphore.c */ 48 #define SYSTEM_SIGQUEUE_MAX 32 49 #define SYSTEM_TIMER_MAX 32 50 #define SYSTEM_LOGIN_NAME_MAX 256 51 #define SYSTEM_TTY_NAME_MAX 32 52 53 /* the following depends on our implementation */ 54 #define SYSTEM_ATEXIT_MAX 65536 /* our implementation is unlimited */ 55 #define SYSTEM_THREAD_KEYS_MAX BIONIC_TLS_SLOTS 56 #define SYSTEM_THREAD_STACK_MIN 32768 /* lower values may be possible, but be conservative */ 57 #define SYSTEM_THREAD_THREADS_MAX 2048 /* really unlimited */ 58 59 #define SYSTEM_2_C_BIND _POSIX_VERSION /* Posix C binding version */ 60 #define SYSTEM_2_C_VER _POSIX2_C_VERSION 61 #define SYSTEM_2_C_DEV -1 /* Posix C development tools unsupported on the device */ 62 #define SYSTEM_2_FORT_DEV -1 /* Fortran development unsupported */ 63 #define SYSTEM_2_FORT_RUN -1 /* Fortran runtime unsupported */ 64 #define SYSTEM_2_SW_DEV -1 /* posix software dev utilities unsupported */ 65 #define SYSTEM_2_LOCALEDEF -1 /* localdef() unimplemented */ 66 #define SYSTEM_2_UPE -1 /* No UPE for you ! (User Portability Utilities) */ 67 #define SYSTEM_2_VERSION -1 /* No posix command-line tools */ 68 69 static int __get_nproc_conf(void); 70 static int __get_nproc_onln(void); 71 static int __get_phys_pages(void); 72 static int __get_avphys_pages(void); 73 74 int 75 sysconf( int name ) 76 { 77 switch (name) { 78 #ifdef _POSIX_ARG_MAX 79 case _SC_ARG_MAX: return _POSIX_ARG_MAX; 80 #endif 81 #ifdef _POSIX2_BC_BASE_MAX 82 case _SC_BC_BASE_MAX: return _POSIX2_BC_BASE_MAX; 83 #endif 84 #ifdef _POSIX2_BC_DIM_MAX 85 case _SC_BC_DIM_MAX: return _POSIX2_BC_DIM_MAX; 86 #endif 87 #ifdef _POSIX2_BC_SCALE_MAX 88 case _SC_BC_SCALE_MAX: return _POSIX2_BC_SCALE_MAX; 89 #endif 90 #ifdef _POSIX2_BC_STRING_MAX 91 case _SC_BC_STRING_MAX: return _POSIX2_BC_STRING_MAX; 92 #endif 93 case _SC_CHILD_MAX: return CHILD_MAX; 94 case _SC_CLK_TCK: return SYSTEM_CLK_TCK; 95 #ifdef _POSIX2_COLL_WEIGHTS_MASK 96 case _SC_COLL_WEIGHTS_MAX: return _POSIX2_COLL_WEIGHTS_MASK; 97 #endif 98 #ifdef _POSIX2_EXPR_NEST_MAX 99 case _SC_EXPR_NEST_MAX: return _POSIX2_EXPR_NEST_MAX; 100 #endif 101 #ifdef _POSIX2_LINE_MAX 102 case _SC_LINE_MAX: return _POSIX2_LINE_MAX; 103 #endif 104 case _SC_NGROUPS_MAX: return NGROUPS_MAX; 105 case _SC_OPEN_MAX: return OPEN_MAX; 106 //case _SC_PASS_MAX: return PASS_MAX; 107 case _SC_2_C_BIND: return SYSTEM_2_C_BIND; 108 case _SC_2_C_DEV: return SYSTEM_2_C_DEV; 109 case _SC_2_C_VERSION: return SYSTEM_2_C_VER; 110 //case _SC_2_CHAR_TERM: return ; 111 case _SC_2_FORT_DEV: return SYSTEM_2_FORT_DEV; 112 case _SC_2_FORT_RUN: return SYSTEM_2_FORT_RUN; 113 case _SC_2_LOCALEDEF: return SYSTEM_2_LOCALEDEF; 114 case _SC_2_SW_DEV: return SYSTEM_2_SW_DEV; 115 case _SC_2_UPE: return SYSTEM_2_UPE; 116 case _SC_2_VERSION: return SYSTEM_2_VERSION; 117 #ifdef _POSIX_JOB_CONTROL 118 case _SC_JOB_CONTROL: return _POSIX_JOB_CONTROL; 119 #endif 120 #ifdef _POSIX_SAVED_IDS 121 case _SC_SAVED_IDS: return _POSIX_SAVED_IDS; 122 #endif 123 #ifdef _POSIX_VERSION 124 case _SC_VERSION: return _POSIX_VERSION; 125 #endif 126 //case _SC_RE_DUP_<AX: return ; 127 case _SC_STREAM_MAX: return FOPEN_MAX; 128 //case _SC_TZNAME_MAX: return ; 129 #if _XOPEN_CRYPT 130 case _SC_XOPEN_CRYPT: return _XOPEN_CRYPT; 131 #endif 132 #ifdef _XOPEN_ENH_I18N 133 case _SC_XOPEN_ENH_I18N: return _XOPEN_ENH_I18N; 134 #endif 135 #ifdef _XOPEN_SHM 136 case _SC_XOPEN_SHM: return _XOPEN_SHM; 137 #endif 138 #ifdef _XOPEN_VERSION 139 case _SC_XOPEN_VERSION: return _XOPEN_VERSION; 140 #endif 141 #ifdef _XOPEN_XCU_VERSION 142 case _SC_XOPEN_XCU_VERSION: return _XOPEN_XCU_VERSION; 143 #endif 144 #ifdef _XOPEN_REALTIME 145 case _SC_XOPEN_REALTIME: return _XOPEN_REALTIME; 146 #endif 147 #ifdef _XOPEN_REALTIME_THREADS 148 case _SC_XOPEN_REALTIME_THREADS: return _XOPEN_REALTIME_THREADS; 149 #endif 150 #ifdef _XOPEN_LEGACY 151 case _SC_XOPEN_LEGACY: return _XOPEN_LEGACY; 152 #endif 153 case _SC_ATEXIT_MAX: return SYSTEM_ATEXIT_MAX; 154 case _SC_IOV_MAX: return SYSTEM_IOV_MAX; 155 case _SC_PAGESIZE: return PAGE_SIZE; 156 case _SC_PAGE_SIZE: return PAGE_SIZE; 157 #ifdef _XOPEN_UNIX 158 case _SC_XOPEN_UNIX: return _XOPEN_UNIX; 159 #endif 160 161 // XXX: TODO: XBS5 nonsense 162 163 #ifdef AIO_LISTIO_MAX 164 case _SC_AIO_LISTIO_MAX: return AIO_LISTIO_MAX; 165 #endif 166 #ifdef AIO_MAX 167 case _SC_AIO_MAX: return AIO_MAX; 168 #endif 169 #ifdef AIO_PRIO_DELTA_MAX 170 case _SC_AIO_PRIO_DELTA_MAX: return AIO_PRIO_DELTA_MAX; 171 #endif 172 case _SC_DELAYTIMER_MAX: return SYSTEM_DELAYTIMER_MAX; 173 case _SC_MQ_OPEN_MAX: return SYSTEM_MQ_OPEN_MAX; 174 case _SC_MQ_PRIO_MAX: return SYSTEM_MQ_PRIO_MAX; 175 case _SC_RTSIG_MAX: return RTSIG_MAX; 176 case _SC_SEM_NSEMS_MAX: return SYSTEM_SEM_NSEMS_MAX; 177 case _SC_SEM_VALUE_MAX: return SYSTEM_SEM_VALUE_MAX; 178 case _SC_SIGQUEUE_MAX: return SYSTEM_SIGQUEUE_MAX; 179 case _SC_TIMER_MAX: return SYSTEM_TIMER_MAX; 180 #ifdef _POSIX_ASYNCHRONOUS_IO 181 case _SC_ASYNCHRONOUS_IO: return _POSIX_ASYNCHRONOUS_IO; 182 #endif 183 #ifdef _POSIX_FSYNC 184 case _SC_FSYNC: return _POSIX_FSYNC; 185 #endif 186 #ifdef _POSIX_MAPPED_FILES 187 case _SC_MAPPED_FILES: return _POSIX_MAPPED_FILES; 188 #endif 189 #ifdef _POSIX_MEMLOCK 190 case _SC_MEMLOCK: return _POSIX_MEMLOCK; 191 #endif 192 #ifdef _POSIX_MEMLOCK_RANGE 193 case _SC_MEMLOCK_RANGE: return _POSIX_MEMLOCK_RANGE 194 #endif 195 #ifdef _POSIX_MEMORY_PROTECTION 196 case _SC_MEMORY_PROTECTION: return _POSIX_MEMORY_PROTECTION; 197 #endif 198 #ifdef _POSIX_MESSAGE_PASSING 199 case _SC_MESSAGE_PASSING: return _POSIX_MESSAGE_PASSING; 200 #endif 201 #ifdef _POSIX_PRIORITIZED_IO 202 case _SC_PRIORITIZED_IO: return _POSIX_PRIORITIZED_IO; 203 #endif 204 #ifdef _POSIX_PRIORITY_SCHEDULING 205 case _SC_PRIORITY_SCHEDULING: return _POSIX_PRIORITY_SCHEDULING; 206 #endif 207 #ifdef _POSIX_REALTIME_SIGNALS 208 case _SC_REALTIME_SIGNALS: return _POSIX_REALTIME_SIGNALS; 209 #endif 210 #ifdef _POSIX_SEMAPHORES 211 case _SC_SEMAPHORES: return _POSIX_SEMAPHORES; 212 #endif 213 #ifdef _POSIX_SHARED_MEMORY_OBJECTS 214 case _SC_SHARED_MEMORY_OBJECTS: return _POSIX_SHARED_MEMORY_OBJECTS; 215 #endif 216 #ifdef _POSIX_SYNCHRONIZED_IO 217 case _SC_SYNCHRONIZED_IO: return _POSIX_SYNCHRONIZED_IO; 218 #endif 219 #ifdef _POSIX_TIMERS 220 case _SC_TIMERS: return _POSIX_TIMERS; 221 #endif 222 223 // GETGR_R_SIZE_MAX ? 224 // GETPW_R_SIZE_MAX ? 225 226 case _SC_LOGIN_NAME_MAX: return SYSTEM_LOGIN_NAME_MAX; 227 #ifdef _POSIX_THREAD_DESTRUCTOR_ITERATIONS 228 case _SC_THREAD_DESTRUCTOR_ITERATIONS: return _POSIX_THREAD_DESTRUCTOR_ITERATIONS; 229 #endif 230 case _SC_THREAD_KEYS_MAX: return SYSTEM_THREAD_KEYS_MAX; 231 case _SC_THREAD_STACK_MIN: return SYSTEM_THREAD_STACK_MIN; 232 case _SC_THREAD_THREADS_MAX: return SYSTEM_THREAD_THREADS_MAX; 233 case _SC_TTY_NAME_MAX: return SYSTEM_TTY_NAME_MAX; 234 #ifdef _POSIX_THREADS 235 case _SC_THREADS: return _POSIX_THREADS; 236 #endif 237 #ifdef _POSIX_THREAD_ATTR_STACKADDR 238 case _SC_THREAD_ATTR_STACKADDR: return _POSIX_THREAD_ATTR_STACKADDR; 239 #endif 240 #ifdef _POSIX_THREAD_ATTR_STACKSIZE 241 case _SC_THREAD_ATTR_STACKSIZE: return _POSIX_THREAD_ATTR_STACKSIZE; 242 #endif 243 #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING 244 case _SC_THREAD_PRIORITY_SCHEDULING: return _POSIX_THREAD_PRIORITY_SCHEDULING; 245 #endif 246 #ifdef _POSIX_THREAD_PRIO_INHERIT 247 case _SC_THREAD_PRIO_INHERIT: return _POSIX_THREAD_PRIO_INHERIT; 248 #endif 249 #ifdef _POSIX_THREAD_PRIO_PROTECT 250 case _SC_THREAD_PRIO_PROTECT: return _POSIX_THREAD_PRIO_PROTECT; 251 #endif 252 #ifdef _POSIX_THREAD_SAFE_FUNCTIONS 253 case _SC_THREAD_SAFE_FUNCTIONS: return _POSIX_THREAD_SAFE_FUNCTIONS 254 #endif 255 256 257 case _SC_NPROCESSORS_CONF: return __get_nproc_conf(); 258 case _SC_NPROCESSORS_ONLN: return __get_nproc_onln(); 259 case _SC_PHYS_PAGES: return __get_phys_pages(); 260 case _SC_AVPHYS_PAGES: return __get_avphys_pages(); 261 262 default: 263 /* Posix says EINVAL is the only error that shall be returned, 264 * but GLibc uses ENOSYS */ 265 errno = ENOSYS; 266 return -1; 267 } 268 } 269 270 271 typedef struct { 272 int rpos; 273 int len; 274 int overflow; 275 int fd; 276 int in_len; 277 int in_pos; 278 char buff[128]; 279 char input[128]; 280 } LineParser; 281 282 static int 283 line_parser_init( LineParser* p, const char* path ) 284 { 285 p->rpos = 0; 286 p->len = (int)sizeof(p->buff); 287 p->overflow = 0; 288 289 p->in_len = 0; 290 p->in_pos = 0; 291 p->fd = open( path, O_RDONLY ); 292 293 return p->fd; 294 } 295 296 297 static int 298 line_parser_addc( LineParser* p, int c ) 299 { 300 if (p->overflow) { 301 p->overflow = (c == '\n'); 302 return 0; 303 } 304 if (p->rpos >= p->len) { 305 p->overflow = 1; 306 return 0; 307 } 308 if (c == '\n') { 309 p->buff[p->rpos] = 0; 310 p->rpos = 0; 311 return 1; 312 } 313 p->buff[p->rpos++] = (char) c; 314 return 0; 315 } 316 317 static int 318 line_parser_getc( LineParser* p ) 319 { 320 if (p->in_pos >= p->in_len) { 321 int ret; 322 323 p->in_len = p->in_pos = 0; 324 do { 325 ret = read(p->fd, p->input, sizeof(p->input)); 326 } while (ret < 0 && errno == EINTR); 327 328 if (ret <= 0) 329 return -1; 330 331 p->in_len = ret; 332 } 333 return p->input[ p->in_pos++ ]; 334 } 335 336 static const char* 337 line_parser_gets( LineParser* p ) 338 { 339 for (;;) { 340 for (;;) { 341 int c = line_parser_getc(p); 342 343 if (c < 0) { 344 close(p->fd); 345 p->fd = -1; 346 return NULL; 347 } 348 if (line_parser_addc(p, c)) 349 return p->buff; 350 } 351 } 352 } 353 354 static void 355 line_parser_done( LineParser* p ) 356 { 357 if (p->fd >= 0) { 358 close(p->fd); 359 p->fd = -1; 360 } 361 } 362 363 static int 364 __get_nproc_conf(void) 365 { 366 LineParser parser[1]; 367 const char* p; 368 int count = 0; 369 370 if (line_parser_init(parser, "/proc/cpuinfo") < 0) 371 return 1; 372 373 while ((p = line_parser_gets(parser))) { 374 if ( !memcmp(p, "processor", 9) ) 375 count += 1; 376 } 377 return (count < 1) ? 1 : count; 378 } 379 380 381 static int 382 __get_nproc_onln(void) 383 { 384 LineParser parser[1]; 385 const char* p; 386 int count = 0; 387 388 if (line_parser_init(parser, "/proc/stat") < 0) 389 return 1; 390 391 while ((p = line_parser_gets(parser))) { 392 if ( !memcmp(p, "cpu", 3) && isdigit(p[3]) ) 393 count += 1; 394 } 395 return (count < 1) ? 1 : count; 396 } 397 398 static int 399 __get_phys_pages(void) 400 { 401 LineParser parser[1]; 402 const char* p; 403 404 if (line_parser_init(parser, "/proc/meminfo") < 0) 405 return -2; /* what ? */ 406 407 while ((p = line_parser_gets(parser))) { 408 long total; 409 if ( sscanf(p, "MemTotal: %ld kB", &total) == 1 ) { 410 line_parser_done(parser); 411 return (int) (total / (PAGE_SIZE/1024)); 412 } 413 } 414 return -3; 415 } 416 417 static int 418 __get_avphys_pages(void) 419 { 420 LineParser parser[1]; 421 const char* p; 422 423 if (line_parser_init(parser, "/proc/meminfo") < 0) 424 return -1; /* what ? */ 425 426 while ((p = line_parser_gets(parser))) { 427 long total; 428 if ( sscanf(p, "MemFree: %ld kB", &total) == 1 ) { 429 line_parser_done(parser); 430 return (int) (total / (PAGE_SIZE/1024)); 431 } 432 } 433 return -1; 434 } 435