1 /**************************************************************************
2  *
3  * Copyright 2008-2010 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 
29 #include "os_misc.h"
30 #include "os_file.h"
31 #include "macros.h"
32 
33 #include <stdarg.h>
34 
35 
36 #if DETECT_OS_WINDOWS
37 
38 #ifndef WIN32_LEAN_AND_MEAN
39 #define WIN32_LEAN_AND_MEAN      // Exclude rarely-used stuff from Windows headers
40 #endif
41 #include <windows.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 
45 #else
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <inttypes.h>
51 
52 #endif
53 
54 
55 #if DETECT_OS_ANDROID
56 #  define LOG_TAG "MESA"
57 #  include <unistd.h>
58 #  include <log/log.h>
59 #  include <cutils/properties.h>
60 #elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD
61 #  include <unistd.h>
62 #elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD || DETECT_OS_DRAGONFLY
63 #  include <sys/resource.h>
64 #  include <sys/sysctl.h>
65 #elif DETECT_OS_APPLE || DETECT_OS_BSD
66 #  include <sys/sysctl.h>
67 #elif DETECT_OS_HAIKU
68 #  include <kernel/OS.h>
69 #elif DETECT_OS_WINDOWS
70 #  include <windows.h>
71 #else
72 #error unexpected platform in os_sysinfo.c
73 #endif
74 
75 
76 void
os_log_message(const char * message)77 os_log_message(const char *message)
78 {
79    /* If the GALLIUM_LOG_FILE environment variable is set to a valid filename,
80     * write all messages to that file.
81     */
82    static FILE *fout = NULL;
83 
84    if (!fout) {
85 #ifdef DEBUG
86       /* one-time init */
87       const char *filename = os_get_option("GALLIUM_LOG_FILE");
88       if (filename) {
89          const char *mode = "w";
90          if (filename[0] == '+') {
91             /* If the filename is prefixed with '+' then open the file for
92              * appending instead of normal writing.
93              */
94             mode = "a";
95             filename++; /* skip the '+' */
96          }
97          fout = fopen(filename, mode);
98       }
99 #endif
100       if (!fout)
101          fout = stderr;
102    }
103 
104 #if DETECT_OS_WINDOWS
105    OutputDebugStringA(message);
106    if(GetConsoleWindow() && !IsDebuggerPresent()) {
107       fflush(stdout);
108       fputs(message, fout);
109       fflush(fout);
110    }
111    else if (fout != stderr) {
112       fputs(message, fout);
113       fflush(fout);
114    }
115 #else /* !DETECT_OS_WINDOWS */
116    fflush(stdout);
117    fputs(message, fout);
118    fflush(fout);
119 #  if DETECT_OS_ANDROID
120    LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", message);
121 #  endif
122 #endif
123 }
124 
125 #if DETECT_OS_ANDROID
126 #  include <ctype.h>
127 #  include "hash_table.h"
128 #  include "ralloc.h"
129 #  include "simple_mtx.h"
130 
131 static struct hash_table *options_tbl;
132 
133 static void
options_tbl_fini(void)134 options_tbl_fini(void)
135 {
136    _mesa_hash_table_destroy(options_tbl, NULL);
137 }
138 
139 /**
140  * Get an option value from android's property system, as a fallback to
141  * getenv() (which is generally less useful on android due to processes
142  * typically being forked from the zygote.
143  *
144  * The option name used for getenv is translated into a property name
145  * by:
146  *
147  *  1) convert to lowercase
148  *  2) replace '_' with '.'
149  *  3) if necessary, prepend "mesa."
150  *
151  * For example:
152  *  - MESA_EXTENSION_OVERRIDE -> mesa.extension.override
153  *  - GALLIUM_HUD -> mesa.gallium.hud
154  *
155  * Note that we use a hashtable for two purposes:
156  *  1) Avoid re-translating the option name on subsequent lookups
157  *  2) Avoid leaking memory.  Because property_get() returns the
158  *     property value into a user allocated buffer, we cannot return
159  *     that directly to the caller, so we need to strdup().  With the
160  *     hashtable, subsquent lookups can return the existing string.
161  */
162 static const char *
os_get_android_option(const char * name)163 os_get_android_option(const char *name)
164 {
165    if (!options_tbl) {
166       options_tbl = _mesa_hash_table_create(NULL, _mesa_hash_string,
167             _mesa_key_string_equal);
168       atexit(options_tbl_fini);
169    }
170 
171    struct hash_entry *entry = _mesa_hash_table_search(options_tbl, name);
172    if (entry) {
173       return entry->data;
174    }
175 
176    char value[PROPERTY_VALUE_MAX];
177    char key[PROPERTY_KEY_MAX];
178    char *p = key, *end = key + PROPERTY_KEY_MAX;
179    /* add "mesa." prefix if necessary: */
180    if (strstr(name, "MESA_") != name)
181       p += strlcpy(p, "mesa.", end - p);
182    p += strlcpy(p, name, end - p);
183    for (int i = 0; key[i]; i++) {
184       if (key[i] == '_') {
185          key[i] = '.';
186       } else {
187          key[i] = tolower(key[i]);
188       }
189    }
190 
191    const char *opt = NULL;
192    int len = property_get(key, value, NULL);
193    if (len > 1) {
194       opt = ralloc_strdup(options_tbl, value);
195    }
196 
197    _mesa_hash_table_insert(options_tbl, name, (void *)opt);
198 
199    return opt;
200 }
201 #endif
202 
203 
204 #if !defined(EMBEDDED_DEVICE)
205 const char *
os_get_option(const char * name)206 os_get_option(const char *name)
207 {
208    const char *opt = getenv(name);
209 #if DETECT_OS_ANDROID
210    if (!opt) {
211       opt = os_get_android_option(name);
212    }
213 #endif
214    return opt;
215 }
216 #endif /* !EMBEDDED_DEVICE */
217 
218 /**
219  * Return the size of the total physical memory.
220  * \param size returns the size of the total physical memory
221  * \return true for success, or false on failure
222  */
223 bool
os_get_total_physical_memory(uint64_t * size)224 os_get_total_physical_memory(uint64_t *size)
225 {
226 #if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD
227    const long phys_pages = sysconf(_SC_PHYS_PAGES);
228    const long page_size = sysconf(_SC_PAGE_SIZE);
229 
230    if (phys_pages <= 0 || page_size <= 0)
231       return false;
232 
233    *size = (uint64_t)phys_pages * (uint64_t)page_size;
234    return true;
235 #elif DETECT_OS_APPLE || DETECT_OS_BSD
236    size_t len = sizeof(*size);
237    int mib[2];
238 
239    mib[0] = CTL_HW;
240 #if DETECT_OS_APPLE
241    mib[1] = HW_MEMSIZE;
242 #elif DETECT_OS_NETBSD || DETECT_OS_OPENBSD
243    mib[1] = HW_PHYSMEM64;
244 #elif DETECT_OS_FREEBSD
245    mib[1] = HW_REALMEM;
246 #elif DETECT_OS_DRAGONFLY
247    mib[1] = HW_PHYSMEM;
248 #else
249 #error Unsupported *BSD
250 #endif
251 
252    return (sysctl(mib, 2, size, &len, NULL, 0) == 0);
253 #elif DETECT_OS_HAIKU
254    system_info info;
255    status_t ret;
256 
257    ret = get_system_info(&info);
258    if (ret != B_OK || info.max_pages <= 0)
259       return false;
260 
261    *size = (uint64_t)info.max_pages * (uint64_t)B_PAGE_SIZE;
262    return true;
263 #elif DETECT_OS_WINDOWS
264    MEMORYSTATUSEX status;
265    BOOL ret;
266 
267    status.dwLength = sizeof(status);
268    ret = GlobalMemoryStatusEx(&status);
269    *size = status.ullTotalPhys;
270    return (ret == TRUE);
271 #else
272 #error unexpected platform in os_sysinfo.c
273    return false;
274 #endif
275 }
276 
277 bool
os_get_available_system_memory(uint64_t * size)278 os_get_available_system_memory(uint64_t *size)
279 {
280 #if DETECT_OS_LINUX
281    char *meminfo = os_read_file("/proc/meminfo", NULL);
282    if (!meminfo)
283       return false;
284 
285    char *str = strstr(meminfo, "MemAvailable:");
286    if (!str) {
287       free(meminfo);
288       return false;
289    }
290 
291    uint64_t kb_mem_available;
292    if (sscanf(str, "MemAvailable: %" PRIu64, &kb_mem_available) == 1) {
293       free(meminfo);
294       *size = kb_mem_available << 10;
295       return true;
296    }
297 
298    free(meminfo);
299    return false;
300 #elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD || DETECT_OS_DRAGONFLY
301    struct rlimit rl;
302 #if DETECT_OS_OPENBSD
303    int mib[] = { CTL_HW, HW_USERMEM64 };
304 #elif DETECT_OS_FREEBSD || DETECT_OS_DRAGONFLY
305    int mib[] = { CTL_HW, HW_USERMEM };
306 #endif
307    int64_t mem_available;
308    size_t len = sizeof(mem_available);
309 
310    /* physmem - wired */
311    if (sysctl(mib, 2, &mem_available, &len, NULL, 0) == -1)
312       return false;
313 
314    /* static login.conf limit */
315    if (getrlimit(RLIMIT_DATA, &rl) == -1)
316       return false;
317 
318    *size = MIN2(mem_available, rl.rlim_cur);
319    return true;
320 #else
321    return false;
322 #endif
323 }
324 
325 /**
326  * Return the size of a page
327  * \param size returns the size of a page
328  * \return true for success, or false on failure
329  */
330 bool
os_get_page_size(uint64_t * size)331 os_get_page_size(uint64_t *size)
332 {
333 #if DETECT_OS_UNIX && !DETECT_OS_APPLE && !DETECT_OS_HAIKU
334    const long page_size = sysconf(_SC_PAGE_SIZE);
335 
336    if (page_size <= 0)
337       return false;
338 
339    *size = (uint64_t)page_size;
340    return true;
341 #elif DETECT_OS_HAIKU
342    *size = (uint64_t)B_PAGE_SIZE;
343    return true;
344 #elif DETECT_OS_WINDOWS
345    SYSTEM_INFO SysInfo;
346 
347    GetSystemInfo(&SysInfo);
348    *size = SysInfo.dwPageSize;
349    return true;
350 #elif DETECT_OS_APPLE
351    size_t len = sizeof(*size);
352    int mib[2];
353 
354    mib[0] = CTL_HW;
355    mib[1] = HW_PAGESIZE;
356    return (sysctl(mib, 2, size, &len, NULL, 0) == 0);
357 #else
358 #error unexpected platform in os_sysinfo.c
359    return false;
360 #endif
361 }
362