From 73cdd86fe78d5ae53bb3d6989a8bc7a78c51e3bb Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 12 Mar 2010 02:15:51 +0000 Subject: pipe communication between installer and other improvements --- examples/lsusb.c | 4 +- libusb/os/driver_install.c | 130 ++++++++++++++++++++++++++++++++++++++-- libusb/os/driver_install.h | 3 +- libusb/os/driver_installer.c | 138 ++++++++++++++++++++++++++++++++++--------- libusb/os/windows_usb.h | 13 ++++ 5 files changed, 251 insertions(+), 37 deletions(-) diff --git a/examples/lsusb.c b/examples/lsusb.c index 488de4e..3b0495f 100644 --- a/examples/lsusb.c +++ b/examples/lsusb.c @@ -55,10 +55,10 @@ main(void) drv_info = list_driverless(); for (; drv_info != NULL; drv_info = drv_info->next) { if (create_inf(drv_info, "C:\\test") == 0) { - install_device("C:\\test"); + run_installer("C:\\test"); } } - + update_drivers(); return 0; r = libusb_init(NULL); diff --git a/libusb/os/driver_install.c b/libusb/os/driver_install.c index 3c2cc36..83b7bde 100644 --- a/libusb/os/driver_install.c +++ b/libusb/os/driver_install.c @@ -12,6 +12,7 @@ #include "windows_usb.h" #include "driver_install.h" +#define INF_NAME "libusb-device.inf" const char inf[] = "Date = \"03/08/2010\"\n\n" \ "ProviderName = \"libusb 1.0\"\n" \ @@ -122,6 +123,8 @@ static int init_cfgmgr32(void) DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE); DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE); DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDW, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Locate_DevNode, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Reenumerate_DevNode, TRUE); return LIBUSB_SUCCESS; } @@ -307,7 +310,7 @@ int extract_dlls(char* path) fclose(fd); } - usbi_dbg("so far, so good"); + usbi_dbg("successfully extracted files to %s", path); return 0; } @@ -332,7 +335,8 @@ int create_inf(struct driver_info* drv_info, char* path) extract_dlls(path); safe_strcpy(filename, MAX_PATH_LENGTH, path); - safe_strcat(filename, MAX_PATH_LENGTH, "\\libusb_device.inf"); + safe_strcat(filename, MAX_PATH_LENGTH, "\\"); + safe_strcat(filename, MAX_PATH_LENGTH, INF_NAME); fd = fopen(filename, "w"); if (fd == NULL) { @@ -353,14 +357,41 @@ int create_inf(struct driver_info* drv_info, char* path) CoCreateGuid(&guid); fprintf(fd, "DeviceGUID = \"%s\"\n", guid_to_string(guid)); fwrite(inf, sizeof(inf)-1, 1, fd); + fclose(fd); + + usbi_dbg("succesfully created %s", filename); return 0; } // TODO: extract driver-installer.exe into the dest dir -int install_device(char* path) +int run_installer(char* path) { SHELLEXECUTEINFO shExecInfo; char exename[MAX_PATH_LENGTH]; + HANDLE handle[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + HANDLE pipe = INVALID_HANDLE_VALUE; + OVERLAPPED overlapped; + int r, ret; + DWORD rd_count; + char buffer[256]; + + + // Use a pipe to communicate with our installer + pipe = CreateNamedPipe("\\\\.\\pipe\\libusb-installer", PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE, 1, 4096, 4096, 0, NULL); + if (pipe == INVALID_HANDLE_VALUE) { + usbi_err(NULL, "could not create read pipe: errcode %d", (int)GetLastError()); + r = -1; goto out; + } + + // Set the overlapped for messaging + memset(&overlapped, 0, sizeof(OVERLAPPED)); + handle[0] = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!handle[0]) { + r = -1; goto out; + } + overlapped.hEvent = handle[0]; + safe_strcpy(exename, MAX_PATH_LENGTH, path); safe_strcat(exename, MAX_PATH_LENGTH, "\\driver-installer.exe"); @@ -370,13 +401,100 @@ int install_device(char* path) shExecInfo.hwnd = NULL; shExecInfo.lpVerb = "runas"; shExecInfo.lpFile = exename; - shExecInfo.lpParameters = NULL; + // if INF_NAME ever has a space, it will be seen as multiple parameters + shExecInfo.lpParameters = INF_NAME; shExecInfo.lpDirectory = path; - shExecInfo.nShow = SW_MAXIMIZE; + shExecInfo.nShow = SW_HIDE; + // SW_NORMAL; shExecInfo.hInstApp = NULL; ShellExecuteEx(&shExecInfo); - usbi_dbg("hProcess = %p", shExecInfo.hProcess); + if (shExecInfo.hProcess == NULL) { + usbi_dbg("Installer did not run"); + r = -1; goto out; + } + handle[1] = shExecInfo.hProcess; + + while (1) { + if (!ReadFile(pipe, buffer, 256, &rd_count, &overlapped)) { + switch(GetLastError()) { + case ERROR_BROKEN_PIPE: + // The pipe has been ended - wait for installer to finish + WaitForSingleObject(handle[1], INFINITE); + usbi_dbg("hProcess1 = %p terminated", shExecInfo.hProcess); + r = 0; goto out; + case ERROR_PIPE_LISTENING: + // Wait for installer to open the pipe + Sleep(100); + continue; + case ERROR_IO_PENDING: + break; + default: + usbi_err(NULL, "pipe read message failed: %d", (int)GetLastError()); + continue; + } + + // We have IO_PENDING + switch(WaitForMultipleObjects(2, handle, FALSE, INFINITE)) { + case WAIT_OBJECT_0: // Pipe event + if (!GetOverlappedResult(pipe, &overlapped, &rd_count, FALSE)) { + switch(GetLastError()) { + case ERROR_BROKEN_PIPE: + // The pipe has been ended - wait for installer to finish + WaitForSingleObject(handle[1], INFINITE); + usbi_dbg("hProcess3 = %p terminated", shExecInfo.hProcess); + r = 0; goto out; + case ERROR_MORE_DATA: + usbi_warn(NULL, "message overflow"); + break; + default: + usbi_warn(NULL, "message async read error: %d", (int)GetLastError()); + break; + } + } else { + usbi_dbg("async: %s", buffer); + } + break; + case WAIT_OBJECT_0+1: + usbi_dbg("hProcess2 = %p terminated", shExecInfo.hProcess); + r = 0; goto out; + default: + usbi_dbg("are?"); + break; + } + } else { + usbi_dbg(" sync: %s", buffer); + } + } +out: + safe_closehandle(handle[0]); + safe_closehandle(handle[1]); + safe_closehandle(pipe); + return r; +} + +// TODO: use devinst from setupdi and pass it as param to driver-installer.exe +int update_drivers(void) +{ + DEVINST devInst; + CONFIGRET status; + + usbi_dbg("updating drivers, please wait..."); + // Get the root devnode. + status = CM_Locate_DevNode(&devInst, NULL, 0); + if (status != CR_SUCCESS) { + printf("failed to locate root devnode: %x\n", status); + return -1; + } + + // Needs admin privileges, but even with admin and the + // http://support.microsoft.com/kb/259697 doesn't work!!! + status = CM_Reenumerate_DevNode(devInst, 0); + if (status != CR_SUCCESS) { + printf("failed to re-enumerate nodes: %x\n", status); + return -1; + } + return 0; } \ No newline at end of file diff --git a/libusb/os/driver_install.h b/libusb/os/driver_install.h index 81688b3..3a3b6a8 100644 --- a/libusb/os/driver_install.h +++ b/libusb/os/driver_install.h @@ -14,7 +14,8 @@ struct driver_info { struct driver_info *list_driverless(void); char* guid_to_string(const GUID guid); int create_inf(struct driver_info* drv_info, char* path); -int install_device(char* path); +int run_installer(char* path); +int update_drivers(void); diff --git a/libusb/os/driver_installer.c b/libusb/os/driver_installer.c index 7f58d92..c6f7d63 100644 --- a/libusb/os/driver_installer.c +++ b/libusb/os/driver_installer.c @@ -9,67 +9,149 @@ #include #include #include +#include +#include +#include - -#define MAX_PATH_LENGTH 128 +#define INF_NAME "libusb-device.inf" +#define MAX_PATH_LENGTH 128 +#define safe_strncpy(dst, dst_max, src, count) strncpy(dst, src, min(count, dst_max - 1)) +#define safe_strcpy(dst, dst_max, src) safe_strncpy(dst, dst_max, src, strlen(src)+1) #define safe_strncat(dst, dst_max, src, count) strncat(dst, src, min(count, dst_max - strlen(dst) - 1)) #define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, strlen(src)+1) +HANDLE pipe = INVALID_HANDLE_VALUE; + +// TODO: return a status byte along with the message +void plog_v(const char *format, va_list args) +{ + char buffer[256]; + int size; + + if (pipe == INVALID_HANDLE_VALUE) + return; + + size = vsnprintf_s(buffer, 256, _TRUNCATE, format, args); + if (size < 0) { + buffer[255] = 0; + size = 255; + } + WriteFile(pipe, buffer, size+1, &size, NULL); +} + +void plog(const char *format, ...) +{ + va_list args; + + va_start (args, format); + plog_v(format, args); + va_end (args); +} + +void __cdecl log_callback(DIFXAPI_LOG Event, DWORD Error, const TCHAR * pEventDescription, PVOID CallbackContext) +{ + if (Error == 0){ + plog("(%u) %s", Event, pEventDescription); + } else { + plog("(%u) Error:%u - %s", Event, Error, pEventDescription); + } +} + int main(int argc, char** argv) { DWORD r; BOOL reboot_needed; char path[MAX_PATH_LENGTH]; -// INSTALLERINFO installer_info; + char log[MAX_PATH_LENGTH]; + FILE *fd; - _getcwd(path, MAX_PATH_LENGTH); - safe_strcat(path, MAX_PATH_LENGTH, "\\libusb_device.inf"); + // Connect to the messaging pipe + pipe = CreateFile("\\\\.\\pipe\\libusb-installer", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL); + if (pipe == INVALID_HANDLE_VALUE) { + // Try to write on console + printf("could not open pipe for writing: errcode %d\n", (int)GetLastError()); + return -1; + } + safe_strcpy(log, MAX_PATH_LENGTH, argv[0]); + // TODO - seek for terminal '.exe' and change extension if needed + safe_strcat(log, MAX_PATH_LENGTH, ".log"); - r = DriverPackagePreinstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR); + fd = fopen(log, "w"); + if (fd == NULL) { + plog("could not open logfile"); + goto out; + } + + if (argc >= 2) { + plog("got parameter %s", argv[1]); + printf("got param %s", argv[1]); + } + + // TODO: use GetFullPathName() to get full inf path + _getcwd(path, MAX_PATH_LENGTH); + safe_strcat(path, MAX_PATH_LENGTH, "\\"); + safe_strcat(path, MAX_PATH_LENGTH, INF_NAME); + + plog("Installing driver - please wait..."); + DIFXAPISetLogCallback(log_callback, NULL); + // TODO: set app dependency? + r = DriverPackageInstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR|DRIVER_PACKAGE_FORCE, + NULL, &reboot_needed); + DIFXAPISetLogCallback(NULL, NULL); // Will fail if inf not signed, unless DRIVER_PACKAGE_LEGACY_MODE is specified. // r = 87 ERROR_INVALID_PARAMETER on path == NULL // r = 2 ERROR_FILE_NOT_FOUND if no inf in path // r = 5 ERROR_ACCESS_DENIED if needs admin elevation - // r = 0xE0000003 ERROR_GENERAL_SYNTAX the syntax of the inf is invalid + // r = 0xE0000003 ERROR_GENERAL_SYNTAX the syntax of the inf is invalid or the inf is empty // r = 0xE0000304 ERROR_INVALID_CATALOG_DATA => no cat + // r = 0xE000023F ERROR_NO_AUTHENTICODE_CATALOG => user cancelled on warnings // r = 0xE0000247 if user decided not to install on warnings // r = 0x800B0100 ERROR_WRONG_INF_STYLE => missing cat entry in inf // r = 0xB7 => missing DRIVER_PACKAGE_REPAIR flag switch(r) { + case 0: + plog(" completed"); + plog("reboot %s needed", reboot_needed?"":"not"); + break; + case ERROR_NO_MORE_ITEMS: + plog("more recent driver was found (DRIVER_PACKAGE_FORCE option required)"); + goto out; + case ERROR_NO_SUCH_DEVINST: + plog("device not detected (DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT needs to be disabled)"); + goto out; case ERROR_INVALID_PARAMETER: - printf("invalid path\n"); - return -1; + plog("invalid path"); + goto out; case ERROR_FILE_NOT_FOUND: - printf("unable to find inf file on %s\n", path); - return -1; + plog("unable to find inf file on %s", path); + goto out; case ERROR_ACCESS_DENIED: - printf("this process needs to be run with administrative privileges\n"); - return -1; + plog("this process needs to be run with administrative privileges"); + goto out; case ERROR_WRONG_INF_STYLE: case ERROR_GENERAL_SYNTAX: - printf("the syntax of the inf is invalid\n"); - return -1; + plog("the syntax of the inf is invalid"); + goto out; case ERROR_INVALID_CATALOG_DATA: - printf("unable to locate cat file\n"); - return -1; + plog("unable to locate cat file"); + goto out; + case ERROR_NO_AUTHENTICODE_CATALOG: case ERROR_DRIVER_STORE_ADD_FAILED: - printf("cancelled by user\n"); - return -1; + plog("cancelled by user"); + goto out; // TODO: make DRIVER_PACKAGE_REPAIR optional case ERROR_ALREADY_EXISTS: - printf("driver already exists\n"); - return -1; + plog("driver already exists"); + goto out; default: - printf("unhandled error %X\n", r); - return -1; + plog("unhandled error %X", r); + goto out; } - // TODO: use - r = DriverPackageInstall(path, DRIVER_PACKAGE_LEGACY_MODE|DRIVER_PACKAGE_REPAIR, - NULL, &reboot_needed); - printf("ret = %X\n", r); - +out: + CloseHandle(pipe); return 0; } \ No newline at end of file diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index 30560b5..a7aaf7e 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -400,11 +400,24 @@ typedef enum _USB_HUB_NODE { } USB_HUB_NODE; /* Cfgmgr32.dll interface */ +typedef CHAR *DEVNODEID_A, *DEVINSTID_A; +typedef WCHAR *DEVNODEID_W, *DEVINSTID_W; + +#ifdef UNICODE +typedef DEVNODEID_W DEVNODEID; +typedef DEVINSTID_W DEVINSTID; +#else +typedef DEVNODEID_A DEVNODEID; +typedef DEVINSTID_A DEVINSTID; +#endif + DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDW, (DEVINST, PWCHAR, ULONG, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Locate_DevNode, (PDEVINST, DEVINSTID, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Reenumerate_DevNode, (DEVINST, ULONG)); #ifdef UNICODE #define CM_Get_Device_ID CM_Get_Device_IDW -- cgit v1.2.1