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