From e71a6c24c41e3d390a81aac1986938a1db71f9e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Wed, 28 May 2014 19:50:51 +0200
Subject: loader: Add commandline option --check-libs.

---
 include/wine/library.h |   2 +
 libs/wine/config.c     | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
 libs/wine/loader.c     |  36 ++++++++++++++++
 libs/wine/wine.def     |   2 +
 libs/wine/wine.map     |   2 +
 loader/main.c          |  50 +++++++++++++++++++++-
 6 files changed, 203 insertions(+), 1 deletion(-)

diff --git a/include/wine/library.h b/include/wine/library.h
index fae73fe..7395a11 100644
--- a/include/wine/library.h
+++ b/include/wine/library.h
@@ -40,6 +40,7 @@ extern "C" {
 extern const char *wine_get_build_dir(void);
 extern const char *wine_get_config_dir(void);
 extern const char *wine_get_data_dir(void);
+extern const char **wine_get_libs(void);
 extern const char *wine_get_server_dir(void);
 extern const char *wine_get_user_name(void);
 extern const char *wine_get_version(void);
@@ -52,6 +53,7 @@ extern void wine_exec_wine_binary( const char *name, char **argv, const char *en
 
 typedef void (*load_dll_callback_t)( void *, const char * );
 
+extern int wine_dladdr( void *addr, void *info, char *error, size_t errorsize );
 extern void *wine_dlopen( const char *filename, int flag, char *error, size_t errorsize );
 extern void *wine_dlsym( void *handle, const char *symbol, char *error, size_t errorsize );
 extern int wine_dlclose( void *handle, char *error, size_t errorsize );
diff --git a/libs/wine/config.c b/libs/wine/config.c
index 5262c76..7acf51b 100644
--- a/libs/wine/config.c
+++ b/libs/wine/config.c
@@ -444,6 +444,118 @@ const char *wine_get_build_dir(void)
     return build_dir;
 }
 
+const char *wine_libs[] = {
+#ifdef SONAME_LIBCAPI20
+    SONAME_LIBCAPI20,
+#endif
+#ifdef SONAME_LIBCUPS
+    SONAME_LIBCUPS,
+#endif
+#ifdef SONAME_LIBCURSES
+    SONAME_LIBCURSES,
+#endif
+#ifdef SONAME_LIBDBUS_1
+    SONAME_LIBDBUS_1,
+#endif
+#ifdef SONAME_LIBFONTCONFIG
+    SONAME_LIBFONTCONFIG,
+#endif
+#ifdef SONAME_LIBFREETYPE
+    SONAME_LIBFREETYPE,
+#endif
+#ifdef SONAME_LIBGL
+    SONAME_LIBGL,
+#endif
+#ifdef SONAME_LIBGNUTLS
+    SONAME_LIBGNUTLS,
+#endif
+#ifdef SONAME_LIBGSM
+    SONAME_LIBGSM,
+#endif
+#ifdef SONAME_LIBHAL
+    SONAME_LIBHAL,
+#endif
+#ifdef SONAME_LIBJPEG
+    SONAME_LIBJPEG,
+#endif
+#ifdef SONAME_LIBNCURSES
+    SONAME_LIBNCURSES,
+#endif
+#ifdef SONAME_LIBNETAPI
+    SONAME_LIBNETAPI,
+#endif
+#ifdef SONAME_LIBODBC
+    SONAME_LIBODBC,
+#endif
+#ifdef SONAME_LIBOSMESA
+    SONAME_LIBOSMESA,
+#endif
+#ifdef SONAME_LIBPCAP
+    SONAME_LIBPCAP,
+#endif
+#ifdef SONAME_LIBPNG
+    SONAME_LIBPNG,
+#endif
+#ifdef SONAME_LIBSANE
+    SONAME_LIBSANE,
+#endif
+#ifdef SONAME_LIBTIFF
+    SONAME_LIBTIFF,
+#endif
+#ifdef SONAME_LIBTXC_DXTN
+    SONAME_LIBTXC_DXTN,
+#endif
+#ifdef SONAME_LIBV4L1
+    SONAME_LIBV4L1,
+#endif
+#ifdef SONAME_LIBVA
+    SONAME_LIBVA,
+#endif
+#ifdef SONAME_LIBVA_DRM
+    SONAME_LIBVA_DRM,
+#endif
+#ifdef SONAME_LIBVA_X11
+    SONAME_LIBVA_X11,
+#endif
+#ifdef SONAME_LIBX11
+    SONAME_LIBX11,
+#endif
+#ifdef SONAME_LIBXCOMPOSITE
+    SONAME_LIBXCOMPOSITE,
+#endif
+#ifdef SONAME_LIBXCURSOR
+    SONAME_LIBXCURSOR,
+#endif
+#ifdef SONAME_LIBXEXT
+    SONAME_LIBXEXT,
+#endif
+#ifdef SONAME_LIBXI
+    SONAME_LIBXI,
+#endif
+#ifdef SONAME_LIBXINERAMA
+    SONAME_LIBXINERAMA,
+#endif
+#ifdef SONAME_LIBXRANDR
+    SONAME_LIBXRANDR,
+#endif
+#ifdef SONAME_LIBXRENDER
+    SONAME_LIBXRENDER,
+#endif
+#ifdef SONAME_LIBXSLT
+    SONAME_LIBXSLT,
+#endif
+#ifdef SONAME_LIBXXF86VM
+    SONAME_LIBXXF86VM,
+#endif
+    NULL
+};
+
+/* return the list of shared libs used by wine */
+const char **wine_get_libs(void)
+{
+    return &wine_libs[0];
+}
+
 /* return the full name of the server directory (the one containing the socket) */
 const char *wine_get_server_dir(void)
 {
diff --git a/libs/wine/loader.c b/libs/wine/loader.c
index 3591ede..2718857 100644
--- a/libs/wine/loader.c
+++ b/libs/wine/loader.c
@@ -1043,6 +1043,42 @@ void *wine_dlopen( const char *filename, int flag, char *error, size_t errorsize
 }
 
 /***********************************************************************
+ *      wine_dladdr
+ */
+int wine_dladdr( void *addr, void *info, char *error, size_t errorsize )
+{
+#ifdef HAVE_DLADDR
+    int ret;
+    const char *s;
+    dlerror(); dlerror();
+    ret = dladdr( addr, (Dl_info *)info );
+    s = dlerror();
+    if (error && errorsize)
+    {
+        if (s)
+        {
+            size_t len = strlen(s);
+            if (len >= errorsize) len = errorsize - 1;
+            memcpy( error, s, len );
+            error[len] = 0;
+        }
+        else error[0] = 0;
+    }
+    dlerror();
+    return ret;
+#else
+    if (error)
+    {
+        static const char msg[] = "dladdr interface not detected by configure";
+        size_t len = min( errorsize, sizeof(msg) );
+        memcpy( error, msg, len );
+        error[len - 1] = 0;
+    }
+    return 0;
+#endif
+}
+
+/***********************************************************************
  *		wine_dlsym
  */
 void *wine_dlsym( void *handle, const char *symbol, char *error, size_t errorsize )
diff --git a/libs/wine/wine.def b/libs/wine/wine.def
index 5b42029..6acf329 100644
--- a/libs/wine/wine.def
+++ b/libs/wine/wine.def
@@ -64,6 +64,7 @@ EXPORTS
     wine_dbg_sprintf
     wine_dbgstr_an
     wine_dbgstr_wn
+    wine_dladdr
     wine_dlclose
     wine_dll_enum_load_path
     wine_dll_get_owner
@@ -79,6 +80,7 @@ EXPORTS
     wine_get_build_id
     wine_get_config_dir
     wine_get_data_dir
+    wine_get_libs
     wine_get_server_dir
     wine_get_sortkey
     wine_get_user_name
diff --git a/libs/wine/wine.map b/libs/wine/wine.map
index 7cb2918..72ffed8 100644
--- a/libs/wine/wine.map
+++ b/libs/wine/wine.map
@@ -65,6 +65,7 @@ WINE_1.0
     wine_dbg_sprintf;
     wine_dbgstr_an;
     wine_dbgstr_wn;
+    wine_dladdr;
     wine_dlclose;
     wine_dll_enum_load_path;
     wine_dll_get_owner;
@@ -85,6 +86,7 @@ WINE_1.0
     wine_get_es;
     wine_get_fs;
     wine_get_gs;
+    wine_get_libs;
     wine_get_server_dir;
     wine_get_sortkey;
     wine_get_ss;
diff --git a/loader/main.c b/loader/main.c
index fa0efa2..e96363d 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -36,6 +36,12 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#ifdef HAVE_DLADDR
+# include <dlfcn.h>
+#endif
+#ifdef HAVE_LINK_H
+# include <link.h>
+#endif
 #include <pthread.h>
 
 #include "wine/library.h"
@@ -90,7 +96,8 @@ static void check_command_line( int argc, char *argv[] )
         "Usage: wine PROGRAM [ARGUMENTS...]   Run the specified program\n"
         "       wine --help                   Display this help and exit\n"
         "       wine --version                Output version information and exit\n"
-        "       wine --patches                Output patch information and exit";
+        "       wine --patches                Output patch information and exit\n"
+        "       wine --check-libs             Checks if shared libs are installed";
 
     if (argc <= 1)
     {
@@ -146,6 +153,47 @@ static void check_command_line( int argc, char *argv[] )
 
         exit(0);
     }
+    if (!strcmp( argv[1], "--check-libs" ))
+    {
+        void* lib_handle;
+        int ret = 0;
+        const char **wine_libs = wine_get_libs();
+
+        for(; *wine_libs; wine_libs++)
+        {
+            lib_handle = wine_dlopen( *wine_libs, RTLD_NOW, NULL, 0 );
+            if (lib_handle)
+            {
+            #ifdef HAVE_DLADDR
+                Dl_info libinfo;
+                void* symbol;
+
+            #ifdef HAVE_LINK_H
+                struct link_map *lm = (struct link_map *)lib_handle;
+                symbol = (void *)lm->l_addr;
+            #else
+                symbol = wine_dlsym( lib_handle, "_init", NULL, 0 );
+            #endif
+                if (symbol && wine_dladdr( symbol, &libinfo, NULL, 0 ))
+                {
+                    printf( "%s: %s\n", *wine_libs, libinfo.dli_fname );
+                }
+                else
+            #endif
+                {
+                    printf( "%s: found\n", *wine_libs );
+                }
+                wine_dlclose( lib_handle, NULL, 0 );
+            }
+            else
+            {
+                printf( "%s: missing\n", *wine_libs );
+                ret = 1;
+            }
+        }
+
+        exit(ret);
+    }
 }
 
 
-- 
2.3.1