sysinfo.c revision 262250
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);
293262250Speter
294262250Speter  /* Now we split the currently allocated buffer in two parts:
295262250Speter      - a const char * HEAD
296262250Speter      - the remaining stringbuf_t. */
297262250Speter
298262250Speter  /* Create HEAD as '\0' terminated const char * */
299251881Speter  key = buffer->data;
300251881Speter  end = strchr(key, delim);
301251881Speter  *end = '\0';
302262250Speter
303262250Speter  /* And update the TAIL to be a smaller, but still valid stringbuf */
304251881Speter  buffer->data = end + 1;
305262250Speter  buffer->len -= 1 + end - key;
306262250Speter  buffer->blocksize -= 1 + end - key;
307262250Speter
308251881Speter  svn_stringbuf_strip_whitespace(buffer);
309251881Speter
310251881Speter  return key;
311251881Speter}
312251881Speter
313251881Speter/* Parse `/usr/bin/lsb_rlease --all` */
314251881Speterstatic const char *
315251881Speterlsb_release(apr_pool_t *pool)
316251881Speter{
317251881Speter  static const char *const args[3] =
318251881Speter    {
319251881Speter      "/usr/bin/lsb_release",
320251881Speter      "--all",
321251881Speter      NULL
322251881Speter    };
323251881Speter
324251881Speter  const char *distributor = NULL;
325251881Speter  const char *description = NULL;
326251881Speter  const char *release = NULL;
327251881Speter  const char *codename = NULL;
328251881Speter
329251881Speter  apr_proc_t lsbproc;
330251881Speter  svn_stream_t *lsbinfo;
331251881Speter  svn_error_t *err;
332251881Speter
333251881Speter  /* Run /usr/bin/lsb_release --all < /dev/null 2>/dev/null */
334251881Speter  {
335251881Speter    apr_file_t *stdin_handle;
336251881Speter    apr_file_t *stdout_handle;
337251881Speter
338251881Speter    err = svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME,
339251881Speter                           APR_READ, APR_OS_DEFAULT, pool);
340251881Speter    if (!err)
341251881Speter      err = svn_io_file_open(&stdout_handle, SVN_NULL_DEVICE_NAME,
342251881Speter                             APR_WRITE, APR_OS_DEFAULT, pool);
343251881Speter    if (!err)
344251881Speter      err = svn_io_start_cmd3(&lsbproc, NULL, args[0], args, NULL, FALSE,
345251881Speter                              FALSE, stdin_handle,
346251881Speter                              TRUE, NULL,
347251881Speter                              FALSE, stdout_handle,
348251881Speter                              pool);
349251881Speter    if (err)
350251881Speter      {
351251881Speter        svn_error_clear(err);
352251881Speter        return NULL;
353251881Speter      }
354251881Speter  }
355251881Speter
356251881Speter  /* Parse the output and try to populate the  */
357251881Speter  lsbinfo = svn_stream_from_aprfile2(lsbproc.out, TRUE, pool);
358251881Speter  if (lsbinfo)
359251881Speter    {
360251881Speter      for (;;)
361251881Speter        {
362251881Speter          svn_boolean_t eof = FALSE;
363251881Speter          svn_stringbuf_t *line;
364251881Speter          const char *key;
365251881Speter
366251881Speter          err = svn_stream_readline(lsbinfo, &line, "\n", &eof, pool);
367251881Speter          if (err || eof)
368251881Speter            break;
369251881Speter
370251881Speter          key = stringbuf_split_key(line, ':');
371251881Speter          if (!key)
372251881Speter            continue;
373251881Speter
374251881Speter          if (0 == svn_cstring_casecmp(key, "Distributor ID"))
375251881Speter            distributor = line->data;
376251881Speter          else if (0 == svn_cstring_casecmp(key, "Description"))
377251881Speter            description = line->data;
378251881Speter          else if (0 == svn_cstring_casecmp(key, "Release"))
379251881Speter            release = line->data;
380251881Speter          else if (0 == svn_cstring_casecmp(key, "Codename"))
381251881Speter            codename = line->data;
382251881Speter        }
383251881Speter      err = svn_error_compose_create(err,
384251881Speter                                     svn_stream_close(lsbinfo));
385251881Speter      if (err)
386251881Speter        {
387251881Speter          svn_error_clear(err);
388251881Speter          apr_proc_kill(&lsbproc, SIGKILL);
389251881Speter          return NULL;
390251881Speter        }
391251881Speter    }
392251881Speter
393251881Speter  /* Reap the child process */
394251881Speter  err = svn_io_wait_for_cmd(&lsbproc, "", NULL, NULL, pool);
395251881Speter  if (err)
396251881Speter    {
397251881Speter      svn_error_clear(err);
398251881Speter      return NULL;
399251881Speter    }
400251881Speter
401251881Speter  if (description)
402251881Speter    return apr_psprintf(pool, "%s%s%s%s", description,
403251881Speter                        (codename ? " (" : ""),
404251881Speter                        (codename ? codename : ""),
405251881Speter                        (codename ? ")" : ""));
406251881Speter  if (distributor)
407251881Speter    return apr_psprintf(pool, "%s%s%s%s%s%s", distributor,
408251881Speter                        (release ? " " : ""),
409251881Speter                        (release ? release : ""),
410251881Speter                        (codename ? " (" : ""),
411251881Speter                        (codename ? codename : ""),
412251881Speter                        (codename ? ")" : ""));
413251881Speter
414251881Speter  return NULL;
415251881Speter}
416251881Speter
417251881Speter/* Read the whole contents of a file. */
418251881Speterstatic svn_stringbuf_t *
419251881Speterread_file_contents(const char *filename, apr_pool_t *pool)
420251881Speter{
421251881Speter  svn_error_t *err;
422251881Speter  svn_stringbuf_t *buffer;
423251881Speter
424251881Speter  err = svn_stringbuf_from_file2(&buffer, filename, pool);
425251881Speter  if (err)
426251881Speter    {
427251881Speter      svn_error_clear(err);
428251881Speter      return NULL;
429251881Speter    }
430251881Speter
431251881Speter  return buffer;
432251881Speter}
433251881Speter
434251881Speter/* Strip everything but the first line from a stringbuf. */
435251881Speterstatic void
436251881Speterstringbuf_first_line_only(svn_stringbuf_t *buffer)
437251881Speter{
438251881Speter  char *eol = strchr(buffer->data, '\n');
439251881Speter  if (eol)
440251881Speter    {
441251881Speter      *eol = '\0';
442251881Speter      buffer->len = 1 + eol - buffer->data;
443251881Speter    }
444251881Speter  svn_stringbuf_strip_whitespace(buffer);
445251881Speter}
446251881Speter
447251881Speter/* Look at /etc/redhat_release to detect RHEL/Fedora/CentOS. */
448251881Speterstatic const char *
449251881Speterredhat_release(apr_pool_t *pool)
450251881Speter{
451251881Speter  svn_stringbuf_t *buffer = read_file_contents("/etc/redhat-release", pool);
452251881Speter  if (buffer)
453251881Speter    {
454251881Speter      stringbuf_first_line_only(buffer);
455251881Speter      return buffer->data;
456251881Speter    }
457251881Speter  return NULL;
458251881Speter}
459251881Speter
460251881Speter/* Look at /etc/SuSE-release to detect non-LSB SuSE. */
461251881Speterstatic const char *
462251881Spetersuse_release(apr_pool_t *pool)
463251881Speter{
464251881Speter  const char *release = NULL;
465251881Speter  const char *codename = NULL;
466251881Speter
467251881Speter  svn_stringbuf_t *buffer = read_file_contents("/etc/SuSE-release", pool);
468251881Speter  svn_stringbuf_t *line;
469251881Speter  svn_stream_t *stream;
470251881Speter  svn_boolean_t eof;
471251881Speter  svn_error_t *err;
472251881Speter  if (!buffer)
473251881Speter      return NULL;
474251881Speter
475251881Speter  stream = svn_stream_from_stringbuf(buffer, pool);
476251881Speter  err = svn_stream_readline(stream, &line, "\n", &eof, pool);
477251881Speter  if (err || eof)
478251881Speter    {
479251881Speter      svn_error_clear(err);
480251881Speter      return NULL;
481251881Speter    }
482251881Speter
483251881Speter  svn_stringbuf_strip_whitespace(line);
484251881Speter  release = line->data;
485251881Speter
486251881Speter  for (;;)
487251881Speter    {
488251881Speter      const char *key;
489251881Speter
490251881Speter      err = svn_stream_readline(stream, &line, "\n", &eof, pool);
491251881Speter      if (err || eof)
492251881Speter        {
493251881Speter          svn_error_clear(err);
494251881Speter          break;
495251881Speter        }
496251881Speter
497251881Speter      key = stringbuf_split_key(line, '=');
498251881Speter      if (!key)
499251881Speter        continue;
500251881Speter
501251881Speter      if (0 == strncmp(key, "CODENAME", 8))
502251881Speter        codename = line->data;
503251881Speter    }
504251881Speter
505251881Speter  return apr_psprintf(pool, "%s%s%s%s",
506251881Speter                      release,
507251881Speter                      (codename ? " (" : ""),
508251881Speter                      (codename ? codename : ""),
509251881Speter                      (codename ? ")" : ""));
510251881Speter}
511251881Speter
512251881Speter/* Look at /etc/debian_version to detect non-LSB Debian. */
513251881Speterstatic const char *
514251881Speterdebian_release(apr_pool_t *pool)
515251881Speter{
516251881Speter  svn_stringbuf_t *buffer = read_file_contents("/etc/debian_version", pool);
517251881Speter  if (!buffer)
518251881Speter      return NULL;
519251881Speter
520251881Speter  stringbuf_first_line_only(buffer);
521251881Speter  return apr_pstrcat(pool, "Debian ", buffer->data, NULL);
522251881Speter}
523251881Speter
524251881Speter/* Try to find the Linux distribution name, or return info from uname. */
525251881Speterstatic const char *
526251881Speterlinux_release_name(apr_pool_t *pool)
527251881Speter{
528251881Speter  const char *uname_release = release_name_from_uname(pool);
529251881Speter
530251881Speter  /* Try anything that has /usr/bin/lsb_release.
531251881Speter     Covers, for example, Debian, Ubuntu and SuSE.  */
532251881Speter  const char *release_name = lsb_release(pool);
533251881Speter
534251881Speter  /* Try RHEL/Fedora/CentOS */
535251881Speter  if (!release_name)
536251881Speter    release_name = redhat_release(pool);
537251881Speter
538251881Speter  /* Try Non-LSB SuSE */
539251881Speter  if (!release_name)
540251881Speter    release_name = suse_release(pool);
541251881Speter
542251881Speter  /* Try non-LSB Debian */
543251881Speter  if (!release_name)
544251881Speter    release_name = debian_release(pool);
545251881Speter
546251881Speter  if (!release_name)
547251881Speter    return uname_release;
548251881Speter
549251881Speter  if (!uname_release)
550251881Speter    return release_name;
551251881Speter
552251881Speter  return apr_psprintf(pool, "%s [%s]", release_name, uname_release);
553251881Speter}
554251881Speter#endif /* __linux__ */
555251881Speter
556251881Speter
557251881Speter#ifdef WIN32
558251881Spetertypedef DWORD (WINAPI *FNGETNATIVESYSTEMINFO)(LPSYSTEM_INFO);
559257936Spetertypedef BOOL (WINAPI *FNENUMPROCESSMODULES) (HANDLE, HMODULE*, DWORD, LPDWORD);
560251881Speter
561251881Speter/* Get system and version info, and try to tell the difference
562251881Speter   between the native system type and the runtime environment of the
563251881Speter   current process. Populate results in SYSINFO, LOCAL_SYSINFO
564251881Speter   (optional) and OSINFO. */
565251881Speterstatic BOOL
566251881Spetersystem_info(SYSTEM_INFO *sysinfo,
567251881Speter            SYSTEM_INFO *local_sysinfo,
568251881Speter            OSVERSIONINFOEXW *osinfo)
569251881Speter{
570251881Speter  FNGETNATIVESYSTEMINFO GetNativeSystemInfo_ = (FNGETNATIVESYSTEMINFO)
571251881Speter    GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
572251881Speter
573251881Speter  ZeroMemory(sysinfo, sizeof *sysinfo);
574251881Speter  if (local_sysinfo)
575251881Speter    {
576251881Speter      ZeroMemory(local_sysinfo, sizeof *local_sysinfo);
577251881Speter      GetSystemInfo(local_sysinfo);
578251881Speter      if (GetNativeSystemInfo_)
579251881Speter        GetNativeSystemInfo_(sysinfo);
580251881Speter      else
581251881Speter        memcpy(sysinfo, local_sysinfo, sizeof *sysinfo);
582251881Speter    }
583251881Speter  else
584251881Speter    GetSystemInfo(sysinfo);
585251881Speter
586251881Speter  ZeroMemory(osinfo, sizeof *osinfo);
587251881Speter  osinfo->dwOSVersionInfoSize = sizeof *osinfo;
588251881Speter  if (!GetVersionExW((LPVOID)osinfo))
589251881Speter    return FALSE;
590251881Speter
591251881Speter  return TRUE;
592251881Speter}
593251881Speter
594251881Speter/* Map the proccessor type from SYSINFO to a string. */
595251881Speterstatic const char *
596251881Speterprocessor_name(SYSTEM_INFO *sysinfo)
597251881Speter{
598251881Speter  switch (sysinfo->wProcessorArchitecture)
599251881Speter    {
600251881Speter    case PROCESSOR_ARCHITECTURE_AMD64:         return "x86_64";
601251881Speter    case PROCESSOR_ARCHITECTURE_IA64:          return "ia64";
602251881Speter    case PROCESSOR_ARCHITECTURE_INTEL:         return "x86";
603251881Speter    case PROCESSOR_ARCHITECTURE_MIPS:          return "mips";
604251881Speter    case PROCESSOR_ARCHITECTURE_ALPHA:         return "alpha32";
605251881Speter    case PROCESSOR_ARCHITECTURE_PPC:           return "powerpc";
606251881Speter    case PROCESSOR_ARCHITECTURE_SHX:           return "shx";
607251881Speter    case PROCESSOR_ARCHITECTURE_ARM:           return "arm";
608251881Speter    case PROCESSOR_ARCHITECTURE_ALPHA64:       return "alpha";
609251881Speter    case PROCESSOR_ARCHITECTURE_MSIL:          return "msil";
610251881Speter    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: return "x86_wow64";
611251881Speter    default: return "unknown";
612251881Speter    }
613251881Speter}
614251881Speter
615251881Speter/* Return the Windows-specific canonical host name. */
616251881Speterstatic const char *
617251881Speterwin32_canonical_host(apr_pool_t *pool)
618251881Speter{
619251881Speter  SYSTEM_INFO sysinfo;
620251881Speter  SYSTEM_INFO local_sysinfo;
621251881Speter  OSVERSIONINFOEXW osinfo;
622251881Speter
623251881Speter  if (system_info(&sysinfo, &local_sysinfo, &osinfo))
624251881Speter    {
625251881Speter      const char *arch = processor_name(&local_sysinfo);
626251881Speter      const char *machine = processor_name(&sysinfo);
627251881Speter      const char *vendor = "microsoft";
628251881Speter      const char *sysname = "windows";
629251881Speter      const char *sysver = apr_psprintf(pool, "%u.%u.%u",
630251881Speter                                        (unsigned int)osinfo.dwMajorVersion,
631251881Speter                                        (unsigned int)osinfo.dwMinorVersion,
632251881Speter                                        (unsigned int)osinfo.dwBuildNumber);
633251881Speter
634251881Speter      if (sysinfo.wProcessorArchitecture
635251881Speter          == local_sysinfo.wProcessorArchitecture)
636251881Speter        return apr_psprintf(pool, "%s-%s-%s%s",
637251881Speter                            machine, vendor, sysname, sysver);
638251881Speter      return apr_psprintf(pool, "%s/%s-%s-%s%s",
639251881Speter                          arch, machine, vendor, sysname, sysver);
640251881Speter    }
641251881Speter
642251881Speter  return "unknown-microsoft-windows";
643251881Speter}
644251881Speter
645251881Speter/* Convert a Unicode string to UTF-8. */
646251881Speterstatic char *
647251881Speterwcs_to_utf8(const wchar_t *wcs, apr_pool_t *pool)
648251881Speter{
649251881Speter  const int bufsize = WideCharToMultiByte(CP_UTF8, 0, wcs, -1,
650251881Speter                                          NULL, 0, NULL, NULL);
651251881Speter  if (bufsize > 0)
652251881Speter    {
653251881Speter      char *const utf8 = apr_palloc(pool, bufsize + 1);
654251881Speter      WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf8, bufsize, NULL, NULL);
655251881Speter      return utf8;
656251881Speter    }
657251881Speter  return NULL;
658251881Speter}
659251881Speter
660251881Speter/* Query the value called NAME of the registry key HKEY. */
661251881Speterstatic char *
662251881Speterregistry_value(HKEY hkey, wchar_t *name, apr_pool_t *pool)
663251881Speter{
664251881Speter  DWORD size;
665251881Speter  wchar_t *value;
666251881Speter
667251881Speter  if (RegQueryValueExW(hkey, name, NULL, NULL, NULL, &size))
668251881Speter    return NULL;
669251881Speter
670251881Speter  value = apr_palloc(pool, size + sizeof *value);
671251881Speter  if (RegQueryValueExW(hkey, name, NULL, NULL, (void*)value, &size))
672251881Speter    return NULL;
673251881Speter  value[size / sizeof *value] = 0;
674251881Speter  return wcs_to_utf8(value, pool);
675251881Speter}
676251881Speter
677251881Speter/* Try to glean the Windows release name and associated info from the
678251881Speter   registry. Failing that, construct a release name from the version
679251881Speter   info. */
680251881Speterstatic const char *
681251881Speterwin32_release_name(apr_pool_t *pool)
682251881Speter{
683251881Speter  SYSTEM_INFO sysinfo;
684251881Speter  OSVERSIONINFOEXW osinfo;
685251881Speter  HKEY hkcv;
686251881Speter
687251881Speter  if (!system_info(&sysinfo, NULL, &osinfo))
688251881Speter    return NULL;
689251881Speter
690251881Speter  if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE,
691251881Speter                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
692251881Speter                     0, KEY_QUERY_VALUE, &hkcv))
693251881Speter    {
694251881Speter      const char *release = registry_value(hkcv, L"ProductName", pool);
695251881Speter      const char *spack = registry_value(hkcv, L"CSDVersion", pool);
696251881Speter      const char *curver = registry_value(hkcv, L"CurrentVersion", pool);
697251881Speter      const char *curtype = registry_value(hkcv, L"CurrentType", pool);
698251881Speter      const char *install = registry_value(hkcv, L"InstallationType", pool);
699251881Speter      const char *curbuild = registry_value(hkcv, L"CurrentBuildNumber", pool);
700251881Speter
701251881Speter      if (!spack && *osinfo.szCSDVersion)
702251881Speter        spack = wcs_to_utf8(osinfo.szCSDVersion, pool);
703251881Speter
704251881Speter      if (!curbuild)
705251881Speter        curbuild = registry_value(hkcv, L"CurrentBuild", pool);
706251881Speter
707251881Speter      if (release || spack || curver || curtype || curbuild)
708251881Speter        {
709251881Speter          const char *bootinfo = "";
710251881Speter          if (curver || install || curtype)
711251881Speter            {
712251881Speter              bootinfo = apr_psprintf(pool, "[%s%s%s%s%s]",
713251881Speter                                      (curver ? curver : ""),
714251881Speter                                      (install ? (curver ? " " : "") : ""),
715251881Speter                                      (install ? install : ""),
716251881Speter                                      (curtype
717251881Speter                                       ? (curver||install ? " " : "")
718251881Speter                                       : ""),
719251881Speter                                      (curtype ? curtype : ""));
720251881Speter            }
721251881Speter
722251881Speter          return apr_psprintf(pool, "%s%s%s%s%s%s%s",
723251881Speter                              (release ? release : ""),
724251881Speter                              (spack ? (release ? ", " : "") : ""),
725251881Speter                              (spack ? spack : ""),
726251881Speter                              (curbuild
727251881Speter                               ? (release||spack ? ", build " : "build ")
728251881Speter                               : ""),
729251881Speter                              (curbuild ? curbuild : ""),
730251881Speter                              (bootinfo
731251881Speter                               ? (release||spack||curbuild ? " " : "")
732251881Speter                               : ""),
733251881Speter                              (bootinfo ? bootinfo : ""));
734251881Speter        }
735251881Speter    }
736251881Speter
737251881Speter  if (*osinfo.szCSDVersion)
738251881Speter    {
739251881Speter      const char *servicepack = wcs_to_utf8(osinfo.szCSDVersion, pool);
740251881Speter
741251881Speter      if (servicepack)
742251881Speter        return apr_psprintf(pool, "Windows NT %u.%u, %s, build %u",
743251881Speter                            (unsigned int)osinfo.dwMajorVersion,
744251881Speter                            (unsigned int)osinfo.dwMinorVersion,
745251881Speter                            servicepack,
746251881Speter                            (unsigned int)osinfo.dwBuildNumber);
747251881Speter
748251881Speter      /* Assume wServicePackMajor > 0 if szCSDVersion is not empty */
749251881Speter      if (osinfo.wServicePackMinor)
750251881Speter        return apr_psprintf(pool, "Windows NT %u.%u SP%u.%u, build %u",
751251881Speter                            (unsigned int)osinfo.dwMajorVersion,
752251881Speter                            (unsigned int)osinfo.dwMinorVersion,
753251881Speter                            (unsigned int)osinfo.wServicePackMajor,
754251881Speter                            (unsigned int)osinfo.wServicePackMinor,
755251881Speter                            (unsigned int)osinfo.dwBuildNumber);
756251881Speter
757251881Speter      return apr_psprintf(pool, "Windows NT %u.%u SP%u, build %u",
758251881Speter                          (unsigned int)osinfo.dwMajorVersion,
759251881Speter                          (unsigned int)osinfo.dwMinorVersion,
760251881Speter                          (unsigned int)osinfo.wServicePackMajor,
761251881Speter                          (unsigned int)osinfo.dwBuildNumber);
762251881Speter    }
763251881Speter
764251881Speter  return apr_psprintf(pool, "Windows NT %u.%u, build %u",
765251881Speter                      (unsigned int)osinfo.dwMajorVersion,
766251881Speter                      (unsigned int)osinfo.dwMinorVersion,
767251881Speter                      (unsigned int)osinfo.dwBuildNumber);
768251881Speter}
769251881Speter
770251881Speter
771251881Speter/* Get a list of handles of shared libs loaded by the current
772251881Speter   process. Returns a NULL-terminated array alocated from POOL. */
773251881Speterstatic HMODULE *
774251881Speterenum_loaded_modules(apr_pool_t *pool)
775251881Speter{
776257936Speter  HMODULE psapi_dll = 0;
777251881Speter  HANDLE current = GetCurrentProcess();
778251881Speter  HMODULE dummy[1];
779251881Speter  HMODULE *handles;
780251881Speter  DWORD size;
781257936Speter  FNENUMPROCESSMODULES EnumProcessModules_;
782251881Speter
783257936Speter  psapi_dll = GetModuleHandleA("psapi.dll");
784257936Speter
785257936Speter  if (!psapi_dll)
786257936Speter    {
787257936Speter      /* Load and never unload, just like static linking */
788257936Speter      psapi_dll = LoadLibraryA("psapi.dll");
789257936Speter    }
790257936Speter
791257936Speter  if (!psapi_dll)
792257936Speter      return NULL;
793257936Speter
794257936Speter  EnumProcessModules_ = (FNENUMPROCESSMODULES)
795257936Speter                              GetProcAddress(psapi_dll, "EnumProcessModules");
796257936Speter
797257936Speter  /* Before Windows XP psapi was an optional module */
798257936Speter  if (! EnumProcessModules_)
799251881Speter    return NULL;
800251881Speter
801257936Speter  if (!EnumProcessModules_(current, dummy, sizeof(dummy), &size))
802257936Speter    return NULL;
803257936Speter
804251881Speter  handles = apr_palloc(pool, size + sizeof *handles);
805257936Speter  if (! EnumProcessModules_(current, handles, size, &size))
806251881Speter    return NULL;
807251881Speter  handles[size / sizeof *handles] = NULL;
808251881Speter  return handles;
809251881Speter}
810251881Speter
811251881Speter/* Find the version number, if any, embedded in FILENAME. */
812251881Speterstatic const char *
813251881Speterfile_version_number(const wchar_t *filename, apr_pool_t *pool)
814251881Speter{
815251881Speter  VS_FIXEDFILEINFO info;
816251881Speter  unsigned int major, minor, micro, nano;
817251881Speter  void *data;
818251881Speter  DWORD data_size = GetFileVersionInfoSizeW(filename, NULL);
819251881Speter  void *vinfo;
820251881Speter  UINT vinfo_size;
821251881Speter
822251881Speter  if (!data_size)
823251881Speter    return NULL;
824251881Speter
825251881Speter  data = apr_palloc(pool, data_size);
826251881Speter  if (!GetFileVersionInfoW(filename, 0, data_size, data))
827251881Speter    return NULL;
828251881Speter
829251881Speter  if (!VerQueryValueW(data, L"\\", &vinfo, &vinfo_size))
830251881Speter    return NULL;
831251881Speter
832251881Speter  if (vinfo_size != sizeof info)
833251881Speter    return NULL;
834251881Speter
835251881Speter  memcpy(&info, vinfo, sizeof info);
836251881Speter  major = (info.dwFileVersionMS >> 16) & 0xFFFF;
837251881Speter  minor = info.dwFileVersionMS & 0xFFFF;
838251881Speter  micro = (info.dwFileVersionLS >> 16) & 0xFFFF;
839251881Speter  nano = info.dwFileVersionLS & 0xFFFF;
840251881Speter
841251881Speter  if (!nano)
842251881Speter    {
843251881Speter      if (!micro)
844251881Speter        return apr_psprintf(pool, "%u.%u", major, minor);
845251881Speter      else
846251881Speter        return apr_psprintf(pool, "%u.%u.%u", major, minor, micro);
847251881Speter    }
848251881Speter  return apr_psprintf(pool, "%u.%u.%u.%u", major, minor, micro, nano);
849251881Speter}
850251881Speter
851251881Speter/* List the shared libraries loaded by the current process. */
852251881Speterstatic const apr_array_header_t *
853251881Speterwin32_shared_libs(apr_pool_t *pool)
854251881Speter{
855251881Speter  apr_array_header_t *array = NULL;
856251881Speter  wchar_t buffer[MAX_PATH + 1];
857251881Speter  HMODULE *handles = enum_loaded_modules(pool);
858251881Speter  HMODULE *module;
859251881Speter
860251881Speter  for (module = handles; module && *module; ++module)
861251881Speter    {
862251881Speter      const char *filename;
863251881Speter      const char *version;
864251881Speter      if (GetModuleFileNameW(*module, buffer, MAX_PATH))
865251881Speter        {
866251881Speter          buffer[MAX_PATH] = 0;
867251881Speter
868251881Speter          version = file_version_number(buffer, pool);
869251881Speter          filename = wcs_to_utf8(buffer, pool);
870251881Speter          if (filename)
871251881Speter            {
872251881Speter              svn_version_ext_loaded_lib_t *lib;
873251881Speter
874251881Speter              if (!array)
875251881Speter                {
876251881Speter                  array = apr_array_make(pool, 32, sizeof(*lib));
877251881Speter                }
878251881Speter              lib = &APR_ARRAY_PUSH(array, svn_version_ext_loaded_lib_t);
879251881Speter              lib->name = svn_dirent_local_style(filename, pool);
880251881Speter              lib->version = version;
881251881Speter            }
882251881Speter        }
883251881Speter    }
884251881Speter
885251881Speter  return array;
886251881Speter}
887251881Speter#endif /* WIN32 */
888251881Speter
889251881Speter
890251881Speter#ifdef SVN_HAVE_MACOS_PLIST
891251881Speter/* Load the SystemVersion.plist or ServerVersion.plist file into a
892251881Speter   property list. Set SERVER to TRUE if the file read was
893251881Speter   ServerVersion.plist. */
894251881Speterstatic CFDictionaryRef
895251881Spetersystem_version_plist(svn_boolean_t *server, apr_pool_t *pool)
896251881Speter{
897251881Speter  static const UInt8 server_version[] =
898251881Speter    "/System/Library/CoreServices/ServerVersion.plist";
899251881Speter  static const UInt8 system_version[] =
900251881Speter    "/System/Library/CoreServices/SystemVersion.plist";
901251881Speter
902251881Speter  CFPropertyListRef plist = NULL;
903251881Speter  CFDataRef resource = NULL;
904251881Speter  CFStringRef errstr = NULL;
905251881Speter  CFURLRef url = NULL;
906251881Speter  SInt32 errcode;
907251881Speter
908251881Speter  url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
909251881Speter                                                server_version,
910251881Speter                                                sizeof(server_version) - 1,
911251881Speter                                                FALSE);
912251881Speter  if (!url)
913251881Speter    return NULL;
914251881Speter
915251881Speter  if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
916251881Speter                                                url, &resource,
917251881Speter                                                NULL, NULL, &errcode))
918251881Speter    {
919251881Speter      CFRelease(url);
920251881Speter      url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
921251881Speter                                                    system_version,
922251881Speter                                                    sizeof(system_version) - 1,
923251881Speter                                                    FALSE);
924251881Speter      if (!url)
925251881Speter        return NULL;
926251881Speter
927251881Speter      if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
928251881Speter                                                    url, &resource,
929251881Speter                                                    NULL, NULL, &errcode))
930251881Speter        {
931251881Speter          CFRelease(url);
932251881Speter          return NULL;
933251881Speter        }
934251881Speter      else
935251881Speter        {
936251881Speter          CFRelease(url);
937251881Speter          *server = FALSE;
938251881Speter        }
939251881Speter    }
940251881Speter  else
941251881Speter    {
942251881Speter      CFRelease(url);
943251881Speter      *server = TRUE;
944251881Speter    }
945251881Speter
946251881Speter  /* ### CFPropertyListCreateFromXMLData is obsolete, but its
947251881Speter         replacement CFPropertyListCreateWithData is only available
948251881Speter         from Mac OS 1.6 onward. */
949251881Speter  plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource,
950251881Speter                                          kCFPropertyListImmutable,
951251881Speter                                          &errstr);
952251881Speter  if (resource)
953251881Speter    CFRelease(resource);
954251881Speter  if (errstr)
955251881Speter    CFRelease(errstr);
956251881Speter
957251881Speter  if (CFDictionaryGetTypeID() != CFGetTypeID(plist))
958251881Speter    {
959251881Speter      /* Oops ... this really should be a dict. */
960251881Speter      CFRelease(plist);
961251881Speter      return NULL;
962251881Speter    }
963251881Speter
964251881Speter  return plist;
965251881Speter}
966251881Speter
967251881Speter/* Return the value for KEY from PLIST, or NULL if not available. */
968251881Speterstatic const char *
969251881Spetervalue_from_dict(CFDictionaryRef plist, CFStringRef key, apr_pool_t *pool)
970251881Speter{
971251881Speter  CFStringRef valref;
972251881Speter  CFIndex bufsize;
973251881Speter  const void *valptr;
974251881Speter  const char *value;
975251881Speter
976251881Speter  if (!CFDictionaryGetValueIfPresent(plist, key, &valptr))
977251881Speter    return NULL;
978251881Speter
979251881Speter  valref = valptr;
980251881Speter  if (CFStringGetTypeID() != CFGetTypeID(valref))
981251881Speter    return NULL;
982251881Speter
983251881Speter  value = CFStringGetCStringPtr(valref, kCFStringEncodingUTF8);
984251881Speter  if (value)
985251881Speter    return apr_pstrdup(pool, value);
986251881Speter
987251881Speter  bufsize =  5 * CFStringGetLength(valref) + 1;
988251881Speter  value = apr_palloc(pool, bufsize);
989251881Speter  if (!CFStringGetCString(valref, (char*)value, bufsize,
990251881Speter                          kCFStringEncodingUTF8))
991251881Speter    value = NULL;
992251881Speter
993251881Speter  return value;
994251881Speter}
995251881Speter
996251881Speter/* Return the commercial name of the OS, given the version number in
997251881Speter   a format that matches the regular expression /^10\.\d+(\..*)?$/ */
998251881Speterstatic const char *
999251881Speterrelease_name_from_version(const char *osver)
1000251881Speter{
1001251881Speter  char *end = NULL;
1002251881Speter  unsigned long num = strtoul(osver, &end, 10);
1003251881Speter
1004251881Speter  if (!end || *end != '.' || num != 10)
1005251881Speter    return NULL;
1006251881Speter
1007251881Speter  osver = end + 1;
1008251881Speter  end = NULL;
1009251881Speter  num = strtoul(osver, &end, 10);
1010251881Speter  if (!end || (*end && *end != '.'))
1011251881Speter    return NULL;
1012251881Speter
1013251881Speter  /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */
1014251881Speter  switch(num)
1015251881Speter    {
1016251881Speter    case 0: return "Cheetah";
1017251881Speter    case 1: return "Puma";
1018251881Speter    case 2: return "Jaguar";
1019251881Speter    case 3: return "Panther";
1020251881Speter    case 4: return "Tiger";
1021251881Speter    case 5: return "Leopard";
1022251881Speter    case 6: return "Snow Leopard";
1023251881Speter    case 7: return "Lion";
1024251881Speter    case 8: return "Mountain Lion";
1025251881Speter    }
1026251881Speter
1027251881Speter  return NULL;
1028251881Speter}
1029251881Speter
1030251881Speter/* Construct the release name from information stored in the Mac OS X
1031251881Speter   "SystemVersion.plist" file (or ServerVersion.plist, for Mac Os
1032251881Speter   Server. */
1033251881Speterstatic const char *
1034251881Spetermacos_release_name(apr_pool_t *pool)
1035251881Speter{
1036251881Speter  svn_boolean_t server;
1037251881Speter  CFDictionaryRef plist = system_version_plist(&server, pool);
1038251881Speter
1039251881Speter  if (plist)
1040251881Speter    {
1041251881Speter      const char *osname = value_from_dict(plist, CFSTR("ProductName"), pool);
1042251881Speter      const char *osver = value_from_dict(plist,
1043251881Speter                                          CFSTR("ProductUserVisibleVersion"),
1044251881Speter                                          pool);
1045251881Speter      const char *build = value_from_dict(plist,
1046251881Speter                                          CFSTR("ProductBuildVersion"),
1047251881Speter                                          pool);
1048251881Speter      const char *release;
1049251881Speter
1050251881Speter      if (!osver)
1051251881Speter        osver = value_from_dict(plist, CFSTR("ProductVersion"), pool);
1052251881Speter      release = release_name_from_version(osver);
1053251881Speter
1054251881Speter      CFRelease(plist);
1055251881Speter      return apr_psprintf(pool, "%s%s%s%s%s%s%s%s",
1056251881Speter                          (osname ? osname : ""),
1057251881Speter                          (osver ? (osname ? " " : "") : ""),
1058251881Speter                          (osver ? osver : ""),
1059251881Speter                          (release ? (osname||osver ? " " : "") : ""),
1060251881Speter                          (release ? release : ""),
1061251881Speter                          (build
1062251881Speter                           ? (osname||osver||release ? ", " : "")
1063251881Speter                           : ""),
1064251881Speter                          (build
1065251881Speter                           ? (server ? "server build " : "build ")
1066251881Speter                           : ""),
1067251881Speter                          (build ? build : ""));
1068251881Speter    }
1069251881Speter
1070251881Speter  return NULL;
1071251881Speter}
1072251881Speter#endif  /* SVN_HAVE_MACOS_PLIST */
1073251881Speter
1074251881Speter#ifdef SVN_HAVE_MACHO_ITERATE
1075251881Speter/* List the shared libraries loaded by the current process.
1076251881Speter   Ignore frameworks and system libraries, they're just clutter. */
1077251881Speterstatic const apr_array_header_t *
1078251881Spetermacos_shared_libs(apr_pool_t *pool)
1079251881Speter{
1080251881Speter  static const char slb_prefix[] = "/usr/lib/system/";
1081251881Speter  static const char fwk_prefix[] = "/System/Library/Frameworks/";
1082251881Speter  static const char pfk_prefix[] = "/System/Library/PrivateFrameworks/";
1083251881Speter
1084251881Speter  const size_t slb_prefix_len = strlen(slb_prefix);
1085251881Speter  const size_t fwk_prefix_len = strlen(fwk_prefix);
1086251881Speter  const size_t pfk_prefix_len = strlen(pfk_prefix);
1087251881Speter
1088251881Speter  apr_array_header_t *result = NULL;
1089251881Speter  apr_array_header_t *dylibs = NULL;
1090251881Speter
1091251881Speter  uint32_t i;
1092251881Speter  for (i = 0;; ++i)
1093251881Speter    {
1094251881Speter      const struct mach_header *header = _dyld_get_image_header(i);
1095251881Speter      const char *filename = _dyld_get_image_name(i);
1096251881Speter      const char *version;
1097251881Speter      char *truename;
1098251881Speter      svn_version_ext_loaded_lib_t *lib;
1099251881Speter
1100251881Speter      if (!(header && filename))
1101251881Speter        break;
1102251881Speter
1103251881Speter      switch (header->cputype)
1104251881Speter        {
1105251881Speter        case CPU_TYPE_I386:      version = _("Intel"); break;
1106251881Speter        case CPU_TYPE_X86_64:    version = _("Intel 64-bit"); break;
1107251881Speter        case CPU_TYPE_POWERPC:   version = _("PowerPC"); break;
1108251881Speter        case CPU_TYPE_POWERPC64: version = _("PowerPC 64-bit"); break;
1109251881Speter        default:
1110251881Speter          version = NULL;
1111251881Speter        }
1112251881Speter
1113251881Speter      if (0 == apr_filepath_merge(&truename, "", filename,
1114251881Speter                                  APR_FILEPATH_NATIVE
1115251881Speter                                  | APR_FILEPATH_TRUENAME,
1116251881Speter                                  pool))
1117251881Speter        filename = truename;
1118251881Speter      else
1119251881Speter        filename = apr_pstrdup(pool, filename);
1120251881Speter
1121251881Speter      if (0 == strncmp(filename, slb_prefix, slb_prefix_len)
1122251881Speter          || 0 == strncmp(filename, fwk_prefix, fwk_prefix_len)
1123251881Speter          || 0 == strncmp(filename, pfk_prefix, pfk_prefix_len))
1124251881Speter        {
1125251881Speter          /* Ignore frameworks and system libraries. */
1126251881Speter          continue;
1127251881Speter        }
1128251881Speter
1129251881Speter      if (header->filetype == MH_EXECUTE)
1130251881Speter        {
1131251881Speter          /* Make sure the program filename is first in the list */
1132251881Speter          if (!result)
1133251881Speter            {
1134251881Speter              result = apr_array_make(pool, 32, sizeof(*lib));
1135251881Speter            }
1136251881Speter          lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t);
1137251881Speter        }
1138251881Speter      else
1139251881Speter        {
1140251881Speter          if (!dylibs)
1141251881Speter            {
1142251881Speter              dylibs = apr_array_make(pool, 32, sizeof(*lib));
1143251881Speter            }
1144251881Speter          lib = &APR_ARRAY_PUSH(dylibs, svn_version_ext_loaded_lib_t);
1145251881Speter        }
1146251881Speter
1147251881Speter      lib->name = filename;
1148251881Speter      lib->version = version;
1149251881Speter    }
1150251881Speter
1151251881Speter  /* Gather results into one array. */
1152251881Speter  if (dylibs)
1153251881Speter    {
1154251881Speter      if (result)
1155251881Speter        apr_array_cat(result, dylibs);
1156251881Speter      else
1157251881Speter        result = dylibs;
1158251881Speter    }
1159251881Speter
1160251881Speter  return result;
1161251881Speter}
1162251881Speter#endif  /* SVN_HAVE_MACHO_ITERATE */
1163