2 * sysinfo.c : information about the running system
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
27 #define WIN32_LEAN_AND_MEAN
28 #define PSAPI_VERSION 1
34 #define APR_WANT_STRFUNC
38 #include <apr_pools.h>
39 #include <apr_file_info.h>
40 #include <apr_signal.h>
41 #include <apr_strings.h>
42 #include <apr_thread_proc.h>
43 #include <apr_version.h>
44 #include <apu_version.h>
46 #include "svn_pools.h"
47 #include "svn_ctype.h"
48 #include "svn_dirent_uri.h"
49 #include "svn_error.h"
51 #include "svn_string.h"
53 #include "svn_version.h"
55 #include "private/svn_sqlite.h"
58 #include "svn_private_config.h"
60 #if HAVE_SYS_UTSNAME_H
61 #include <sys/utsname.h>
64 #ifdef SVN_HAVE_MACOS_PLIST
65 #include <CoreFoundation/CoreFoundation.h>
68 #ifdef SVN_HAVE_MACHO_ITERATE
69 #include <mach-o/dyld.h>
70 #include <mach-o/loader.h>
74 static const char *canonical_host_from_uname(apr_pool_t *pool);
75 # ifndef SVN_HAVE_MACOS_PLIST
76 static const char *release_name_from_uname(apr_pool_t *pool);
81 static const char *win32_canonical_host(apr_pool_t *pool);
82 static const char *win32_release_name(apr_pool_t *pool);
83 static const apr_array_header_t *win32_shared_libs(apr_pool_t *pool);
86 #ifdef SVN_HAVE_MACOS_PLIST
87 static const char *macos_release_name(apr_pool_t *pool);
90 #ifdef SVN_HAVE_MACHO_ITERATE
91 static const apr_array_header_t *macos_shared_libs(apr_pool_t *pool);
96 static const char *linux_release_name(apr_pool_t *pool);
100 svn_sysinfo__canonical_host(apr_pool_t *pool)
103 return win32_canonical_host(pool);
105 return canonical_host_from_uname(pool);
107 return "unknown-unknown-unknown";
113 svn_sysinfo__release_name(apr_pool_t *pool)
116 return win32_release_name(pool);
117 #elif defined(SVN_HAVE_MACOS_PLIST)
118 return macos_release_name(pool);
120 return linux_release_name(pool);
122 return release_name_from_uname(pool);
128 const apr_array_header_t *
129 svn_sysinfo__linked_libs(apr_pool_t *pool)
131 svn_version_ext_linked_lib_t *lib;
132 apr_array_header_t *array = apr_array_make(pool, 3, sizeof(*lib));
134 lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
136 lib->compiled_version = APR_VERSION_STRING;
137 lib->runtime_version = apr_pstrdup(pool, apr_version_string());
139 /* Don't list APR-Util if it isn't linked in, which it may not be if
140 * we're using APR 2.x+ which combined APR-Util into APR. */
141 #ifdef APU_VERSION_STRING
142 lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
143 lib->name = "APR-Util";
144 lib->compiled_version = APU_VERSION_STRING;
145 lib->runtime_version = apr_pstrdup(pool, apu_version_string());
148 lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
149 lib->name = "SQLite";
150 lib->compiled_version = apr_pstrdup(pool, svn_sqlite__compiled_version());
151 #ifdef SVN_SQLITE_INLINE
152 lib->runtime_version = NULL;
154 lib->runtime_version = apr_pstrdup(pool, svn_sqlite__runtime_version());
160 const apr_array_header_t *
161 svn_sysinfo__loaded_libs(apr_pool_t *pool)
164 return win32_shared_libs(pool);
165 #elif defined(SVN_HAVE_MACHO_ITERATE)
166 return macos_shared_libs(pool);
175 canonical_host_from_uname(apr_pool_t *pool)
177 const char *machine = "unknown";
178 const char *vendor = "unknown";
179 const char *sysname = "unknown";
180 const char *sysver = "";
183 if (0 <= uname(&info))
188 err = svn_utf_cstring_to_utf8(&tmp, info.machine, pool);
190 svn_error_clear(err);
194 err = svn_utf_cstring_to_utf8(&tmp, info.sysname, pool);
196 svn_error_clear(err);
199 char *lwr = apr_pstrdup(pool, tmp);
203 if (svn_ctype_isupper(*it))
204 *it = apr_tolower(*it);
210 if (0 == strcmp(sysname, "darwin"))
212 if (0 == strcmp(sysname, "linux"))
216 err = svn_utf_cstring_to_utf8(&tmp, info.release, pool);
218 svn_error_clear(err);
221 apr_size_t n = strspn(tmp, ".0123456789");
224 char *ver = apr_pstrdup(pool, tmp);
234 return apr_psprintf(pool, "%s-%s-%s%s", machine, vendor, sysname, sysver);
237 # ifndef SVN_HAVE_MACOS_PLIST
238 /* Generate a release name from the uname(3) info, effectively
239 returning "`uname -s` `uname -r`". */
241 release_name_from_uname(apr_pool_t *pool)
244 if (0 <= uname(&info))
250 err = svn_utf_cstring_to_utf8(&sysname, info.sysname, pool);
254 svn_error_clear(err);
258 err = svn_utf_cstring_to_utf8(&sysver, info.release, pool);
262 svn_error_clear(err);
265 if (sysname || sysver)
267 return apr_psprintf(pool, "%s%s%s",
268 (sysname ? sysname : ""),
269 (sysver ? (sysname ? " " : "") : ""),
270 (sysver ? sysver : ""));
275 # endif /* !SVN_HAVE_MACOS_PLIST */
276 #endif /* HAVE_UNAME */
280 /* Split a stringbuf into a key/value pair.
281 Return the key, leaving the striped value in the stringbuf. */
283 stringbuf_split_key(svn_stringbuf_t *buffer, char delim)
288 end = strchr(buffer->data, delim);
292 svn_stringbuf_strip_whitespace(buffer);
294 end = strchr(key, delim);
296 buffer->len = 1 + end - key;
297 buffer->data = end + 1;
298 svn_stringbuf_strip_whitespace(buffer);
303 /* Parse `/usr/bin/lsb_rlease --all` */
305 lsb_release(apr_pool_t *pool)
307 static const char *const args[3] =
309 "/usr/bin/lsb_release",
314 const char *distributor = NULL;
315 const char *description = NULL;
316 const char *release = NULL;
317 const char *codename = NULL;
320 svn_stream_t *lsbinfo;
323 /* Run /usr/bin/lsb_release --all < /dev/null 2>/dev/null */
325 apr_file_t *stdin_handle;
326 apr_file_t *stdout_handle;
328 err = svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME,
329 APR_READ, APR_OS_DEFAULT, pool);
331 err = svn_io_file_open(&stdout_handle, SVN_NULL_DEVICE_NAME,
332 APR_WRITE, APR_OS_DEFAULT, pool);
334 err = svn_io_start_cmd3(&lsbproc, NULL, args[0], args, NULL, FALSE,
337 FALSE, stdout_handle,
341 svn_error_clear(err);
346 /* Parse the output and try to populate the */
347 lsbinfo = svn_stream_from_aprfile2(lsbproc.out, TRUE, pool);
352 svn_boolean_t eof = FALSE;
353 svn_stringbuf_t *line;
356 err = svn_stream_readline(lsbinfo, &line, "\n", &eof, pool);
360 key = stringbuf_split_key(line, ':');
364 if (0 == svn_cstring_casecmp(key, "Distributor ID"))
365 distributor = line->data;
366 else if (0 == svn_cstring_casecmp(key, "Description"))
367 description = line->data;
368 else if (0 == svn_cstring_casecmp(key, "Release"))
369 release = line->data;
370 else if (0 == svn_cstring_casecmp(key, "Codename"))
371 codename = line->data;
373 err = svn_error_compose_create(err,
374 svn_stream_close(lsbinfo));
377 svn_error_clear(err);
378 apr_proc_kill(&lsbproc, SIGKILL);
383 /* Reap the child process */
384 err = svn_io_wait_for_cmd(&lsbproc, "", NULL, NULL, pool);
387 svn_error_clear(err);
392 return apr_psprintf(pool, "%s%s%s%s", description,
393 (codename ? " (" : ""),
394 (codename ? codename : ""),
395 (codename ? ")" : ""));
397 return apr_psprintf(pool, "%s%s%s%s%s%s", distributor,
398 (release ? " " : ""),
399 (release ? release : ""),
400 (codename ? " (" : ""),
401 (codename ? codename : ""),
402 (codename ? ")" : ""));
407 /* Read the whole contents of a file. */
408 static svn_stringbuf_t *
409 read_file_contents(const char *filename, apr_pool_t *pool)
412 svn_stringbuf_t *buffer;
414 err = svn_stringbuf_from_file2(&buffer, filename, pool);
417 svn_error_clear(err);
424 /* Strip everything but the first line from a stringbuf. */
426 stringbuf_first_line_only(svn_stringbuf_t *buffer)
428 char *eol = strchr(buffer->data, '\n');
432 buffer->len = 1 + eol - buffer->data;
434 svn_stringbuf_strip_whitespace(buffer);
437 /* Look at /etc/redhat_release to detect RHEL/Fedora/CentOS. */
439 redhat_release(apr_pool_t *pool)
441 svn_stringbuf_t *buffer = read_file_contents("/etc/redhat-release", pool);
444 stringbuf_first_line_only(buffer);
450 /* Look at /etc/SuSE-release to detect non-LSB SuSE. */
452 suse_release(apr_pool_t *pool)
454 const char *release = NULL;
455 const char *codename = NULL;
457 svn_stringbuf_t *buffer = read_file_contents("/etc/SuSE-release", pool);
458 svn_stringbuf_t *line;
459 svn_stream_t *stream;
465 stream = svn_stream_from_stringbuf(buffer, pool);
466 err = svn_stream_readline(stream, &line, "\n", &eof, pool);
469 svn_error_clear(err);
473 svn_stringbuf_strip_whitespace(line);
474 release = line->data;
480 err = svn_stream_readline(stream, &line, "\n", &eof, pool);
483 svn_error_clear(err);
487 key = stringbuf_split_key(line, '=');
491 if (0 == strncmp(key, "CODENAME", 8))
492 codename = line->data;
495 return apr_psprintf(pool, "%s%s%s%s",
497 (codename ? " (" : ""),
498 (codename ? codename : ""),
499 (codename ? ")" : ""));
502 /* Look at /etc/debian_version to detect non-LSB Debian. */
504 debian_release(apr_pool_t *pool)
506 svn_stringbuf_t *buffer = read_file_contents("/etc/debian_version", pool);
510 stringbuf_first_line_only(buffer);
511 return apr_pstrcat(pool, "Debian ", buffer->data, NULL);
514 /* Try to find the Linux distribution name, or return info from uname. */
516 linux_release_name(apr_pool_t *pool)
518 const char *uname_release = release_name_from_uname(pool);
520 /* Try anything that has /usr/bin/lsb_release.
521 Covers, for example, Debian, Ubuntu and SuSE. */
522 const char *release_name = lsb_release(pool);
524 /* Try RHEL/Fedora/CentOS */
526 release_name = redhat_release(pool);
528 /* Try Non-LSB SuSE */
530 release_name = suse_release(pool);
532 /* Try non-LSB Debian */
534 release_name = debian_release(pool);
537 return uname_release;
542 return apr_psprintf(pool, "%s [%s]", release_name, uname_release);
544 #endif /* __linux__ */
548 typedef DWORD (WINAPI *FNGETNATIVESYSTEMINFO)(LPSYSTEM_INFO);
549 typedef BOOL (WINAPI *FNENUMPROCESSMODULES) (HANDLE, HMODULE, DWORD, LPDWORD);
551 /* Get system and version info, and try to tell the difference
552 between the native system type and the runtime environment of the
553 current process. Populate results in SYSINFO, LOCAL_SYSINFO
554 (optional) and OSINFO. */
556 system_info(SYSTEM_INFO *sysinfo,
557 SYSTEM_INFO *local_sysinfo,
558 OSVERSIONINFOEXW *osinfo)
560 FNGETNATIVESYSTEMINFO GetNativeSystemInfo_ = (FNGETNATIVESYSTEMINFO)
561 GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
563 ZeroMemory(sysinfo, sizeof *sysinfo);
566 ZeroMemory(local_sysinfo, sizeof *local_sysinfo);
567 GetSystemInfo(local_sysinfo);
568 if (GetNativeSystemInfo_)
569 GetNativeSystemInfo_(sysinfo);
571 memcpy(sysinfo, local_sysinfo, sizeof *sysinfo);
574 GetSystemInfo(sysinfo);
576 ZeroMemory(osinfo, sizeof *osinfo);
577 osinfo->dwOSVersionInfoSize = sizeof *osinfo;
578 if (!GetVersionExW((LPVOID)osinfo))
584 /* Map the proccessor type from SYSINFO to a string. */
586 processor_name(SYSTEM_INFO *sysinfo)
588 switch (sysinfo->wProcessorArchitecture)
590 case PROCESSOR_ARCHITECTURE_AMD64: return "x86_64";
591 case PROCESSOR_ARCHITECTURE_IA64: return "ia64";
592 case PROCESSOR_ARCHITECTURE_INTEL: return "x86";
593 case PROCESSOR_ARCHITECTURE_MIPS: return "mips";
594 case PROCESSOR_ARCHITECTURE_ALPHA: return "alpha32";
595 case PROCESSOR_ARCHITECTURE_PPC: return "powerpc";
596 case PROCESSOR_ARCHITECTURE_SHX: return "shx";
597 case PROCESSOR_ARCHITECTURE_ARM: return "arm";
598 case PROCESSOR_ARCHITECTURE_ALPHA64: return "alpha";
599 case PROCESSOR_ARCHITECTURE_MSIL: return "msil";
600 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: return "x86_wow64";
601 default: return "unknown";
605 /* Return the Windows-specific canonical host name. */
607 win32_canonical_host(apr_pool_t *pool)
610 SYSTEM_INFO local_sysinfo;
611 OSVERSIONINFOEXW osinfo;
613 if (system_info(&sysinfo, &local_sysinfo, &osinfo))
615 const char *arch = processor_name(&local_sysinfo);
616 const char *machine = processor_name(&sysinfo);
617 const char *vendor = "microsoft";
618 const char *sysname = "windows";
619 const char *sysver = apr_psprintf(pool, "%u.%u.%u",
620 (unsigned int)osinfo.dwMajorVersion,
621 (unsigned int)osinfo.dwMinorVersion,
622 (unsigned int)osinfo.dwBuildNumber);
624 if (sysinfo.wProcessorArchitecture
625 == local_sysinfo.wProcessorArchitecture)
626 return apr_psprintf(pool, "%s-%s-%s%s",
627 machine, vendor, sysname, sysver);
628 return apr_psprintf(pool, "%s/%s-%s-%s%s",
629 arch, machine, vendor, sysname, sysver);
632 return "unknown-microsoft-windows";
635 /* Convert a Unicode string to UTF-8. */
637 wcs_to_utf8(const wchar_t *wcs, apr_pool_t *pool)
639 const int bufsize = WideCharToMultiByte(CP_UTF8, 0, wcs, -1,
640 NULL, 0, NULL, NULL);
643 char *const utf8 = apr_palloc(pool, bufsize + 1);
644 WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf8, bufsize, NULL, NULL);
650 /* Query the value called NAME of the registry key HKEY. */
652 registry_value(HKEY hkey, wchar_t *name, apr_pool_t *pool)
657 if (RegQueryValueExW(hkey, name, NULL, NULL, NULL, &size))
660 value = apr_palloc(pool, size + sizeof *value);
661 if (RegQueryValueExW(hkey, name, NULL, NULL, (void*)value, &size))
663 value[size / sizeof *value] = 0;
664 return wcs_to_utf8(value, pool);
667 /* Try to glean the Windows release name and associated info from the
668 registry. Failing that, construct a release name from the version
671 win32_release_name(apr_pool_t *pool)
674 OSVERSIONINFOEXW osinfo;
677 if (!system_info(&sysinfo, NULL, &osinfo))
680 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE,
681 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
682 0, KEY_QUERY_VALUE, &hkcv))
684 const char *release = registry_value(hkcv, L"ProductName", pool);
685 const char *spack = registry_value(hkcv, L"CSDVersion", pool);
686 const char *curver = registry_value(hkcv, L"CurrentVersion", pool);
687 const char *curtype = registry_value(hkcv, L"CurrentType", pool);
688 const char *install = registry_value(hkcv, L"InstallationType", pool);
689 const char *curbuild = registry_value(hkcv, L"CurrentBuildNumber", pool);
691 if (!spack && *osinfo.szCSDVersion)
692 spack = wcs_to_utf8(osinfo.szCSDVersion, pool);
695 curbuild = registry_value(hkcv, L"CurrentBuild", pool);
697 if (release || spack || curver || curtype || curbuild)
699 const char *bootinfo = "";
700 if (curver || install || curtype)
702 bootinfo = apr_psprintf(pool, "[%s%s%s%s%s]",
703 (curver ? curver : ""),
704 (install ? (curver ? " " : "") : ""),
705 (install ? install : ""),
707 ? (curver||install ? " " : "")
709 (curtype ? curtype : ""));
712 return apr_psprintf(pool, "%s%s%s%s%s%s%s",
713 (release ? release : ""),
714 (spack ? (release ? ", " : "") : ""),
715 (spack ? spack : ""),
717 ? (release||spack ? ", build " : "build ")
719 (curbuild ? curbuild : ""),
721 ? (release||spack||curbuild ? " " : "")
723 (bootinfo ? bootinfo : ""));
727 if (*osinfo.szCSDVersion)
729 const char *servicepack = wcs_to_utf8(osinfo.szCSDVersion, pool);
732 return apr_psprintf(pool, "Windows NT %u.%u, %s, build %u",
733 (unsigned int)osinfo.dwMajorVersion,
734 (unsigned int)osinfo.dwMinorVersion,
736 (unsigned int)osinfo.dwBuildNumber);
738 /* Assume wServicePackMajor > 0 if szCSDVersion is not empty */
739 if (osinfo.wServicePackMinor)
740 return apr_psprintf(pool, "Windows NT %u.%u SP%u.%u, build %u",
741 (unsigned int)osinfo.dwMajorVersion,
742 (unsigned int)osinfo.dwMinorVersion,
743 (unsigned int)osinfo.wServicePackMajor,
744 (unsigned int)osinfo.wServicePackMinor,
745 (unsigned int)osinfo.dwBuildNumber);
747 return apr_psprintf(pool, "Windows NT %u.%u SP%u, build %u",
748 (unsigned int)osinfo.dwMajorVersion,
749 (unsigned int)osinfo.dwMinorVersion,
750 (unsigned int)osinfo.wServicePackMajor,
751 (unsigned int)osinfo.dwBuildNumber);
754 return apr_psprintf(pool, "Windows NT %u.%u, build %u",
755 (unsigned int)osinfo.dwMajorVersion,
756 (unsigned int)osinfo.dwMinorVersion,
757 (unsigned int)osinfo.dwBuildNumber);
761 /* Get a list of handles of shared libs loaded by the current
762 process. Returns a NULL-terminated array alocated from POOL. */
764 enum_loaded_modules(apr_pool_t *pool)
766 HANDLE current = GetCurrentProcess();
771 if (!EnumProcessModules(current, dummy, sizeof(dummy), &size))
774 handles = apr_palloc(pool, size + sizeof *handles);
775 if (!EnumProcessModules(current, handles, size, &size))
777 handles[size / sizeof *handles] = NULL;
781 /* Find the version number, if any, embedded in FILENAME. */
783 file_version_number(const wchar_t *filename, apr_pool_t *pool)
785 VS_FIXEDFILEINFO info;
786 unsigned int major, minor, micro, nano;
788 DWORD data_size = GetFileVersionInfoSizeW(filename, NULL);
795 data = apr_palloc(pool, data_size);
796 if (!GetFileVersionInfoW(filename, 0, data_size, data))
799 if (!VerQueryValueW(data, L"\\", &vinfo, &vinfo_size))
802 if (vinfo_size != sizeof info)
805 memcpy(&info, vinfo, sizeof info);
806 major = (info.dwFileVersionMS >> 16) & 0xFFFF;
807 minor = info.dwFileVersionMS & 0xFFFF;
808 micro = (info.dwFileVersionLS >> 16) & 0xFFFF;
809 nano = info.dwFileVersionLS & 0xFFFF;
814 return apr_psprintf(pool, "%u.%u", major, minor);
816 return apr_psprintf(pool, "%u.%u.%u", major, minor, micro);
818 return apr_psprintf(pool, "%u.%u.%u.%u", major, minor, micro, nano);
821 /* List the shared libraries loaded by the current process. */
822 static const apr_array_header_t *
823 win32_shared_libs(apr_pool_t *pool)
825 apr_array_header_t *array = NULL;
826 wchar_t buffer[MAX_PATH + 1];
827 HMODULE *handles = enum_loaded_modules(pool);
830 for (module = handles; module && *module; ++module)
832 const char *filename;
834 if (GetModuleFileNameW(*module, buffer, MAX_PATH))
836 buffer[MAX_PATH] = 0;
838 version = file_version_number(buffer, pool);
839 filename = wcs_to_utf8(buffer, pool);
842 svn_version_ext_loaded_lib_t *lib;
846 array = apr_array_make(pool, 32, sizeof(*lib));
848 lib = &APR_ARRAY_PUSH(array, svn_version_ext_loaded_lib_t);
849 lib->name = svn_dirent_local_style(filename, pool);
850 lib->version = version;
860 #ifdef SVN_HAVE_MACOS_PLIST
861 /* Load the SystemVersion.plist or ServerVersion.plist file into a
862 property list. Set SERVER to TRUE if the file read was
863 ServerVersion.plist. */
864 static CFDictionaryRef
865 system_version_plist(svn_boolean_t *server, apr_pool_t *pool)
867 static const UInt8 server_version[] =
868 "/System/Library/CoreServices/ServerVersion.plist";
869 static const UInt8 system_version[] =
870 "/System/Library/CoreServices/SystemVersion.plist";
872 CFPropertyListRef plist = NULL;
873 CFDataRef resource = NULL;
874 CFStringRef errstr = NULL;
878 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
880 sizeof(server_version) - 1,
885 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
887 NULL, NULL, &errcode))
890 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
892 sizeof(system_version) - 1,
897 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
899 NULL, NULL, &errcode))
916 /* ### CFPropertyListCreateFromXMLData is obsolete, but its
917 replacement CFPropertyListCreateWithData is only available
918 from Mac OS 1.6 onward. */
919 plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource,
920 kCFPropertyListImmutable,
927 if (CFDictionaryGetTypeID() != CFGetTypeID(plist))
929 /* Oops ... this really should be a dict. */
937 /* Return the value for KEY from PLIST, or NULL if not available. */
939 value_from_dict(CFDictionaryRef plist, CFStringRef key, apr_pool_t *pool)
946 if (!CFDictionaryGetValueIfPresent(plist, key, &valptr))
950 if (CFStringGetTypeID() != CFGetTypeID(valref))
953 value = CFStringGetCStringPtr(valref, kCFStringEncodingUTF8);
955 return apr_pstrdup(pool, value);
957 bufsize = 5 * CFStringGetLength(valref) + 1;
958 value = apr_palloc(pool, bufsize);
959 if (!CFStringGetCString(valref, (char*)value, bufsize,
960 kCFStringEncodingUTF8))
966 /* Return the commercial name of the OS, given the version number in
967 a format that matches the regular expression /^10\.\d+(\..*)?$/ */
969 release_name_from_version(const char *osver)
972 unsigned long num = strtoul(osver, &end, 10);
974 if (!end || *end != '.' || num != 10)
979 num = strtoul(osver, &end, 10);
980 if (!end || (*end && *end != '.'))
983 /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */
986 case 0: return "Cheetah";
987 case 1: return "Puma";
988 case 2: return "Jaguar";
989 case 3: return "Panther";
990 case 4: return "Tiger";
991 case 5: return "Leopard";
992 case 6: return "Snow Leopard";
993 case 7: return "Lion";
994 case 8: return "Mountain Lion";
1000 /* Construct the release name from information stored in the Mac OS X
1001 "SystemVersion.plist" file (or ServerVersion.plist, for Mac Os
1004 macos_release_name(apr_pool_t *pool)
1006 svn_boolean_t server;
1007 CFDictionaryRef plist = system_version_plist(&server, pool);
1011 const char *osname = value_from_dict(plist, CFSTR("ProductName"), pool);
1012 const char *osver = value_from_dict(plist,
1013 CFSTR("ProductUserVisibleVersion"),
1015 const char *build = value_from_dict(plist,
1016 CFSTR("ProductBuildVersion"),
1018 const char *release;
1021 osver = value_from_dict(plist, CFSTR("ProductVersion"), pool);
1022 release = release_name_from_version(osver);
1025 return apr_psprintf(pool, "%s%s%s%s%s%s%s%s",
1026 (osname ? osname : ""),
1027 (osver ? (osname ? " " : "") : ""),
1028 (osver ? osver : ""),
1029 (release ? (osname||osver ? " " : "") : ""),
1030 (release ? release : ""),
1032 ? (osname||osver||release ? ", " : "")
1035 ? (server ? "server build " : "build ")
1037 (build ? build : ""));
1042 #endif /* SVN_HAVE_MACOS_PLIST */
1044 #ifdef SVN_HAVE_MACHO_ITERATE
1045 /* List the shared libraries loaded by the current process.
1046 Ignore frameworks and system libraries, they're just clutter. */
1047 static const apr_array_header_t *
1048 macos_shared_libs(apr_pool_t *pool)
1050 static const char slb_prefix[] = "/usr/lib/system/";
1051 static const char fwk_prefix[] = "/System/Library/Frameworks/";
1052 static const char pfk_prefix[] = "/System/Library/PrivateFrameworks/";
1054 const size_t slb_prefix_len = strlen(slb_prefix);
1055 const size_t fwk_prefix_len = strlen(fwk_prefix);
1056 const size_t pfk_prefix_len = strlen(pfk_prefix);
1058 apr_array_header_t *result = NULL;
1059 apr_array_header_t *dylibs = NULL;
1064 const struct mach_header *header = _dyld_get_image_header(i);
1065 const char *filename = _dyld_get_image_name(i);
1066 const char *version;
1068 svn_version_ext_loaded_lib_t *lib;
1070 if (!(header && filename))
1073 switch (header->cputype)
1075 case CPU_TYPE_I386: version = _("Intel"); break;
1076 case CPU_TYPE_X86_64: version = _("Intel 64-bit"); break;
1077 case CPU_TYPE_POWERPC: version = _("PowerPC"); break;
1078 case CPU_TYPE_POWERPC64: version = _("PowerPC 64-bit"); break;
1083 if (0 == apr_filepath_merge(&truename, "", filename,
1085 | APR_FILEPATH_TRUENAME,
1087 filename = truename;
1089 filename = apr_pstrdup(pool, filename);
1091 if (0 == strncmp(filename, slb_prefix, slb_prefix_len)
1092 || 0 == strncmp(filename, fwk_prefix, fwk_prefix_len)
1093 || 0 == strncmp(filename, pfk_prefix, pfk_prefix_len))
1095 /* Ignore frameworks and system libraries. */
1099 if (header->filetype == MH_EXECUTE)
1101 /* Make sure the program filename is first in the list */
1104 result = apr_array_make(pool, 32, sizeof(*lib));
1106 lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t);
1112 dylibs = apr_array_make(pool, 32, sizeof(*lib));
1114 lib = &APR_ARRAY_PUSH(dylibs, svn_version_ext_loaded_lib_t);
1117 lib->name = filename;
1118 lib->version = version;
1121 /* Gather results into one array. */
1125 apr_array_cat(result, dylibs);
1132 #endif /* SVN_HAVE_MACHO_ITERATE */