Chris@2: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /** Chris@1: * Plugin Load Checker Helper Chris@0: * Chris@4: * This program accepts the name of a descriptor symbol as its only Chris@1: * command-line argument. It then reads a list of plugin library paths Chris@1: * from stdin, one per line. For each path read, it attempts to load Chris@4: * that library and retrieve the named descriptor symbol, printing a Chris@1: * line to stdout reporting whether this was successful or not and Chris@1: * then flushing stdout. The output line format is described Chris@1: * below. The program exits with code 0 if all libraries were loaded Chris@1: * successfully and non-zero otherwise. Chris@0: * Chris@0: * Note that library paths must be ready to pass to dlopen() or Chris@0: * equivalent; this usually means they should be absolute paths. Chris@0: * Chris@0: * Output line for successful load of library libname.so: Chris@0: * SUCCESS|/path/to/libname.so| Chris@0: * Chris@0: * Output line for failed load of library libname.so: Chris@0: * FAILURE|/path/to/libname.so|Reason for failure if available Chris@0: * Chris@2: * Sometimes plugins will crash completely on load, bringing down this Chris@2: * program with them. If the program exits before all listed plugins Chris@2: * have been checked, this means that the plugin following the last Chris@2: * reported one has crashed. Typically the caller may want to run it Chris@2: * again, omitting that plugin. Chris@0: */ Chris@0: Chris@5: /* Chris@5: Copyright (c) 2016 Queen Mary, University of London Chris@5: Chris@5: Permission is hereby granted, free of charge, to any person Chris@5: obtaining a copy of this software and associated documentation Chris@5: files (the "Software"), to deal in the Software without Chris@5: restriction, including without limitation the rights to use, copy, Chris@5: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@5: of the Software, and to permit persons to whom the Software is Chris@5: furnished to do so, subject to the following conditions: Chris@5: Chris@5: The above copyright notice and this permission notice shall be Chris@5: included in all copies or substantial portions of the Software. Chris@5: Chris@5: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@5: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@5: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@5: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY Chris@5: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@5: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@5: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@5: Chris@5: Except as contained in this notice, the names of the Centre for Chris@5: Digital Music and Queen Mary, University of London shall not be Chris@5: used in advertising or otherwise to promote the sale, use or other Chris@5: dealings in this Software without prior written authorization. Chris@5: */ Chris@5: Chris@0: #ifdef _WIN32 Chris@0: #include Chris@0: #include Chris@10: #include Chris@10: #ifdef UNICODE Chris@10: static HMODULE LoadLibraryUTF8(std::string name) { Chris@10: int n = name.size(); Chris@10: wchar_t *wname = new wchar_t[n*2+1]; Chris@10: MultiByteToWideChar(CP_UTF8, 0, name.c_str(), n, wname, n*2); Chris@10: HMODULE h = LoadLibraryW(wname); Chris@10: delete[] wname; Chris@10: return h; Chris@10: } Chris@10: static std::string GetErrorText() { Chris@10: wchar_t *buffer; Chris@10: DWORD err = GetLastError(); Chris@10: FormatMessage( Chris@10: FORMAT_MESSAGE_ALLOCATE_BUFFER | Chris@10: FORMAT_MESSAGE_FROM_SYSTEM | Chris@10: FORMAT_MESSAGE_IGNORE_INSERTS, Chris@10: NULL, Chris@10: err, Chris@10: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), Chris@10: (LPTSTR) &buffer, Chris@10: 0, NULL ); Chris@10: int n = wcslen(buffer); Chris@10: char *text = new char[n*8 + 1]; Chris@10: WideCharToMultiByte(CP_UTF8, 0, buffer, n, text, n*8, 0, 0); Chris@10: std::string s(text); Chris@10: LocalFree(&buffer); Chris@10: delete[] text; Chris@10: for (int i = s.size(); i > 0; ) { Chris@10: --i; Chris@10: if (s[i] == '\n' || s[i] == '\r') { Chris@10: s.erase(i, 1); Chris@10: } Chris@10: } Chris@10: return s; Chris@10: } Chris@10: #define DLOPEN(a,b) LoadLibraryUTF8(a) Chris@10: #else Chris@10: #define DLOPEN(a,b) LoadLibrary((a).c_str()) Chris@10: #define GetErrorText() "" Chris@10: #endif Chris@10: #define DLSYM(a,b) (void *)GetProcAddress((HINSTANCE)(a),(b).c_str()) Chris@0: #define DLCLOSE(a) (!FreeLibrary((HINSTANCE)(a))) Chris@10: #define DLERROR() (GetErrorText()) Chris@0: #else Chris@0: #include Chris@0: #define DLOPEN(a,b) dlopen((a).c_str(),(b)) Chris@0: #define DLSYM(a,b) dlsym((a),(b).c_str()) Chris@0: #define DLCLOSE(a) dlclose((a)) Chris@0: #define DLERROR() dlerror() Chris@0: #endif Chris@0: Chris@0: #include Chris@0: #include Chris@0: Chris@12: //#include Chris@6: Chris@0: using namespace std; Chris@0: Chris@0: string error() Chris@0: { Chris@10: string e = DLERROR(); Chris@0: if (e == "") return "(unknown error)"; Chris@0: else return e; Chris@0: } Chris@0: Chris@1: string check(string soname, string descriptor) Chris@0: { Chris@0: void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); Chris@0: if (!handle) { Chris@10: return "Unable to open plugin library: " + error(); Chris@0: } Chris@0: Chris@0: void *fn = DLSYM(handle, descriptor); Chris@0: if (!fn) { Chris@10: return "Failed to find plugin descriptor " + descriptor + Chris@10: " in library: " + error(); Chris@0: } Chris@0: Chris@0: return ""; Chris@0: } Chris@0: Chris@0: int main(int argc, char **argv) Chris@0: { Chris@0: bool allGood = true; Chris@0: string soname; Chris@0: Chris@1: if (argc != 2) { Chris@11: cerr << "\nUsage:\n " << argv[0] << " descriptorname\n" Chris@11: "\nwhere descriptorname is the name of a plugin descriptor symbol to be sought\n" Chris@11: "in each library (e.g. vampGetPluginDescriptor for Vamp plugins). The list of\n" Chris@11: "candidate plugin library filenames is read from stdin.\n" << endl; Chris@11: return 2; Chris@1: } Chris@1: Chris@1: string descriptor = argv[1]; Chris@1: Chris@0: while (getline(cin, soname)) { Chris@11: string report = check(soname, descriptor); Chris@11: if (report != "") { Chris@11: cout << "FAILURE|" << soname << "|" << report << endl; Chris@11: allGood = false; Chris@11: } else { Chris@11: cout << "SUCCESS|" << soname << "|" << endl; Chris@11: } Chris@0: } Chris@11: Chris@0: return allGood ? 0 : 1; Chris@0: }