OpenCBM
startstop.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 2004, 2008, 2012 Spiro Trikaliotis
8  *
9  */
10 
20 #include <windows.h>
21 #include <stdio.h>
22 #include "cbmioctl.h"
23 
24 #include "i_opencbm.h"
25 
26 #include "archlib.h"
27 
28 #include "version.h"
29 
30 #include <stdlib.h>
31 
33 #define DBG_USERMODE
34 
36 #define DBG_PROGNAME "INSTCBM.EXE"
37 
38 #include "debug.h"
39 
40 #include "libmisc.h"
41 
42 static BOOL CheckVersions(PCBMT_I_INSTALL_OUT InstallOutBuffer);
43 static BOOL CbmCheckCorrectInstallation(BOOL HaveAdminRights);
44 
45 
56 static VOID
57 OutputPathString(IN PCHAR Text, IN PCHAR Path)
58 {
59  FUNC_ENTER();
60 
61  DBG_PRINT((DBG_PREFIX "%s%s", Text, Path));
62  printf("%s%s\n", Text, Path);
63 
64  FUNC_LEAVE();
65 }
66 
78 static VOID
79 OutputVersionString(IN PCHAR Text, IN ULONG Version, IN ULONG VersionEx)
80 {
81  char buffer[100];
82  char buffer2[100];
83 
84  FUNC_ENTER();
85 
86  if (Version != 0)
87  {
88  char patchlevelVersion[] = "pl0";
89 
90  if (CBMT_I_INSTALL_OUT_GET_VERSION_EX_BUGFIX(VersionEx) != 0)
91  {
92  patchlevelVersion[2] =
93  (char) (CBMT_I_INSTALL_OUT_GET_VERSION_EX_BUGFIX(VersionEx) + '0');
94  }
95  else
96  {
97  patchlevelVersion[0] = 0;
98  }
99 
100  _snprintf(buffer2, sizeof(buffer)-1,
102  ? "%u.%u.%u.%u"
103  : "%u.%u.%u"),
104  (unsigned int) CBMT_I_INSTALL_OUT_GET_VERSION_MAJOR(Version),
105  (unsigned int) CBMT_I_INSTALL_OUT_GET_VERSION_MINOR(Version),
106  (unsigned int) CBMT_I_INSTALL_OUT_GET_VERSION_SUBMINOR(Version),
107  (unsigned int) CBMT_I_INSTALL_OUT_GET_VERSION_DEVEL(Version));
108 
109  _snprintf(buffer, sizeof(buffer)-1,
111  ? "%s%s (Development)"
112  : "%s%s"),
113  buffer2,
114  patchlevelVersion);
115  }
116  else
117  {
118  _snprintf(buffer, sizeof(buffer)-1, "COULD NOT DETERMINE VERSION");
119  }
120  buffer[sizeof(buffer)-1] = 0;
121 
122  OutputPathString(Text, buffer);
123 
124  FUNC_LEAVE();
125 }
126 
127 
154 static BOOL
155 ReadDriverData(char *DriverPath, ULONG DriverPathLen, DWORD *StartMode, DWORD *LptPort, DWORD *LptLocking, DWORD *CableType)
156 {
157  BOOL error = TRUE;
158 
159  HKEY regKey = NULL;
160 
161  FUNC_ENTER();
162 
163  do {
164  DWORD regLength;
165  DWORD regReturn;
166  DWORD regType;
167  char driverPathFromRegistry[MAX_PATH];
168  char *pColon;
169 
170  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
172  0,
173  KEY_QUERY_VALUE,
174  &regKey)
175  )
176  {
177  DBG_WARN((DBG_PREFIX "RegOpenKeyEx() failed!"));
178  fprintf(stderr, "Could not open registry key\n");
179  regKey = NULL;
180  break;
181  }
182 
183  // now, get the number of the port to use
184 
185  regLength = sizeof(driverPathFromRegistry);
186 
187  regReturn = RegQueryValueEx(regKey, "ImagePath", NULL, &regType,
188  (LPBYTE)driverPathFromRegistry, &regLength);
189 
190  if (regReturn != ERROR_SUCCESS)
191  {
192  DBG_ERROR((DBG_PREFIX "No HKLM\\" CBM_REGKEY_SERVICE "\\ImagePath"
193  " value: %s", cbmlibmisc_format_error_message(regReturn)));
194 
195  break;
196  }
197 
198 
200 
201  // Make sure there is a trailing zero
202 
203  driverPathFromRegistry[sizeof(driverPathFromRegistry)-1] = 0;
204 
205  // Find out if there is a colon ":" in the path
206 
207  pColon = strchr(driverPathFromRegistry, ':');
208 
209  if (pColon)
210  {
211  // There is a colon, that is, the path is absolute
212 
213  if (strncmp(driverPathFromRegistry, "\\??\\", sizeof("\\??\\")-1) == 0)
214  {
215  // There is the \??\ prefix, skip that
216 
217  strncpy(DriverPath, &driverPathFromRegistry[sizeof("\\??\\")-1],
218  DriverPathLen);
219  }
220  else
221  {
222  strncpy(DriverPath, driverPathFromRegistry, DriverPathLen);
223  }
224  }
225  else
226  {
227  DWORD lengthString;
228 
229  // There is no colon, that is, the path is relative (to the windows directory)
230  // Thus, make sure the windows directory is appended in front of it
231 
232  lengthString = GetWindowsDirectory(DriverPath, DriverPathLen);
233 
234  if ((lengthString != 0) && (lengthString < DriverPathLen))
235  {
236  strncat(&DriverPath[lengthString], "\\", DriverPathLen-lengthString);
237  ++lengthString;
238 
239  strncat(&DriverPath[lengthString], driverPathFromRegistry,
240  DriverPathLen-lengthString);
241  }
242  }
243 
244 
245 #if DBG
246  // find out the start mode of the driver
247 
248  RegGetDWORD(regKey, "Start", StartMode);
249 
250  // find out the default lpt port of the driver
251 
252  RegGetDWORD(regKey, CBM_REGKEY_SERVICE_DEFAULTLPT, LptPort);
253 
254  // find out the configured LPT port locking behaviour
255 
256  RegGetDWORD(regKey, CBM_REGKEY_SERVICE_PERMLOCK, LptLocking);
257 
258  // find out the configured cable type
259 
260  RegGetDWORD(regKey, CBM_REGKEY_SERVICE_IECCABLE, CableType);
261 
262 #endif
263 
264  error = FALSE;
265 
266  } while (0);
267 
268  // We're done, close the registry handle.
269 
270  if (regKey != NULL) {
271  RegCloseKey(regKey);
272  }
273 
274  FUNC_LEAVE_BOOL(error);
275 }
276 
277 
278 
299 static BOOL
300 getVersionInfoOfFile(char * Filename, ULONG *VersionNumber, ULONG *PatchLevelNumber)
301 {
302  ULONG error = TRUE;
303 
304  DWORD versionInfoSize;
305  DWORD dummyhandle;
306 
307  FUNC_ENTER();
308 
309  DBG_ASSERT(PatchLevelNumber);
310 
311  *PatchLevelNumber = 0;
312 
313  versionInfoSize = GetFileVersionInfoSize(Filename, &dummyhandle);
314 
315  if (versionInfoSize > 0)
316  {
317  void *versionInfo = malloc(versionInfoSize);
318 
319  if (versionInfo && GetFileVersionInfo(Filename, 0, versionInfoSize, versionInfo))
320  {
321  VS_FIXEDFILEINFO *fileInfo;
322  DWORD fileInfoSize = 0;
323  TCHAR *versionInfoText = 0;
324 
325  if (VerQueryValue(versionInfo, TEXT("\\"), &fileInfo, &fileInfoSize))
326  {
327  *VersionNumber = ((fileInfo->dwFileVersionMS & 0x00FF0000) >> 8) | fileInfo->dwFileVersionMS & 0xFF;
328  *VersionNumber <<= 16;
329  *VersionNumber |= ((fileInfo->dwFileVersionLS & 0x00FF0000) >> 8) | fileInfo->dwFileVersionLS & 0xFF;
330 
331  error = FALSE;
332  }
333 
334  // determine if there is some patch-level involved
335 
336  if (VerQueryValue(versionInfo, TEXT("\\StringFileInfo\\000004B0\\FileVersion"), &versionInfoText, &fileInfoSize))
337  {
338  char *patch_level = strstr(versionInfoText, "pl");
339 
340  if (patch_level)
341  {
342  *PatchLevelNumber = atoi(patch_level + 2);
343  }
344  else
345  {
346  // handling of old 0.1.0a version, which handled the patch-level in a different format:
347 
348  if (strcmp(versionInfoText, TEXT("0.1.0a")) == 0)
349  *PatchLevelNumber = 1;
350  }
351  }
352  }
353 
354  free(versionInfo);
355  }
356 
357  FUNC_LEAVE_ULONG(error);
358 }
359 
385 static BOOL
386 ReadDllVersion(char * Filename, char * Path, ULONG PathLen, ULONG * VersionNumber, ULONG * VersionNumberEx)
387 {
388  BOOL error = TRUE;
389 
390  HMODULE handleDll;
391 
392  FUNC_ENTER();
393 
394  // Try to load the DLL. If this succeeds, get the version information
395  // from there
396 
397  handleDll = LoadLibrary(Filename);
398 
399  if (handleDll)
400  {
401  DWORD length;
402 
403  length = GetModuleFileName(handleDll, Path, PathLen);
404 
405  if (length >= PathLen)
406  {
407  Path[PathLen-1] = 0;
408  }
409 
410  error = getVersionInfoOfFile(Path, VersionNumber, VersionNumberEx);
411 
412  FreeLibrary(handleDll);
413  }
414 
415  FUNC_LEAVE_BOOL(error);
416 }
417 
430 static BOOL
431 CompleteDriverInstallation(HMODULE HandleDll)
432 {
433  BOOL error = TRUE;
434 
435 #if 0
436 
437  cbm_install_complete_t * p_cbm_install_complete;
438  CBMT_I_INSTALL_OUT dllInstallOutBuffer;
439 
440  FUNC_ENTER();
441 
442  memset(&dllInstallOutBuffer, 0, sizeof(dllInstallOutBuffer));
443 
444  p_cbm_install_complete =
445  (cbm_install_complete_t *) GetProcAddress(HandleDll, "cbm_install_complete");
446 
447  if (p_cbm_install_complete) {
448  error = p_cbm_install_complete((PULONG) &dllInstallOutBuffer, sizeof(dllInstallOutBuffer));
449  }
450 
451 #endif
452 
453  FUNC_LEAVE_BOOL(error);
454 }
455 
464 int
466 {
467  int error;
468 
469  FUNC_ENTER();
470 
471  DBG_PRINT((DBG_PREFIX "Checking configuration for OpenCBM"));
472  printf("Checking configuration for OpenCBM\n");
473 
474  if (CbmCheckCorrectInstallation(TRUE ))
475  {
476  DBG_PRINT((DBG_PREFIX "There were errors in the current configuration."
477  "Please fix them before trying to use the driver!"));
478  fprintf(stderr, "*** There were errors in the current configuration.\n"
479  "*** Please fix them before trying to use the driver!\n");
480  error = 11;
481  }
482  else
483  {
484  error = 0;
485  DBG_PRINT((DBG_PREFIX "No problems found in current configuration"));
486  printf("No problems found in current configuration\n\n");
487 
497  }
498 
499  FUNC_LEAVE_INT(error);
500 }
501 
502 
506 static BOOL
507 checkIfDifferentVersions(Version1, VersionEx1, Version2, VersionEx2)
508 {
509  return ((Version1 != Version2) || (VersionEx1 != VersionEx2)) ? TRUE : FALSE;
510 }
511 
512 static char *
513 get_plugin_filename(char *PluginName)
514 {
515  char *filename;
516 
517  FUNC_ENTER();
518 
519  filename = malloc(sizeof("opencbm-.dll") + strlen(PluginName));
520 
521  if (filename)
522  sprintf(filename, "opencbm-%s.dll", PluginName);
523 
524  FUNC_LEAVE_STRING(filename);
525 }
526 
545 static BOOL
546 CheckVersions(PCBMT_I_INSTALL_OUT InstallOutBuffer)
547 {
548  ULONG instcbmVersion;
549  ULONG instcbmVersionEx;
550  DWORD startMode;
551  DWORD lptPort;
552  DWORD lptLocking;
553  DWORD cableType;
554  char dllPath[MAX_PATH] = "<unknown>";
555  char driverPath[MAX_PATH] = "<unknown>";
556  BOOL error;
557  BOOL differentVersion = FALSE;
558  char **PluginNames = NULL;
559 
560  FUNC_ENTER();
561 
562  error = FALSE;
563 
564  // Default value for unset/unconfigured registry settings
565 
566  startMode = -1;
567  lptPort = 0;
568  lptLocking = 1;
569  cableType = -1;
570 
571  // Try to find out the version and path of the DLL
572 
573  error = ReadDllVersion("OPENCBM.DLL", dllPath, sizeof(dllPath),
574  &InstallOutBuffer->DllVersion, &InstallOutBuffer->DllVersionEx);
575 
576  // Try to find the path to the driver
577 
578  error = ReadDriverData(driverPath, sizeof(driverPath), &startMode, &lptPort, &lptLocking, &cableType);
579 
580  // Print out the configuration we just obtained
581 
582  printf("\n\nThe following configuration is used:\n\n");
583 
584  instcbmVersion =
585  CBMT_I_INSTALL_OUT_MAKE_VERSION(OPENCBM_VERSION_MAJOR,
586  OPENCBM_VERSION_MINOR,
587  OPENCBM_VERSION_SUBMINOR,
588  OPENCBM_VERSION_DEVEL);
589 
590  instcbmVersionEx =
591  CBMT_I_INSTALL_OUT_MAKE_VERSION_EX(OPENCBM_VERSION_PATCHLEVEL);
592 
593  OutputVersionString("INSTCBM version: ", instcbmVersion, instcbmVersionEx);
594 
595  OutputVersionString("Driver version: ", InstallOutBuffer->DriverVersion,
596  InstallOutBuffer->DriverVersionEx);
597  OutputPathString ("Driver path: ", driverPath);
598  differentVersion |= checkIfDifferentVersions(instcbmVersion, instcbmVersionEx,
599  InstallOutBuffer->DriverVersion, InstallOutBuffer->DriverVersionEx);
600 
601  OutputVersionString("DLL version: ", InstallOutBuffer->DllVersion,
602  InstallOutBuffer->DllVersionEx);
603  OutputPathString ("DLL path: ", dllPath);
604  differentVersion |= checkIfDifferentVersions(instcbmVersion, instcbmVersionEx,
605  InstallOutBuffer->DllVersion, InstallOutBuffer->DllVersionEx);
606 
607 #if 0 // def _X86_
608  {
609  ULONG dllVersionVdd = 0;
610  ULONG dllVersionVddEx = 0;
611 
612  dllPath[0] = 0;
613 
614  ReadDllVersion("opencbmvdd.dll", dllPath, sizeof(dllPath),
615  &dllVersionVdd, &dllVersionVddEx);
616 
617  OutputVersionString("VDD version: ", dllVersionVdd, dllVersionVddEx);
618  OutputPathString ("VDD path: ", dllPath);
619  differentVersion |= checkIfDifferentVersions(instcbmVersion, instcbmVersionEx,
620  dllVersionVdd, dllVersionVddEx);
621  }
622 #endif // #ifdef _X86_
623 
624  if (PluginNames)
625  {
626  unsigned int i;
627 
628  for (i = 0; PluginNames[i] != NULL; i++)
629  {
630  ULONG dllVersionPlugin = 0;
631  ULONG dllVersionPluginEx = 0;
632 
633  char *filename = get_plugin_filename(PluginNames[i]);
634 
635  dllPath[0] = 0;
636 
637  if (!filename)
638  {
639  error = TRUE;
640  break;
641  }
642 
643  error = ReadDllVersion(filename, dllPath, sizeof(dllPath),
644  &dllVersionPlugin, &dllVersionPluginEx);
645 
646  free(filename);
647 
648  printf("\nPlugin '%s':\n", PluginNames[i]);
649  OutputVersionString("Plugin version: ", dllVersionPlugin, dllVersionPluginEx);
650  OutputPathString ("Plugin path: ", dllPath);
651 
656  }
657  }
658 
659  printf("\n");
660 
661  if (differentVersion)
662  {
663  error = TRUE;
664  printf("There are mixed versions, THIS IS NOT RECOMMENDED!\n\n");
665  }
666 
667  printf("Driver configuration:\n");
668  DBG_PRINT((DBG_PREFIX "Driver configuration:"));
669 
670  printf( " Default port: ........ LPT%i\n", lptPort ? lptPort : 1);
671  DBG_PRINT((DBG_PREFIX " Default port: ........ LPT%i", lptPort ? lptPort : 1));
672 
673  {
674  const char *startModeName;
675 
676  switch (startMode)
677  {
678  case -1:
679  startModeName = "NO ENTRY FOUND!";
680  break;
681 
682  case SERVICE_BOOT_START:
683  startModeName = "boot";
684  break;
685 
686  case SERVICE_SYSTEM_START:
687  startModeName = "system";
688  break;
689 
690  case SERVICE_AUTO_START:
691  startModeName = "auto";
692  break;
693 
694  case SERVICE_DEMAND_START:
695  startModeName = "demand";
696  break;
697 
698  case SERVICE_DISABLED:
699  startModeName = "disabled";
700  break;
701 
702  default:
703  startModeName = "<UNKNOWN>";
704  break;
705  }
706 
707  printf(" Driver start mode: ... %s (%i)\n", startModeName, startMode);
708  DBG_PRINT((DBG_PREFIX " Driver start mode: ... %s (%i)", startModeName,
709  startMode));
710  }
711 
712  printf( " LPT port locking: .... %s\n", lptLocking ? "yes" : "no");
713  DBG_PRINT((DBG_PREFIX " LPT port locking: .... %s", lptLocking ? "yes" : "no"));
714 
715  {
716  const char *cableTypeName;
717 
718  switch (cableType)
719  {
720  case -1:
721  cableTypeName = "auto";
722  break;
723 
724  case 0:
725  cableTypeName = "xm1541";
726  break;
727 
728  case 1:
729  cableTypeName = "xa1541";
730  break;
731 
732  default:
733  cableTypeName = "<UNKNOWN>";
734  break;
735  }
736 
737  printf(" Cable type: .......... %s (%i)\n\n", cableTypeName, cableType);
738  DBG_PRINT((DBG_PREFIX " Cable type: .......... %s (%i)", cableTypeName,
739  cableType));
740  }
741 
742  FUNC_LEAVE_BOOL(error);
743 }
744 
766 static BOOL
767 CbmCheckCorrectInstallation(BOOL HaveAdminRights)
768 {
769  CBMT_I_INSTALL_OUT outBuffer;
770  BOOL error;
771  BOOL driverAlreadyStarted = FALSE;
772  int tries;
773 
774  FUNC_ENTER();
775 
776  memset(&outBuffer, 0, sizeof(outBuffer));
777 
778  for (tries = 1; tries >= 0; --tries)
779  {
780  if (driverAlreadyStarted) {
781  cbm_driver_stop();
782  }
783 
784  error = HaveAdminRights ? (cbm_driver_start() ? FALSE : TRUE) : FALSE;
785 
786  error = FALSE;
787 
788  driverAlreadyStarted = TRUE;
789 
790  if (error)
791  {
792  DBG_PRINT((DBG_PREFIX "Driver or DLL not correctly installed."));
793  printf("Driver or DLL not correctly installed.\n");
794  break;
795  }
796  else
797  {
798  error = cbm_driver_install((PULONG) &outBuffer, sizeof(outBuffer));
799 
800  outBuffer.DllVersion = 0;
801 
802  if (error)
803  {
804  DBG_PRINT((DBG_PREFIX "Driver problem: Could not check install."));
805  printf("Driver problem: Could not check install.\n");
806  break;
807  }
808 
809  // did we fail to gather an interrupt?
810 
811  if (outBuffer.ErrorFlags & CBM_I_DRIVER_INSTALL_0M_NO_INTERRUPT)
812  {
813  if (tries > 0)
814  {
815  //
816  // stop the driver to be able to restart the parallel port
817  //
818 
819  cbm_driver_stop();
820  driverAlreadyStarted = FALSE;
821 
822  //
823  // No IRQ available: Try to restart the parallel port to enable it.
824  //
825 
826  printf("Please wait some seconds...\n");
827 
829  }
830  else
831  {
832  DBG_PRINT((DBG_PREFIX "No interrupt available."));
833  printf("\n*** Could not get an interrupt. Please try again after a reboot.\n");
834  error = TRUE;
835  }
836  }
837  else
838  {
839  error = FALSE;
840 
841  // no problem so far. Now, check if the IRQ is actually working
842 // error = CbmTestIrq();
843 
844  // no problem, we can stop the loop
845 
846  break;
847  }
848  }
849  }
850 
851  //
852  // If the driver is not set to be started automatically, stop it now
853  //
854 
856  {
857  cbm_driver_stop();
858  }
859 
860  if (CheckVersions(&outBuffer))
861  {
862  error = TRUE;
863  }
864 
865  FUNC_LEAVE_BOOL(error);
866 }
#define CBMT_I_INSTALL_OUT_GET_VERSION_SUBMINOR(_x)
Definition: cbmioctl.h:150
#define DBG_WARN(_xxx)
Definition: debug.h:395
#define FUNC_LEAVE_INT(_xxx)
Definition: debug.h:358
Define makros for debugging purposes.
int CbmCheckDriver(void)
Check for the correct installation.
Definition: startstop.c:465
#define CBM_REGKEY_SERVICE
Definition: cbmioctl.h:38
LONG RegGetDWORD(IN HKEY RegKey, IN char *SubKey, OUT LPDWORD Value)
Get a DWORD value from the registry.
Definition: registry.c:54
#define CBM_REGKEY_SERVICE_IECCABLE
Definition: cbmioctl.h:46
Define the IOCTL codes for the opencbm driver.
#define FUNC_LEAVE_ULONG(_xxx)
Definition: debug.h:370
ULONG DriverVersionEx
Definition: cbmioctl.h:185
#define CBM_REGKEY_SERVICE_DEFAULTLPT
Definition: cbmioctl.h:42
#define CBM_REGKEY_SERVICE_PERMLOCK
Definition: cbmioctl.h:50
#define FUNC_LEAVE()
Definition: debug.h:349
#define CBMT_I_INSTALL_OUT_GET_VERSION_MAJOR(_x)
Definition: cbmioctl.h:146
BOOL cbm_driver_install(OUT PULONG Buffer, IN ULONG BufferLen)
Complete driver installation, "direct version".
Definition: i_opencbm.c:704
#define CBMT_I_INSTALL_OUT_GET_VERSION_EX_BUGFIX(_x)
Definition: cbmioctl.h:160
#define CBMT_I_INSTALL_OUT_MAKE_VERSION(_x, _y, _z, _w)
Definition: cbmioctl.h:155
#define DBG_ASSERT(_xxx)
Definition: debug.h:401
#define FUNC_LEAVE_BOOL(_xxx)
Definition: debug.h:354
#define CBMT_I_INSTALL_OUT_GET_VERSION_MINOR(_x)
Definition: cbmioctl.h:148
#define CBMT_I_INSTALL_OUT_MAKE_VERSION_EX(_w)
Definition: cbmioctl.h:163
#define DBG_ERROR(_xxx)
Definition: debug.h:397
Defining OpenCBM version.
#define FUNC_ENTER()
Definition: debug.h:347
#define CBM_I_DRIVER_INSTALL_0M_NO_INTERRUPT
CBMCTRL_I_INSTALL: No interrupt available.
Definition: cbmioctl.h:356
#define DBG_PREFIX
Definition: debug.h:320
#define FUNC_LEAVE_STRING(_xxx)
Definition: debug.h:368
VOID CbmParportRestart(VOID)
Restart the parallel port.
Definition: parport.c:143
BOOL cbm_driver_stop(VOID)
Stop a device driver.
Definition: i_opencbm.c:639
#define CBMT_I_INSTALL_OUT_GET_VERSION_DEVEL(_x)
Definition: cbmioctl.h:152
BOOL cbm_driver_start(VOID)
Start a device driver.
Definition: i_opencbm.c:564
Internal API for opencbm installation.
Some functions for string handling.
char * cbmlibmisc_format_error_message(unsigned int ErrorNumber)
Format a returned error code into a string.
#define DBG_PRINT(_xxx)
Definition: debug.h:403
BOOL IsDriverStartedAutomatically(VOID)
Is the driver started automatically?
Definition: i_opencbm.c:763