sysinfo.c revision 257936
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);
549257936Spetertypedef 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{
766257936Speter  HMODULE psapi_dll = 0;
767251881Speter  HANDLE current = GetCurrentProcess();
768251881Speter  HMODULE dummy[1];
769251881Speter  HMODULE *handles;
770251881Speter  DWORD size;
771257936Speter  FNENUMPROCESSMODULES EnumProcessModules_;
772251881Speter
773257936Speter  psapi_dll = GetModuleHandleA("psapi.dll");
774257936Speter
775257936Speter  if (!psapi_dll)
776257936Speter    {
777257936Speter      /* Load and never unload, just like static linking */
778257936Speter      psapi_dll = LoadLibraryA("psapi.dll");
779257936Speter    }
780257936Speter
781257936Speter  if (!psapi_dll)
782257936Speter      return NULL;
783257936Speter
784257936Speter  EnumProcessModules_ = (FNENUMPROCESSMODULES)
785257936Speter                              GetProcAddress(psapi_dll, "EnumProcessModules");
786257936Speter
787257936Speter  /* Before Windows XP psapi was an optional module */
788257936Speter  if (! EnumProcessModules_)
789251881Speter    return NULL;
790251881Speter
791257936Speter  if (!EnumProcessModules_(current, dummy, sizeof(dummy), &size))
792257936Speter    return NULL;
793257936Speter
794251881Speter  handles = apr_palloc(pool, size + sizeof *handles);
795257936Speter  if (! EnumProcessModules_(current, handles, size, &size))
796251881Speter    return NULL;
797251881Speter  handles[size / sizeof *handles] = NULL;
798251881Speter  return handles;
799251881Speter}
800251881Speter
801251881Speter/* Find the version number, if any, embedded in FILENAME. */
802251881Speterstatic const char *
803251881Speterfile_version_number(const wchar_t *filename, apr_pool_t *pool)
804251881Speter{
805251881Speter  VS_FIXEDFILEINFO info;
806251881Speter  unsigned int major, minor, micro, nano;
807251881Speter  void *data;
808251881Speter  DWORD data_size = GetFileVersionInfoSizeW(filename, NULL);
809251881Speter  void *vinfo;
810251881Speter  UINT vinfo_size;
811251881Speter
812251881Speter  if (!data_size)
813251881Speter    return NULL;
814251881Speter
815251881Speter  data = apr_palloc(pool, data_size);
816251881Speter  if (!GetFileVersionInfoW(filename, 0, data_size, data))
817251881Speter    return NULL;
818251881Speter
819251881Speter  if (!VerQueryValueW(data, L"\\", &vinfo, &vinfo_size))
820251881Speter    return NULL;
821251881Speter
822251881Speter  if (vinfo_size != sizeof info)
823251881Speter    return NULL;
824251881Speter
825251881Speter  memcpy(&info, vinfo, sizeof info);
826251881Speter  major = (info.dwFileVersionMS >> 16) & 0xFFFF;
827251881Speter  minor = info.dwFileVersionMS & 0xFFFF;
828251881Speter  micro = (info.dwFileVersionLS >> 16) & 0xFFFF;
829251881Speter  nano = info.dwFileVersionLS & 0xFFFF;
830251881Speter
831251881Speter  if (!nano)
832251881Speter    {
833251881Speter      if (!micro)
834251881Speter        return apr_psprintf(pool, "%u.%u", major, minor);
835251881Speter      else
836251881Speter        return apr_psprintf(pool, "%u.%u.%u", major, minor, micro);
837251881Speter    }
838251881Speter  return apr_psprintf(pool, "%u.%u.%u.%u", major, minor, micro, nano);
839251881Speter}
840251881Speter
841251881Speter/* List the shared libraries loaded by the current process. */
842251881Speterstatic const apr_array_header_t *
843251881Speterwin32_shared_libs(apr_pool_t *pool)
844251881Speter{
845251881Speter  apr_array_header_t *array = NULL;
846251881Speter  wchar_t buffer[MAX_PATH + 1];
847251881Speter  HMODULE *handles = enum_loaded_modules(pool);
848251881Speter  HMODULE *module;
849251881Speter
850251881Speter  for (module = handles; module && *module; ++module)
851251881Speter    {
852251881Speter      const char *filename;
853251881Speter      const char *version;
854251881Speter      if (GetModuleFileNameW(*module, buffer, MAX_PATH))
855251881Speter        {
856251881Speter          buffer[MAX_PATH] = 0;
857251881Speter
858251881Speter          version = file_version_number(buffer, pool);
859251881Speter          filename = wcs_to_utf8(buffer, pool);
860251881Speter          if (filename)
861251881Speter            {
862251881Speter              svn_version_ext_loaded_lib_t *lib;
863251881Speter
864251881Speter              if (!array)
865251881Speter                {
866251881Speter                  array = apr_array_make(pool, 32, sizeof(*lib));
867251881Speter                }
868251881Speter              lib = &APR_ARRAY_PUSH(array, svn_version_ext_loaded_lib_t);
869251881Speter              lib->name = svn_dirent_local_style(filename, pool);
870251881Speter              lib->version = version;
871251881Speter            }
872251881Speter        }
873251881Speter    }
874251881Speter
875251881Speter  return array;
876251881Speter}
877251881Speter#endif /* WIN32 */
878251881Speter
879251881Speter
880251881Speter#ifdef SVN_HAVE_MACOS_PLIST
881251881Speter/* Load the SystemVersion.plist or ServerVersion.plist file into a
882251881Speter   property list. Set SERVER to TRUE if the file read was
883251881Speter   ServerVersion.plist. */
884251881Speterstatic CFDictionaryRef
885251881Spetersystem_version_plist(svn_boolean_t *server, apr_pool_t *pool)
886251881Speter{
887251881Speter  static const UInt8 server_version[] =
888251881Speter    "/System/Library/CoreServices/ServerVersion.plist";
889251881Speter  static const UInt8 system_version[] =
890251881Speter    "/System/Library/CoreServices/SystemVersion.plist";
891251881Speter
892251881Speter  CFPropertyListRef plist = NULL;
893251881Speter  CFDataRef resource = NULL;
894251881Speter  CFStringRef errstr = NULL;
895251881Speter  CFURLRef url = NULL;
896251881Speter  SInt32 errcode;
897251881Speter
898251881Speter  url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
899251881Speter                                                server_version,
900251881Speter                                                sizeof(server_version) - 1,
901251881Speter                                                FALSE);
902251881Speter  if (!url)
903251881Speter    return NULL;
904251881Speter
905251881Speter  if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
906251881Speter                                                url, &resource,
907251881Speter                                                NULL, NULL, &errcode))
908251881Speter    {
909251881Speter      CFRelease(url);
910251881Speter      url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
911251881Speter                                                    system_version,
912251881Speter                                                    sizeof(system_version) - 1,
913251881Speter                                                    FALSE);
914251881Speter      if (!url)
915251881Speter        return NULL;
916251881Speter
917251881Speter      if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
918251881Speter                                                    url, &resource,
919251881Speter                                                    NULL, NULL, &errcode))
920251881Speter        {
921251881Speter          CFRelease(url);
922251881Speter          return NULL;
923251881Speter        }
924251881Speter      else
925251881Speter        {
926251881Speter          CFRelease(url);
927251881Speter          *server = FALSE;
928251881Speter        }
929251881Speter    }
930251881Speter  else
931251881Speter    {
932251881Speter      CFRelease(url);
933251881Speter      *server = TRUE;
934251881Speter    }
935251881Speter
936251881Speter  /* ### CFPropertyListCreateFromXMLData is obsolete, but its
937251881Speter         replacement CFPropertyListCreateWithData is only available
938251881Speter         from Mac OS 1.6 onward. */
939251881Speter  plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource,
940251881Speter                                          kCFPropertyListImmutable,
941251881Speter                                          &errstr);
942251881Speter  if (resource)
943251881Speter    CFRelease(resource);
944251881Speter  if (errstr)
945251881Speter    CFRelease(errstr);
946251881Speter
947251881Speter  if (CFDictionaryGetTypeID() != CFGetTypeID(plist))
948251881Speter    {
949251881Speter      /* Oops ... this really should be a dict. */
950251881Speter      CFRelease(plist);
951251881Speter      return NULL;
952251881Speter    }
953251881Speter
954251881Speter  return plist;
955251881Speter}
956251881Speter
957251881Speter/* Return the value for KEY from PLIST, or NULL if not available. */
958251881Speterstatic const char *
959251881Spetervalue_from_dict(CFDictionaryRef plist, CFStringRef key, apr_pool_t *pool)
960251881Speter{
961251881Speter  CFStringRef valref;
962251881Speter  CFIndex bufsize;
963251881Speter  const void *valptr;
964251881Speter  const char *value;
965251881Speter
966251881Speter  if (!CFDictionaryGetValueIfPresent(plist, key, &valptr))
967251881Speter    return NULL;
968251881Speter
969251881Speter  valref = valptr;
970251881Speter  if (CFStringGetTypeID() != CFGetTypeID(valref))
971251881Speter    return NULL;
972251881Speter
973251881Speter  value = CFStringGetCStringPtr(valref, kCFStringEncodingUTF8);
974251881Speter  if (value)
975251881Speter    return apr_pstrdup(pool, value);
976251881Speter
977251881Speter  bufsize =  5 * CFStringGetLength(valref) + 1;
978251881Speter  value = apr_palloc(pool, bufsize);
979251881Speter  if (!CFStringGetCString(valref, (char*)value, bufsize,
980251881Speter                          kCFStringEncodingUTF8))
981251881Speter    value = NULL;
982251881Speter
983251881Speter  return value;
984251881Speter}
985251881Speter
986251881Speter/* Return the commercial name of the OS, given the version number in
987251881Speter   a format that matches the regular expression /^10\.\d+(\..*)?$/ */
988251881Speterstatic const char *
989251881Speterrelease_name_from_version(const char *osver)
990251881Speter{
991251881Speter  char *end = NULL;
992251881Speter  unsigned long num = strtoul(osver, &end, 10);
993251881Speter
994251881Speter  if (!end || *end != '.' || num != 10)
995251881Speter    return NULL;
996251881Speter
997251881Speter  osver = end + 1;
998251881Speter  end = NULL;
999251881Speter  num = strtoul(osver, &end, 10);
1000251881Speter  if (!end || (*end && *end != '.'))
1001251881Speter    return NULL;
1002251881Speter
1003251881Speter  /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */
1004251881Speter  switch(num)
1005251881Speter    {
1006251881Speter    case 0: return "Cheetah";
1007251881Speter    case 1: return "Puma";
1008251881Speter    case 2: return "Jaguar";
1009251881Speter    case 3: return "Panther";
1010251881Speter    case 4: return "Tiger";
1011251881Speter    case 5: return "Leopard";
1012251881Speter    case 6: return "Snow Leopard";
1013251881Speter    case 7: return "Lion";
1014251881Speter    case 8: return "Mountain Lion";
1015251881Speter    }
1016251881Speter
1017251881Speter  return NULL;
1018251881Speter}
1019251881Speter
1020251881Speter/* Construct the release name from information stored in the Mac OS X
1021251881Speter   "SystemVersion.plist" file (or ServerVersion.plist, for Mac Os
1022251881Speter   Server. */
1023251881Speterstatic const char *
1024251881Spetermacos_release_name(apr_pool_t *pool)
1025251881Speter{
1026251881Speter  svn_boolean_t server;
1027251881Speter  CFDictionaryRef plist = system_version_plist(&server, pool);
1028251881Speter
1029251881Speter  if (plist)
1030251881Speter    {
1031251881Speter      const char *osname = value_from_dict(plist, CFSTR("ProductName"), pool);
1032251881Speter      const char *osver = value_from_dict(plist,
1033251881Speter                                          CFSTR("ProductUserVisibleVersion"),
1034251881Speter                                          pool);
1035251881Speter      const char *build = value_from_dict(plist,
1036251881Speter                                          CFSTR("ProductBuildVersion"),
1037251881Speter                                          pool);
1038251881Speter      const char *release;
1039251881Speter
1040251881Speter      if (!osver)
1041251881Speter        osver = value_from_dict(plist, CFSTR("ProductVersion"), pool);
1042251881Speter      release = release_name_from_version(osver);
1043251881Speter
1044251881Speter      CFRelease(plist);
1045251881Speter      return apr_psprintf(pool, "%s%s%s%s%s%s%s%s",
1046251881Speter                          (osname ? osname : ""),
1047251881Speter                          (osver ? (osname ? " " : "") : ""),
1048251881Speter                          (osver ? osver : ""),
1049251881Speter                          (release ? (osname||osver ? " " : "") : ""),
1050251881Speter                          (release ? release : ""),
1051251881Speter                          (build
1052251881Speter                           ? (osname||osver||release ? ", " : "")
1053251881Speter                           : ""),
1054251881Speter                          (build
1055251881Speter                           ? (server ? "server build " : "build ")
1056251881Speter                           : ""),
1057251881Speter                          (build ? build : ""));
1058251881Speter    }
1059251881Speter
1060251881Speter  return NULL;
1061251881Speter}
1062251881Speter#endif  /* SVN_HAVE_MACOS_PLIST */
1063251881Speter
1064251881Speter#ifdef SVN_HAVE_MACHO_ITERATE
1065251881Speter/* List the shared libraries loaded by the current process.
1066251881Speter   Ignore frameworks and system libraries, they're just clutter. */
1067251881Speterstatic const apr_array_header_t *
1068251881Spetermacos_shared_libs(apr_pool_t *pool)
1069251881Speter{
1070251881Speter  static const char slb_prefix[] = "/usr/lib/system/";
1071251881Speter  static const char fwk_prefix[] = "/System/Library/Frameworks/";
1072251881Speter  static const char pfk_prefix[] = "/System/Library/PrivateFrameworks/";
1073251881Speter
1074251881Speter  const size_t slb_prefix_len = strlen(slb_prefix);
1075251881Speter  const size_t fwk_prefix_len = strlen(fwk_prefix);
1076251881Speter  const size_t pfk_prefix_len = strlen(pfk_prefix);
1077251881Speter
1078251881Speter  apr_array_header_t *result = NULL;
1079251881Speter  apr_array_header_t *dylibs = NULL;
1080251881Speter
1081251881Speter  uint32_t i;
1082251881Speter  for (i = 0;; ++i)
1083251881Speter    {
1084251881Speter      const struct mach_header *header = _dyld_get_image_header(i);
1085251881Speter      const char *filename = _dyld_get_image_name(i);
1086251881Speter      const char *version;
1087251881Speter      char *truename;
1088251881Speter      svn_version_ext_loaded_lib_t *lib;
1089251881Speter
1090251881Speter      if (!(header && filename))
1091251881Speter        break;
1092251881Speter
1093251881Speter      switch (header->cputype)
1094251881Speter        {
1095251881Speter        case CPU_TYPE_I386:      version = _("Intel"); break;
1096251881Speter        case CPU_TYPE_X86_64:    version = _("Intel 64-bit"); break;
1097251881Speter        case CPU_TYPE_POWERPC:   version = _("PowerPC"); break;
1098251881Speter        case CPU_TYPE_POWERPC64: version = _("PowerPC 64-bit"); break;
1099251881Speter        default:
1100251881Speter          version = NULL;
1101251881Speter        }
1102251881Speter
1103251881Speter      if (0 == apr_filepath_merge(&truename, "", filename,
1104251881Speter                                  APR_FILEPATH_NATIVE
1105251881Speter                                  | APR_FILEPATH_TRUENAME,
1106251881Speter                                  pool))
1107251881Speter        filename = truename;
1108251881Speter      else
1109251881Speter        filename = apr_pstrdup(pool, filename);
1110251881Speter
1111251881Speter      if (0 == strncmp(filename, slb_prefix, slb_prefix_len)
1112251881Speter          || 0 == strncmp(filename, fwk_prefix, fwk_prefix_len)
1113251881Speter          || 0 == strncmp(filename, pfk_prefix, pfk_prefix_len))
1114251881Speter        {
1115251881Speter          /* Ignore frameworks and system libraries. */
1116251881Speter          continue;
1117251881Speter        }
1118251881Speter
1119251881Speter      if (header->filetype == MH_EXECUTE)
1120251881Speter        {
1121251881Speter          /* Make sure the program filename is first in the list */
1122251881Speter          if (!result)
1123251881Speter            {
1124251881Speter              result = apr_array_make(pool, 32, sizeof(*lib));
1125251881Speter            }
1126251881Speter          lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t);
1127251881Speter        }
1128251881Speter      else
1129251881Speter        {
1130251881Speter          if (!dylibs)
1131251881Speter            {
1132251881Speter              dylibs = apr_array_make(pool, 32, sizeof(*lib));
1133251881Speter            }
1134251881Speter          lib = &APR_ARRAY_PUSH(dylibs, svn_version_ext_loaded_lib_t);
1135251881Speter        }
1136251881Speter
1137251881Speter      lib->name = filename;
1138251881Speter      lib->version = version;
1139251881Speter    }
1140251881Speter
1141251881Speter  /* Gather results into one array. */
1142251881Speter  if (dylibs)
1143251881Speter    {
1144251881Speter      if (result)
1145251881Speter        apr_array_cat(result, dylibs);
1146251881Speter      else
1147251881Speter        result = dylibs;
1148251881Speter    }
1149251881Speter
1150251881Speter  return result;
1151251881Speter}
1152251881Speter#endif  /* SVN_HAVE_MACHO_ITERATE */
1153