sysinfo.c revision 251881
1251881Speter/* 2251881Speter * sysinfo.c : information about the running system 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#ifdef WIN32 27251881Speter#define WIN32_LEAN_AND_MEAN 28251881Speter#define PSAPI_VERSION 1 29251881Speter#include <windows.h> 30251881Speter#include <psapi.h> 31251881Speter#include <Ws2tcpip.h> 32251881Speter#endif 33251881Speter 34251881Speter#define APR_WANT_STRFUNC 35251881Speter#include <apr_want.h> 36251881Speter 37251881Speter#include <apr_lib.h> 38251881Speter#include <apr_pools.h> 39251881Speter#include <apr_file_info.h> 40251881Speter#include <apr_signal.h> 41251881Speter#include <apr_strings.h> 42251881Speter#include <apr_thread_proc.h> 43251881Speter#include <apr_version.h> 44251881Speter#include <apu_version.h> 45251881Speter 46251881Speter#include "svn_pools.h" 47251881Speter#include "svn_ctype.h" 48251881Speter#include "svn_dirent_uri.h" 49251881Speter#include "svn_error.h" 50251881Speter#include "svn_io.h" 51251881Speter#include "svn_string.h" 52251881Speter#include "svn_utf.h" 53251881Speter#include "svn_version.h" 54251881Speter 55251881Speter#include "private/svn_sqlite.h" 56251881Speter 57251881Speter#include "sysinfo.h" 58251881Speter#include "svn_private_config.h" 59251881Speter 60251881Speter#if HAVE_SYS_UTSNAME_H 61251881Speter#include <sys/utsname.h> 62251881Speter#endif 63251881Speter 64251881Speter#ifdef SVN_HAVE_MACOS_PLIST 65251881Speter#include <CoreFoundation/CoreFoundation.h> 66251881Speter#endif 67251881Speter 68251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 69251881Speter#include <mach-o/dyld.h> 70251881Speter#include <mach-o/loader.h> 71251881Speter#endif 72251881Speter 73251881Speter#if HAVE_UNAME 74251881Speterstatic const char *canonical_host_from_uname(apr_pool_t *pool); 75251881Speter# ifndef SVN_HAVE_MACOS_PLIST 76251881Speterstatic const char *release_name_from_uname(apr_pool_t *pool); 77251881Speter# endif 78251881Speter#endif 79251881Speter 80251881Speter#ifdef WIN32 81251881Speterstatic const char *win32_canonical_host(apr_pool_t *pool); 82251881Speterstatic const char *win32_release_name(apr_pool_t *pool); 83251881Speterstatic const apr_array_header_t *win32_shared_libs(apr_pool_t *pool); 84251881Speter#endif /* WIN32 */ 85251881Speter 86251881Speter#ifdef SVN_HAVE_MACOS_PLIST 87251881Speterstatic const char *macos_release_name(apr_pool_t *pool); 88251881Speter#endif 89251881Speter 90251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 91251881Speterstatic const apr_array_header_t *macos_shared_libs(apr_pool_t *pool); 92251881Speter#endif 93251881Speter 94251881Speter 95251881Speter#if __linux__ 96251881Speterstatic const char *linux_release_name(apr_pool_t *pool); 97251881Speter#endif 98251881Speter 99251881Speterconst char * 100251881Spetersvn_sysinfo__canonical_host(apr_pool_t *pool) 101251881Speter{ 102251881Speter#ifdef WIN32 103251881Speter return win32_canonical_host(pool); 104251881Speter#elif HAVE_UNAME 105251881Speter return canonical_host_from_uname(pool); 106251881Speter#else 107251881Speter return "unknown-unknown-unknown"; 108251881Speter#endif 109251881Speter} 110251881Speter 111251881Speter 112251881Speterconst char * 113251881Spetersvn_sysinfo__release_name(apr_pool_t *pool) 114251881Speter{ 115251881Speter#ifdef WIN32 116251881Speter return win32_release_name(pool); 117251881Speter#elif defined(SVN_HAVE_MACOS_PLIST) 118251881Speter return macos_release_name(pool); 119251881Speter#elif __linux__ 120251881Speter return linux_release_name(pool); 121251881Speter#elif HAVE_UNAME 122251881Speter return release_name_from_uname(pool); 123251881Speter#else 124251881Speter return NULL; 125251881Speter#endif 126251881Speter} 127251881Speter 128251881Speterconst apr_array_header_t * 129251881Spetersvn_sysinfo__linked_libs(apr_pool_t *pool) 130251881Speter{ 131251881Speter svn_version_ext_linked_lib_t *lib; 132251881Speter apr_array_header_t *array = apr_array_make(pool, 3, sizeof(*lib)); 133251881Speter 134251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 135251881Speter lib->name = "APR"; 136251881Speter lib->compiled_version = APR_VERSION_STRING; 137251881Speter lib->runtime_version = apr_pstrdup(pool, apr_version_string()); 138251881Speter 139251881Speter/* Don't list APR-Util if it isn't linked in, which it may not be if 140251881Speter * we're using APR 2.x+ which combined APR-Util into APR. */ 141251881Speter#ifdef APU_VERSION_STRING 142251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 143251881Speter lib->name = "APR-Util"; 144251881Speter lib->compiled_version = APU_VERSION_STRING; 145251881Speter lib->runtime_version = apr_pstrdup(pool, apu_version_string()); 146251881Speter#endif 147251881Speter 148251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 149251881Speter lib->name = "SQLite"; 150251881Speter lib->compiled_version = apr_pstrdup(pool, svn_sqlite__compiled_version()); 151251881Speter#ifdef SVN_SQLITE_INLINE 152251881Speter lib->runtime_version = NULL; 153251881Speter#else 154251881Speter lib->runtime_version = apr_pstrdup(pool, svn_sqlite__runtime_version()); 155251881Speter#endif 156251881Speter 157251881Speter return array; 158251881Speter} 159251881Speter 160251881Speterconst apr_array_header_t * 161251881Spetersvn_sysinfo__loaded_libs(apr_pool_t *pool) 162251881Speter{ 163251881Speter#ifdef WIN32 164251881Speter return win32_shared_libs(pool); 165251881Speter#elif defined(SVN_HAVE_MACHO_ITERATE) 166251881Speter return macos_shared_libs(pool); 167251881Speter#else 168251881Speter return NULL; 169251881Speter#endif 170251881Speter} 171251881Speter 172251881Speter 173251881Speter#if HAVE_UNAME 174251881Speterstatic const char* 175251881Spetercanonical_host_from_uname(apr_pool_t *pool) 176251881Speter{ 177251881Speter const char *machine = "unknown"; 178251881Speter const char *vendor = "unknown"; 179251881Speter const char *sysname = "unknown"; 180251881Speter const char *sysver = ""; 181251881Speter struct utsname info; 182251881Speter 183251881Speter if (0 <= uname(&info)) 184251881Speter { 185251881Speter svn_error_t *err; 186251881Speter const char *tmp; 187251881Speter 188251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.machine, pool); 189251881Speter if (err) 190251881Speter svn_error_clear(err); 191251881Speter else 192251881Speter machine = tmp; 193251881Speter 194251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.sysname, pool); 195251881Speter if (err) 196251881Speter svn_error_clear(err); 197251881Speter else 198251881Speter { 199251881Speter char *lwr = apr_pstrdup(pool, tmp); 200251881Speter char *it = lwr; 201251881Speter while (*it) 202251881Speter { 203251881Speter if (svn_ctype_isupper(*it)) 204251881Speter *it = apr_tolower(*it); 205251881Speter ++it; 206251881Speter } 207251881Speter sysname = lwr; 208251881Speter } 209251881Speter 210251881Speter if (0 == strcmp(sysname, "darwin")) 211251881Speter vendor = "apple"; 212251881Speter if (0 == strcmp(sysname, "linux")) 213251881Speter sysver = "-gnu"; 214251881Speter else 215251881Speter { 216251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.release, pool); 217251881Speter if (err) 218251881Speter svn_error_clear(err); 219251881Speter else 220251881Speter { 221251881Speter apr_size_t n = strspn(tmp, ".0123456789"); 222251881Speter if (n > 0) 223251881Speter { 224251881Speter char *ver = apr_pstrdup(pool, tmp); 225251881Speter ver[n] = 0; 226251881Speter sysver = ver; 227251881Speter } 228251881Speter else 229251881Speter sysver = tmp; 230251881Speter } 231251881Speter } 232251881Speter } 233251881Speter 234251881Speter return apr_psprintf(pool, "%s-%s-%s%s", machine, vendor, sysname, sysver); 235251881Speter} 236251881Speter 237251881Speter# ifndef SVN_HAVE_MACOS_PLIST 238251881Speter/* Generate a release name from the uname(3) info, effectively 239251881Speter returning "`uname -s` `uname -r`". */ 240251881Speterstatic const char * 241251881Speterrelease_name_from_uname(apr_pool_t *pool) 242251881Speter{ 243251881Speter struct utsname info; 244251881Speter if (0 <= uname(&info)) 245251881Speter { 246251881Speter svn_error_t *err; 247251881Speter const char *sysname; 248251881Speter const char *sysver; 249251881Speter 250251881Speter err = svn_utf_cstring_to_utf8(&sysname, info.sysname, pool); 251251881Speter if (err) 252251881Speter { 253251881Speter sysname = NULL; 254251881Speter svn_error_clear(err); 255251881Speter } 256251881Speter 257251881Speter 258251881Speter err = svn_utf_cstring_to_utf8(&sysver, info.release, pool); 259251881Speter if (err) 260251881Speter { 261251881Speter sysver = NULL; 262251881Speter svn_error_clear(err); 263251881Speter } 264251881Speter 265251881Speter if (sysname || sysver) 266251881Speter { 267251881Speter return apr_psprintf(pool, "%s%s%s", 268251881Speter (sysname ? sysname : ""), 269251881Speter (sysver ? (sysname ? " " : "") : ""), 270251881Speter (sysver ? sysver : "")); 271251881Speter } 272251881Speter } 273251881Speter return NULL; 274251881Speter} 275251881Speter# endif /* !SVN_HAVE_MACOS_PLIST */ 276251881Speter#endif /* HAVE_UNAME */ 277251881Speter 278251881Speter 279251881Speter#if __linux__ 280251881Speter/* Split a stringbuf into a key/value pair. 281251881Speter Return the key, leaving the striped value in the stringbuf. */ 282251881Speterstatic const char * 283251881Speterstringbuf_split_key(svn_stringbuf_t *buffer, char delim) 284251881Speter{ 285251881Speter char *key; 286251881Speter char *end; 287251881Speter 288251881Speter end = strchr(buffer->data, delim); 289251881Speter if (!end) 290251881Speter return NULL; 291251881Speter 292251881Speter svn_stringbuf_strip_whitespace(buffer); 293251881Speter key = buffer->data; 294251881Speter end = strchr(key, delim); 295251881Speter *end = '\0'; 296251881Speter buffer->len = 1 + end - key; 297251881Speter buffer->data = end + 1; 298251881Speter svn_stringbuf_strip_whitespace(buffer); 299251881Speter 300251881Speter return key; 301251881Speter} 302251881Speter 303251881Speter/* Parse `/usr/bin/lsb_rlease --all` */ 304251881Speterstatic const char * 305251881Speterlsb_release(apr_pool_t *pool) 306251881Speter{ 307251881Speter static const char *const args[3] = 308251881Speter { 309251881Speter "/usr/bin/lsb_release", 310251881Speter "--all", 311251881Speter NULL 312251881Speter }; 313251881Speter 314251881Speter const char *distributor = NULL; 315251881Speter const char *description = NULL; 316251881Speter const char *release = NULL; 317251881Speter const char *codename = NULL; 318251881Speter 319251881Speter apr_proc_t lsbproc; 320251881Speter svn_stream_t *lsbinfo; 321251881Speter svn_error_t *err; 322251881Speter 323251881Speter /* Run /usr/bin/lsb_release --all < /dev/null 2>/dev/null */ 324251881Speter { 325251881Speter apr_file_t *stdin_handle; 326251881Speter apr_file_t *stdout_handle; 327251881Speter 328251881Speter err = svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME, 329251881Speter APR_READ, APR_OS_DEFAULT, pool); 330251881Speter if (!err) 331251881Speter err = svn_io_file_open(&stdout_handle, SVN_NULL_DEVICE_NAME, 332251881Speter APR_WRITE, APR_OS_DEFAULT, pool); 333251881Speter if (!err) 334251881Speter err = svn_io_start_cmd3(&lsbproc, NULL, args[0], args, NULL, FALSE, 335251881Speter FALSE, stdin_handle, 336251881Speter TRUE, NULL, 337251881Speter FALSE, stdout_handle, 338251881Speter pool); 339251881Speter if (err) 340251881Speter { 341251881Speter svn_error_clear(err); 342251881Speter return NULL; 343251881Speter } 344251881Speter } 345251881Speter 346251881Speter /* Parse the output and try to populate the */ 347251881Speter lsbinfo = svn_stream_from_aprfile2(lsbproc.out, TRUE, pool); 348251881Speter if (lsbinfo) 349251881Speter { 350251881Speter for (;;) 351251881Speter { 352251881Speter svn_boolean_t eof = FALSE; 353251881Speter svn_stringbuf_t *line; 354251881Speter const char *key; 355251881Speter 356251881Speter err = svn_stream_readline(lsbinfo, &line, "\n", &eof, pool); 357251881Speter if (err || eof) 358251881Speter break; 359251881Speter 360251881Speter key = stringbuf_split_key(line, ':'); 361251881Speter if (!key) 362251881Speter continue; 363251881Speter 364251881Speter if (0 == svn_cstring_casecmp(key, "Distributor ID")) 365251881Speter distributor = line->data; 366251881Speter else if (0 == svn_cstring_casecmp(key, "Description")) 367251881Speter description = line->data; 368251881Speter else if (0 == svn_cstring_casecmp(key, "Release")) 369251881Speter release = line->data; 370251881Speter else if (0 == svn_cstring_casecmp(key, "Codename")) 371251881Speter codename = line->data; 372251881Speter } 373251881Speter err = svn_error_compose_create(err, 374251881Speter svn_stream_close(lsbinfo)); 375251881Speter if (err) 376251881Speter { 377251881Speter svn_error_clear(err); 378251881Speter apr_proc_kill(&lsbproc, SIGKILL); 379251881Speter return NULL; 380251881Speter } 381251881Speter } 382251881Speter 383251881Speter /* Reap the child process */ 384251881Speter err = svn_io_wait_for_cmd(&lsbproc, "", NULL, NULL, pool); 385251881Speter if (err) 386251881Speter { 387251881Speter svn_error_clear(err); 388251881Speter return NULL; 389251881Speter } 390251881Speter 391251881Speter if (description) 392251881Speter return apr_psprintf(pool, "%s%s%s%s", description, 393251881Speter (codename ? " (" : ""), 394251881Speter (codename ? codename : ""), 395251881Speter (codename ? ")" : "")); 396251881Speter if (distributor) 397251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s", distributor, 398251881Speter (release ? " " : ""), 399251881Speter (release ? release : ""), 400251881Speter (codename ? " (" : ""), 401251881Speter (codename ? codename : ""), 402251881Speter (codename ? ")" : "")); 403251881Speter 404251881Speter return NULL; 405251881Speter} 406251881Speter 407251881Speter/* Read the whole contents of a file. */ 408251881Speterstatic svn_stringbuf_t * 409251881Speterread_file_contents(const char *filename, apr_pool_t *pool) 410251881Speter{ 411251881Speter svn_error_t *err; 412251881Speter svn_stringbuf_t *buffer; 413251881Speter 414251881Speter err = svn_stringbuf_from_file2(&buffer, filename, pool); 415251881Speter if (err) 416251881Speter { 417251881Speter svn_error_clear(err); 418251881Speter return NULL; 419251881Speter } 420251881Speter 421251881Speter return buffer; 422251881Speter} 423251881Speter 424251881Speter/* Strip everything but the first line from a stringbuf. */ 425251881Speterstatic void 426251881Speterstringbuf_first_line_only(svn_stringbuf_t *buffer) 427251881Speter{ 428251881Speter char *eol = strchr(buffer->data, '\n'); 429251881Speter if (eol) 430251881Speter { 431251881Speter *eol = '\0'; 432251881Speter buffer->len = 1 + eol - buffer->data; 433251881Speter } 434251881Speter svn_stringbuf_strip_whitespace(buffer); 435251881Speter} 436251881Speter 437251881Speter/* Look at /etc/redhat_release to detect RHEL/Fedora/CentOS. */ 438251881Speterstatic const char * 439251881Speterredhat_release(apr_pool_t *pool) 440251881Speter{ 441251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/redhat-release", pool); 442251881Speter if (buffer) 443251881Speter { 444251881Speter stringbuf_first_line_only(buffer); 445251881Speter return buffer->data; 446251881Speter } 447251881Speter return NULL; 448251881Speter} 449251881Speter 450251881Speter/* Look at /etc/SuSE-release to detect non-LSB SuSE. */ 451251881Speterstatic const char * 452251881Spetersuse_release(apr_pool_t *pool) 453251881Speter{ 454251881Speter const char *release = NULL; 455251881Speter const char *codename = NULL; 456251881Speter 457251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/SuSE-release", pool); 458251881Speter svn_stringbuf_t *line; 459251881Speter svn_stream_t *stream; 460251881Speter svn_boolean_t eof; 461251881Speter svn_error_t *err; 462251881Speter if (!buffer) 463251881Speter return NULL; 464251881Speter 465251881Speter stream = svn_stream_from_stringbuf(buffer, pool); 466251881Speter err = svn_stream_readline(stream, &line, "\n", &eof, pool); 467251881Speter if (err || eof) 468251881Speter { 469251881Speter svn_error_clear(err); 470251881Speter return NULL; 471251881Speter } 472251881Speter 473251881Speter svn_stringbuf_strip_whitespace(line); 474251881Speter release = line->data; 475251881Speter 476251881Speter for (;;) 477251881Speter { 478251881Speter const char *key; 479251881Speter 480251881Speter err = svn_stream_readline(stream, &line, "\n", &eof, pool); 481251881Speter if (err || eof) 482251881Speter { 483251881Speter svn_error_clear(err); 484251881Speter break; 485251881Speter } 486251881Speter 487251881Speter key = stringbuf_split_key(line, '='); 488251881Speter if (!key) 489251881Speter continue; 490251881Speter 491251881Speter if (0 == strncmp(key, "CODENAME", 8)) 492251881Speter codename = line->data; 493251881Speter } 494251881Speter 495251881Speter return apr_psprintf(pool, "%s%s%s%s", 496251881Speter release, 497251881Speter (codename ? " (" : ""), 498251881Speter (codename ? codename : ""), 499251881Speter (codename ? ")" : "")); 500251881Speter} 501251881Speter 502251881Speter/* Look at /etc/debian_version to detect non-LSB Debian. */ 503251881Speterstatic const char * 504251881Speterdebian_release(apr_pool_t *pool) 505251881Speter{ 506251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/debian_version", pool); 507251881Speter if (!buffer) 508251881Speter return NULL; 509251881Speter 510251881Speter stringbuf_first_line_only(buffer); 511251881Speter return apr_pstrcat(pool, "Debian ", buffer->data, NULL); 512251881Speter} 513251881Speter 514251881Speter/* Try to find the Linux distribution name, or return info from uname. */ 515251881Speterstatic const char * 516251881Speterlinux_release_name(apr_pool_t *pool) 517251881Speter{ 518251881Speter const char *uname_release = release_name_from_uname(pool); 519251881Speter 520251881Speter /* Try anything that has /usr/bin/lsb_release. 521251881Speter Covers, for example, Debian, Ubuntu and SuSE. */ 522251881Speter const char *release_name = lsb_release(pool); 523251881Speter 524251881Speter /* Try RHEL/Fedora/CentOS */ 525251881Speter if (!release_name) 526251881Speter release_name = redhat_release(pool); 527251881Speter 528251881Speter /* Try Non-LSB SuSE */ 529251881Speter if (!release_name) 530251881Speter release_name = suse_release(pool); 531251881Speter 532251881Speter /* Try non-LSB Debian */ 533251881Speter if (!release_name) 534251881Speter release_name = debian_release(pool); 535251881Speter 536251881Speter if (!release_name) 537251881Speter return uname_release; 538251881Speter 539251881Speter if (!uname_release) 540251881Speter return release_name; 541251881Speter 542251881Speter return apr_psprintf(pool, "%s [%s]", release_name, uname_release); 543251881Speter} 544251881Speter#endif /* __linux__ */ 545251881Speter 546251881Speter 547251881Speter#ifdef WIN32 548251881Spetertypedef DWORD (WINAPI *FNGETNATIVESYSTEMINFO)(LPSYSTEM_INFO); 549251881Spetertypedef BOOL (WINAPI *FNENUMPROCESSMODULES) (HANDLE, HMODULE, DWORD, LPDWORD); 550251881Speter 551251881Speter/* Get system and version info, and try to tell the difference 552251881Speter between the native system type and the runtime environment of the 553251881Speter current process. Populate results in SYSINFO, LOCAL_SYSINFO 554251881Speter (optional) and OSINFO. */ 555251881Speterstatic BOOL 556251881Spetersystem_info(SYSTEM_INFO *sysinfo, 557251881Speter SYSTEM_INFO *local_sysinfo, 558251881Speter OSVERSIONINFOEXW *osinfo) 559251881Speter{ 560251881Speter FNGETNATIVESYSTEMINFO GetNativeSystemInfo_ = (FNGETNATIVESYSTEMINFO) 561251881Speter GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); 562251881Speter 563251881Speter ZeroMemory(sysinfo, sizeof *sysinfo); 564251881Speter if (local_sysinfo) 565251881Speter { 566251881Speter ZeroMemory(local_sysinfo, sizeof *local_sysinfo); 567251881Speter GetSystemInfo(local_sysinfo); 568251881Speter if (GetNativeSystemInfo_) 569251881Speter GetNativeSystemInfo_(sysinfo); 570251881Speter else 571251881Speter memcpy(sysinfo, local_sysinfo, sizeof *sysinfo); 572251881Speter } 573251881Speter else 574251881Speter GetSystemInfo(sysinfo); 575251881Speter 576251881Speter ZeroMemory(osinfo, sizeof *osinfo); 577251881Speter osinfo->dwOSVersionInfoSize = sizeof *osinfo; 578251881Speter if (!GetVersionExW((LPVOID)osinfo)) 579251881Speter return FALSE; 580251881Speter 581251881Speter return TRUE; 582251881Speter} 583251881Speter 584251881Speter/* Map the proccessor type from SYSINFO to a string. */ 585251881Speterstatic const char * 586251881Speterprocessor_name(SYSTEM_INFO *sysinfo) 587251881Speter{ 588251881Speter switch (sysinfo->wProcessorArchitecture) 589251881Speter { 590251881Speter case PROCESSOR_ARCHITECTURE_AMD64: return "x86_64"; 591251881Speter case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; 592251881Speter case PROCESSOR_ARCHITECTURE_INTEL: return "x86"; 593251881Speter case PROCESSOR_ARCHITECTURE_MIPS: return "mips"; 594251881Speter case PROCESSOR_ARCHITECTURE_ALPHA: return "alpha32"; 595251881Speter case PROCESSOR_ARCHITECTURE_PPC: return "powerpc"; 596251881Speter case PROCESSOR_ARCHITECTURE_SHX: return "shx"; 597251881Speter case PROCESSOR_ARCHITECTURE_ARM: return "arm"; 598251881Speter case PROCESSOR_ARCHITECTURE_ALPHA64: return "alpha"; 599251881Speter case PROCESSOR_ARCHITECTURE_MSIL: return "msil"; 600251881Speter case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: return "x86_wow64"; 601251881Speter default: return "unknown"; 602251881Speter } 603251881Speter} 604251881Speter 605251881Speter/* Return the Windows-specific canonical host name. */ 606251881Speterstatic const char * 607251881Speterwin32_canonical_host(apr_pool_t *pool) 608251881Speter{ 609251881Speter SYSTEM_INFO sysinfo; 610251881Speter SYSTEM_INFO local_sysinfo; 611251881Speter OSVERSIONINFOEXW osinfo; 612251881Speter 613251881Speter if (system_info(&sysinfo, &local_sysinfo, &osinfo)) 614251881Speter { 615251881Speter const char *arch = processor_name(&local_sysinfo); 616251881Speter const char *machine = processor_name(&sysinfo); 617251881Speter const char *vendor = "microsoft"; 618251881Speter const char *sysname = "windows"; 619251881Speter const char *sysver = apr_psprintf(pool, "%u.%u.%u", 620251881Speter (unsigned int)osinfo.dwMajorVersion, 621251881Speter (unsigned int)osinfo.dwMinorVersion, 622251881Speter (unsigned int)osinfo.dwBuildNumber); 623251881Speter 624251881Speter if (sysinfo.wProcessorArchitecture 625251881Speter == local_sysinfo.wProcessorArchitecture) 626251881Speter return apr_psprintf(pool, "%s-%s-%s%s", 627251881Speter machine, vendor, sysname, sysver); 628251881Speter return apr_psprintf(pool, "%s/%s-%s-%s%s", 629251881Speter arch, machine, vendor, sysname, sysver); 630251881Speter } 631251881Speter 632251881Speter return "unknown-microsoft-windows"; 633251881Speter} 634251881Speter 635251881Speter/* Convert a Unicode string to UTF-8. */ 636251881Speterstatic char * 637251881Speterwcs_to_utf8(const wchar_t *wcs, apr_pool_t *pool) 638251881Speter{ 639251881Speter const int bufsize = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, 640251881Speter NULL, 0, NULL, NULL); 641251881Speter if (bufsize > 0) 642251881Speter { 643251881Speter char *const utf8 = apr_palloc(pool, bufsize + 1); 644251881Speter WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf8, bufsize, NULL, NULL); 645251881Speter return utf8; 646251881Speter } 647251881Speter return NULL; 648251881Speter} 649251881Speter 650251881Speter/* Query the value called NAME of the registry key HKEY. */ 651251881Speterstatic char * 652251881Speterregistry_value(HKEY hkey, wchar_t *name, apr_pool_t *pool) 653251881Speter{ 654251881Speter DWORD size; 655251881Speter wchar_t *value; 656251881Speter 657251881Speter if (RegQueryValueExW(hkey, name, NULL, NULL, NULL, &size)) 658251881Speter return NULL; 659251881Speter 660251881Speter value = apr_palloc(pool, size + sizeof *value); 661251881Speter if (RegQueryValueExW(hkey, name, NULL, NULL, (void*)value, &size)) 662251881Speter return NULL; 663251881Speter value[size / sizeof *value] = 0; 664251881Speter return wcs_to_utf8(value, pool); 665251881Speter} 666251881Speter 667251881Speter/* Try to glean the Windows release name and associated info from the 668251881Speter registry. Failing that, construct a release name from the version 669251881Speter info. */ 670251881Speterstatic const char * 671251881Speterwin32_release_name(apr_pool_t *pool) 672251881Speter{ 673251881Speter SYSTEM_INFO sysinfo; 674251881Speter OSVERSIONINFOEXW osinfo; 675251881Speter HKEY hkcv; 676251881Speter 677251881Speter if (!system_info(&sysinfo, NULL, &osinfo)) 678251881Speter return NULL; 679251881Speter 680251881Speter if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, 681251881Speter L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 682251881Speter 0, KEY_QUERY_VALUE, &hkcv)) 683251881Speter { 684251881Speter const char *release = registry_value(hkcv, L"ProductName", pool); 685251881Speter const char *spack = registry_value(hkcv, L"CSDVersion", pool); 686251881Speter const char *curver = registry_value(hkcv, L"CurrentVersion", pool); 687251881Speter const char *curtype = registry_value(hkcv, L"CurrentType", pool); 688251881Speter const char *install = registry_value(hkcv, L"InstallationType", pool); 689251881Speter const char *curbuild = registry_value(hkcv, L"CurrentBuildNumber", pool); 690251881Speter 691251881Speter if (!spack && *osinfo.szCSDVersion) 692251881Speter spack = wcs_to_utf8(osinfo.szCSDVersion, pool); 693251881Speter 694251881Speter if (!curbuild) 695251881Speter curbuild = registry_value(hkcv, L"CurrentBuild", pool); 696251881Speter 697251881Speter if (release || spack || curver || curtype || curbuild) 698251881Speter { 699251881Speter const char *bootinfo = ""; 700251881Speter if (curver || install || curtype) 701251881Speter { 702251881Speter bootinfo = apr_psprintf(pool, "[%s%s%s%s%s]", 703251881Speter (curver ? curver : ""), 704251881Speter (install ? (curver ? " " : "") : ""), 705251881Speter (install ? install : ""), 706251881Speter (curtype 707251881Speter ? (curver||install ? " " : "") 708251881Speter : ""), 709251881Speter (curtype ? curtype : "")); 710251881Speter } 711251881Speter 712251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s%s", 713251881Speter (release ? release : ""), 714251881Speter (spack ? (release ? ", " : "") : ""), 715251881Speter (spack ? spack : ""), 716251881Speter (curbuild 717251881Speter ? (release||spack ? ", build " : "build ") 718251881Speter : ""), 719251881Speter (curbuild ? curbuild : ""), 720251881Speter (bootinfo 721251881Speter ? (release||spack||curbuild ? " " : "") 722251881Speter : ""), 723251881Speter (bootinfo ? bootinfo : "")); 724251881Speter } 725251881Speter } 726251881Speter 727251881Speter if (*osinfo.szCSDVersion) 728251881Speter { 729251881Speter const char *servicepack = wcs_to_utf8(osinfo.szCSDVersion, pool); 730251881Speter 731251881Speter if (servicepack) 732251881Speter return apr_psprintf(pool, "Windows NT %u.%u, %s, build %u", 733251881Speter (unsigned int)osinfo.dwMajorVersion, 734251881Speter (unsigned int)osinfo.dwMinorVersion, 735251881Speter servicepack, 736251881Speter (unsigned int)osinfo.dwBuildNumber); 737251881Speter 738251881Speter /* Assume wServicePackMajor > 0 if szCSDVersion is not empty */ 739251881Speter if (osinfo.wServicePackMinor) 740251881Speter return apr_psprintf(pool, "Windows NT %u.%u SP%u.%u, build %u", 741251881Speter (unsigned int)osinfo.dwMajorVersion, 742251881Speter (unsigned int)osinfo.dwMinorVersion, 743251881Speter (unsigned int)osinfo.wServicePackMajor, 744251881Speter (unsigned int)osinfo.wServicePackMinor, 745251881Speter (unsigned int)osinfo.dwBuildNumber); 746251881Speter 747251881Speter return apr_psprintf(pool, "Windows NT %u.%u SP%u, build %u", 748251881Speter (unsigned int)osinfo.dwMajorVersion, 749251881Speter (unsigned int)osinfo.dwMinorVersion, 750251881Speter (unsigned int)osinfo.wServicePackMajor, 751251881Speter (unsigned int)osinfo.dwBuildNumber); 752251881Speter } 753251881Speter 754251881Speter return apr_psprintf(pool, "Windows NT %u.%u, build %u", 755251881Speter (unsigned int)osinfo.dwMajorVersion, 756251881Speter (unsigned int)osinfo.dwMinorVersion, 757251881Speter (unsigned int)osinfo.dwBuildNumber); 758251881Speter} 759251881Speter 760251881Speter 761251881Speter/* Get a list of handles of shared libs loaded by the current 762251881Speter process. Returns a NULL-terminated array alocated from POOL. */ 763251881Speterstatic HMODULE * 764251881Speterenum_loaded_modules(apr_pool_t *pool) 765251881Speter{ 766251881Speter HANDLE current = GetCurrentProcess(); 767251881Speter HMODULE dummy[1]; 768251881Speter HMODULE *handles; 769251881Speter DWORD size; 770251881Speter 771251881Speter if (!EnumProcessModules(current, dummy, sizeof(dummy), &size)) 772251881Speter return NULL; 773251881Speter 774251881Speter handles = apr_palloc(pool, size + sizeof *handles); 775251881Speter if (!EnumProcessModules(current, handles, size, &size)) 776251881Speter return NULL; 777251881Speter handles[size / sizeof *handles] = NULL; 778251881Speter return handles; 779251881Speter} 780251881Speter 781251881Speter/* Find the version number, if any, embedded in FILENAME. */ 782251881Speterstatic const char * 783251881Speterfile_version_number(const wchar_t *filename, apr_pool_t *pool) 784251881Speter{ 785251881Speter VS_FIXEDFILEINFO info; 786251881Speter unsigned int major, minor, micro, nano; 787251881Speter void *data; 788251881Speter DWORD data_size = GetFileVersionInfoSizeW(filename, NULL); 789251881Speter void *vinfo; 790251881Speter UINT vinfo_size; 791251881Speter 792251881Speter if (!data_size) 793251881Speter return NULL; 794251881Speter 795251881Speter data = apr_palloc(pool, data_size); 796251881Speter if (!GetFileVersionInfoW(filename, 0, data_size, data)) 797251881Speter return NULL; 798251881Speter 799251881Speter if (!VerQueryValueW(data, L"\\", &vinfo, &vinfo_size)) 800251881Speter return NULL; 801251881Speter 802251881Speter if (vinfo_size != sizeof info) 803251881Speter return NULL; 804251881Speter 805251881Speter memcpy(&info, vinfo, sizeof info); 806251881Speter major = (info.dwFileVersionMS >> 16) & 0xFFFF; 807251881Speter minor = info.dwFileVersionMS & 0xFFFF; 808251881Speter micro = (info.dwFileVersionLS >> 16) & 0xFFFF; 809251881Speter nano = info.dwFileVersionLS & 0xFFFF; 810251881Speter 811251881Speter if (!nano) 812251881Speter { 813251881Speter if (!micro) 814251881Speter return apr_psprintf(pool, "%u.%u", major, minor); 815251881Speter else 816251881Speter return apr_psprintf(pool, "%u.%u.%u", major, minor, micro); 817251881Speter } 818251881Speter return apr_psprintf(pool, "%u.%u.%u.%u", major, minor, micro, nano); 819251881Speter} 820251881Speter 821251881Speter/* List the shared libraries loaded by the current process. */ 822251881Speterstatic const apr_array_header_t * 823251881Speterwin32_shared_libs(apr_pool_t *pool) 824251881Speter{ 825251881Speter apr_array_header_t *array = NULL; 826251881Speter wchar_t buffer[MAX_PATH + 1]; 827251881Speter HMODULE *handles = enum_loaded_modules(pool); 828251881Speter HMODULE *module; 829251881Speter 830251881Speter for (module = handles; module && *module; ++module) 831251881Speter { 832251881Speter const char *filename; 833251881Speter const char *version; 834251881Speter if (GetModuleFileNameW(*module, buffer, MAX_PATH)) 835251881Speter { 836251881Speter buffer[MAX_PATH] = 0; 837251881Speter 838251881Speter version = file_version_number(buffer, pool); 839251881Speter filename = wcs_to_utf8(buffer, pool); 840251881Speter if (filename) 841251881Speter { 842251881Speter svn_version_ext_loaded_lib_t *lib; 843251881Speter 844251881Speter if (!array) 845251881Speter { 846251881Speter array = apr_array_make(pool, 32, sizeof(*lib)); 847251881Speter } 848251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_loaded_lib_t); 849251881Speter lib->name = svn_dirent_local_style(filename, pool); 850251881Speter lib->version = version; 851251881Speter } 852251881Speter } 853251881Speter } 854251881Speter 855251881Speter return array; 856251881Speter} 857251881Speter#endif /* WIN32 */ 858251881Speter 859251881Speter 860251881Speter#ifdef SVN_HAVE_MACOS_PLIST 861251881Speter/* Load the SystemVersion.plist or ServerVersion.plist file into a 862251881Speter property list. Set SERVER to TRUE if the file read was 863251881Speter ServerVersion.plist. */ 864251881Speterstatic CFDictionaryRef 865251881Spetersystem_version_plist(svn_boolean_t *server, apr_pool_t *pool) 866251881Speter{ 867251881Speter static const UInt8 server_version[] = 868251881Speter "/System/Library/CoreServices/ServerVersion.plist"; 869251881Speter static const UInt8 system_version[] = 870251881Speter "/System/Library/CoreServices/SystemVersion.plist"; 871251881Speter 872251881Speter CFPropertyListRef plist = NULL; 873251881Speter CFDataRef resource = NULL; 874251881Speter CFStringRef errstr = NULL; 875251881Speter CFURLRef url = NULL; 876251881Speter SInt32 errcode; 877251881Speter 878251881Speter url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 879251881Speter server_version, 880251881Speter sizeof(server_version) - 1, 881251881Speter FALSE); 882251881Speter if (!url) 883251881Speter return NULL; 884251881Speter 885251881Speter if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, 886251881Speter url, &resource, 887251881Speter NULL, NULL, &errcode)) 888251881Speter { 889251881Speter CFRelease(url); 890251881Speter url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 891251881Speter system_version, 892251881Speter sizeof(system_version) - 1, 893251881Speter FALSE); 894251881Speter if (!url) 895251881Speter return NULL; 896251881Speter 897251881Speter if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, 898251881Speter url, &resource, 899251881Speter NULL, NULL, &errcode)) 900251881Speter { 901251881Speter CFRelease(url); 902251881Speter return NULL; 903251881Speter } 904251881Speter else 905251881Speter { 906251881Speter CFRelease(url); 907251881Speter *server = FALSE; 908251881Speter } 909251881Speter } 910251881Speter else 911251881Speter { 912251881Speter CFRelease(url); 913251881Speter *server = TRUE; 914251881Speter } 915251881Speter 916251881Speter /* ### CFPropertyListCreateFromXMLData is obsolete, but its 917251881Speter replacement CFPropertyListCreateWithData is only available 918251881Speter from Mac OS 1.6 onward. */ 919251881Speter plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, 920251881Speter kCFPropertyListImmutable, 921251881Speter &errstr); 922251881Speter if (resource) 923251881Speter CFRelease(resource); 924251881Speter if (errstr) 925251881Speter CFRelease(errstr); 926251881Speter 927251881Speter if (CFDictionaryGetTypeID() != CFGetTypeID(plist)) 928251881Speter { 929251881Speter /* Oops ... this really should be a dict. */ 930251881Speter CFRelease(plist); 931251881Speter return NULL; 932251881Speter } 933251881Speter 934251881Speter return plist; 935251881Speter} 936251881Speter 937251881Speter/* Return the value for KEY from PLIST, or NULL if not available. */ 938251881Speterstatic const char * 939251881Spetervalue_from_dict(CFDictionaryRef plist, CFStringRef key, apr_pool_t *pool) 940251881Speter{ 941251881Speter CFStringRef valref; 942251881Speter CFIndex bufsize; 943251881Speter const void *valptr; 944251881Speter const char *value; 945251881Speter 946251881Speter if (!CFDictionaryGetValueIfPresent(plist, key, &valptr)) 947251881Speter return NULL; 948251881Speter 949251881Speter valref = valptr; 950251881Speter if (CFStringGetTypeID() != CFGetTypeID(valref)) 951251881Speter return NULL; 952251881Speter 953251881Speter value = CFStringGetCStringPtr(valref, kCFStringEncodingUTF8); 954251881Speter if (value) 955251881Speter return apr_pstrdup(pool, value); 956251881Speter 957251881Speter bufsize = 5 * CFStringGetLength(valref) + 1; 958251881Speter value = apr_palloc(pool, bufsize); 959251881Speter if (!CFStringGetCString(valref, (char*)value, bufsize, 960251881Speter kCFStringEncodingUTF8)) 961251881Speter value = NULL; 962251881Speter 963251881Speter return value; 964251881Speter} 965251881Speter 966251881Speter/* Return the commercial name of the OS, given the version number in 967251881Speter a format that matches the regular expression /^10\.\d+(\..*)?$/ */ 968251881Speterstatic const char * 969251881Speterrelease_name_from_version(const char *osver) 970251881Speter{ 971251881Speter char *end = NULL; 972251881Speter unsigned long num = strtoul(osver, &end, 10); 973251881Speter 974251881Speter if (!end || *end != '.' || num != 10) 975251881Speter return NULL; 976251881Speter 977251881Speter osver = end + 1; 978251881Speter end = NULL; 979251881Speter num = strtoul(osver, &end, 10); 980251881Speter if (!end || (*end && *end != '.')) 981251881Speter return NULL; 982251881Speter 983251881Speter /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */ 984251881Speter switch(num) 985251881Speter { 986251881Speter case 0: return "Cheetah"; 987251881Speter case 1: return "Puma"; 988251881Speter case 2: return "Jaguar"; 989251881Speter case 3: return "Panther"; 990251881Speter case 4: return "Tiger"; 991251881Speter case 5: return "Leopard"; 992251881Speter case 6: return "Snow Leopard"; 993251881Speter case 7: return "Lion"; 994251881Speter case 8: return "Mountain Lion"; 995251881Speter } 996251881Speter 997251881Speter return NULL; 998251881Speter} 999251881Speter 1000251881Speter/* Construct the release name from information stored in the Mac OS X 1001251881Speter "SystemVersion.plist" file (or ServerVersion.plist, for Mac Os 1002251881Speter Server. */ 1003251881Speterstatic const char * 1004251881Spetermacos_release_name(apr_pool_t *pool) 1005251881Speter{ 1006251881Speter svn_boolean_t server; 1007251881Speter CFDictionaryRef plist = system_version_plist(&server, pool); 1008251881Speter 1009251881Speter if (plist) 1010251881Speter { 1011251881Speter const char *osname = value_from_dict(plist, CFSTR("ProductName"), pool); 1012251881Speter const char *osver = value_from_dict(plist, 1013251881Speter CFSTR("ProductUserVisibleVersion"), 1014251881Speter pool); 1015251881Speter const char *build = value_from_dict(plist, 1016251881Speter CFSTR("ProductBuildVersion"), 1017251881Speter pool); 1018251881Speter const char *release; 1019251881Speter 1020251881Speter if (!osver) 1021251881Speter osver = value_from_dict(plist, CFSTR("ProductVersion"), pool); 1022251881Speter release = release_name_from_version(osver); 1023251881Speter 1024251881Speter CFRelease(plist); 1025251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s%s%s", 1026251881Speter (osname ? osname : ""), 1027251881Speter (osver ? (osname ? " " : "") : ""), 1028251881Speter (osver ? osver : ""), 1029251881Speter (release ? (osname||osver ? " " : "") : ""), 1030251881Speter (release ? release : ""), 1031251881Speter (build 1032251881Speter ? (osname||osver||release ? ", " : "") 1033251881Speter : ""), 1034251881Speter (build 1035251881Speter ? (server ? "server build " : "build ") 1036251881Speter : ""), 1037251881Speter (build ? build : "")); 1038251881Speter } 1039251881Speter 1040251881Speter return NULL; 1041251881Speter} 1042251881Speter#endif /* SVN_HAVE_MACOS_PLIST */ 1043251881Speter 1044251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 1045251881Speter/* List the shared libraries loaded by the current process. 1046251881Speter Ignore frameworks and system libraries, they're just clutter. */ 1047251881Speterstatic const apr_array_header_t * 1048251881Spetermacos_shared_libs(apr_pool_t *pool) 1049251881Speter{ 1050251881Speter static const char slb_prefix[] = "/usr/lib/system/"; 1051251881Speter static const char fwk_prefix[] = "/System/Library/Frameworks/"; 1052251881Speter static const char pfk_prefix[] = "/System/Library/PrivateFrameworks/"; 1053251881Speter 1054251881Speter const size_t slb_prefix_len = strlen(slb_prefix); 1055251881Speter const size_t fwk_prefix_len = strlen(fwk_prefix); 1056251881Speter const size_t pfk_prefix_len = strlen(pfk_prefix); 1057251881Speter 1058251881Speter apr_array_header_t *result = NULL; 1059251881Speter apr_array_header_t *dylibs = NULL; 1060251881Speter 1061251881Speter uint32_t i; 1062251881Speter for (i = 0;; ++i) 1063251881Speter { 1064251881Speter const struct mach_header *header = _dyld_get_image_header(i); 1065251881Speter const char *filename = _dyld_get_image_name(i); 1066251881Speter const char *version; 1067251881Speter char *truename; 1068251881Speter svn_version_ext_loaded_lib_t *lib; 1069251881Speter 1070251881Speter if (!(header && filename)) 1071251881Speter break; 1072251881Speter 1073251881Speter switch (header->cputype) 1074251881Speter { 1075251881Speter case CPU_TYPE_I386: version = _("Intel"); break; 1076251881Speter case CPU_TYPE_X86_64: version = _("Intel 64-bit"); break; 1077251881Speter case CPU_TYPE_POWERPC: version = _("PowerPC"); break; 1078251881Speter case CPU_TYPE_POWERPC64: version = _("PowerPC 64-bit"); break; 1079251881Speter default: 1080251881Speter version = NULL; 1081251881Speter } 1082251881Speter 1083251881Speter if (0 == apr_filepath_merge(&truename, "", filename, 1084251881Speter APR_FILEPATH_NATIVE 1085251881Speter | APR_FILEPATH_TRUENAME, 1086251881Speter pool)) 1087251881Speter filename = truename; 1088251881Speter else 1089251881Speter filename = apr_pstrdup(pool, filename); 1090251881Speter 1091251881Speter if (0 == strncmp(filename, slb_prefix, slb_prefix_len) 1092251881Speter || 0 == strncmp(filename, fwk_prefix, fwk_prefix_len) 1093251881Speter || 0 == strncmp(filename, pfk_prefix, pfk_prefix_len)) 1094251881Speter { 1095251881Speter /* Ignore frameworks and system libraries. */ 1096251881Speter continue; 1097251881Speter } 1098251881Speter 1099251881Speter if (header->filetype == MH_EXECUTE) 1100251881Speter { 1101251881Speter /* Make sure the program filename is first in the list */ 1102251881Speter if (!result) 1103251881Speter { 1104251881Speter result = apr_array_make(pool, 32, sizeof(*lib)); 1105251881Speter } 1106251881Speter lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t); 1107251881Speter } 1108251881Speter else 1109251881Speter { 1110251881Speter if (!dylibs) 1111251881Speter { 1112251881Speter dylibs = apr_array_make(pool, 32, sizeof(*lib)); 1113251881Speter } 1114251881Speter lib = &APR_ARRAY_PUSH(dylibs, svn_version_ext_loaded_lib_t); 1115251881Speter } 1116251881Speter 1117251881Speter lib->name = filename; 1118251881Speter lib->version = version; 1119251881Speter } 1120251881Speter 1121251881Speter /* Gather results into one array. */ 1122251881Speter if (dylibs) 1123251881Speter { 1124251881Speter if (result) 1125251881Speter apr_array_cat(result, dylibs); 1126251881Speter else 1127251881Speter result = dylibs; 1128251881Speter } 1129251881Speter 1130251881Speter return result; 1131251881Speter} 1132251881Speter#endif /* SVN_HAVE_MACHO_ITERATE */ 1133