/*
 **************************************************************************
 *                                                                        *
 * File Name.....: hybernat.c                                             *
 *                                                                        *
 * Component Name: Hybernation / Trapdoor                                 *
 *                                                                        *
 * Description...: Hybernation / Trapdoor driver program.                 *
 *                                                                        *
 * Functions.....: 1. main()                                              *
 *                 2. thread1 ()                                          *
 *                 3. apmopen (), apmclose ()                             *
 *                 4. sendevent ()                                        *
 *                 5. setBootManagerTimeOut (),                           *
 *                 6. setBootManagerUnAttended (), setBootManagerAttended *
 *                 7. getBootDrive ()                                     *
 *                 8. cleanupAndExit ()                                   *
 *                 9. setupConfigSys (), setupSysIni ()                   *
 *                                                                        *
 *                                                                        *
 * (C) COPYRIGHT International Business Machines Corp. 1994 - 1996        *
 * All Rights Reserved                                                    *
 * Licenced Materials - Property of IBM                                   *
 *                                                                        *
 * US Government Users Restricted Rights - Use, duplication or disclosure *
 * restricted by GSA ADP Schedule Contract with IBM Corp.                 *
 *                                                                        *
 *                                                                        *
 * Created.......:  January 1, 1995                                       *
 *                                                                        *
 **************************************************************************
 * Change                                                             Chg *
 * Activity  Date     By    Reason                                    Num *
 * --------  -------- ---   ------                                    --- *
 * 149884    03/27/96 bhm   Add concise response message to user      001 *
 *                          hibernation if trapdoor fails.                *
 * 149965    04/02/96 bhm   If boot manager installed then switch     002 *
 *                          to unattended mode when hibernating.          *
 * 150306    04/04/96 bhm   HPFS not currently supported for this     003 *
 *                          release.  Add appropriate message and         *
 *                          return code.  HPFS support is broken.         *
 * 150698    04/04/96 MT    Rewrite setupConfigSys()                  004 *
 * 150806    04/08/96 TPL   Add DD save/restore notification          005 *
 * 151019    04/08/96 bhm   HPFS not currently supported for this     006 *
 *                          release.  Qualify OS/2 drive letters          *
 *                          to target OS drive letter.                    *
 * 150281    04/11/96 TPL   Use SYS_FREEZE_THAW_SYS to gain complete  007 *
 *                          control of the system                         *
 * 151802    04/13/96 MT    NLS/DBCS enabling                         008 *
 * 151952    04/16/96 bhm   HPFS not currently supported for this     009 *
 *                          release.  Qualify boot drive as non HPFS      *
 * 150744    04/19/96 MT    Fix DOS.CFG to load DOS/WINDOWS apps      010 *
 *                          Add HIBER.DAT to launch DOS apps              *
 * 151055    04/23/96 bhm   Add DosQueryAppType support to launch     011 *
 *                          applications.                                 *
 * 153225    04/30/96 bhm   Create a working directory even if not    012 *
 *                          specified.                                    *
 * 153500    05/08/96 bhm   Provide specific command interpreter and  013 *
 *                          and share.exe programs for applications       *
 *                          with downlevel versions of DOS.               *
 * 152859    05/10/96 bhm   Provide support for a 2nd physical disk   014 *
 *                          on any controller.                            *
 *                          config.sys or autoexec.bat regardless         *
 *                          of application type.                          *
 * 154378    05/11/96 bhm   Install mouse driver if found in          015 *
 *                          config.sys or autoexec.bat regardless         *
 *                          of application type.                          *
 * 154465    05/11/96 MT    add mscdex.exe in dos.cfg                     *
 * 154366    05/16/96 bhm   Validate DosQueryAppType and return error 016 *
 * 151221    05/28/96 MT    Process AUTOEXEC.DOS                      017 *
 * 153620    05/31/96 TPL   Moved DD save/restore notification to     018 *
 *                          HYBERNATE() in the Kernel                     *
 * 156774    06/05/96 bhm   Switch display to text then graphics on   019 *
 *                          restore to have PM apps repaint themselves.   *
 * 156227    06/05/96 MT    Preloaded Aptiva Systems related changes  020 *
 * 156898    06/06/96 MT    Use current EMM386.exe parameters         021 *
 * 156773    06/14/96 TPL   Remove dependency on SWAPPER.DAT          022 *
 * 157446    06/13/96 bhm   Copy system files to root for dos & win   023 *
 * 157476    06/13/96 bhm   Add working directory to original path.   024 *
 * 154878    06/25/96 bhm   Add NUMLOCK directive to dos.cfg.         025 *
 * 159396    07/09/96 bhm   Save off existing autoexec.bat for mvdm   026 *
 * 158857    07/10/96 bhm   remove mwave support to improve perf.     027 *
 * 159629    07/12/96 bhm   Grow env by 256 bytes for command.com     028 *
 * 159722    07/12/96 bhm   Map ERROR_DISK_FULL to correct message.   029 *
 * 157818    07/09/96 MT    Always use EMM386.exe                     030 *
 * 159979    07/18/96 TPL   Move DD restore notification to           031 *
 *                          hyberRestart()                                *
 * 160439    07/19/96 TPL   use mdmAPMEntry in MDM.DLL to assist      032 *
 *                          MMOS2 in saving the multi-media states    033 *
 *                          and for MWAVE, SUSPEND/RESUME IOCtl must      *
 *                          be issued to preserve the MWAVE environment.  *
 * 162169    08/04/96 bhm   Map crlf to blanks for long app names.    034 *
 **************************************************************************
*/

#define INCL_BASE
#define INCL_DOSERRORS
#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_PM
#define PIPESIZE 256
#define HF_STDOUT 1

#include <string.h>
#include <time.h>
#include <io.h>
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef APM                                                        /* 150806 */
#include "../../../h/apmioctl.h"
#endif                                                            /* 150806 */



#ifdef APM                                                        /* 150806 */
/*
**------------------------------------------------------
** Advanced Power Management
**------------------------------------------------------
*/

void apmopen ( void );
void apmclose ( void );
void sendevent( USHORT SubId, USHORT DevId, USHORT PwrState );
#endif                                                            /* 150806 */
int  mwaveSuspend( ULONG reqType );                               /* 160439 */

/*
**------------------------------------------------------
** Boot Manager
**------------------------------------------------------
*/

#define BOOT_MANAGER_NOT_INSTALLED -1
#define BOOT_MANAGER_INSTALLED bootMgr.timeout != BOOT_MANAGER_NOT_INSTALLED

static struct BootMgr {

  int timeout;
  char system0 [16];
  char system4 [16];

} bootMgr = { BOOT_MANAGER_NOT_INSTALLED, "", "" };

int setBootManagerUnAttended (void);
int setBootManagerAttended (void);
int setBootManager (int timeout, char *system0);
char * getBootDrive (void);


/*
**------------------------------------------------------
** Dos Startup
**------------------------------------------------------
*/

#include "cons.h"
#include "types.h"
extern FATDIRENT Dir[];
extern UCHAR BioFile[];
extern UCHAR BootBPB[];
long GetDosInfo();
void setupConfigSys();
void setupSysini();
static isSystemFilesCopied = FALSE;  /* did we move around any system files? */


typedef unsigned short ushort_t;
typedef unsigned long ulong_t;
typedef unsigned char uchar_t;

#include "hybernat.h"
#include "hyber.h"

APIRET APIENTRY DosSysCtl(ULONG func, PULONG p);

void cleanupAndExit (int code, int subcode);
void thread1();
ULONG _System excptHandler(PEXCEPTIONREPORTRECORD,
               PEXCEPTIONREGISTRATIONRECORD, PCONTEXTRECORD, PVOID);
EXCEPTIONREGISTRATIONRECORD *pExcpt;
ULONG fileSize;                         // size of hybernat.dat
ULONG junk;
ULONG p;
long  rc;

#define DLIST_SIZ       200
#define ILIST_SIZ       200
struct dlist_s dlist[DLIST_SIZ];        // points to hybernation storage
struct dlist_s infolist[ILIST_SIZ];     // points to hybernation info
ULONG hyberOpPkt[HOP_SIZE];             // passed to hybernat api
char bootDrive[3] = {0};                // "C:"
char hyberFileName[20];
char ps1pfilePath[] = {"c:\\ps1tools\\ps1pfile.exe"};
//156773 char swapperFileName[80];
static PCHAR workingDir = NULL;
static PCHAR appName = NULL;
static PCHAR appFileName = NULL;

/* cleanupAndExit */
#ifdef APM                                                        /* 150806 */
int apmSuspendSent;
#endif                                                            /* 150806 */
int SuspendSent;                        // DD save notification   /* 150806 */
int holdSys;
int hyberFileAllocated;
int freezeSys;                          // system frozen flag     /* 150281 */
int mwaveSuspendSent;                                             /* 160439 */

#define SUSPEND        0                                          /* 160439 */
#define RESUME         1                                          /* 160439 */
#define MMPM_SAVE      1                                          /* 160439 */

enum {                 // System Return Codes
                       // All went well
  FAIL_SWAP1 = 1,      // Failure doing first swapout
  FAIL_HYBEROK,        // Nested hybernat attempt or conditions not good
  FAIL_BOOTDRV,        // Problem determining boot drive
  FAIL_SWAPOPEN,       // Couldn't open swapper2.dat
  FAIL_SYNC,           // Flushbuf wasn't sucessful
  FAIL_MFSEXTENT,      // Failure determining swapper extents - fragmentation
  FAIL_INFOEXTENT,     // Failure determining hyberinfo extents
  FAIL_SWAPPERPATH,    // Failure getting swapper path
  FAIL_DOSINFO,        // Error setting up dos data
  FAIL_SWAP2,          // Failure doing second swapout
  FAIL_APM,            // Couldn't open APM device driver
  FAIL_APMIOCTL,       // Failure doing APM ioctl call
  FAIL_MFSINIT,        // Couldn't init MFS
  FAIL_NOTDUALBOOT,    // We only do dual boot system - i.e. must be drive C:
  FAIL_CONFIGDOS,      // Couldn't open a CONFIG.DOS prototype
  FAIL_HYBERNATE,      // Failure hybernating system
  FAIL_DOSCFGWRIT,     // Failure writing to DOS.CFG
  FAIL_EXCEPT,         // Took exception - probably ^C
  FAIL_DOSCFG,         // Couldn't open DOS.CFG
  FAIL_SYSINICOPY,     // Failure copying windows system.ini file to backup
  FAIL_SYSINI,         // Failure opening windows system.ini for input
  FAIL_SYSINIOUT,      // Failure opening windows system.ini for output
  FAIL_SYSINIWRIT,     // Failure writing windows system.ini file
  FAIL_INFOFRAG,       // swapper2.dat fragmented - must be a PAGESIZE block
  FAIL_SWAPPERINUSE,   // The swapfile was in use
  FAIL_HIBER_BAT       // Could not create hiber.bat

};  // return codes



/*
**----------------------------------------------------------
** Determine the application type.  App is generated from
** a call to DosQueryAppType.
**----------------------------------------------------------
*/

#define WINDOWS31_APP(app) (app & (FAPPTYP_WINDOWSREAL |        \
                                   FAPPTYP_WINDOWSPROT |        \
                                   FAPPTYP_WINDOWSPROT31)) &&   \
                           !(app & FAPPTYP_32BIT)

#define WINDOWS95_APP(app) (app & FAPPTYP_WINDOWSPROT31 &&      \
                            app & FAPPTYP_32BIT)

#define DOS_APP(app) (app & FAPPTYP_DOS)

static struct _win31 {

  PCHAR winDir;
  PCHAR sysini;
  PCHAR sysiniBak;

} win31 = { NULL, NULL, "C:\\OS2\\SYSTEM\\SYSINI.WIN" };


static ULONG appType;   /* Application type flags (returned) */


/* arg flags */
int pageout;
int reboot;
int sticky;
#ifdef DEBUG
int hiber_debug = 0;
#endif

/** PRELOADED APTIVA SYSTEMS **/
BOOL fPreload = FALSE;

#ifdef PM_GUI
#define DOSDD                   "\\DEV\\DOS$    \0"
#endif

#define HIBER_BAT               "C:\\HIBER.BAT"
#define ENV_COMSPEC             "COMSPEC"
#define DOS_COMMAND             "COMMAND.COM"
#define DOS_MOUSE_COM           "MOUSE.COM"
#define DOS_MSCDEX              "MSCDEX"
#define DOS_MSCDEX_EXE          "MSCDEX.EXE"
#define WIN31_COM               "WIN.COM"
#define WIN_WORKGROUP_COM       "WINDOS.COM"
#define OS2_SYSTEM_DIR          "OS2\\SYSTEM"
#define CONFIG_DOS              "CONFIG.DOS"
#define AUTOEXEC_DOS            "AUTOEXEC.DOS"
#define DOS_CFG                 "C:\\DOS.CFG"

#ifdef PM_GUI

HAB   hab;                              /* Anchor block handle          */
HMQ   hmq;                              /* Message queue handle         */
HWND  hwndDlg = 0;
HFILE dossys_handle = (HFILE)0;

void hyberComplete();

MRESULT EXPENTRY SimpleDlgProc( HWND hwnd,
                                ULONG msg,
                                MPARAM mp1,
                                MPARAM mp2);
#else


#define MSG_FILENAME      "HYBERNAT.MSG"
#define MSG_MAX_MSG_LEN   128
#define MSG_MAX_MESSAGES  32
#define MSG_START_MSG_NUM 100

static struct msgRec {

  PCHAR msg;
  USHORT len;

} messages[MSG_MAX_MESSAGES];    /* preloaded message array */

static ULONG msgNum = MSG_START_MSG_NUM;    /* starting message number */

#endif


APIRET hyberDisplayMessage(
   ULONG  ulHiberMsgNumber,   /* Hibernate Subsystem message number  */
   PCHAR  pString,            /* Additional string to a message      */
   BOOL   fError);            /* Error flag                          */


BOOL FileExist(char *pathname);
VOID APIENTRY MyExit(void);
int RestorePM ();


/**
 **  Define useful macros here....
 **/
           /** NOTE: pointer moves **/
#define SKIP_BLANKS(ptr) \
   while (*ptr == ' ') ptr++;

           /** NOTE: pointer moves **/
#define SKIP_BLANKS_AND_EQUAL(ptr) \
   while (*ptr == ' ' || *ptr == '=') ptr++;

           /** NOTE: pointer moves **/
#define SET_FIRST_BLANK_OR_CRLF_TO_NULL(ptr) \
   while (*ptr) { \
     if (*ptr == ' ' || *ptr == '\n' || *ptr == '\r') { \
        *ptr = '\0'; \
        break; \
     } \
     ptr++; \
   }

           /** NOTE: pointer moves **/
#define SET_CRLF_TO_NULL(ptr) \
   while (*ptr) { \
     if (*ptr == '\n' || *ptr == '\r') { \
        *ptr = '\0'; \
        break; \
     } \
     ptr++; \
   }

#define SET_CRLF_TO_BLANK(ptr) \
   while (*ptr) { \
     if (*ptr == '\n' || *ptr == '\r') { \
        *ptr = ' '; \
        break; \
     } \
     ptr++; \
   }

int main (int argc, char **argv)
{
  ULONG dlistCHS;
  ULONG infolistCHS;
  ULONG pid;
  ULONG tid1;                                   /* thread ID */
  ULONG handle;
  ULONG action;
  ULONG i,j;
  FILE *fin;
  char buf[128];
  char *ptr;
  float f;
  EXCEPTIONREGISTRATIONRECORD ERegRec;
#ifndef PM_GUI
  const  USHORT row = 25;
  const  USHORT col = 80;
  USHORT line;
  BYTE   pAttr;
  PCHAR  *IvTable = NULL;
  ULONG  IvCount = 0;
  ULONG  msgNum = MSG_START_MSG_NUM;    /* starting message number */
  ULONG  msgCnt;
  APIRET rc;
  VIOCURSORINFO curInfo;
  KBDKEYINFO charData;

  HMODULE hmod;                                                   /* 160439 */
  PFN mdmAPMEntry;                                                /* 160439 */

#endif

  /*
  **----------------------------------------------------------
  ** hold system now!
  **----------------------------------------------------------
  */

  /* set myself to a high priority */
  DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0); /* me */

  /*
  **----------------------------------------------------------
  ** Scan the parameters passed and setup env.
  **----------------------------------------------------------
  */

  while (--argc > 0 && (**++argv == '-' || **argv == '/')) {

    register unsigned c;
    register unsigned len;

    while ((c = *++*argv) != 0) {

      switch (c) {

#ifdef DEBUG
      case 'd':
         hiber_debug = 1;
              break;
#endif

      case 'n':

        if (*(*argv + 1)) {  // is value on same line

          len = strlen (++*argv);

          if (appName = (PCHAR) malloc (len + 1))
            strcpy (appName, *argv);

          *argv += len - 1;       // move ptr to end

        }

        else if (*(argv + 1) && **(argv + 1) != '-' && **(argv + 1) != '/') {

          // value is on different line

          len = strlen (*++argv);

          if (appName = (PCHAR) malloc (len + 1))
            strcpy (appName, *argv);

          *argv += len - 1; --argc;

        }

        break;

      case 'p':                 // do a pageout

        pageout++;
        break;

      case 'r':                 // do a reboot

        reboot++;
        break;

      case 's':                 // make it sticky

        sticky++;
        break;

      case 't':                 // trapdoor

        if (*(*argv + 1)) { // is value on same line

          len = strlen (++*argv);

          if (appFileName = (PCHAR) malloc (len + 1))
            strcpy (appFileName, *argv);

          *argv += len - 1;       // move ptr to end


        }

        else if (*(argv + 1) && **(argv + 1) != '-' && **(argv + 1) != '/') {

          // value is on different line

          len = strlen (*++argv);

          if (appFileName = (PCHAR) malloc (len + 1))
            strcpy (appFileName, *argv);

          *argv += len - 1; --argc;

        }

        /*
        **----------------------------------------------------------
        ** Check and see if the application requests any parameters
        ** to pass.  Parameter String must be sent in quotes.
        **----------------------------------------------------------
        */

        if (*(argv + 1) && **(argv + 1) != '-' && **(argv + 1) != '/') {

          if (realloc (appFileName, len + strlen (*++argv) + 2)) {  // 2 nulls

            *(appFileName + len) = ' ';  // space apps and parms
            strcpy (appFileName + len + 1, *argv);

          }

          *argv += strlen (*argv) - 1; --argc;

        }

        break;

      case 'w':

        if (*(*argv + 1)) {  // is value on same line

          len = strlen (++*argv);

          if (workingDir = (PCHAR) malloc (len + 1))
            strcpy (workingDir, *argv);

          *argv += len - 1;       // move ptr to end

        }

        else if (*(argv + 1) && **(argv + 1) != '-' && **(argv + 1) != '/') {

          // value is on different line

          len = strlen (*++argv);

          if (workingDir = (PCHAR) malloc (len + 1))
            strcpy (workingDir, *argv);

          *argv += len - 1; --argc;

        }

        break;

#ifdef DEBUG
      case 'h':
      case '?':
        printf ("Usage: hybernat [-nprstw]\nWhere:\n"
                "\t-n Application Name\n"
                "\t-p Pageout Hybernate\n"
                "\t-r Hybernate reboot\n"
                "\t-s Sticky hybernate\n"
                "\t-t Application File Name & Args to Trapdoor\n"
                "\t-w Working directory\n"
                "\t-Press a key to continue\n");
           KbdCharIn (&charData, 0, 0);
          exit (0);
#endif
      default:

#ifdef DEBUG
           printf ("Unknown switch -%c\n", c);
#endif
           break;

      } // end switch

    } // end while

  } // end while




  DosExitList(EXLST_ADD | 0x00000000, (PFNEXITLIST)MyExit);

#ifdef PM_GUI

  hab = WinInitialize( 0 );
  if(!hab) {
    exit(1);
  }

  hmq = WinCreateMsgQueue( hab, 0 );
  if(!hmq)
    {
      WinTerminate(hab);
      exit(1);
    }

  hwndDlg = WinLoadDlg( HWND_DESKTOP,    /* Place anywhere on desktop    */
                       HWND_DESKTOP,    /* Owned by desk top            */
                       NULL,
                       (HMODULE)0,      /* Module handle                */
                       ID_PRODINFO,     /* Dialog identifier in resource*/
                       NULL);           /* Initialization data          */

  if (hwndDlg == 0) {
    DosExit(EXIT_PROCESS, 1);
  }

#else


  /*
  **-----------------------------------------------------------------
  ** DosGetMessage retrieves a message from the specified system
  ** message file, and inserts variable text-string information
  ** into the message.  Preload the message file since we won't have
  ** message services when we need them.
  **-----------------------------------------------------------------
  */

  while (msgNum - MSG_START_MSG_NUM < MSG_MAX_MESSAGES) {

    CHAR msg[MSG_MAX_MSG_LEN];
    ULONG msgLength;


    rc = DosGetMessage (IvTable,
                        IvCount,
                        &msg[0],
                        MSG_MAX_MSG_LEN,
                        msgNum,
                        MSG_FILENAME,
                        &msgLength);

    if (NO_ERROR == rc) {

      USHORT index = msgNum - MSG_START_MSG_NUM;

      if (messages [index].msg = (PCHAR) malloc (msgLength)) {

        /*
        **--------------------------------------------------
        ** Get rid of the CR/LF.
        **--------------------------------------------------
        */

        msg[msgLength - 1] = '\0';
        msg[msgLength - 2] = '\0';
        memcpy (messages [index].msg, &msg[0], msgLength);
        messages [index].len = msgLength;

      }

      ++msgNum;

    }
    else {

      break;

    }
  }

  pAttr = 0x07;

  VioGetCurType(&curInfo, 0);

  curInfo.attr = -1;
  VioSetCurType(&curInfo, 0);


  VioWrtNAttr(&pAttr, row * col , 0, 0, 0);

#endif

  /* Determine our boot drive */
  /* Move code up here because bootDrive is now cached */
  if (!getBootDrive()) {
    cleanupAndExit(FAIL_BOOTDRV, 0);                   // FAIL 3
  }

  /* set up an exception handler so we don't leave things in a wacky state */
  pExcpt = &ERegRec;
  ERegRec.prev_structure = NULL;
  ERegRec.ExceptionHandler = excptHandler;
  DosSetExceptionHandler(pExcpt);

  /* set myself to a high priority */
  // DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0); /* me */

  /**************************************************************************/
  /* We are now at a high priority, do any chores that could potentially    */
  /* cause us to block between here and when 'holdSys' is set.              */
  /**************************************************************************/


  /*
  **----------------------------------------------------------
  ** Get the application type, if we are trapdooring.
  **----------------------------------------------------------
  */

  if (appFileName) {

    /*
    **----------------------------------------------------------
    ** Truncate the parameters to the application, if any.
    **----------------------------------------------------------
    */

    if (ptr = strchr (appFileName, ' '))
      *ptr = NULL;

    rc = DosQueryAppType (appFileName, &appType);

    switch (rc) {

    case ERROR_FILE_NOT_FOUND:
    case ERROR_PATH_NOT_FOUND:

      hyberDisplayMessage(HIBER_MSG_ERROR_FILE_NOT_FOUND, appFileName, TRUE);
      break;

    case ERROR_INVALID_EXE_SIGNATURE:
    case ERROR_BAD_EXE_FORMAT:

      /*
      **----------------------------------------------------------
      ** Maybe a dos batch file.  Default to dos application.
      **----------------------------------------------------------
      */

      appType = FAPPTYP_DOS;

      break;

    default:


      /*
      **----------------------------------------------------------
      ** Some stupid DOS app's don't mark their exe hdrs, so 
      ** default to DOS app.
      **----------------------------------------------------------
      */

      appType = (0 == appType) ? FAPPTYP_DOS : appType;


      break;

    } // end switch

    if (ptr) // put back parms
      *ptr = ' ';

    /*
    **----------------------------------------------------------
    ** Is this a preloaded aptiva system?
    **----------------------------------------------------------
    */
    fPreload = FileExist(ps1pfilePath);

  } // end if


  /*
  **----------------------------------------------------------
  ** Display loading message.
  **----------------------------------------------------------
  */

  if (appName) {

    ptr = appName;

    SET_CRLF_TO_BLANK (ptr);

    hyberDisplayMessage(HIBER_MSG_LOADING_FILE, appName, FALSE);

  }
  else if (appFileName) {

    /*
    **----------------------------------------------------------
    ** Truncate the parameters to the application, if any.
    **----------------------------------------------------------
    */
    if (ptr = strchr (appFileName, ' '))
      *ptr = NULL;

    hyberDisplayMessage(HIBER_MSG_LOADING_FILE, appFileName, FALSE);

    if (ptr != NULL)
      *ptr = ' ';
  }
  else {

    /** Hibernation only **/
    /** Display message and open dos.sys device driver **/
    hyberDisplayMessage( HIBER_MSG_HIBERNATION_START, NULL, FALSE);
#ifdef PM_GUI
    rc = DosOpen( (PSZ)DOSDD,
                 &dossys_handle,
                 &action,
                 0,
                 FILE_SYSTEM,
                 OPEN_ACTION_OPEN_IF_EXISTS,
                 OPEN_SHARE_DENYNONE,
                 (PEAOP2)NULL);
#endif
  }


  /* do swapout if so requested */
  if (pageout) {
    rc = DosSysCtl(SYS_SWAPOUT, &p);                   // swap system out
      if (rc) {
        cleanupAndExit(FAIL_SWAP1, rc);                // FAIL 1
      }
  }


   /* Delete our control/data file */
   strcpy(hyberFileName, bootDrive);
   strcat(hyberFileName, HYBERFILENAME);
   // We do this before hyberOK in the event that its a sticky and there
   // is a shortage of disk space.
   DosDelete(hyberFileName);

   /* If its sticky do a check to see if there are any files open that pose
      a risk when doing multiple restors (network, writable, etc).          */
   if (sticky) {
     p = (ULONG)buf;
     rc = DosSysCtl(SYS_CHKSTICKY, &p);                         // hyberFileCheck
       // Because we haven't really started anything yet, we can abort without
        // using abend. This way our exit message can be more to the point.
        if (rc) {
                DosUnsetExceptionHandler(pExcpt);
                // TBR - If this ever leaves the U.S. the following
                // message must be moved to mri.h.
                // msgout(2, 0, 10, "File state not acceptable for this operation",
                //        buf);
                DosSleep(6000);
                exit(1);
        }
   }



   /* check to see if hybernation is feasible */
   // On input fileSize tells whether its sticky or not.
   // On output it either gives the expanded size of the swapfile or
   // the amount of space needed in the hybernation file (hyberfilename).
   fileSize = sticky;                           // tell hyberOK its sticky
   p = (ULONG)&fileSize;
   rc = DosSysCtl(SYS_HYBEROK, &p);                             // hyberOK
   if (rc) {
        if (rc == ERROR_BAD_ENVIRONMENT) {
                // this says that there were pages swapped out - fileSize
                // will tell how many
                cleanupAndExit (FAIL_SWAPPERINUSE, fileSize);   // FAIL 25
        }
        cleanupAndExit (FAIL_HYBEROK, rc);                      // FAIL 2
   }
   fileSize *= PAGESIZE;

   /* Get the pathname of the swapper file */
//156773    if (!sticky) {               // if sticky we won't be using the swapper file
//156773         p = (ULONG)swapperFileName;
//156773         rc = DosSysCtl(SYS_SWAPPATH, &p);                       // getSwapperPath
//156773         if (rc) {
//156773                 cleanupAndExit (FAIL_SWAPPERPATH, rc);                  // FAIL 8
//156773         }
//156773    }

   /* Create the data file where we will save our control info */
   rc = DosOpen(hyberFileName,
        &handle,
        &action,
        fileSize,                       // size                   /* 165773 */
        0,                              // attributes
        OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, // flag word
        OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE,          // mode
        0);                                                        // ea buf
   if (rc) {
     cleanupAndExit (FAIL_SWAPOPEN, rc);                // FAIL 4
   }
   DosClose(handle);
   hyberFileAllocated++;

  /*
  **----------------------------------------------------------
  ** If boot manager installed then set to unattended.
  ** Note: MFS uses DosPhysical disk, so does Boot Manager so
  ** becareful here.
  **----------------------------------------------------------
  */

  setBootManagerUnAttended ();


  /*
  **----------------------------------------------------------
  ** Initialize the mini file system here.  This sets up
  ** volumes and drive letters.
  **----------------------------------------------------------
  */


  if (rc = MFSInit()) {

    cleanupAndExit (FAIL_MFSINIT, rc);

  }



  /*
  **----------------------------------------------------------
  ** If we are going to run an application then resolve the
  ** OS/2 drive letter to the target OS's drive letter and
  ** validate.  No HPFS partitions supported. Don't forget
  ** to map the working directory also.
  **----------------------------------------------------------
  */

  if (appFileName && (rc = MFSMapDrive (&appFileName [0])))

    cleanupAndExit (FAIL_MFSINIT, rc);

  if (workingDir && (rc = MFSMapDrive (&workingDir [0])))

    cleanupAndExit (FAIL_MFSINIT, rc);


  /*
  **----------------------------------------------------------
  ** If we are going to run an APP and it is a Windows 3.1 app
  ** setup system ini files.
  **----------------------------------------------------------
  */

  if (WINDOWS31_APP (appType))

    setupSysini ();



  /*
  **----------------------------------------------------------
  ** If we are going to run an APP and its not Win95 then
  ** setup config.sys.
  **----------------------------------------------------------
  */

  if (appType && !WINDOWS95_APP (appType)) {

    UCHAR sourceName [48];
    UCHAR targetName [48];


    setupConfigSys ();


    /*
    **----------------------------------------------------------
    ** Copy Autoexec.dos and config.dos to root directory so
    ** any applications that modify them will not get OS/2's
    ** config.sys.  Save OS/2 system file.
    **----------------------------------------------------------
    */

    sprintf (sourceName, "%s\\CONFIG.SYS", bootDrive);
    sprintf (targetName, "%s\\OS2\\SYSTEM\\CONFIG.OS2", bootDrive);

    DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);

    sprintf (sourceName, "%s\\AUTOEXEC.BAT", bootDrive);
    sprintf (targetName, "%s\\OS2\\SYSTEM\\AUTOEXEC.OS2", bootDrive);

    DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);

    sprintf (sourceName, "%s\\OS2\\SYSTEM\\%s", bootDrive, AUTOEXEC_DOS);
    sprintf (targetName, "%s\\AUTOEXEC.BAT", bootDrive);

    DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);


    sprintf (sourceName, "%s\\OS2\\SYSTEM\\%s", bootDrive, CONFIG_DOS);
    sprintf (targetName, "%s\\CONFIG.SYS", bootDrive);

    DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);

    isSystemFilesCopied = TRUE;

  }


   /* get the NPX */
   f = 0.123456;

   if (!DosLoadModule(NULL, 0, "MDM", &hmod)) {                /* 160439 */
     if (!DosQueryProcAddr(hmod, 0x16, NULL, (PFN *)&mdmAPMEntry)) {
       (*mdmAPMEntry)(MMPM_SAVE);                              /* 160439 */
       SuspendSent ++;                                         /* 160439 */
     }                                                         /* 160439 */
   }                                                           /* 160439 */

   /* special for mwave - should go away with newer apm driver */
   if (!mwaveSuspend(SUSPEND)) {                               /* 160439 */
     mwaveSuspendSent ++;                                      /* 160439 */
   }                                                           /* 160439 */

#ifdef CREATETHREAD                                            /* 150281 */
   /* create thread to busy out the system */
   holdSys = 1;
   rc = DosCreateThread((PTID)&tid1, (PFNTHREAD)thread1, 0, 0, 1000);
   DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM-4, tid1);
   /**************************************************************************/
   /* At this point we pretty much have exclusive use of the system.         */
   /*           No more filesystem activity.                                 */
   /**************************************************************************/
#endif                                                         /* 150281 */


   /* freeze the system now, so we can hybernate */         /* 150281 Start */

   p = 0;                  // setup for system freeze
   rc = DosSysCtl(SYS_FREEZE_THAW_SYS, &p);
   if (rc) {
     cleanupAndExit(FAIL_BOOTDRV, rc);  // ** NEW FAIL CODE NEEDED
   }
   freezeSys = 1;          // indicate system frozen        /* 150281 End */

restart:
  holdSys = 1;

  /* sync filesystems */
  p = 2;
  for (i=0;;) {
    rc = DosSysCtl(SYS_SYNCFS, &p);
    if (rc) {
      if (i++ == 5)
        cleanupAndExit (FAIL_SYNC, rc); // FAIL 5
          holdSys = 0;
      DosSleep(100);                    // let the problem clear
        holdSys = 1;
      DosSleep(10);                     // freeze thread back on line
        continue;
    }
        break;
   }
   if (!holdSys) goto restart;

//156773    if (!sticky) {
//156773
//156773      /* get the swapfile extents */
//156773
//156773
//156773      /* DLIST_SIZ-1 (need stopper entry (-1)) */
//156773
//156773      if (rc = extent (swapperFileName, &dlist, DLIST_SIZ-1, &dlistCHS)) {
//156773
//156773        cleanupAndExit (FAIL_MFSEXTENT, rc);
//156773
//156773      }
//156773    }

//156773    if (!holdSys) goto restart;

   /* get the SWAPPER2.DAT extents */
   if (rc = extent(hyberFileName, &infolist, ILIST_SIZ, &infolistCHS)) {
     cleanupAndExit (FAIL_INFOEXTENT, rc);              // FAIL 7
   }

   // necessary because the kernel only uses one dlist entry to write this out
   if (infolist[0].dl_count < PAGESIZE/SECTORSIZE) {

     cleanupAndExit (FAIL_INFOFRAG, infolist[0].dl_count);      // FAIL 24

   }

   /* if its sticky finish setting up the disk lists */
//156773    if (sticky) {
        // In this situation all of our space (hyberInfo and save) is
        // represented in the infolist at this point.
        // The kernel wants two lists; one for hyberInfo and the other for
        // the save area. So here we split it up. One page is left in infolist
        // and the rest is copied to dlist.
        if (infolist[0].dl_count == PAGESIZE/SECTORSIZE) {
                // entry is even page, skip it
                j = 0;
        } else {
                // subtract the infolist page
                dlist[0].dl_count = infolist[0].dl_count - PAGESIZE/SECTORSIZE;
                dlist[0].dl_sector = infolist[0].dl_sector+PAGESIZE/SECTORSIZE;
                infolist[0].dl_count = PAGESIZE/SECTORSIZE;
                j = 1;
        }
        // j points to starting entry in dlist
        for (i=1; infolist[i].dl_count; i++,j++) {
                dlist[j].dl_count = infolist[i].dl_count;
                dlist[j].dl_sector = infolist[i].dl_sector;
        }
        dlist[j].dl_count = 0;                  // stopper
//156773    }

   /* setup the op packet for the hybernat call */
   if (sticky)
        hyberOpPkt[HOP_OP] = HOPOP_STICKY;
   else
   if (appType && !WINDOWS95_APP(appType)) {
        rc = GetDosInfo();                      // fills in following structures
        if (rc) {
                cleanupAndExit (FAIL_DOSINFO, rc);      // FAIL 9
        }
        hyberOpPkt[HOP_OP] = HOPOP_TRAPDOOR;
        hyberOpPkt[HOP_DOSDIR] = (ULONG)Dir;
        hyberOpPkt[HOP_BIOFILE] = (ULONG)BioFile;
        hyberOpPkt[HOP_BPB] = (ULONG)BootBPB;
   } else
        hyberOpPkt[HOP_OP] = HOPOP_HYBERNATE;
   if (reboot) {
        hyberOpPkt[HOP_OP] |= HOPOP_REBOOT << 16;
   }

   /*
    * At this point it looks like things are OK for the hybernat.
    *
    * Do some misc setup then doit.
    */


   if (pageout) {
        rc = DosSysCtl(SYS_SWAPOUT, &p);                        // swap system out
        if (rc) {
                cleanupAndExit (FAIL_SWAP2, rc);                // FAIL 10
        }
   }
   if (!holdSys) goto restart;

#ifdef APM                                                        /* 150806 */
   /* Do APM shutdown notification */
   apmopen();
   sendevent(APMEVENT_SetPowerState, 0x0001, 0x0002);
   apmSuspendSent++;                                    // FAIL flag
   apmclose();
#endif                                                            /* 150806 */

   /* Send DD Save notifications */                               /* 150806 */
// p = 0;                           /* function code for Save */  /* 150806 */
// rc = DosSysCtl(SYS_SAVERESTORE, &p);          /* send save notification */  /* 150806 */
// if (!rc)                                                       /* 150806 */
//      SuspendSent++;              /* successful Save */         /* 150806 */

   /* One last touch of the NPX */
   f += 0.987;

   /* Hybernate the system passing in the location of the save areas
      and if trapdooring the information needed to get DOS started.       */
   hyberOpPkt[HOP_DLIST] = (ULONG)&dlist;
   hyberOpPkt[HOP_DLIST_CHS] = infolistCHS;                       /* 156773 */
   hyberOpPkt[HOP_INFOFILE] = (ULONG)&infolist;
   hyberOpPkt[HOP_INFO_CHS] = infolistCHS;
   p = (ULONG)hyberOpPkt;


   /**************************************************************************/
   /* Do It                                                                  */
   /**************************************************************************/
   rc = DosSysCtl(SYS_HIBERNATE, &p);           // hybernate

   if (rc == 1) {                       // hybernation complete

     CHAR blank = ' ';

        /*
        **-----------------------------------------------------
        ** thaw the system in order to allow other threads
        ** blocked waiting for hyberation to end
        **-----------------------------------------------------
        */
        p = 1;              // setup to release all threads
        DosSysCtl(SYS_FREEZE_THAW_SYS, &p);
#ifdef PM_GUI
        WinDestroyWindow(hwndDlg);
        hyberComplete();
#else

        VioWrtNChar (&blank, 80, 0, 0, 0);
        VioWrtCharStr (messages[3].msg, messages[3].len, 0, 0, 0);
        while (1);
#endif
   }
   if (rc) {
        cleanupAndExit (FAIL_HYBERNATE, rc);    // FAIL 16
   }

   /**************************************************************************/
   /* We're back!!!                                                          */
   /**************************************************************************/

   /* open and read a file so we force the filesystem to re-init itself */
   fin = fopen(hyberFileName, "r");
   if (fin)
        junk = fgetc(fin);
   fclose(fin);

#ifdef APM                                                        /* 150806 */
   /* Tell the APM world to restore their devices */
   apmopen();
   sendevent(APMEVENT_NormalResume, 0x0000, 0x0000);
   apmclose();
#endif                                                            /* 150806 */

#ifdef D159979                                                    /* 159979 */
   /* Send DD Restore notification */                             /* 150806 */
   p = 1;                     /* setup for DD Restore */          /* 150806 */
   rc = DosSysCtl(SYS_SAVERESTORE, &p);    /* send restore notification */     /* 150806 */
#endif                                                            /* 159979 */

   /* Restore windows system.ini */
   if (win31.sysini) {
     rc = DosCopy (win31.sysiniBak, win31.sysini, DCPY_EXISTING);
        if (!rc)
                DosDelete(win31.sysiniBak);
   }

   /* get rid of the hybernation data file */
   if (!sticky)
        DosDelete(hyberFileName);

   /* and the dos config file */

#ifdef DEBUG
  if (!hiber_debug) {
     DosDelete(DOS_CFG);
     DosDelete(HIBER_BAT);
  }
#else
     DosDelete(DOS_CFG);
     DosDelete(HIBER_BAT);
#endif


   /* reset hyberstat and release the lock on the swap file */
   p = 0;
   rc = DosSysCtl(SYS_RESETSTAT, &p);           // reset hyberStat
   DosUnsetExceptionHandler(&ERegRec);

   holdSys = 0;                                 // release thread1

   /* Close MFS partitions - needed so others can use DosPhysicalDisk */
   DD_CloseDrives();

   /*
   **-----------------------------------------------------
   ** thaw the system in order to allow other threads
   ** blocked waiting for hyberation to end
   **-----------------------------------------------------
   */

   if (freezeSys) {           // system frozen?             /* 150281 Start */
     p = 1;                   // setup to release all threads
     rc = DosSysCtl(SYS_FREEZE_THAW_SYS, &p);
   }                                                        /* 150281 End */

   if (mwaveSuspendSent) {                                     /* 160439 */
     rc = mwaveSuspend(RESUME);                                /* 160439 */
   }                                                           /* 160439 */

   /* if this is an aptiva re-enable the rapid resume capability */
   // if (!access(ps1pfilePath, 0)) {
   if (fPreload == TRUE) {
        sprintf(buf, "start /c /min %s", ps1pfilePath);
        system(buf);
   }

  /*
  **--------------------------------------------------------
  ** If Boot Manager is installed then set back to attended
  ** mode.  NOTE: This call must be made AFTER DD_CloseDrives
  ** as setboot.exe uses DosPhysicalDisk along with the MFS.
  **--------------------------------------------------------
  */

  setBootManagerAttended ();


  free (appName);
  free (appFileName);
  free (win31.winDir);
  free (win31.sysini);

// #ifdef PM_GUI

  RestorePM();

// #endif
  return 0;
}
#ifdef CREATETHREAD                                            /* 150281 */
void
thread1 ()
{
  int   stat;
  int   laststat = 0;
  time_t        t1;

  DosSleep(10);
  while (1) {
    if (holdSys) {
      stat = DosSysCtl(SYS_GETHYBERSTAT, &junk);   // get hyberStat
        if (!laststat) {
          laststat = stat;
          time(&t1);
        } else if (stat != laststat) {
          laststat = stat;
          time(&t1);
        } else if ((time(NULL) - t1) > 10) {
          holdSys = 0;
        }
    } else {
      DosSleep(90);
      laststat = 0;
    }
  }
}
#endif                                                            /* 150281 */
#ifdef APM                                                        /* 150806 */
/*****************************************************************************/
/*                           APM                                             */
/*****************************************************************************/

APIRET  result  = 0;
HFILE   handle  = 0;
ULONG   action  = 0;

ULONG   cbParm  = 0;
ULONG   cbData  = 0;

APMGIO_BROADCAST_PPKT sendevent_ppkt = {  0,  /* subid */
                                          0,  /* reserved */
                                          0,  /* devid */
                                          0   /* pwrstate */
                                       };

APMGIO_DPKT dpkt;

VOID apmopen( void )
{
  result = DosOpen(
      (PVOID)    "APM$    ",  /* File ID                          */
      (PHFILE)   &handle,     /* File Handle                      */
      (PULONG)   &action,     /* File Action (created/opened)     */
      (ULONG)     0,          /* File Size (if opened or replaced)*/
      (ULONG)     0,          /* File Attributes (if created)     */
      (ULONG)     1,          /* Open Function Type               */
      (ULONG)     0x6041,     /* Open Mode of File                */
                              /* Flags in BSEDOS.H                */
                              /*   0x4000 - fs can cache          */
                              /*   0x2000 - fail on error         */
                              /*   0x2000 - fail on error         */
                              /*   0x0f00 - "locality" flags      */
                              /*   0x0040 - open sharing          */
                              /*   0x0001 - access mode - write.  */
      (ULONG)     0           /* Extended attributes.             */
  );

  if (result != 0)
    {
      cleanupAndExit (FAIL_APM, result);                        // FAIL 11
    }
}

VOID apmclose( void )
{
  DosClose(handle);
}

VOID sendevent( USHORT SubId, USHORT DevId, USHORT PwrState )
{
  sendevent_ppkt.SubId    = SubId;
  sendevent_ppkt.reserved = 0x0000;
  sendevent_ppkt.DevId    = DevId;
  sendevent_ppkt.PwrState = PwrState;

  cbParm = sizeof(APMGIO_BROADCAST_PPKT);
  cbData = sizeof(APMGIO_DPKT);

  result = DosDevIOCtl( handle, APMGIO_Category, APMGIO_BroadcastEvent,
                        (PVOID) &sendevent_ppkt, cbParm, &cbParm,
                        (PVOID) &dpkt,           cbData, &cbData );

  if (result != 0)
    {
      cleanupAndExit (FAIL_APMIOCTL, result);           // FAIL 12
    }
}
#endif                                                            /* 150806 */
/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: cleanupAndExit ()                                  *
 *                                                                        *
 * Description.......: Provides support for abnormal termination          *
 *                     during the hibernation process which includes      *
 *                     clean up and notification.                         *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............: (I) - code : Hibernate subsystem error code        *
 *                     (I) - subcode : OS/2 system error code             *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Return codes are typically encoded as follows:     *
 *                     A failure in the driver 1 -31                      *
 *                     A failure from the kernel 0x40 & x                 *
 *                     A kernel I/O failure 0x80 + i/o status byte        *
 *                                                                        *
 **************************************************************************
*/

void cleanupAndExit (int code, int subcode)
{
  ULONG ulHyberError;
  PCHAR pString = NULL;

  /*
  **-----------------------------------------------------
  ** thaw the system in order to allow other threads
  ** blocked waiting for hyberation to end
  **-----------------------------------------------------
  */

  if (freezeSys) {            // system frozen?             /* 150281 Start */
    p = 1;                    // setup to release all threads
    rc = DosSysCtl(SYS_FREEZE_THAW_SYS, &p);
  }                                                         /* 150281 End */

  /*
  **-----------------------------------------------------
  ** Release system.
  **-----------------------------------------------------
  */

  holdSys = 0;


  /*
  **-----------------------------------------------------
  ** Rollback transactions already in progress.
  **-----------------------------------------------------
  */

  if (hyberFileAllocated)
    DosDelete(hyberFileName);

#ifdef APM
  if (apmSuspendSent) {

    apmopen();
    sendevent( APMEVENT_NormalResume, 0x0000, 0x0000);
    apmclose();

  }
#endif                                                            /* 150806 */

  if (mwaveSuspendSent) {                                         /* 160439 */
    rc = mwaveSuspend(RESUME);                                    /* 160439 */
  }                                                               /* 160439 */

  /*
  **-----------------------------------------------------
  ** Send DD Restore notification if hybernation failed
  **-----------------------------------------------------
  */
  if (SuspendSent) {          // DD Save notification sent?       /* 160439 */
    p = 1;                                // Setup for Restore    /* 160439 */
    rc = DosSysCtl(SYS_SAVERESTORE, &p);  // Send Restore notification 160439
  }                                                               /* 160439 */

  if (win31.sysini) {

    rc = DosCopy(win31.sysiniBak, win31.sysini, DCPY_EXISTING);

    if (!rc)
      DosDelete(win31.sysiniBak);


  }


  /*
  **-----------------------------------------------------
  ** Close MFS partitions - needed so others can use
  ** DosPhysicalDisk .
  **-----------------------------------------------------
  */

  DD_CloseDrives ();


  /*
  **--------------------------------------------------------
  ** If Boot Manager is installed then set back to attended
  ** mode.  NOTE: This call must be made AFTER DD_CloseDrives
  ** as setboot.exe uses DosPhysicalDisk along with the MFS.
  **--------------------------------------------------------
  */

  setBootManagerAttended ();

  DosDelete (DOS_CFG);


  /*
  **-----------------------------------------------------
  ** signal that its ok to try again.
  **-----------------------------------------------------
  */

  if (!(code == FAIL_HYBEROK && subcode == ERROR_INVALID_ACCESS)) {

    /* it was not nested */
    p = 0;
    rc = DosSysCtl(SYS_RESETSTAT, &p);          // reset hyberStat

  }



  switch (code) {

  case FAIL_SWAPOPEN:

    switch (subcode) {

    case ERR_FILE_NOT_FOUND:

      ulHyberError = HIBER_MSG_ERROR_HPFS_SYS_FILE;
      break;

    default:

      ulHyberError = HIBER_MSG_ERROR_DISK_FULL;
      break;

    }

    break;

  case FAIL_MFSEXTENT:

    switch (subcode) {

    case ERR_INTERNAL_ERROR:
      ulHyberError = HIBER_MSG_ERROR_HPFS_SWAP_FILE;
      break;

    default:
      ulHyberError = HIBER_MSG_ERROR_INTERNAL;
      break;

    }

    break;

  case FAIL_HYBEROK:

    switch (subcode) {

    case ERROR_SWAPPER_NOT_ACTIVE:
      ulHyberError = HIBER_MSG_ERROR_NO_SWAP_FILE;
      break;

    case ERROR_BAD_ENVIRONMENT:

      ulHyberError = HIBER_MSG_ERROR_INTERNAL;

      break;

    case ERROR_INVALID_ACCESS:
      ulHyberError = HIBER_MSG_ERROR_HIBER_IN_PROGRESS;
      break;

    case ERROR_DISK_FULL:
      ulHyberError = HIBER_MSG_ERROR_DISK_FULL;
      break;

    case ERROR_NOT_SUPPORTED:
      ulHyberError = HIBER_MSG_ERROR_MODIFY_SWAP_FILE;
      break;

    default:
      ulHyberError = HIBER_MSG_ERROR_INTERNAL;
      break;

    }  // end switch

      break;

  default:
    ulHyberError = HIBER_MSG_ERROR_INTERNAL;
    break;

  } // end switch

  free (appName);
  free (appFileName);
  free (win31.winDir);
  free (win31.sysini);


  hyberDisplayMessage( ulHyberError, pString, TRUE);


} // FAIL


ULONG
_System excptHandler(PEXCEPTIONREPORTRECORD pRepRec,
               PEXCEPTIONREGISTRATIONRECORD pRegRec,
               PCONTEXTRECORD pConRec, PVOID pDispCon)
{
   ULONG ulMemSize, flMemAttrs;
   APIRET rc;

   switch (pRepRec->ExceptionNum) {
   case XCPT_ACCESS_VIOLATION:
      if (pRepRec->ExceptionAddress != (PVOID) XCPT_DATA_UNKNOWN)
      {
         /* page fault */
         if ((pRepRec->ExceptionInfo[0]== XCPT_READ_ACCESS ||
              pRepRec->ExceptionInfo[0] ==XCPT_WRITE_ACCESS)
           && (pRepRec->ExceptionInfo[1] != XCPT_DATA_UNKNOWN)) {
            ulMemSize = 1;
            DosQueryMem((PVOID)pRepRec->ExceptionInfo[1], &ulMemSize, &flMemAttrs);
            if (!(flMemAttrs & (PAG_FREE | PAG_COMMIT))) {
               rc = DosSetMem((PVOID)pRepRec->ExceptionInfo[1], 4096, PAG_DEFAULT | PAG_COMMIT);
               if (rc) {
                  DosUnsetExceptionHandler(pExcpt);
                  cleanupAndExit (FAIL_EXCEPT, pRepRec->ExceptionNum);
               }
               else
                  return(XCPT_CONTINUE_EXECUTION);
            }
         }
      }
      break;
   case XCPT_PROCESS_TERMINATE:
           DosUnsetExceptionHandler(pExcpt);
      break;
   }
   return(XCPT_CONTINUE_SEARCH);
}

/** FuncChange@017 **/
void setupConfigSys() {
   FILE *fin = NULL, *fDosCfg, *fHiber;
   char buf[256];
   char szShare[128];
   char *p;
   int skip = 0;
   int i;
   int fEMM386 = 0;
   int fSHELL  = 0;
   int fPATH = 0;
   int fshare = 0;
   BOOL fDoneScanAutoexec = FALSE;



   /*
   **---------------------------------------------------
   ** If not specified, setup a working directory based
   ** upon the application file name. Some apps must be
   ** launched from their directory.
   **---------------------------------------------------
   */

   if (NULL == workingDir) {

     register unsigned long len;

     len = strrchr (appFileName, '\\') - appFileName;

     if (workingDir = (PCHAR) malloc (len + 1)) {

       strncpy (workingDir, appFileName, len);
       workingDir [len] = '\0';

     }

   }


   /* find the prototype first */

   if (workingDir) {
      i = strlen(workingDir) - 1;
      if (workingDir[i] != '\\' && workingDir[i] != ':') {
         // there is a working dir and its not a root dir
         strcpy(buf, workingDir);
         strcat(buf, "\\config.sys");
         fin = fopen(buf, "r");     /** user-defined config.sys **/
      }
   }

   if (fin == NULL) {           /** no special so use dual boot's copy **/
      sprintf(buf, "%s\\%s\\%s", bootDrive, OS2_SYSTEM_DIR, CONFIG_DOS);
      fin = fopen(buf, "r");
      if (fin == NULL) {        /** why we do the following ?? **/
         sprintf(buf, "%s\\%s\\dos.cfg", bootDrive, OS2_SYSTEM_DIR);
         fin = fopen(buf, "r");
         if (fin == NULL) {
            cleanupAndExit (FAIL_CONFIGDOS, ferror(fin));   /** FAIL 15 **/
         }
      }
   }

   fDosCfg = fopen(DOS_CFG, "w");
   if (fDosCfg == NULL) {
      cleanupAndExit (FAIL_DOSCFG, ferror(fDosCfg));                     // FAIL 19
   }

   /** Line 1 & 2 of DOS.CFG **/
   fputs("SWITCHES=/N /F\n", fDosCfg);

#ifdef DEBUG
   if (hiber_debug)
      fprintf(fDosCfg, "DEVICE=%s\\%s\\HIDE.SYS /X\n", bootDrive, OS2_SYSTEM_DIR);
   else
      fprintf(fDosCfg, "DEVICE=%s\\%s\\HIDE.SYS\n", bootDrive, OS2_SYSTEM_DIR);
#else
   fprintf(fDosCfg, "DEVICE=%s\\%s\\HIDE.SYS\n", bootDrive, OS2_SYSTEM_DIR);
#endif

   while (fgets(buf, sizeof(buf), fin) != NULL) {
      strupr(buf);
      if (strncmp(buf, "REM", 3)==0)
        continue;                                       /** skip comments **/
      if (buf[0] == '[')                                /** no menu stuff **/
         skip++;
      if (!skip) {

        if ( (fEMM386==0) && ((p = strstr(buf, "EMM386.EXE")) != NULL)) {

          fEMM386 = 1;  //set flag
          /*
           **-----------------------------------------
           ** Use our own EMM386.exe
           ** but keep the parameters
           **-----------------------------------------
           */
          /* 1c@156898 */
          fprintf(fDosCfg,
                  "DEVICE=%s\\%s\\%s",
                  bootDrive, OS2_SYSTEM_DIR, p);
          continue;

        }
        else if ( (fSHELL==0) && (strncmp(buf, "SHELL", 5) == 0)) {

                  fSHELL = 1;
                  continue;

        }
        else if (p = strstr (buf, "SHARE")) {

           fshare = 1;
                 /*
                 **----------------------------------------------
                 ** We use our own SHARE.exe, so skip it for now
                 **----------------------------------------------
                 */
           while (!isspace (*p)) ++p;
           SKIP_BLANKS_AND_EQUAL (p);
           strcpy (szShare, p);
           SET_CRLF_TO_NULL (p);
           continue;

        }
        else if (strncmp(buf, "SET", 3)==0) {

          p = buf+3;
          SKIP_BLANKS(p);

          /*
          **-----------------------------------------------------
          ** Remove SET COMSPEC from the buffer since we write
          ** our own version.
          **-----------------------------------------------------
          */

          if (strncmp(p, ENV_COMSPEC, 7) == 0)
            continue;

          if ((strncmp (p, "PATH", 4)) == 0 && workingDir)

            sprintf (strpbrk (buf, "\r\n"), ";%s\n", workingDir);

        }

         /*
         **-----------------------------------------------------
         ** If we come here, write the line to DOS.cfg
         **-----------------------------------------------------
         */
        rc = fputs(buf, fDosCfg);
        if (rc == EOF) {
          cleanupAndExit (FAIL_DOSCFGWRIT, ferror(fDosCfg));  /** FAIL 17 **/
        }

      }
      if (strncmp("[COMMON]", buf, 8) == 0)           /** allow common cmds **/
              skip = 0;

   } //end_while()
   fclose(fin);    // Done with CONFIG.dos


   /*
   **-------------------------------------------------
   ** If EMM386.exe has not been found, load it anyway
   ** EMM386 is required to fix the system hang during
   ** initialization of WINDOWS (ie. win.com)
   **-------------------------------------------------
   */
   if (!fEMM386 && WINDOWS31_APP (appType)) {            //157818
      fprintf(fDosCfg,                                   //157818
              "DEVICE=%s\\%s\\EMM386.EXE\n",             //157818
              bootDrive, OS2_SYSTEM_DIR);                //157818
   }                                                     //157818


   /*
   **-------------------------------------------------
   ** Open HIBER.bat
   ** write to this file as we scan AUTOEXEC.dos
   **-------------------------------------------------
   */
   fHiber = fopen (HIBER_BAT, "w");

   if (fHiber == NULL)
     cleanupAndExit (FAIL_HIBER_BAT, ferror(fHiber));

   fprintf(fHiber,"@echo off\n");

   /**
    **  Now process AUTOEXEC.DOS if any
    **/
   sprintf(buf,"%s\\%s\\%s", bootDrive, OS2_SYSTEM_DIR, AUTOEXEC_DOS);
   fin = fopen(buf, "r");
   if (fin)
   {
      while ( fDoneScanAutoexec == FALSE
              && (fgets(buf, sizeof(buf), fin) != NULL)) {
         strupr(buf);
         if (strncmp(buf, "REM", 3)==0)
           continue;                             /** skip comments **/

         if (fPreload==TRUE) {
            // Skip %config%
            // Skip :APTIVA
            // Skip HWCHECK
           if (strstr (buf, "%CONFIG%") )
              continue;
           if (strstr (buf, ":APTIVA") )
              continue;
           if (strstr (buf, "HWCHECK") )
              continue;

           // Skip PS1START.BAT
           if (strstr (buf, "PS1START.BAT") ) {
              fDoneScanAutoexec = TRUE;
              continue;
           }

         }
         if (p = strstr (buf, "SHARE")) {

           fshare = 1;
           while (!isspace (*p)) ++p;
           SKIP_BLANKS_AND_EQUAL (p);
           strcpy (szShare, p);
           SET_CRLF_TO_NULL (p);
           continue; // skip

         }

         if (strncmp (buf, "PATH", 4) == 0)

            sprintf (strpbrk (buf, "\r\n"), ";%s\n", workingDir);




         if (strncmp(buf, "SET", 3)==0) {

            p = buf+3;
            SKIP_BLANKS(p);

            /*
            **-----------------------------------------------------
            ** Remove SET COMSPEC from the buffer since we write
            ** our own version.
            **-----------------------------------------------------
            */

            if ((strncmp(p, ENV_COMSPEC, 7)) == 0)
                   continue;

            if ((strncmp (p, "PATH", 4)) == 0 && workingDir)

              sprintf (strpbrk (buf, "\r\n"), ";%s\n", workingDir);



         }
         /*
         **-----------------------------------------------------
         ** If we come here, write the line to HIBER.bat
         **-----------------------------------------------------
         */
         rc = fputs(buf, fHiber);
         if (rc == EOF)
            cleanupAndExit (FAIL_HIBER_BAT, ferror(fHiber));  /** FAIL 17 **/

      } //end_while()
      fclose(fin);      // Done with AUTOEXEC.dos
   }

   if (workingDir) {

     fprintf(fHiber,"CD %s\n%c:\n", workingDir, workingDir[0]);

     /*
     **---------------------------------------------------
     ** Some application like QUICKEN requires the path to be setup
     ** correctly.

     fprintf(fHiber, "SET PATH=%s;%s\n", "%PATH%", workingDir);

     **---------------------------------------------------
     */

   }


   if (WINDOWS31_APP (appType))

     fprintf (fHiber, "WIN\n");

   else {  // must be a DOS app of some sort

     /*
     **---------------------------------------------------
     ** If the user's specifies COMMAND.COM as the app to
     ** run then swap it out with our version since we
     ** cannot support downlevel version of the interpreter.
     **---------------------------------------------------
     */

     if (strstr (strupr (appFileName), "COMMAND.COM"))
       fprintf ( fHiber, "%s\\%s\\%s\n",
                 bootDrive, OS2_SYSTEM_DIR, DOS_COMMAND);
     else
       fprintf(fHiber,"%s\n", appFileName);

   }
   fprintf(fHiber,"EXIT\n");
   fclose(fHiber);              // Done with HIBER.bat


   /*
   **----------------------------------------------------
   ** If user had SHARE.EXE installed then install it here
   ** using our SHARE program with the users parameters.
   **----------------------------------------------------
   */

   if (fshare)

     fprintf (fDosCfg, "INSTALL=%s\\%s\\SHARE.EXE %s\n",
              bootDrive, OS2_SYSTEM_DIR, szShare);

   /*
   **----------------------------------------------------
   ** Set command interpreter to the system command.com.
   ** SHELL.COM is not a valid command interpreter for
   ** applications like JAZZ and DOOM.
   **----------------------------------------------------
   */

   fprintf(fDosCfg, "SET COMSPEC=%s\\%s\\%s\n", bootDrive, OS2_SYSTEM_DIR,
           DOS_COMMAND);


   /*
   **----------------------------------------------------
   ** Set the NUMLOCK to the OFF state.  We do this so that
   ** it can be in a reliable state when starting DOS/WIN
   ** applications.  During sysinit of the DOS environment
   ** the Power ON NUMLOCK state is retrieved however the
   ** LED may or maynot reflect that state so set it to
   ** the default state of off.
   **----------------------------------------------------
   */

   fprintf (fDosCfg, "%s\n", "NUMLOCK=OFF");

   /*
   **---------------------------------------------------
   ** Now setup to run the batch file via the SHELL =.
   **---------------------------------------------------
   */

   fprintf(fDosCfg, "SHELL=%s\\%s\\SHELL.COM %s\\%s\\%s /E:512 /C %s\n",
           bootDrive, OS2_SYSTEM_DIR,
           bootDrive, OS2_SYSTEM_DIR, DOS_COMMAND,
           HIBER_BAT);



   fclose(fDosCfg);     // Done with DOS.cfg

} // setupConfigSys

void setupSysini()
{
  FILE *fin, *fout;
  char buf[256];
  PCHAR windowsDir;
  PCHAR defaultWindowsDir = "C:\\WINDOWS";


  /*
  **----------------------------------------------------------
  ** We're a WINDOWS 3.1 Application. Now get the directory
  ** to work in.
  **----------------------------------------------------------
  */

  windowsDir = (PCHAR) getenv ("WIN3DIR");

  if (NULL == windowsDir)

    windowsDir = defaultWindowsDir;


  if (win31.winDir = (PCHAR) malloc (strlen (windowsDir) + 1))

    strcpy (win31.winDir, windowsDir);

  if (win31.sysini = (PCHAR) malloc (strlen (windowsDir) + 12))

    sprintf(win31.sysini, "%s\\SYSTEM.INI", windowsDir);


  if (rc = DosCopy (win31.sysini, win31.sysiniBak, DCPY_EXISTING))

    cleanupAndExit (FAIL_SYSINICOPY, rc);

  fin = fopen(win31.sysiniBak, "r");
  if (fin == NULL)

    cleanupAndExit (FAIL_SYSINI, ferror(fin));

  fout = fopen(win31.sysini, "w");
  if (fout == NULL) {

    fclose (fin);
    cleanupAndExit (FAIL_SYSINIOUT, ferror(fout));

  }

  while (fgets(buf, sizeof(buf), fin) != NULL) {

    strlwr(buf);
    if (strncmp(buf, "shell", 5)==0) {
      fprintf(fout, ";%s", buf);      // comment it out
        fprintf(fout, "shell=%s\n", appFileName);
    } else {
      rc = fputs(buf, fout);
      if (rc == EOF) {

        fclose (fin);
        fclose (fout);
        cleanupAndExit (FAIL_SYSINIWRIT, ferror(fout));
      }
    }
  }

  fclose(fin);
  fclose(fout);

}

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: getBootDrive ()                                    *
 *                                                                        *
 * Description.......: Queries the system for the booted drive.           *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Set up bootDrive[]                                 *
 *                                                                        *
 **************************************************************************
*/

char * getBootDrive (void)
{
  APIRET rc;
  ULONG DataBuf[16];

  if (bootDrive[0])     /** Have we been here before? **/
     return(bootDrive); /** Yes, so just return       **/

  rc = DosQuerySysInfo (QSV_BOOT_DRIVE,
                        QSV_BOOT_DRIVE,
                        (PVOID) DataBuf,
                        sizeof (DataBuf));

  if (NO_ERROR == rc) {

    bootDrive[0] = (char) DataBuf[0] - 1 + 'A';
    bootDrive[1] = ':';
    bootDrive[2] = '\000';
    return(bootDrive);
  }

  return(NULL);

} // getBootDrive


/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: setBootManagerTimeOut                              *
 *                                                                        *
 * Description.......: Set the timeout value for (un)attended mode.       *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............: (I) - newTimeOut : the new timeout value to assign *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Timeout value of 0 set unattended mode.            *
 *                                                                        *
 **************************************************************************
*/

int setBootManager (int timeout, char *system0)
{
  APIRET rc;
  RESULTCODES resc;
  char szFailName[CCHMAXPATH];
  char setboot_Args [128];
  unsigned argPtr;


  /*
  **------------------------------------------------------
  ** Use CMD.EXE's convention when passing arguments to
  ** executables.  Build arg string.
  **------------------------------------------------------
  */


  sprintf (setboot_Args, "%s\\os2\\setboot.exe", bootDrive);

  argPtr = strlen (setboot_Args);

  setboot_Args [argPtr++] = '\x0';
  setboot_Args [argPtr++] = '/';
  setboot_Args [argPtr++] = 't';
  setboot_Args [argPtr++] = ':';
  argPtr += strlen ((char *) _itoa (timeout, setboot_Args + argPtr, 10));
  setboot_Args [argPtr++] = ' ';
  setboot_Args [argPtr++] = '/';
  setboot_Args [argPtr++] = '0';
  setboot_Args [argPtr++] = ':';
  setboot_Args [argPtr++] = '"';
  strcpy (setboot_Args + argPtr, system0);
  argPtr += strlen (system0);
  setboot_Args [argPtr++] = '"';
  setboot_Args [argPtr++] = '\x0';
  setboot_Args [argPtr++] = '\x0';


  /*
  **------------------------------------------------------
  ** Start setboot.exe as a child process and pass it the
  ** new timeout value.  Note 0 = unattended boot manager,
  ** and must be synchronous in case reenablement is fast.
  **------------------------------------------------------
  */

  rc = DosExecPgm (szFailName,
                   sizeof (szFailName),
                   EXEC_SYNC,
                   setboot_Args,
                   (PSZ) NULL,
                   &resc,
                   "setboot.exe");



  return (NO_ERROR == rc) ? resc.codeResult : rc;

} // setBootManagerTimeOut

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: setBootManagerUnAttended                           *
 *                                                                        *
 * Description.......: If boot manager is installed set to unattended     *
 *                     mode.                                              *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Timeout value of 0 sets unattended mode.           *
 *                                                                        *
 **************************************************************************
*/

int setBootManagerUnAttended (void)
{
  HPIPE hpRead = -1, hpWrite = -1;
  RESULTCODES resc;
  ULONG cbRead, cbWritten;
  APIRET rc;
  char bootInfoBuf[PIPESIZE], szFailName[CCHMAXPATH];
  char setboot_Args [128];
  HFILE hfSave = -1, hfNew = HF_STDOUT;
  unsigned argPtr;


  /*
  **------------------------------------------------------
  ** An application can use unnamed pipes to redirect the
  ** standard input and the standard output for a child process.
  ** A typical use of an unnamed pipe is to read the output
  ** of a child process. An application creates a pipe and then
  ** duplicates the standard output handle. When the child
  ** process is started, its standard output will be written
  ** into the pipe, where the application can read and display
  ** The parent process controls the meanings for standard I/O
  ** for the child process.
  **------------------------------------------------------
  */


  /*
  **------------------------------------------------------
  ** Save standard output handle
  **------------------------------------------------------
  */

  if (rc = DosDupHandle (HF_STDOUT, &hfSave))
    goto OnError;

  /*
  **------------------------------------------------------
  ** Create an anonymous pipe for parent and child to
  ** read/write from.
  **------------------------------------------------------
  */

  if (rc = DosCreatePipe (&hpRead, &hpWrite, PIPESIZE))
    goto OnError;

  /*
  **------------------------------------------------------
  ** Alias standard output handle for child to inherit.
  **------------------------------------------------------
  */

  if (rc = DosDupHandle (hpWrite, &hfNew))
    goto OnError;


  /*
  **------------------------------------------------------
  ** Use CMD.EXE's convention when passing arguments to
  ** executables.  Build arg string.
  **------------------------------------------------------
  */


  sprintf (setboot_Args, "%s\\os2\\setboot.exe", bootDrive);

  argPtr = strlen (setboot_Args);

  setboot_Args [argPtr++] = '\x0';
  setboot_Args [argPtr++] = '/';
  setboot_Args [argPtr++] = 'q';
  setboot_Args [argPtr++] = '\x0';
  setboot_Args [argPtr++] = '\x0';



  /*
  **------------------------------------------------------
  ** Start a child process which will inherit parent handles.
  **------------------------------------------------------
  */

  if (rc = DosExecPgm (szFailName,
                       sizeof (szFailName),
                       EXEC_SYNC,
                       setboot_Args,
                       (PSZ) NULL,
                       &resc,
                       "setboot.exe"))
    goto OnError;

  if (rc = resc.codeResult)
    goto OnError;


  /*
  **------------------------------------------------------
  ** Two write handles exist.  Close this one to ensure
  ** notification at child termination.
  **------------------------------------------------------
  */

  DosClose (hpWrite);


  /*
  **------------------------------------------------------
  ** Bring back HF_STDOUT.
  **------------------------------------------------------
  */

  if (rc = DosDupHandle (hfSave, &hfNew))
    goto OnError;


  if (rc = DosRead (hpRead, bootInfoBuf, sizeof (bootInfoBuf), &cbRead))
    goto OnError;


  rc = DosClose (hpRead);


  /*
  **------------------------------------------------------
  ** Check to see if boot manager is installed.  If it
  ** is then a timeout value will be returned in the
  ** buffer. Save the boot manager timeout value so we can
  ** restore it at a later time.
  **------------------------------------------------------
  */

  if (cbRead) {

    char *pTimeout, *pSystem0, *pSystem4;


    if (pTimeout = strstr (bootInfoBuf, "Timeout")) {

      bootMgr.timeout = atoi (pTimeout + strlen ("Timeout"));


      pSystem0 = strstr (pTimeout, "System 0");

      pSystem0 += strlen ("System 0");
      while (isspace (*pSystem0)) ++pSystem0;
      strncpy (bootMgr.system0, pSystem0, strcspn (pSystem0, "\r\n"));

      pSystem4 = strstr (pSystem0, "System 4");

      pSystem4 += strlen ("System 4");
      while (isspace (*pSystem4)) ++pSystem4;
      strncpy (bootMgr.system4, pSystem4, strcspn (pSystem4, "\r\n"));


      /*
      **------------------------------------------------------
      ** Setting the boot managers timeout to zero puts the
      ** boot manager in unattended mode.  Move the system 4
      ** index into the system 0 slot so we startup the
      ** right partition.
      **------------------------------------------------------
      */

      if (rc = setBootManager (0, bootMgr.system4))
        goto OnError;

    }

  }



  return rc;

 OnError:


  DosDupHandle (hfSave, &hfNew);
  DosClose (hpRead);
  DosClose (hpWrite);

} // setBootManagerUnattended

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: setBootManagerAttended                             *
 *                                                                        *
 * Description.......: If boot manager is installed set back to attended  *
 *                     mode.                                              *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Upon return from hibernation we restore the        *
 *                     boot managers availability via this function.      *
 *                                                                        *
 **************************************************************************
*/

int setBootManagerAttended (void)
{

  return (BOOT_MANAGER_INSTALLED) ?
    setBootManager (bootMgr.timeout, bootMgr.system0) : NO_ERROR;

} /* setBootManagerAttended */

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: extent                                             *
 *                                                                        *
 * Description.......: Locate the file extents allocated for the file     *
 *                     specified.                                         *
 *                                                                        *
 * Restrictions......: None                                               *
 *                                                                        *
 * Entry.............: (I) - hyberFileName : qualified path and file name *
 *                     (I) - dlist : pointer to dlist                     *
 *                     (I) - list_siz : size of dlist                     *
 *                                                                        *
 * Exit..............: OS/2 system return code                            *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: Upon return from hibernation we restore the        *
 *                     boot managers availability via this function.      *
 *                                                                        *
 **************************************************************************
*/

#include "mfs.h"

int extent (char *hyberFileName, struct dlist_s *dlist, int list_siz,
            PULONG dlistDiskNum)
{
  ULONG         rc;
  ULONG         i;
  PMFSFILEINFO  pFSfileInfo;
  PVOL          pVol;
  HFILE         hHyberFile;

  /* MFSInit() must be called before using the other MFS functions. */

  /* Get the pointer to the volume control block matching the drive */
  /* specified in the input file name.                              */
  if (rc = MFSFindVol( hyberFileName, &pVol ) )
    return rc;

  if ( pVol->Flags & VOLF_MOUNT_REQ )         /* volume information missing? */
    if (rc = (*pVol->pFSMount)( pVol ))           /* go get the info we need */
      return rc;

  /* Accommodate the maximum number of disk frames specified in list_siz */
  i = sizeof(MFSFILEINFO) + sizeof(EXTENT) * list_siz;

  if ( !(pFSfileInfo=(PMFSFILEINFO) malloc( i )) )
    return ERROR_NOT_ENOUGH_MEMORY;

  memset( pFSfileInfo, 0, i );

  pFSfileInfo->cMaxExtents = list_siz;      /* maximum size of the Extents[] */

  /* Obtain file extents for the file specified in hyberFileName */
  if (rc = MFSGetFileInfo( (PSZ) hyberFileName, (PMFSFILEINFO) pFSfileInfo ) )
    return rc;

  *dlistDiskNum = (ULONG)&pVol->pDCB->DiskNum;

  for ( i=0; i < pFSfileInfo->cExtents; i++ ) {   /* return file extent list */

    dlist[i].dl_sector = pFSfileInfo->Extents[i].ExtentRBA;
    dlist[i].dl_count = pFSfileInfo->Extents[i].ExtentSec;

  }

  dlist[i].dl_count = 0;                        // end flag

  return rc;
}


/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: hyberDisplayMessage                                *
 *                                                                        *
 * Description.......: Write info/error message in the dialog             *
 *                                                                        *
 * Restrictions......:                                                    *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 * Notes.............: If error, the CANCEL button is enabled, and this   *
 *                     process will terminate.                            *
 **************************************************************************
*/
APIRET hyberDisplayMessage(
   ULONG  ulHiberMsgNumber,   /* Hibernate Subsystem message number  */
   PCHAR  pString,            /* Additional string to a message      */
   BOOL   fError)             /* Error flag                          */
{
#ifdef PM_GUI
   QMSG     qmsg;
   HWND     hwndButton;
   char     pMsg[256];
   ULONG    ulMsgLen;
#endif
   APIRET   rc;
   ULONG    ulMsgNumber[MAX_MESSAGES];
   BOOL     fInsertString[MAX_MESSAGES];
   int      msgCount=0;
   int      i,j;
   int      str_len;
   char      blank = ' ';

#ifndef PM_GUI
   VIOCURSORINFO curInfo;
   KBDKEYINFO charData;
   BYTE ch_attr[2]= {0x20, 0x7};

   rc = VioScrollUp (0, 0, 25, 80, 65535,  &ch_attr[0], 0);
   if (rc)
      return(rc);


#endif

   if (fError) {
      ulMsgNumber[msgCount] = IDS_MSG_UNABLE_TO_HIBERNATE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
   }

   switch (ulHiberMsgNumber) {
   case HIBER_MSG_HIBERNATION_START:
      ulMsgNumber[msgCount] = IDS_MSG_HIBERNATION_START;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_HIBERNATION_COMPLETE:
      ulMsgNumber[msgCount] = IDS_MSG_HIBERNATION_COMPLETE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_LOADING_FILE:
      ulMsgNumber[msgCount] = IDS_MSG_LOADING_FILE;
      fInsertString[msgCount] = TRUE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_FILE_NOT_FOUND:
      ulMsgNumber[msgCount] = IDS_MSG_FILE_NOT_FOUND;
      fInsertString[msgCount] = TRUE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_NO_SWAP_FILE:
      ulMsgNumber[msgCount] = IDS_MSG_NO_SWAP_FILE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_DISK_FULL:
      ulMsgNumber[msgCount] = IDS_MSG_DISK_FULL;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_MODIFY_SWAP_FILE:
      ulMsgNumber[msgCount] = IDS_MSG_MODIFY_SWAP_FILE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_HPFS_SWAP_FILE:
      ulMsgNumber[msgCount] = IDS_MSG_HPFS_SWAP_FILE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_HIBER_IN_PROGRESS:
      ulMsgNumber[msgCount] = IDS_MSG_HIBER_IN_PROGRESS;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
   case HIBER_MSG_ERROR_HPFS_SYS_FILE:
      ulMsgNumber[msgCount] = IDS_MSG_ERROR_HPFS_SYS_FILE;
      fInsertString[msgCount] = FALSE;
      ++msgCount;
      break;
    case HIBER_MSG_ERROR_INTERNAL:
      break;
   }

#ifdef PM_GUI
   for (i=0; i<msgCount; i++) {

      ulMsgLen =  WinLoadString( hab,
                                 NULLHANDLE,
                                 ulMsgNumber[i],
                                 sizeof(pMsg),
                                 pMsg);

      if (fInsertString[i])
      {
         pMsg[ulMsgLen++] = ' ';
         pMsg[ulMsgLen] = '\0';
         strcat( pMsg, pString);
      }

      WinSetDlgItemText(hwndDlg, IDC_CONTROL_BASE+i, pMsg);

   }

   if (fError) {

      hwndButton = WinWindowFromID(hwndDlg, IDC_CANCEL_BUTTON);
      if (!WinIsWindowVisible(hwndButton))
        {
          WinEnableWindowUpdate(hwndButton, TRUE);
        }

      WinEnableWindow( hwndButton,
                       TRUE);
      while (WinGetDlgMsg(hwndDlg, &qmsg)) {
         SimpleDlgProc(hwndDlg, qmsg.msg, qmsg.mp1, qmsg.mp2);
      }
      WinDestroyWindow(hwndDlg);

      DosExit (EXIT_PROCESS, 0);

   }

#else

   for (i = 0; i<msgCount; i++) {

     VioWrtNChar (&blank, 80, i, 0, 0);          // clear the line
     j = ulMsgNumber[i] - MSG_START_MSG_NUM;

     VioWrtCharStr (messages[j].msg, messages[j].len, i, 0, 0);

     if (fInsertString[i])
     {
        /*
        **----------------------------------------
        ** We must append the additional message
        **----------------------------------------
        */
        str_len=strlen(pString);
        VioWrtCharStr (pString, str_len, i, messages[j].len, 0);
        if (str_len+messages[j].len>80)
           i++;
     }
   }

   if (fError) {

     VioWrtNChar (&blank, 80, i, 0, 0);
     VioWrtNChar (&blank, 80, i, 0, 0);

     VioWrtCharStr (messages[13].msg, messages[13].len, i, 0, 0);
     KbdCharIn (&charData, 0, 0);

     DosExit (EXIT_PROCESS, 0);

   }

#endif
   return 0;
} /*------------------------- HyberDisplayMessage ----------------------*/


/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: SimpleDlgProc                                      *
 *                                                                        *
 * Description.......: A simple PM procedure for the dialog               *
 *                                                                        *
 * Restrictions......:                                                    *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 **************************************************************************
*/
#ifdef PM_GUI
MRESULT EXPENTRY SimpleDlgProc(
   HWND hwnd,
   ULONG msg,
   MPARAM mp1,
   MPARAM mp2)
{
   switch(msg)
   {

      case WM_COMMAND:
         /**
          ** No matter what the command, close the dialog
          **/
         WinDismissDlg(hwnd, TRUE);
         break;

      default:
         return(WinDefDlgProc(hwnd, msg, mp1, mp2));
         break;
   }
   return (MRESULT)0;
} /*------------------------- SimpleDlgProc ----------------------*/

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: RestorePM                                          *
 *                                                                        *
 * Description.......: Restore PM after resume by starting a full-screen  *
 *                     session.                                           *
 *                                                                        *
 * Restrictions......:                                                    *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............: RC from DosStartSession                            *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 **************************************************************************
*/
int RestorePM ()
{
    STARTDATA SData       = {0};
    APIRET    rc          = NO_ERROR;   /* Return code                  */
    PID       pid         = 0;          /* PID returned                 */
    ULONG     ulSessID    = 0;          /* Session ID returned          */
    UCHAR     achObjBuf[256] = {0};     /* Error data if DosStart fails */
    char      PgmName[256];

    SData.Length  = sizeof(STARTDATA);
    SData.Related = SSF_RELATED_INDEPENDENT; /* start an independent session */
    SData.FgBg    = SSF_FGBG_FORE;           /* start session in foreground  */
    SData.TraceOpt = SSF_TRACEOPT_NONE;      /* No trace                     */

    SData.PgmTitle = 0;


    sprintf (PgmName, "%s\\os2\\system\\hyberset.exe", bootDrive);

    SData.PgmName = PgmName;
    SData.PgmInputs = "/S";                     /* tell hyberset to SETMODE  */

    SData.TermQ = 0;                            /* No termination queue      */
    SData.Environment = 0;                      /* No environment string     */
    SData.InheritOpt = SSF_INHERTOPT_SHELL;     /* Inherit shell's environ.  */
    SData.SessionType = SSF_TYPE_FULLSCREEN;    /* Full screen session       */
    SData.IconFile = 0;                         /* No icon association       */
    SData.PgmHandle = 0;
    SData.Reserved = 0;
    SData.ObjectBuffer  = achObjBuf;            /* Contains info if DosExecPgm fails */
    SData.ObjectBuffLen = (ULONG) sizeof(achObjBuf);

    rc = DosStartSession(&SData, &ulSessID, &pid);  /* Start the session */

    return rc;
}/*--------------------- RestorePM -------------------------*/

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: hyberComplete                                      *
 *                                                                        *
 * Description.......: Prompt the user that HIBERNATION has been completed*
 *                     If Reboot button is clicked, invoke Reboot command *
 *                     in DOS.SYS                                         *
 *                                                                        *
 * Restrictions......: DOS.SYS must be installed to reboot.               *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............:                                                    *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 **************************************************************************
*/
void hyberComplete()
{
   MB2INFO   mb2info;           /* message box input structure         */
   char      Msg[256];
   ULONG     ulMsgLen;
   char      szHibernation[40];     /* this string contains the word "Hibernation" */
   char      szRestore[40];         /* this string contains the word "Restore" */

   /*---------------------------------------------
    * Load the word "Hibernation"
    *---------------------------------------------*/
    ulMsgLen = WinLoadString( hab,
                              NULLHANDLE,
                              IDS_MSG_HIBERNATION,
                              sizeof(szHibernation),
                              szHibernation);

   ulMsgLen =  WinLoadString( hab,
                              NULLHANDLE,
                              IDS_MSG_HIBERNATION_COMPLETE,
                              sizeof(Msg),
                              Msg);

   mb2info.cb = sizeof(MB2INFO);
   // mb2info.hIcon = WinLoadPointer(HWND_DESKTOP, 0, IDPTR_HIBERNATION);
   mb2info.hIcon = NULLHANDLE;
   mb2info.cButtons = 1;
   mb2info.flStyle = MB_CUSTOMICON | MB_SYSTEMMODAL;
   mb2info.hwndNotify = NULLHANDLE;

   /* button */
   if (dossys_handle)
   {
      /*---------------------------------------------
       * Load the word "Restore"
       *---------------------------------------------*/
      ulMsgLen = WinLoadString( hab,
                              NULLHANDLE,
                              IDS_MSG_RESTORE,
                              sizeof(szRestore),
                              szRestore);
      strcpy(mb2info.mb2d[0].achText, szRestore);
   } else
      strcpy(mb2info.mb2d[0].achText, szHibernation);

   mb2info.mb2d[0].idButton = IDB_HIBER_COMPLETE;
   mb2info.mb2d[0].flStyle = 0;

   while(1)
   {
      WinMessageBox2(HWND_DESKTOP,
                  HWND_DESKTOP,            /* client-window handle     */
                  Msg,                     /* body of the message      */
                  szHibernation,           /* title of the message     */
                  IDMB_HIBER_COMPLETE,     /* message box id           */
                  &mb2info);               /* message box input structure */

      if (dossys_handle)
      {
         DosDevIOCtl ( dossys_handle,
                       0xD5,
                       0xAB,
                       (PVOID)NULL,
                       0,
                       (PULONG)NULL,
                       (PVOID)NULL,
                       0,
                       (PULONG)NULL);
      }
   }
} /*--------------------- hyberComplete -------------------------*/
#endif
#ifdef VIO
/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: RestorePM                                          *
 *                                                                        *
 * Description.......: Restore PM after resume by starting a full-screen  *
 *                     session.                                           *
 *                                                                        *
 * Restrictions......:                                                    *
 *                                                                        *
 * Entry.............:                                                    *
 *                                                                        *
 * Exit..............: RC from DosStartSession                            *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 **************************************************************************
*/
int RestorePM ()
{
   APIRET rc;
   VIOMODEINFO modedata;

   /* viosetmode setup */
   modedata.cb = 12;
   modedata.fbType = 3;
   modedata.color = 4;
   modedata.col = 80;
   modedata.row = 30;
   modedata.hres = 640;
   modedata.vres = 480;
   rc = VioSetMode(&modedata, 0);
   if (rc) {
      return(rc);
   }

   /* viosetmode setup */
   modedata.cb = 12;
   modedata.fbType = 1;
   modedata.color = 4;
   modedata.col = 80;
   modedata.row = 25;
   modedata.hres = 640;
   modedata.vres = 400;
   rc = VioSetMode(&modedata, 0);
   return(rc);
}
#endif

/*
 **************************************************************************
 *                                                                        *
 * Function Name.....: FileExist                                          *
 *                                                                        *
 * Description.......: Determine if file exists                           *
 *                                                                        *
 *                                                                        *
 * Restrictions......: No wildcards                                       *
 *                                                                        *
 * Entry.............: (I) - pathname : full qualified path name          *
 *                                                                        *
 * Exit..............: TRUE / FALSE                                       *
 *                                                                        *
 * External Functions:                                                    *
 *                                                                        *
 * Pseudocode........:                                                    *
 *                                                                        *
 * Status............: Complete                                           *
 *                                                                        *
 **************************************************************************
*/
BOOL FileExist(char * pathname)
{
  HDIR          hdirFindHandle = HDIR_CREATE;
  FILEFINDBUF3  FindBuffer;
  ULONG         ulBufLen = sizeof(FILEFINDBUF3);
  ULONG         ulFindCount = 1;
  APIRET        rc;

  rc = DosFindFirst( pathname,
                     &hdirFindHandle,
                     FILE_NORMAL,
                     &FindBuffer,
                     ulBufLen,
                     &ulFindCount,
                     FIL_STANDARD);
  if (rc == NO_ERROR) {
     DosFindClose(hdirFindHandle);
     return(TRUE);
  } else
     return(FALSE);
} /*--------------------- FileExist ---------------------*/


VOID APIENTRY MyExit(void)
{
#ifdef PM_GUI
   if (hwndDlg) {
      WinDestroyWindow(hwndDlg);
   }
   WinDestroyMsgQueue( hmq );
   WinTerminate( hab );

   if (dossys_handle)
      DosClose(dossys_handle);
#else

   ULONG  msgCnt;
   for (msgCnt = 0; msgCnt < msgNum - MSG_START_MSG_NUM; msgCnt++)
      free (messages[msgCnt].msg);

#endif



   if (isSystemFilesCopied) {

     UCHAR sourceName [48];
     UCHAR targetName [48];


     /*
     **----------------------------------------------------------
     ** Copy autoexec.bat and config.sys to system directory so
     ** that any modifications will be saved.  Then restore
     ** OS/2 config.sys to root directory.
     **----------------------------------------------------------
     */

     sprintf (targetName, "%s\\OS2\\SYSTEM\\%s", bootDrive, CONFIG_DOS);
     sprintf (sourceName, "%s\\CONFIG.SYS", bootDrive);

     DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);


     sprintf (targetName, "%s\\CONFIG.SYS", bootDrive);
     sprintf (sourceName, "%s\\OS2\\SYSTEM\\CONFIG.OS2", bootDrive);

     DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);
     DosDelete (sourceName);


     sprintf (targetName, "%s\\OS2\\SYSTEM\\%s", bootDrive, AUTOEXEC_DOS);
     sprintf (sourceName, "%s\\AUTOEXEC.BAT", bootDrive);

     DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);

     sprintf (targetName, "%s\\AUTOEXEC.BAT", bootDrive);
     sprintf (sourceName, "%s\\OS2\\SYSTEM\\AUTOEXEC.OS2", bootDrive);

     DosCopy (sourceName, targetName,  DCPY_EXISTING | DCPY_FAILEAS);
     DosDelete (sourceName);

   }


   DosExitList(EXLST_EXIT, (PFNEXITLIST)NULL);
 } /*------------------- MyExit -----------------------------*/
