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#define APR_WANT_STRFUNC 27251881Speter#include <apr_want.h> 28251881Speter 29251881Speter#include <apr_lib.h> 30251881Speter#include <apr_pools.h> 31251881Speter#include <apr_file_info.h> 32251881Speter#include <apr_signal.h> 33251881Speter#include <apr_strings.h> 34251881Speter#include <apr_thread_proc.h> 35251881Speter#include <apr_version.h> 36251881Speter#include <apu_version.h> 37251881Speter 38251881Speter#include "svn_pools.h" 39251881Speter#include "svn_ctype.h" 40251881Speter#include "svn_dirent_uri.h" 41251881Speter#include "svn_error.h" 42251881Speter#include "svn_io.h" 43251881Speter#include "svn_string.h" 44251881Speter#include "svn_utf.h" 45251881Speter#include "svn_version.h" 46251881Speter 47251881Speter#include "private/svn_sqlite.h" 48299742Sdim#include "private/svn_subr_private.h" 49299742Sdim#include "private/svn_utf_private.h" 50251881Speter 51251881Speter#include "sysinfo.h" 52251881Speter#include "svn_private_config.h" 53251881Speter 54251881Speter#if HAVE_SYS_UTSNAME_H 55251881Speter#include <sys/utsname.h> 56251881Speter#endif 57251881Speter 58251881Speter#ifdef SVN_HAVE_MACOS_PLIST 59251881Speter#include <CoreFoundation/CoreFoundation.h> 60299742Sdim#include <AvailabilityMacros.h> 61299742Sdim# ifndef MAC_OS_X_VERSION_10_6 62299742Sdim# define MAC_OS_X_VERSION_10_6 1060 63299742Sdim# endif 64251881Speter#endif 65251881Speter 66251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 67251881Speter#include <mach-o/dyld.h> 68251881Speter#include <mach-o/loader.h> 69251881Speter#endif 70251881Speter 71251881Speter#if HAVE_UNAME 72251881Speterstatic const char *canonical_host_from_uname(apr_pool_t *pool); 73251881Speter# ifndef SVN_HAVE_MACOS_PLIST 74251881Speterstatic const char *release_name_from_uname(apr_pool_t *pool); 75251881Speter# endif 76251881Speter#endif 77251881Speter 78251881Speter#ifdef WIN32 79251881Speterstatic const char *win32_canonical_host(apr_pool_t *pool); 80251881Speterstatic const char *win32_release_name(apr_pool_t *pool); 81251881Speterstatic const apr_array_header_t *win32_shared_libs(apr_pool_t *pool); 82251881Speter#endif /* WIN32 */ 83251881Speter 84251881Speter#ifdef SVN_HAVE_MACOS_PLIST 85251881Speterstatic const char *macos_release_name(apr_pool_t *pool); 86251881Speter#endif 87251881Speter 88251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 89251881Speterstatic const apr_array_header_t *macos_shared_libs(apr_pool_t *pool); 90251881Speter#endif 91251881Speter 92251881Speter 93251881Speter#if __linux__ 94251881Speterstatic const char *linux_release_name(apr_pool_t *pool); 95251881Speter#endif 96251881Speter 97251881Speterconst char * 98251881Spetersvn_sysinfo__canonical_host(apr_pool_t *pool) 99251881Speter{ 100251881Speter#ifdef WIN32 101251881Speter return win32_canonical_host(pool); 102251881Speter#elif HAVE_UNAME 103251881Speter return canonical_host_from_uname(pool); 104251881Speter#else 105251881Speter return "unknown-unknown-unknown"; 106251881Speter#endif 107251881Speter} 108251881Speter 109251881Speter 110251881Speterconst char * 111251881Spetersvn_sysinfo__release_name(apr_pool_t *pool) 112251881Speter{ 113251881Speter#ifdef WIN32 114251881Speter return win32_release_name(pool); 115251881Speter#elif defined(SVN_HAVE_MACOS_PLIST) 116251881Speter return macos_release_name(pool); 117251881Speter#elif __linux__ 118251881Speter return linux_release_name(pool); 119251881Speter#elif HAVE_UNAME 120251881Speter return release_name_from_uname(pool); 121251881Speter#else 122251881Speter return NULL; 123251881Speter#endif 124251881Speter} 125251881Speter 126251881Speterconst apr_array_header_t * 127251881Spetersvn_sysinfo__linked_libs(apr_pool_t *pool) 128251881Speter{ 129251881Speter svn_version_ext_linked_lib_t *lib; 130299742Sdim apr_array_header_t *array = apr_array_make(pool, 6, sizeof(*lib)); 131251881Speter 132251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 133251881Speter lib->name = "APR"; 134251881Speter lib->compiled_version = APR_VERSION_STRING; 135251881Speter lib->runtime_version = apr_pstrdup(pool, apr_version_string()); 136251881Speter 137251881Speter/* Don't list APR-Util if it isn't linked in, which it may not be if 138251881Speter * we're using APR 2.x+ which combined APR-Util into APR. */ 139251881Speter#ifdef APU_VERSION_STRING 140251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 141251881Speter lib->name = "APR-Util"; 142251881Speter lib->compiled_version = APU_VERSION_STRING; 143251881Speter lib->runtime_version = apr_pstrdup(pool, apu_version_string()); 144251881Speter#endif 145251881Speter 146251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 147299742Sdim lib->name = "Expat"; 148299742Sdim lib->compiled_version = apr_pstrdup(pool, svn_xml__compiled_version()); 149299742Sdim lib->runtime_version = apr_pstrdup(pool, svn_xml__runtime_version()); 150299742Sdim 151299742Sdim lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 152251881Speter lib->name = "SQLite"; 153251881Speter lib->compiled_version = apr_pstrdup(pool, svn_sqlite__compiled_version()); 154251881Speter#ifdef SVN_SQLITE_INLINE 155251881Speter lib->runtime_version = NULL; 156251881Speter#else 157251881Speter lib->runtime_version = apr_pstrdup(pool, svn_sqlite__runtime_version()); 158251881Speter#endif 159251881Speter 160299742Sdim lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 161299742Sdim lib->name = "Utf8proc"; 162299742Sdim lib->compiled_version = apr_pstrdup(pool, svn_utf__utf8proc_compiled_version()); 163299742Sdim lib->runtime_version = apr_pstrdup(pool, svn_utf__utf8proc_runtime_version()); 164299742Sdim 165299742Sdim lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t); 166299742Sdim lib->name = "ZLib"; 167299742Sdim lib->compiled_version = apr_pstrdup(pool, svn_zlib__compiled_version()); 168299742Sdim lib->runtime_version = apr_pstrdup(pool, svn_zlib__runtime_version()); 169299742Sdim 170251881Speter return array; 171251881Speter} 172251881Speter 173251881Speterconst apr_array_header_t * 174251881Spetersvn_sysinfo__loaded_libs(apr_pool_t *pool) 175251881Speter{ 176251881Speter#ifdef WIN32 177251881Speter return win32_shared_libs(pool); 178251881Speter#elif defined(SVN_HAVE_MACHO_ITERATE) 179251881Speter return macos_shared_libs(pool); 180251881Speter#else 181251881Speter return NULL; 182251881Speter#endif 183251881Speter} 184251881Speter 185251881Speter 186251881Speter#if HAVE_UNAME 187251881Speterstatic const char* 188251881Spetercanonical_host_from_uname(apr_pool_t *pool) 189251881Speter{ 190251881Speter const char *machine = "unknown"; 191251881Speter const char *vendor = "unknown"; 192251881Speter const char *sysname = "unknown"; 193251881Speter const char *sysver = ""; 194251881Speter struct utsname info; 195251881Speter 196251881Speter if (0 <= uname(&info)) 197251881Speter { 198251881Speter svn_error_t *err; 199251881Speter const char *tmp; 200251881Speter 201251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.machine, pool); 202251881Speter if (err) 203251881Speter svn_error_clear(err); 204251881Speter else 205251881Speter machine = tmp; 206251881Speter 207251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.sysname, pool); 208251881Speter if (err) 209251881Speter svn_error_clear(err); 210251881Speter else 211251881Speter { 212251881Speter char *lwr = apr_pstrdup(pool, tmp); 213251881Speter char *it = lwr; 214251881Speter while (*it) 215251881Speter { 216251881Speter if (svn_ctype_isupper(*it)) 217251881Speter *it = apr_tolower(*it); 218251881Speter ++it; 219251881Speter } 220251881Speter sysname = lwr; 221251881Speter } 222251881Speter 223251881Speter if (0 == strcmp(sysname, "darwin")) 224251881Speter vendor = "apple"; 225251881Speter if (0 == strcmp(sysname, "linux")) 226251881Speter sysver = "-gnu"; 227251881Speter else 228251881Speter { 229251881Speter err = svn_utf_cstring_to_utf8(&tmp, info.release, pool); 230251881Speter if (err) 231251881Speter svn_error_clear(err); 232251881Speter else 233251881Speter { 234251881Speter apr_size_t n = strspn(tmp, ".0123456789"); 235251881Speter if (n > 0) 236251881Speter { 237251881Speter char *ver = apr_pstrdup(pool, tmp); 238251881Speter ver[n] = 0; 239251881Speter sysver = ver; 240251881Speter } 241251881Speter else 242251881Speter sysver = tmp; 243251881Speter } 244251881Speter } 245251881Speter } 246251881Speter 247251881Speter return apr_psprintf(pool, "%s-%s-%s%s", machine, vendor, sysname, sysver); 248251881Speter} 249251881Speter 250251881Speter# ifndef SVN_HAVE_MACOS_PLIST 251251881Speter/* Generate a release name from the uname(3) info, effectively 252251881Speter returning "`uname -s` `uname -r`". */ 253251881Speterstatic const char * 254251881Speterrelease_name_from_uname(apr_pool_t *pool) 255251881Speter{ 256251881Speter struct utsname info; 257251881Speter if (0 <= uname(&info)) 258251881Speter { 259251881Speter svn_error_t *err; 260251881Speter const char *sysname; 261251881Speter const char *sysver; 262251881Speter 263251881Speter err = svn_utf_cstring_to_utf8(&sysname, info.sysname, pool); 264251881Speter if (err) 265251881Speter { 266251881Speter sysname = NULL; 267251881Speter svn_error_clear(err); 268251881Speter } 269251881Speter 270251881Speter 271251881Speter err = svn_utf_cstring_to_utf8(&sysver, info.release, pool); 272251881Speter if (err) 273251881Speter { 274251881Speter sysver = NULL; 275251881Speter svn_error_clear(err); 276251881Speter } 277251881Speter 278251881Speter if (sysname || sysver) 279251881Speter { 280251881Speter return apr_psprintf(pool, "%s%s%s", 281251881Speter (sysname ? sysname : ""), 282251881Speter (sysver ? (sysname ? " " : "") : ""), 283251881Speter (sysver ? sysver : "")); 284251881Speter } 285251881Speter } 286251881Speter return NULL; 287251881Speter} 288251881Speter# endif /* !SVN_HAVE_MACOS_PLIST */ 289251881Speter#endif /* HAVE_UNAME */ 290251881Speter 291251881Speter 292251881Speter#if __linux__ 293251881Speter/* Split a stringbuf into a key/value pair. 294299742Sdim Return the key, leaving the stripped value in the stringbuf. */ 295251881Speterstatic const char * 296251881Speterstringbuf_split_key(svn_stringbuf_t *buffer, char delim) 297251881Speter{ 298251881Speter char *key; 299251881Speter char *end; 300251881Speter 301251881Speter end = strchr(buffer->data, delim); 302251881Speter if (!end) 303251881Speter return NULL; 304251881Speter 305251881Speter svn_stringbuf_strip_whitespace(buffer); 306262253Speter 307262253Speter /* Now we split the currently allocated buffer in two parts: 308262253Speter - a const char * HEAD 309262253Speter - the remaining stringbuf_t. */ 310262253Speter 311262253Speter /* Create HEAD as '\0' terminated const char * */ 312251881Speter key = buffer->data; 313251881Speter end = strchr(key, delim); 314251881Speter *end = '\0'; 315262253Speter 316262253Speter /* And update the TAIL to be a smaller, but still valid stringbuf */ 317251881Speter buffer->data = end + 1; 318262253Speter buffer->len -= 1 + end - key; 319262253Speter buffer->blocksize -= 1 + end - key; 320262253Speter 321251881Speter svn_stringbuf_strip_whitespace(buffer); 322251881Speter 323251881Speter return key; 324251881Speter} 325251881Speter 326251881Speter/* Parse `/usr/bin/lsb_rlease --all` */ 327251881Speterstatic const char * 328251881Speterlsb_release(apr_pool_t *pool) 329251881Speter{ 330251881Speter static const char *const args[3] = 331251881Speter { 332251881Speter "/usr/bin/lsb_release", 333251881Speter "--all", 334251881Speter NULL 335251881Speter }; 336251881Speter 337251881Speter const char *distributor = NULL; 338251881Speter const char *description = NULL; 339251881Speter const char *release = NULL; 340251881Speter const char *codename = NULL; 341251881Speter 342251881Speter apr_proc_t lsbproc; 343251881Speter svn_stream_t *lsbinfo; 344251881Speter svn_error_t *err; 345251881Speter 346251881Speter /* Run /usr/bin/lsb_release --all < /dev/null 2>/dev/null */ 347251881Speter { 348251881Speter apr_file_t *stdin_handle; 349251881Speter apr_file_t *stdout_handle; 350251881Speter 351251881Speter err = svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME, 352251881Speter APR_READ, APR_OS_DEFAULT, pool); 353251881Speter if (!err) 354251881Speter err = svn_io_file_open(&stdout_handle, SVN_NULL_DEVICE_NAME, 355251881Speter APR_WRITE, APR_OS_DEFAULT, pool); 356251881Speter if (!err) 357251881Speter err = svn_io_start_cmd3(&lsbproc, NULL, args[0], args, NULL, FALSE, 358251881Speter FALSE, stdin_handle, 359251881Speter TRUE, NULL, 360251881Speter FALSE, stdout_handle, 361251881Speter pool); 362251881Speter if (err) 363251881Speter { 364251881Speter svn_error_clear(err); 365251881Speter return NULL; 366251881Speter } 367251881Speter } 368251881Speter 369251881Speter /* Parse the output and try to populate the */ 370251881Speter lsbinfo = svn_stream_from_aprfile2(lsbproc.out, TRUE, pool); 371251881Speter if (lsbinfo) 372251881Speter { 373251881Speter for (;;) 374251881Speter { 375251881Speter svn_boolean_t eof = FALSE; 376251881Speter svn_stringbuf_t *line; 377251881Speter const char *key; 378251881Speter 379251881Speter err = svn_stream_readline(lsbinfo, &line, "\n", &eof, pool); 380251881Speter if (err || eof) 381251881Speter break; 382251881Speter 383251881Speter key = stringbuf_split_key(line, ':'); 384251881Speter if (!key) 385251881Speter continue; 386251881Speter 387251881Speter if (0 == svn_cstring_casecmp(key, "Distributor ID")) 388251881Speter distributor = line->data; 389251881Speter else if (0 == svn_cstring_casecmp(key, "Description")) 390251881Speter description = line->data; 391251881Speter else if (0 == svn_cstring_casecmp(key, "Release")) 392251881Speter release = line->data; 393251881Speter else if (0 == svn_cstring_casecmp(key, "Codename")) 394251881Speter codename = line->data; 395251881Speter } 396251881Speter err = svn_error_compose_create(err, 397251881Speter svn_stream_close(lsbinfo)); 398251881Speter if (err) 399251881Speter { 400251881Speter svn_error_clear(err); 401251881Speter apr_proc_kill(&lsbproc, SIGKILL); 402251881Speter return NULL; 403251881Speter } 404251881Speter } 405251881Speter 406251881Speter /* Reap the child process */ 407251881Speter err = svn_io_wait_for_cmd(&lsbproc, "", NULL, NULL, pool); 408251881Speter if (err) 409251881Speter { 410251881Speter svn_error_clear(err); 411251881Speter return NULL; 412251881Speter } 413251881Speter 414251881Speter if (description) 415251881Speter return apr_psprintf(pool, "%s%s%s%s", description, 416251881Speter (codename ? " (" : ""), 417251881Speter (codename ? codename : ""), 418251881Speter (codename ? ")" : "")); 419251881Speter if (distributor) 420251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s", distributor, 421251881Speter (release ? " " : ""), 422251881Speter (release ? release : ""), 423251881Speter (codename ? " (" : ""), 424251881Speter (codename ? codename : ""), 425251881Speter (codename ? ")" : "")); 426251881Speter 427251881Speter return NULL; 428251881Speter} 429251881Speter 430299742Sdim/* Read /etc/os-release, as documented here: 431299742Sdim * http://www.freedesktop.org/software/systemd/man/os-release.html 432299742Sdim */ 433299742Sdimstatic const char * 434299742Sdimsystemd_release(apr_pool_t *pool) 435299742Sdim{ 436299742Sdim svn_error_t *err; 437299742Sdim svn_stream_t *stream; 438299742Sdim 439299742Sdim /* Open the file. */ 440299742Sdim err = svn_stream_open_readonly(&stream, "/etc/os-release", pool, pool); 441299742Sdim if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 442299742Sdim { 443299742Sdim svn_error_clear(err); 444299742Sdim err = svn_stream_open_readonly(&stream, "/usr/lib/os-release", pool, 445299742Sdim pool); 446299742Sdim } 447299742Sdim if (err) 448299742Sdim { 449299742Sdim svn_error_clear(err); 450299742Sdim return NULL; 451299742Sdim } 452299742Sdim 453299742Sdim /* Look for the PRETTY_NAME line. */ 454299742Sdim while (TRUE) 455299742Sdim { 456299742Sdim svn_stringbuf_t *line; 457299742Sdim svn_boolean_t eof; 458299742Sdim 459299742Sdim err = svn_stream_readline(stream, &line, "\n", &eof, pool); 460299742Sdim if (err) 461299742Sdim { 462299742Sdim svn_error_clear(err); 463299742Sdim return NULL; 464299742Sdim } 465299742Sdim 466299742Sdim if (!strncmp(line->data, "PRETTY_NAME=", 12)) 467299742Sdim { 468299742Sdim svn_stringbuf_t *release_name; 469299742Sdim 470299742Sdim /* The value may or may not be enclosed by double quotes. We don't 471299742Sdim * attempt to strip them. */ 472299742Sdim release_name = svn_stringbuf_create(line->data + 12, pool); 473299742Sdim svn_error_clear(svn_stream_close(stream)); 474299742Sdim svn_stringbuf_strip_whitespace(release_name); 475299742Sdim return release_name->data; 476299742Sdim } 477299742Sdim 478299742Sdim if (eof) 479299742Sdim break; 480299742Sdim } 481299742Sdim 482299742Sdim /* The file did not contain a PRETTY_NAME line. */ 483299742Sdim svn_error_clear(svn_stream_close(stream)); 484299742Sdim return NULL; 485299742Sdim} 486299742Sdim 487251881Speter/* Read the whole contents of a file. */ 488251881Speterstatic svn_stringbuf_t * 489251881Speterread_file_contents(const char *filename, apr_pool_t *pool) 490251881Speter{ 491251881Speter svn_error_t *err; 492251881Speter svn_stringbuf_t *buffer; 493251881Speter 494251881Speter err = svn_stringbuf_from_file2(&buffer, filename, pool); 495251881Speter if (err) 496251881Speter { 497251881Speter svn_error_clear(err); 498251881Speter return NULL; 499251881Speter } 500251881Speter 501251881Speter return buffer; 502251881Speter} 503251881Speter 504251881Speter/* Strip everything but the first line from a stringbuf. */ 505251881Speterstatic void 506251881Speterstringbuf_first_line_only(svn_stringbuf_t *buffer) 507251881Speter{ 508251881Speter char *eol = strchr(buffer->data, '\n'); 509251881Speter if (eol) 510251881Speter { 511251881Speter *eol = '\0'; 512251881Speter buffer->len = 1 + eol - buffer->data; 513251881Speter } 514251881Speter svn_stringbuf_strip_whitespace(buffer); 515251881Speter} 516251881Speter 517251881Speter/* Look at /etc/redhat_release to detect RHEL/Fedora/CentOS. */ 518251881Speterstatic const char * 519251881Speterredhat_release(apr_pool_t *pool) 520251881Speter{ 521251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/redhat-release", pool); 522251881Speter if (buffer) 523251881Speter { 524251881Speter stringbuf_first_line_only(buffer); 525251881Speter return buffer->data; 526251881Speter } 527251881Speter return NULL; 528251881Speter} 529251881Speter 530251881Speter/* Look at /etc/SuSE-release to detect non-LSB SuSE. */ 531251881Speterstatic const char * 532251881Spetersuse_release(apr_pool_t *pool) 533251881Speter{ 534251881Speter const char *release = NULL; 535251881Speter const char *codename = NULL; 536251881Speter 537251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/SuSE-release", pool); 538251881Speter svn_stringbuf_t *line; 539251881Speter svn_stream_t *stream; 540251881Speter svn_boolean_t eof; 541251881Speter svn_error_t *err; 542251881Speter if (!buffer) 543251881Speter return NULL; 544251881Speter 545251881Speter stream = svn_stream_from_stringbuf(buffer, pool); 546251881Speter err = svn_stream_readline(stream, &line, "\n", &eof, pool); 547251881Speter if (err || eof) 548251881Speter { 549251881Speter svn_error_clear(err); 550251881Speter return NULL; 551251881Speter } 552251881Speter 553251881Speter svn_stringbuf_strip_whitespace(line); 554251881Speter release = line->data; 555251881Speter 556251881Speter for (;;) 557251881Speter { 558251881Speter const char *key; 559251881Speter 560251881Speter err = svn_stream_readline(stream, &line, "\n", &eof, pool); 561251881Speter if (err || eof) 562251881Speter { 563251881Speter svn_error_clear(err); 564251881Speter break; 565251881Speter } 566251881Speter 567251881Speter key = stringbuf_split_key(line, '='); 568251881Speter if (!key) 569251881Speter continue; 570251881Speter 571251881Speter if (0 == strncmp(key, "CODENAME", 8)) 572251881Speter codename = line->data; 573251881Speter } 574251881Speter 575251881Speter return apr_psprintf(pool, "%s%s%s%s", 576251881Speter release, 577251881Speter (codename ? " (" : ""), 578251881Speter (codename ? codename : ""), 579251881Speter (codename ? ")" : "")); 580251881Speter} 581251881Speter 582251881Speter/* Look at /etc/debian_version to detect non-LSB Debian. */ 583251881Speterstatic const char * 584251881Speterdebian_release(apr_pool_t *pool) 585251881Speter{ 586251881Speter svn_stringbuf_t *buffer = read_file_contents("/etc/debian_version", pool); 587251881Speter if (!buffer) 588251881Speter return NULL; 589251881Speter 590251881Speter stringbuf_first_line_only(buffer); 591299742Sdim return apr_pstrcat(pool, "Debian ", buffer->data, SVN_VA_NULL); 592251881Speter} 593251881Speter 594251881Speter/* Try to find the Linux distribution name, or return info from uname. */ 595251881Speterstatic const char * 596251881Speterlinux_release_name(apr_pool_t *pool) 597251881Speter{ 598251881Speter const char *uname_release = release_name_from_uname(pool); 599251881Speter 600251881Speter /* Try anything that has /usr/bin/lsb_release. 601251881Speter Covers, for example, Debian, Ubuntu and SuSE. */ 602251881Speter const char *release_name = lsb_release(pool); 603251881Speter 604299742Sdim /* Try the systemd way (covers Arch). */ 605299742Sdim if (!release_name) 606299742Sdim release_name = systemd_release(pool); 607299742Sdim 608251881Speter /* Try RHEL/Fedora/CentOS */ 609251881Speter if (!release_name) 610251881Speter release_name = redhat_release(pool); 611251881Speter 612251881Speter /* Try Non-LSB SuSE */ 613251881Speter if (!release_name) 614251881Speter release_name = suse_release(pool); 615251881Speter 616251881Speter /* Try non-LSB Debian */ 617251881Speter if (!release_name) 618251881Speter release_name = debian_release(pool); 619251881Speter 620251881Speter if (!release_name) 621251881Speter return uname_release; 622251881Speter 623251881Speter if (!uname_release) 624251881Speter return release_name; 625251881Speter 626251881Speter return apr_psprintf(pool, "%s [%s]", release_name, uname_release); 627251881Speter} 628251881Speter#endif /* __linux__ */ 629251881Speter 630251881Speter 631251881Speter#ifdef WIN32 632251881Spetertypedef DWORD (WINAPI *FNGETNATIVESYSTEMINFO)(LPSYSTEM_INFO); 633262253Spetertypedef BOOL (WINAPI *FNENUMPROCESSMODULES) (HANDLE, HMODULE*, DWORD, LPDWORD); 634251881Speter 635299742Sdimsvn_boolean_t 636299742Sdimsvn_sysinfo___fill_windows_version(OSVERSIONINFOEXW *version_info) 637299742Sdim{ 638299742Sdim memset(version_info, 0, sizeof(*version_info)); 639299742Sdim 640299742Sdim version_info->dwOSVersionInfoSize = sizeof(*version_info); 641299742Sdim 642299742Sdim /* Kill warnings with the Windows 8 and later platform SDK */ 643299742Sdim#if _MSC_VER > 1600 && NTDDI_VERSION >= _0x06020000 644299742Sdim /* Windows 8 deprecated the API to retrieve the Windows version to avoid 645299742Sdim backwards compatibility problems... It might return a constant version 646299742Sdim in future Windows versions... But let's kill the warning. 647299742Sdim 648299742Sdim We can implementation this using a different function later. */ 649299742Sdim#pragma warning(push) 650299742Sdim#pragma warning(disable: 4996) 651299742Sdim#endif 652299742Sdim 653299742Sdim /* Prototype supports OSVERSIONINFO */ 654299742Sdim return GetVersionExW((LPVOID)version_info); 655299742Sdim#if _MSC_VER > 1600 && NTDDI_VERSION >= _0x06020000 656299742Sdim#pragma warning(pop) 657299742Sdim#pragma warning(disable: 4996) 658299742Sdim#endif 659299742Sdim} 660299742Sdim 661299742Sdim/* Get system info, and try to tell the difference between the native 662299742Sdim system type and the runtime environment of the current process. 663299742Sdim Populate results in SYSINFO and LOCAL_SYSINFO (optional). */ 664251881Speterstatic BOOL 665251881Spetersystem_info(SYSTEM_INFO *sysinfo, 666299742Sdim SYSTEM_INFO *local_sysinfo) 667251881Speter{ 668251881Speter FNGETNATIVESYSTEMINFO GetNativeSystemInfo_ = (FNGETNATIVESYSTEMINFO) 669251881Speter GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); 670251881Speter 671299742Sdim memset(sysinfo, 0, sizeof *sysinfo); 672251881Speter if (local_sysinfo) 673251881Speter { 674299742Sdim memset(local_sysinfo, 0, sizeof *local_sysinfo); 675251881Speter GetSystemInfo(local_sysinfo); 676251881Speter if (GetNativeSystemInfo_) 677251881Speter GetNativeSystemInfo_(sysinfo); 678251881Speter else 679251881Speter memcpy(sysinfo, local_sysinfo, sizeof *sysinfo); 680251881Speter } 681251881Speter else 682251881Speter GetSystemInfo(sysinfo); 683251881Speter 684251881Speter return TRUE; 685251881Speter} 686251881Speter 687251881Speter/* Map the proccessor type from SYSINFO to a string. */ 688251881Speterstatic const char * 689251881Speterprocessor_name(SYSTEM_INFO *sysinfo) 690251881Speter{ 691251881Speter switch (sysinfo->wProcessorArchitecture) 692251881Speter { 693251881Speter case PROCESSOR_ARCHITECTURE_AMD64: return "x86_64"; 694251881Speter case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; 695251881Speter case PROCESSOR_ARCHITECTURE_INTEL: return "x86"; 696251881Speter case PROCESSOR_ARCHITECTURE_MIPS: return "mips"; 697251881Speter case PROCESSOR_ARCHITECTURE_ALPHA: return "alpha32"; 698251881Speter case PROCESSOR_ARCHITECTURE_PPC: return "powerpc"; 699251881Speter case PROCESSOR_ARCHITECTURE_SHX: return "shx"; 700251881Speter case PROCESSOR_ARCHITECTURE_ARM: return "arm"; 701251881Speter case PROCESSOR_ARCHITECTURE_ALPHA64: return "alpha"; 702251881Speter case PROCESSOR_ARCHITECTURE_MSIL: return "msil"; 703251881Speter case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: return "x86_wow64"; 704251881Speter default: return "unknown"; 705251881Speter } 706251881Speter} 707251881Speter 708251881Speter/* Return the Windows-specific canonical host name. */ 709251881Speterstatic const char * 710251881Speterwin32_canonical_host(apr_pool_t *pool) 711251881Speter{ 712251881Speter SYSTEM_INFO sysinfo; 713251881Speter SYSTEM_INFO local_sysinfo; 714251881Speter OSVERSIONINFOEXW osinfo; 715251881Speter 716299742Sdim if (system_info(&sysinfo, &local_sysinfo) 717299742Sdim && svn_sysinfo___fill_windows_version(&osinfo)) 718251881Speter { 719251881Speter const char *arch = processor_name(&local_sysinfo); 720251881Speter const char *machine = processor_name(&sysinfo); 721251881Speter const char *vendor = "microsoft"; 722251881Speter const char *sysname = "windows"; 723251881Speter const char *sysver = apr_psprintf(pool, "%u.%u.%u", 724251881Speter (unsigned int)osinfo.dwMajorVersion, 725251881Speter (unsigned int)osinfo.dwMinorVersion, 726251881Speter (unsigned int)osinfo.dwBuildNumber); 727251881Speter 728251881Speter if (sysinfo.wProcessorArchitecture 729251881Speter == local_sysinfo.wProcessorArchitecture) 730251881Speter return apr_psprintf(pool, "%s-%s-%s%s", 731251881Speter machine, vendor, sysname, sysver); 732251881Speter return apr_psprintf(pool, "%s/%s-%s-%s%s", 733251881Speter arch, machine, vendor, sysname, sysver); 734251881Speter } 735251881Speter 736251881Speter return "unknown-microsoft-windows"; 737251881Speter} 738251881Speter 739251881Speter/* Convert a Unicode string to UTF-8. */ 740251881Speterstatic char * 741251881Speterwcs_to_utf8(const wchar_t *wcs, apr_pool_t *pool) 742251881Speter{ 743251881Speter const int bufsize = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, 744251881Speter NULL, 0, NULL, NULL); 745251881Speter if (bufsize > 0) 746251881Speter { 747251881Speter char *const utf8 = apr_palloc(pool, bufsize + 1); 748251881Speter WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf8, bufsize, NULL, NULL); 749251881Speter return utf8; 750251881Speter } 751251881Speter return NULL; 752251881Speter} 753251881Speter 754251881Speter/* Query the value called NAME of the registry key HKEY. */ 755251881Speterstatic char * 756251881Speterregistry_value(HKEY hkey, wchar_t *name, apr_pool_t *pool) 757251881Speter{ 758251881Speter DWORD size; 759251881Speter wchar_t *value; 760251881Speter 761251881Speter if (RegQueryValueExW(hkey, name, NULL, NULL, NULL, &size)) 762251881Speter return NULL; 763251881Speter 764251881Speter value = apr_palloc(pool, size + sizeof *value); 765251881Speter if (RegQueryValueExW(hkey, name, NULL, NULL, (void*)value, &size)) 766251881Speter return NULL; 767251881Speter value[size / sizeof *value] = 0; 768251881Speter return wcs_to_utf8(value, pool); 769251881Speter} 770251881Speter 771251881Speter/* Try to glean the Windows release name and associated info from the 772251881Speter registry. Failing that, construct a release name from the version 773251881Speter info. */ 774251881Speterstatic const char * 775251881Speterwin32_release_name(apr_pool_t *pool) 776251881Speter{ 777251881Speter SYSTEM_INFO sysinfo; 778251881Speter OSVERSIONINFOEXW osinfo; 779251881Speter HKEY hkcv; 780251881Speter 781299742Sdim if (!system_info(&sysinfo, NULL) 782299742Sdim || !svn_sysinfo___fill_windows_version(&osinfo)) 783251881Speter return NULL; 784251881Speter 785251881Speter if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, 786251881Speter L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 787251881Speter 0, KEY_QUERY_VALUE, &hkcv)) 788251881Speter { 789251881Speter const char *release = registry_value(hkcv, L"ProductName", pool); 790251881Speter const char *spack = registry_value(hkcv, L"CSDVersion", pool); 791251881Speter const char *curver = registry_value(hkcv, L"CurrentVersion", pool); 792251881Speter const char *curtype = registry_value(hkcv, L"CurrentType", pool); 793251881Speter const char *install = registry_value(hkcv, L"InstallationType", pool); 794251881Speter const char *curbuild = registry_value(hkcv, L"CurrentBuildNumber", pool); 795251881Speter 796251881Speter if (!spack && *osinfo.szCSDVersion) 797251881Speter spack = wcs_to_utf8(osinfo.szCSDVersion, pool); 798251881Speter 799251881Speter if (!curbuild) 800251881Speter curbuild = registry_value(hkcv, L"CurrentBuild", pool); 801251881Speter 802251881Speter if (release || spack || curver || curtype || curbuild) 803251881Speter { 804251881Speter const char *bootinfo = ""; 805251881Speter if (curver || install || curtype) 806251881Speter { 807251881Speter bootinfo = apr_psprintf(pool, "[%s%s%s%s%s]", 808251881Speter (curver ? curver : ""), 809251881Speter (install ? (curver ? " " : "") : ""), 810251881Speter (install ? install : ""), 811251881Speter (curtype 812251881Speter ? (curver||install ? " " : "") 813251881Speter : ""), 814251881Speter (curtype ? curtype : "")); 815251881Speter } 816251881Speter 817251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s%s", 818251881Speter (release ? release : ""), 819251881Speter (spack ? (release ? ", " : "") : ""), 820251881Speter (spack ? spack : ""), 821251881Speter (curbuild 822251881Speter ? (release||spack ? ", build " : "build ") 823251881Speter : ""), 824251881Speter (curbuild ? curbuild : ""), 825251881Speter (bootinfo 826251881Speter ? (release||spack||curbuild ? " " : "") 827251881Speter : ""), 828251881Speter (bootinfo ? bootinfo : "")); 829251881Speter } 830251881Speter } 831251881Speter 832251881Speter if (*osinfo.szCSDVersion) 833251881Speter { 834251881Speter const char *servicepack = wcs_to_utf8(osinfo.szCSDVersion, pool); 835251881Speter 836251881Speter if (servicepack) 837251881Speter return apr_psprintf(pool, "Windows NT %u.%u, %s, build %u", 838251881Speter (unsigned int)osinfo.dwMajorVersion, 839251881Speter (unsigned int)osinfo.dwMinorVersion, 840251881Speter servicepack, 841251881Speter (unsigned int)osinfo.dwBuildNumber); 842251881Speter 843251881Speter /* Assume wServicePackMajor > 0 if szCSDVersion is not empty */ 844251881Speter if (osinfo.wServicePackMinor) 845251881Speter return apr_psprintf(pool, "Windows NT %u.%u SP%u.%u, build %u", 846251881Speter (unsigned int)osinfo.dwMajorVersion, 847251881Speter (unsigned int)osinfo.dwMinorVersion, 848251881Speter (unsigned int)osinfo.wServicePackMajor, 849251881Speter (unsigned int)osinfo.wServicePackMinor, 850251881Speter (unsigned int)osinfo.dwBuildNumber); 851251881Speter 852251881Speter return apr_psprintf(pool, "Windows NT %u.%u SP%u, build %u", 853251881Speter (unsigned int)osinfo.dwMajorVersion, 854251881Speter (unsigned int)osinfo.dwMinorVersion, 855251881Speter (unsigned int)osinfo.wServicePackMajor, 856251881Speter (unsigned int)osinfo.dwBuildNumber); 857251881Speter } 858251881Speter 859251881Speter return apr_psprintf(pool, "Windows NT %u.%u, build %u", 860251881Speter (unsigned int)osinfo.dwMajorVersion, 861251881Speter (unsigned int)osinfo.dwMinorVersion, 862251881Speter (unsigned int)osinfo.dwBuildNumber); 863251881Speter} 864251881Speter 865251881Speter 866251881Speter/* Get a list of handles of shared libs loaded by the current 867251881Speter process. Returns a NULL-terminated array alocated from POOL. */ 868251881Speterstatic HMODULE * 869251881Speterenum_loaded_modules(apr_pool_t *pool) 870251881Speter{ 871262253Speter HMODULE psapi_dll = 0; 872251881Speter HANDLE current = GetCurrentProcess(); 873251881Speter HMODULE dummy[1]; 874251881Speter HMODULE *handles; 875251881Speter DWORD size; 876262253Speter FNENUMPROCESSMODULES EnumProcessModules_; 877251881Speter 878262253Speter psapi_dll = GetModuleHandleA("psapi.dll"); 879262253Speter 880262253Speter if (!psapi_dll) 881262253Speter { 882262253Speter /* Load and never unload, just like static linking */ 883262253Speter psapi_dll = LoadLibraryA("psapi.dll"); 884262253Speter } 885262253Speter 886262253Speter if (!psapi_dll) 887262253Speter return NULL; 888262253Speter 889262253Speter EnumProcessModules_ = (FNENUMPROCESSMODULES) 890262253Speter GetProcAddress(psapi_dll, "EnumProcessModules"); 891262253Speter 892262253Speter /* Before Windows XP psapi was an optional module */ 893262253Speter if (! EnumProcessModules_) 894251881Speter return NULL; 895251881Speter 896262253Speter if (!EnumProcessModules_(current, dummy, sizeof(dummy), &size)) 897262253Speter return NULL; 898262253Speter 899251881Speter handles = apr_palloc(pool, size + sizeof *handles); 900262253Speter if (! EnumProcessModules_(current, handles, size, &size)) 901251881Speter return NULL; 902251881Speter handles[size / sizeof *handles] = NULL; 903251881Speter return handles; 904251881Speter} 905251881Speter 906251881Speter/* Find the version number, if any, embedded in FILENAME. */ 907251881Speterstatic const char * 908251881Speterfile_version_number(const wchar_t *filename, apr_pool_t *pool) 909251881Speter{ 910251881Speter VS_FIXEDFILEINFO info; 911251881Speter unsigned int major, minor, micro, nano; 912251881Speter void *data; 913251881Speter DWORD data_size = GetFileVersionInfoSizeW(filename, NULL); 914251881Speter void *vinfo; 915251881Speter UINT vinfo_size; 916251881Speter 917251881Speter if (!data_size) 918251881Speter return NULL; 919251881Speter 920251881Speter data = apr_palloc(pool, data_size); 921251881Speter if (!GetFileVersionInfoW(filename, 0, data_size, data)) 922251881Speter return NULL; 923251881Speter 924251881Speter if (!VerQueryValueW(data, L"\\", &vinfo, &vinfo_size)) 925251881Speter return NULL; 926251881Speter 927251881Speter if (vinfo_size != sizeof info) 928251881Speter return NULL; 929251881Speter 930251881Speter memcpy(&info, vinfo, sizeof info); 931251881Speter major = (info.dwFileVersionMS >> 16) & 0xFFFF; 932251881Speter minor = info.dwFileVersionMS & 0xFFFF; 933251881Speter micro = (info.dwFileVersionLS >> 16) & 0xFFFF; 934251881Speter nano = info.dwFileVersionLS & 0xFFFF; 935251881Speter 936251881Speter if (!nano) 937251881Speter { 938251881Speter if (!micro) 939251881Speter return apr_psprintf(pool, "%u.%u", major, minor); 940251881Speter else 941251881Speter return apr_psprintf(pool, "%u.%u.%u", major, minor, micro); 942251881Speter } 943251881Speter return apr_psprintf(pool, "%u.%u.%u.%u", major, minor, micro, nano); 944251881Speter} 945251881Speter 946251881Speter/* List the shared libraries loaded by the current process. */ 947251881Speterstatic const apr_array_header_t * 948251881Speterwin32_shared_libs(apr_pool_t *pool) 949251881Speter{ 950251881Speter apr_array_header_t *array = NULL; 951251881Speter wchar_t buffer[MAX_PATH + 1]; 952251881Speter HMODULE *handles = enum_loaded_modules(pool); 953251881Speter HMODULE *module; 954251881Speter 955251881Speter for (module = handles; module && *module; ++module) 956251881Speter { 957251881Speter const char *filename; 958251881Speter const char *version; 959251881Speter if (GetModuleFileNameW(*module, buffer, MAX_PATH)) 960251881Speter { 961251881Speter buffer[MAX_PATH] = 0; 962251881Speter 963251881Speter version = file_version_number(buffer, pool); 964251881Speter filename = wcs_to_utf8(buffer, pool); 965251881Speter if (filename) 966251881Speter { 967251881Speter svn_version_ext_loaded_lib_t *lib; 968251881Speter 969251881Speter if (!array) 970251881Speter { 971251881Speter array = apr_array_make(pool, 32, sizeof(*lib)); 972251881Speter } 973251881Speter lib = &APR_ARRAY_PUSH(array, svn_version_ext_loaded_lib_t); 974251881Speter lib->name = svn_dirent_local_style(filename, pool); 975251881Speter lib->version = version; 976251881Speter } 977251881Speter } 978251881Speter } 979251881Speter 980251881Speter return array; 981251881Speter} 982251881Speter#endif /* WIN32 */ 983251881Speter 984251881Speter 985251881Speter#ifdef SVN_HAVE_MACOS_PLIST 986299742Sdim/* implements svn_write_fn_t to copy the data into a CFMutableDataRef that's 987299742Sdim * in the baton. */ 988299742Sdimstatic svn_error_t * 989299742Sdimwrite_to_cfmutabledata(void *baton, const char *data, apr_size_t *len) 990299742Sdim{ 991299742Sdim CFMutableDataRef *resource = (CFMutableDataRef *) baton; 992299742Sdim 993299742Sdim CFDataAppendBytes(*resource, (UInt8 *)data, *len); 994299742Sdim 995299742Sdim return SVN_NO_ERROR; 996299742Sdim} 997299742Sdim 998251881Speter/* Load the SystemVersion.plist or ServerVersion.plist file into a 999251881Speter property list. Set SERVER to TRUE if the file read was 1000251881Speter ServerVersion.plist. */ 1001251881Speterstatic CFDictionaryRef 1002251881Spetersystem_version_plist(svn_boolean_t *server, apr_pool_t *pool) 1003251881Speter{ 1004299742Sdim static const char server_version[] = 1005251881Speter "/System/Library/CoreServices/ServerVersion.plist"; 1006299742Sdim static const char system_version[] = 1007251881Speter "/System/Library/CoreServices/SystemVersion.plist"; 1008299742Sdim svn_stream_t *read_stream, *write_stream; 1009299742Sdim svn_error_t *err; 1010251881Speter CFPropertyListRef plist = NULL; 1011299742Sdim CFMutableDataRef resource = CFDataCreateMutable(kCFAllocatorDefault, 0); 1012251881Speter 1013299742Sdim /* failed getting the CFMutableDataRef, shouldn't happen */ 1014299742Sdim if (!resource) 1015251881Speter return NULL; 1016251881Speter 1017299742Sdim /* Try to open the plist files to get the data */ 1018299742Sdim err = svn_stream_open_readonly(&read_stream, server_version, pool, pool); 1019299742Sdim if (err) 1020251881Speter { 1021299742Sdim if (!APR_STATUS_IS_ENOENT(err->apr_err)) 1022251881Speter { 1023299742Sdim svn_error_clear(err); 1024299742Sdim CFRelease(resource); 1025251881Speter return NULL; 1026251881Speter } 1027251881Speter else 1028251881Speter { 1029299742Sdim svn_error_clear(err); 1030299742Sdim err = svn_stream_open_readonly(&read_stream, system_version, 1031299742Sdim pool, pool); 1032299742Sdim if (err) 1033299742Sdim { 1034299742Sdim svn_error_clear(err); 1035299742Sdim CFRelease(resource); 1036299742Sdim return NULL; 1037299742Sdim } 1038299742Sdim 1039251881Speter *server = FALSE; 1040251881Speter } 1041251881Speter } 1042251881Speter else 1043251881Speter { 1044251881Speter *server = TRUE; 1045251881Speter } 1046251881Speter 1047299742Sdim /* copy the data onto the CFMutableDataRef to allow us to provide it to 1048299742Sdim * the CoreFoundation functions that parse proprerty lists */ 1049299742Sdim write_stream = svn_stream_create(&resource, pool); 1050299742Sdim svn_stream_set_write(write_stream, write_to_cfmutabledata); 1051299742Sdim err = svn_stream_copy3(read_stream, write_stream, NULL, NULL, pool); 1052299742Sdim if (err) 1053299742Sdim { 1054299742Sdim svn_error_clear(err); 1055299742Sdim return NULL; 1056299742Sdim } 1057299742Sdim 1058299742Sdim#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 1059299742Sdim /* This function is only available from Mac OS 10.6 onward. */ 1060299742Sdim plist = CFPropertyListCreateWithData(kCFAllocatorDefault, resource, 1061299742Sdim kCFPropertyListImmutable, 1062299742Sdim NULL, NULL); 1063299742Sdim#else /* Mac OS 10.5 or earlier */ 1064299742Sdim /* This function obsolete and deprecated since Mac OS 10.10. */ 1065251881Speter plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource, 1066251881Speter kCFPropertyListImmutable, 1067299742Sdim NULL); 1068299742Sdim#endif /* MAC_OS_X_VERSION_10_6 */ 1069299742Sdim 1070251881Speter if (resource) 1071251881Speter CFRelease(resource); 1072251881Speter 1073299742Sdim if (!plist) 1074299742Sdim return NULL; 1075299742Sdim 1076251881Speter if (CFDictionaryGetTypeID() != CFGetTypeID(plist)) 1077251881Speter { 1078251881Speter /* Oops ... this really should be a dict. */ 1079251881Speter CFRelease(plist); 1080251881Speter return NULL; 1081251881Speter } 1082251881Speter 1083251881Speter return plist; 1084251881Speter} 1085251881Speter 1086251881Speter/* Return the value for KEY from PLIST, or NULL if not available. */ 1087251881Speterstatic const char * 1088251881Spetervalue_from_dict(CFDictionaryRef plist, CFStringRef key, apr_pool_t *pool) 1089251881Speter{ 1090251881Speter CFStringRef valref; 1091251881Speter CFIndex bufsize; 1092251881Speter const void *valptr; 1093251881Speter const char *value; 1094251881Speter 1095251881Speter if (!CFDictionaryGetValueIfPresent(plist, key, &valptr)) 1096251881Speter return NULL; 1097251881Speter 1098251881Speter valref = valptr; 1099251881Speter if (CFStringGetTypeID() != CFGetTypeID(valref)) 1100251881Speter return NULL; 1101251881Speter 1102251881Speter value = CFStringGetCStringPtr(valref, kCFStringEncodingUTF8); 1103251881Speter if (value) 1104251881Speter return apr_pstrdup(pool, value); 1105251881Speter 1106251881Speter bufsize = 5 * CFStringGetLength(valref) + 1; 1107251881Speter value = apr_palloc(pool, bufsize); 1108251881Speter if (!CFStringGetCString(valref, (char*)value, bufsize, 1109251881Speter kCFStringEncodingUTF8)) 1110251881Speter value = NULL; 1111251881Speter 1112251881Speter return value; 1113251881Speter} 1114251881Speter 1115251881Speter/* Return the commercial name of the OS, given the version number in 1116251881Speter a format that matches the regular expression /^10\.\d+(\..*)?$/ */ 1117251881Speterstatic const char * 1118251881Speterrelease_name_from_version(const char *osver) 1119251881Speter{ 1120251881Speter char *end = NULL; 1121251881Speter unsigned long num = strtoul(osver, &end, 10); 1122251881Speter 1123251881Speter if (!end || *end != '.' || num != 10) 1124251881Speter return NULL; 1125251881Speter 1126251881Speter osver = end + 1; 1127251881Speter end = NULL; 1128251881Speter num = strtoul(osver, &end, 10); 1129251881Speter if (!end || (*end && *end != '.')) 1130251881Speter return NULL; 1131251881Speter 1132251881Speter /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */ 1133251881Speter switch(num) 1134251881Speter { 1135299742Sdim case 0: return "Cheetah"; 1136299742Sdim case 1: return "Puma"; 1137299742Sdim case 2: return "Jaguar"; 1138299742Sdim case 3: return "Panther"; 1139299742Sdim case 4: return "Tiger"; 1140299742Sdim case 5: return "Leopard"; 1141299742Sdim case 6: return "Snow Leopard"; 1142299742Sdim case 7: return "Lion"; 1143299742Sdim case 8: return "Mountain Lion"; 1144299742Sdim case 9: return "Mavericks"; 1145299742Sdim case 10: return "Yosemite"; 1146309512Speter case 11: return "El Capitan"; 1147309512Speter case 12: return "Sierra"; 1148251881Speter } 1149251881Speter 1150251881Speter return NULL; 1151251881Speter} 1152251881Speter 1153251881Speter/* Construct the release name from information stored in the Mac OS X 1154251881Speter "SystemVersion.plist" file (or ServerVersion.plist, for Mac Os 1155251881Speter Server. */ 1156251881Speterstatic const char * 1157251881Spetermacos_release_name(apr_pool_t *pool) 1158251881Speter{ 1159251881Speter svn_boolean_t server; 1160251881Speter CFDictionaryRef plist = system_version_plist(&server, pool); 1161251881Speter 1162251881Speter if (plist) 1163251881Speter { 1164251881Speter const char *osname = value_from_dict(plist, CFSTR("ProductName"), pool); 1165251881Speter const char *osver = value_from_dict(plist, 1166251881Speter CFSTR("ProductUserVisibleVersion"), 1167251881Speter pool); 1168251881Speter const char *build = value_from_dict(plist, 1169251881Speter CFSTR("ProductBuildVersion"), 1170251881Speter pool); 1171251881Speter const char *release; 1172251881Speter 1173251881Speter if (!osver) 1174251881Speter osver = value_from_dict(plist, CFSTR("ProductVersion"), pool); 1175251881Speter release = release_name_from_version(osver); 1176251881Speter 1177251881Speter CFRelease(plist); 1178251881Speter return apr_psprintf(pool, "%s%s%s%s%s%s%s%s", 1179251881Speter (osname ? osname : ""), 1180251881Speter (osver ? (osname ? " " : "") : ""), 1181251881Speter (osver ? osver : ""), 1182251881Speter (release ? (osname||osver ? " " : "") : ""), 1183251881Speter (release ? release : ""), 1184251881Speter (build 1185251881Speter ? (osname||osver||release ? ", " : "") 1186251881Speter : ""), 1187251881Speter (build 1188251881Speter ? (server ? "server build " : "build ") 1189251881Speter : ""), 1190251881Speter (build ? build : "")); 1191251881Speter } 1192251881Speter 1193251881Speter return NULL; 1194251881Speter} 1195251881Speter#endif /* SVN_HAVE_MACOS_PLIST */ 1196251881Speter 1197251881Speter#ifdef SVN_HAVE_MACHO_ITERATE 1198251881Speter/* List the shared libraries loaded by the current process. 1199251881Speter Ignore frameworks and system libraries, they're just clutter. */ 1200251881Speterstatic const apr_array_header_t * 1201251881Spetermacos_shared_libs(apr_pool_t *pool) 1202251881Speter{ 1203251881Speter static const char slb_prefix[] = "/usr/lib/system/"; 1204251881Speter static const char fwk_prefix[] = "/System/Library/Frameworks/"; 1205251881Speter static const char pfk_prefix[] = "/System/Library/PrivateFrameworks/"; 1206251881Speter 1207251881Speter const size_t slb_prefix_len = strlen(slb_prefix); 1208251881Speter const size_t fwk_prefix_len = strlen(fwk_prefix); 1209251881Speter const size_t pfk_prefix_len = strlen(pfk_prefix); 1210251881Speter 1211251881Speter apr_array_header_t *result = NULL; 1212251881Speter apr_array_header_t *dylibs = NULL; 1213251881Speter 1214251881Speter uint32_t i; 1215251881Speter for (i = 0;; ++i) 1216251881Speter { 1217251881Speter const struct mach_header *header = _dyld_get_image_header(i); 1218251881Speter const char *filename = _dyld_get_image_name(i); 1219251881Speter const char *version; 1220251881Speter char *truename; 1221251881Speter svn_version_ext_loaded_lib_t *lib; 1222251881Speter 1223251881Speter if (!(header && filename)) 1224251881Speter break; 1225251881Speter 1226251881Speter switch (header->cputype) 1227251881Speter { 1228251881Speter case CPU_TYPE_I386: version = _("Intel"); break; 1229251881Speter case CPU_TYPE_X86_64: version = _("Intel 64-bit"); break; 1230251881Speter case CPU_TYPE_POWERPC: version = _("PowerPC"); break; 1231251881Speter case CPU_TYPE_POWERPC64: version = _("PowerPC 64-bit"); break; 1232251881Speter default: 1233251881Speter version = NULL; 1234251881Speter } 1235251881Speter 1236251881Speter if (0 == apr_filepath_merge(&truename, "", filename, 1237251881Speter APR_FILEPATH_NATIVE 1238251881Speter | APR_FILEPATH_TRUENAME, 1239251881Speter pool)) 1240251881Speter filename = truename; 1241251881Speter else 1242251881Speter filename = apr_pstrdup(pool, filename); 1243251881Speter 1244251881Speter if (0 == strncmp(filename, slb_prefix, slb_prefix_len) 1245251881Speter || 0 == strncmp(filename, fwk_prefix, fwk_prefix_len) 1246251881Speter || 0 == strncmp(filename, pfk_prefix, pfk_prefix_len)) 1247251881Speter { 1248251881Speter /* Ignore frameworks and system libraries. */ 1249251881Speter continue; 1250251881Speter } 1251251881Speter 1252251881Speter if (header->filetype == MH_EXECUTE) 1253251881Speter { 1254251881Speter /* Make sure the program filename is first in the list */ 1255251881Speter if (!result) 1256251881Speter { 1257251881Speter result = apr_array_make(pool, 32, sizeof(*lib)); 1258251881Speter } 1259251881Speter lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t); 1260251881Speter } 1261251881Speter else 1262251881Speter { 1263251881Speter if (!dylibs) 1264251881Speter { 1265251881Speter dylibs = apr_array_make(pool, 32, sizeof(*lib)); 1266251881Speter } 1267251881Speter lib = &APR_ARRAY_PUSH(dylibs, svn_version_ext_loaded_lib_t); 1268251881Speter } 1269251881Speter 1270251881Speter lib->name = filename; 1271251881Speter lib->version = version; 1272251881Speter } 1273251881Speter 1274251881Speter /* Gather results into one array. */ 1275251881Speter if (dylibs) 1276251881Speter { 1277251881Speter if (result) 1278251881Speter apr_array_cat(result, dylibs); 1279251881Speter else 1280251881Speter result = dylibs; 1281251881Speter } 1282251881Speter 1283251881Speter return result; 1284251881Speter} 1285251881Speter#endif /* SVN_HAVE_MACHO_ITERATE */ 1286