cdesktopenv/cde/programs/dtsession/SmRestore.c

4780 lines
113 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: SmRestore.c /main/26 1998/12/14 20:13:07 mgreess $ */
/* *
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
* (c) Copyright 1993, 1994 International Business Machines Corp. *
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
* (c) Copyright 1993, 1994 Novell, Inc. *
*/
/*************************************<+>*************************************
*****************************************************************************
**
** File: SmRestore.c
**
** Project: HP DT Session Manager (dtsession)
**
** Description:
** -----------
** This file contains functions that are in charge of restoring state.
** When the session manager is first started, it restores the state that
** was either last saved (home state), or last exited (current state). The
** state restored depends on values the user has configured.
**
**
**
*******************************************************************
** (c) Copyright Hewlett-Packard Company, 1990. All rights are
** reserved. Copying or other reproduction of this program
** except for archival purposes is prohibited without prior
** written consent of Hewlett-Packard Company.
********************************************************************
**
**
**
*****************************************************************************
*************************************<+>*************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#ifdef _SUN_OS /* to get the define for NOFILE */
#include <sys/param.h>
#endif /* _SUN_OS */
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <ctype.h>
#include <X11/Intrinsic.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/StringDefs.h>
#include <X11/keysymdef.h>
#include <X11/SM/SMlib.h>
#include <Xm/Xm.h>
# include <stdarg.h>
# define Va_start(a,b) va_start(a,b)
#include <Dt/DtP.h>
#include <Dt/Message.h>
#include <Dt/CommandM.h>
#include <Dt/Connect.h>
#include <Dt/Wsm.h>
#include <Dt/WsmP.h>
#include <Dt/UserMsg.h>
#include <Dt/SessionM.h>
#include <Dt/EnvControlP.h>
#include <Dt/Utility.h>
#include <Dt/MsgLog.h>
#include <bms/spc.h>
#include <Dt/CmdInv.h>
#include <Dt/ActionUtilP.h>
#include "Sm.h"
#include "SmResource.h"
#include "SmError.h"
#include "SmCommun.h"
#include "SmRestore.h"
#include "SmProtocol.h"
#include "SmConMgmt.h"
#include "SmSave.h"
#include "SmUI.h"
#include "SmGlobals.h"
#include "SmXSMP.h"
#include "SmDB.h"
#include "SmProp.h"
#include <X11/Xlibint.h>
/*
* Local variables
*/
static const char * DISPLAY_NAME_EQUAL = "DISPLAY=";
static const char * DISPLAY_NAME = "DISPLAY";
static char * savedDisplay = NULL;
/*
* #define statements
*/
#define MAXLINE 1024
#define MAXPATHSM 1023
#define MAX_QUOTE_DEPTH 10
#define SM_MAX_ARGS MAXLINE
#if defined (SVR4)
#define REMOTE_CMD_STRING "rsh %s -n %s &"
#else
#define REMOTE_CMD_STRING "remsh %s -n %s &"
#endif
/*
* typedef statements
*/
typedef struct
{
unsigned char *hostPtr;
unsigned char *cmdPtr;
} RemoteReq;
/*
* Variables global to this module only
*/
static XtResource settingsResources[] =
{
{SmNaccelNum, SmCaccelNum, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, accelNum),
XtRImmediate, (XtPointer) -1},
{SmNaccelDenom, SmCaccelDenom, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, accelDenom),
XtRImmediate, (XtPointer) -1},
{SmNthreshold, SmCthreshold, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, threshold),
XtRImmediate, (XtPointer) -1},
{SmNtimeout, SmCtimeout, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, timeout),
XtRImmediate, (XtPointer) -1},
{SmNinterval, SmCinterval, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, interval),
XtRImmediate, (XtPointer) -1},
{SmNpreferBlank, SmCpreferBlank, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, preferBlank),
XtRImmediate, (XtPointer) 0},
{SmNallowExp, SmCallowExp, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, allowExp),
XtRImmediate, (XtPointer) 0},
{SmNfontPath, SmCfontPath, XtRString, sizeof(String),
XtOffset(SessionSettingsPtr, fontDirs), XtRString, (XtPointer) ""},
{SmNkeyClick, SmCkeyClick, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.key_click_percent),
XtRImmediate, (XtPointer) -1},
{SmNbellPercent, SmCbellPercent, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.bell_percent),
XtRImmediate, (XtPointer) -1},
{SmNbellPitch, SmCbellPitch, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.bell_pitch),
XtRImmediate, (XtPointer) -1},
{SmNbellDuration, SmCbellDuration, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.bell_duration),
XtRImmediate, (XtPointer) -1},
{SmNledMask, SmCledMask, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.led_mask),
XtRImmediate, (XtPointer) 0},
{SmNglobalRepeats, SmCglobalRepeats, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, kbdState.global_auto_repeat),
XtRImmediate, (XtPointer) 2},
{SmNautoRepeats, SmCautoRepeats, XtRString, sizeof(String),
XtOffset(SessionSettingsPtr, autoRepeats), XtRString, (XtPointer) ""},
{SmNbuttonMap, SmCbuttonMap, XtRString, sizeof(String),
XtOffset(SessionSettingsPtr, buttonMap), XtRString, (XtPointer) ""},
{SmNnumKeyCode, SmCnumKeyCode, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, numKeyCode), XtRImmediate, (XtPointer) 0},
{SmNkeySymsPerKey, SmCkeySymsPerKey, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, keySymPerCode),
XtRImmediate, (XtPointer) 0},
{SmNkeySyms, SmCkeySyms, XtRString, sizeof(String),
XtOffset(SessionSettingsPtr, keySyms), XtRString, (XtPointer) ""},
{SmNmaxKeyPerMod, SmCmaxKeyPerMod, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, maxKeyPerMod),
XtRImmediate, (XtPointer) 0},
{SmNmodMap, SmCmodMap, XtRString, sizeof(String),
XtOffset(SessionSettingsPtr, modSyms),
XtRString, (XtPointer) ""},
{SmNdidQuerySettings, SmCdidQuerySettings, XtRBoolean, sizeof(Boolean),
XtOffset(SessionSettingsPtr, didQuery),
XtRImmediate, (XtPointer) False},
{SmNshutDownState, SmCshutDownState, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, confirmMode),
XtRImmediate, (XtPointer) 1},
{SmNshutDownMode, SmCshutDownMode, XtRInt, sizeof(int),
XtOffset(SessionSettingsPtr, startState),
XtRImmediate, (XtPointer) 4},
};
/*
* Variables used for parsing code
*/
static unsigned char fallBackLine[MAXLINE+2]; /* line buffer */
static unsigned char *line; /* line buffer */
static FILE *cfileP = NULL; /* fopen'ed configuration file or NULL */
static int linec = 0; /* line counter for parser */
static unsigned char *parseP = NULL; /* pointer to parse string */
static int fileSize = 0;
char **smExecArray = NULL;
/*
* Variables used for remote execution
*/
static int numRemoteExecs = 0;
unsigned char *remoteBuf[MAX_SCREENS_SAVED];
unsigned int actRemoteSize[MAX_SCREENS_SAVED];
RemoteReq remoteBufPtr[MAX_REMOTE_CLIENTS];
static char localHost[MAXHOSTNAMELEN];
static char ** ignoreEnvPtr = NULL;
/*
* Timeout for workspace manager handshake
*/
static Boolean wmTimeout;
/*
* These lines were added to support the builtin
* panacomm dtwm.
*/
char tmpExecWmFile[MAXPATHSM+1];
static Boolean localWmLaunched = False;
/*
* ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^
* End of lines were added to support the builtin
* panacomm dtwm.
*/
/*
* Fonts
*/
char *fonttype[] = {
"*systemFont",
"*userFont",
"*FontList",
"*buttonFontList",
"*labelFontList",
"*textFontList",
"*XmText*FontList",
"*XmTextField*FontList",
"*DtEditor*textFontList",
"*Font",
"*FontSet"
};
static char *fontclass[] = {
"*SystemFont",
"*UserFont",
"*FontList",
"*ButtonFontList",
"*LabelFontList",
"*TextFontList",
"*XmText*FontList",
"*XmTextField*FontList",
"*DtEditor*textFontList",
"*Font",
"*FontSet"
};
/*
* Local functions
*/
static int RestoreSettings( void ) ;
static int RestoreClients( void ) ;
static unsigned char * GetNextLine( void ) ;
static unsigned int PeekAhead( unsigned char *, unsigned int ) ;
static unsigned char * GetSmartString( unsigned char **) ;
static void ForkWM( void ) ;
static int FillCmdBuf( unsigned char *, unsigned char **,
unsigned int *, unsigned int *,
unsigned int, unsigned int *) ;
static int FillRemoteBuf( unsigned char *, unsigned char *,
unsigned char *, unsigned char **,
unsigned int *, unsigned int *, unsigned int) ;
static int FillHintBuf(unsigned char *, unsigned char **,
unsigned int *, unsigned int *,
unsigned int, unsigned int *);
static void WaitForWM( void ) ;
static void HandleWMClientMessage(Widget smWidget, XtPointer dummy,
XEvent *event);
static void WaitWMTimeout( XtPointer , XtIntervalId *) ;
static void FixEnvironmentData( void ) ;
static void ResetScreenInfo(unsigned char **,
int *, unsigned int *,
Boolean *, char *,
char *);
static void RemoteRequestFailed(char *, void *);
static void RemoteRequestSucceeded(char *, void *);
static void SetTemporaryDisplay (
int screenNum);
int RestorePreferences(char *filename);
static void RestoreDisplay (
int screenNum);
static Boolean StartLocalClient (
char * program,
char ** argv,
char * cwd,
char ** envp,
Boolean doChdir,
Boolean useIgnoreEnvResource);
static Boolean StartRemoteClient (
char * program,
char ** argv,
char * hostName,
char * cwd,
char ** envp,
Boolean useIgnoreEnvResource);
static Boolean CheckRequiredProperties (
XSMPClientDBRecPtr pDbRec,
char * databaseName);
static Boolean CheckRequiredFields (
ProxyClientDBRecPtr pDbRec,
char * databaseName,
int clientNum);
static void LogXSMPOpenDatabaseFailure (
char * databaseName,
DtMsgLogType msgType,
int errorNum);
static void LogMissingPropertyMessage (
XSMPClientDBRecPtr pDbRec,
char * propName,
char * databaseName,
DtMsgLogType msgType);
static void LogCWDMessage (
char * badDir,
char * appName,
char * goodDir);
static char ** RemoveEnvironmentVars (
char **envp);
static void MarkFileDescriptors (
int start_fd,
int cmd,
int data);
/*************************************<->*************************************
*
* SetCompatState ()
*
*
* Description:
* -----------
* Sets _DT_SM_STATE_INFO for dtstyle indicating compatibility mode
*
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
* The only thing dtstyle should be looking at is the compatMode
*
*************************************<->***********************************/
int
SetCompatState( void )
{
SmStateInfo state;
/*
* BEFORE any clients are started
* set a property on the top level window
* which lets the style manager know what state the sm is in
*/
state.flags = SM_STATE_ALL;
state.smStartState = 0;
state.smConfirmMode = 0;
state.smCompatMode = True;
state.smSendSettings = False;
state.smCoverScreen = True;
state.smLockOnTimeoutStatus = smGD.lockOnTimeoutStatus;
state.smCycleTimeout = 0;
state.smLockTimeout = 0;
state.smSaverTimeout = 0;
state.smRandom = 0;
state.smDisplaySpecific = smGD.displaySpecific;
_DtSetSmState(smGD.display, smGD.topLevelWindow, &state);
XFlush(smGD.display);
return(0);
} /* END OF FUNCTION SetCompatState */
/*************************************<->*************************************
*
* SystemCmd (pchCmd)
*
*
* Description:
* -----------
* This function fiddles with our signal handling and calls the
* system() function to invoke a unix command.
*
*
* Inputs:
* ------
* pchCmd = string with the command we want to exec.
*
* Outputs:
* -------
*
*
* Comments:
* --------
* The system() command is touchy about the SIGCLD behavior. Restore
* the default SIGCLD handler during the time we run system().
*
*************************************<->***********************************/
void
SystemCmd (char *pchCmd)
{
void (*signalHandler) ();
signalHandler = (void (*)())signal (SIGCHLD, SIG_DFL);
system (pchCmd);
signal (SIGCHLD, signalHandler);
} /* END OF FUNTION SystemCmd */
/*************************************<->*************************************
*
* RestoreState ()
*
*
* Description:
* -----------
*
* Inputs:
* ------
*
* Outputs:
* -------
*
* Comments:
* --------
* When this routine is finished, all settings and resources will be restored.
* Clients may not be, as they are actually restored by different processes.
*
*************************************<->***********************************/
int
RestoreState( void )
{
SmStateInfo state;
SmSaverInfo saver;
char convertCommand[MAXPATHSM+1];
int status;
Boolean fixedBuffer = False;
struct stat buf;
char *pchar;
Boolean useXrmDB = False;
/*
* Restore all the X settings which were active at the time of shutdown
*/
RestoreSettings();
if (smGD.sessionType == HOME_SESSION)
smSettings.startState = DtSM_HOME_STATE;
else
smSettings.startState = DtSM_CURRENT_STATE;
/*
* BEFORE any clients are started
* set a property on the top level window
* which lets the style manager know what state the sm is in
*/
state.flags = SM_STATE_ALL;
state.smStartState = smSettings.startState;
state.smConfirmMode = smSettings.confirmMode;
state.smCompatMode = smGD.compatMode;
state.smSendSettings = !smRes.querySettings;
state.smLockOnTimeoutStatus = smGD.lockOnTimeoutStatus;
state.smCycleTimeout = smSaverRes.cycleTimeout;
state.smLockTimeout = smSaverRes.lockTimeout;
state.smSaverTimeout = smSaverRes.saverTimeout;
state.smRandom = smSaverRes.random;
state.smDisplaySpecific = smGD.displaySpecific;
_DtSetSmState(smGD.display, smGD.topLevelWindow, &state);
saver.saverList = smGD.saverList;
_DtSetSmSaver(smGD.display, smGD.topLevelWindow, &saver);
/*
* Set up the Property telling all applications what session is being
* restored
*/
XaSmRestoreMode = XInternAtom(smGD.display, _XA_DT_RESTORE_MODE, False);
XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
XaSmRestoreMode, XA_STRING, 8, PropModeReplace,
(unsigned char *)smGD.restoreSession, strlen(smGD.restoreSession));
XFlush(smGD.display);
/*
* Check the session database and either parse it as an
* Xrm-database or the CDE1.0 format
*/
if ((pchar = strrchr (smGD.clientPath, '/')) != NULL)
{
pchar ++;
if ((*pchar != '\0') && (!strcmp (pchar, SM_CLIENT_FILE2)))
useXrmDB = True;
}
if (useXrmDB)
{
return (StartXSMPSession (smGD.clientPath));
} else {
/*
* Malloc line for parsing.
*/
status = stat(smGD.clientPath, &buf);
if(status != -1)
{
fileSize = buf.st_size;
}
if (fileSize < MAXLINE + 1)
{
fileSize = MAXLINE + 1;
}
line = malloc(fileSize + 1);
if (line == NULL)
{
line = fallBackLine;
fileSize = MAXLINE + 1;
fixedBuffer = True;
}
cfileP = fopen(smGD.clientPath, "r");
if (cfileP == NULL)
{
PrintErrnoError(DtError, smNLS.cantOpenFileString);
if (!fixedBuffer && line)
{
SM_FREE((char *)line);
}
return(-1);
}
RestoreClients();
if (!fixedBuffer && line)
{
SM_FREE((char *)line);
}
}
return(0);
}
/*************************************<->*************************************
*
* StartWM ()
*
*
* Description:
* -----------
* Start up the window manager. The default is to start dtmwm unless
* another one is specified in a resource.
*
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
* When this routine is finished, all settings and resources will be restored.
* Clients may not be, as they are actually restored by different processes.
*
*************************************<->***********************************/
int
StartWM( void )
{
char wmStartupErrorString[(2 * MAXPATHSM) + 1];
char localWmErrorString[(2 * MAXPATHSM) + 1];
Boolean goodWmStartup = True;
int status;
if((smGD.wmStartup == NULL) || (*smGD.wmStartup == 0))
{
ForkWM();
}
else
{
CreateExecString(smGD.wmStartup);
/*
* check to see if the wmStartup string exists and is
* executable.
*/
status = access(smExecArray[0], F_OK | X_OK);
if(status == -1)
{
goodWmStartup = False;
CreateExecString(CDE_INSTALLATION_TOP "/bin/dtwm");
}
if(smExecArray[0] != NULL)
{
(void) StartClient(smExecArray[0], smExecArray, NULL, NULL,
NULL, False, False, -1);
}
}
/*
* We used to start the message server before the window
* manager and then if the message server did not start
* we would exit. Now we start the window manager, then
* start the message server and then wait for the window
* manager. This seems to improve performance.
*/
StartMsgServer();
if (goodWmStartup == False)
{
sprintf(wmStartupErrorString, GETMESSAGE(16, 7,
"The wmStartupCommand resource is set to:\n\n"
"%s\n\n"
"This file does not exist or is not executable.\n"
CDE_INSTALLATION_TOP "/bin/dtwm will be started "
"instead.\n"),
smGD.wmStartup);
PrintError(DtError, wmStartupErrorString);
}
WaitForWM();
/*
* These lines were added to support the builtin
* panacomm dtwm.
*/
if (localWmLaunched && wmTimeout)
{
if (!smGD.userSetWaitWmTimeout)
{
smRes.waitWmTimeout = smGD.savedWaitWmTimeout;
}
localWmLaunched = False;
/*
* A special version of a built-in Xterminal dtwm
* was attempted and failed.
* Try to launch .../dt/bin/dtwm instead
*/
CreateExecString(CDE_INSTALLATION_TOP "/bin/dtwm");
if(smExecArray[0] != NULL)
{
(void) StartClient(smExecArray[0], smExecArray, NULL,
NULL, NULL, False, False, -1);
}
WaitForWM();
sprintf(localWmErrorString, GETMESSAGE(16, 9,
"The following window manager did not start:\n\n"
" %s\n\n"
"This message indicates you tried to start a\n"
"window manager that is built into an X terminal.\n"
"This will only work with X terminals that support this protocol.\n"
CDE_INSTALLATION_TOP "/bin/dtwm will be started instead.\n"),
tmpExecWmFile);
PrintError(DtError, localWmErrorString);
}
/*
* ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^
* End of lines were added to support the builtin
* panacomm dtwm.
*/
return(0);
}
/*************************************<->*************************************
*
* ReloadResources ()
*
*
* Description:
* -----------
* Reloads RESOURCE_MANAGER during running session
*
*
* Inputs:
* ------
*
* Outputs:
* -------
*
* Comments:
* --------
*
*************************************<->***********************************/
void
ReloadResources(void)
{
/*
* Load sys.resources and .Xdefaults
*/
RestoreResources(True,
"-load",
"-system",
"-xdefaults",
NULL);
/*
* Merge _DT_SM_PREFERENCES
*/
RestorePreferences(NULL);
SetSystemReady();
}
/*************************************<->*************************************
*
* RestoreResources (errorHandlerInstalled, options ... )
*
*
* Description:
* -----------
* Calls routines responsible for restoring resources.
* Resources are restored by a fork and exec of dtsession_res.
*
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
* When this routine is finished, all settings and resources will be restored.
* Clients may not be, as they are actually restored by different processes.
*
*************************************<->***********************************/
int
RestoreResources( Boolean errorHandlerInstalled, ... )
{
pid_t forkrc;
int childStatus, execStatus, i;
char *pgrm, *p;
char *argv[20];
va_list args;
#if 0
/* JET - this seems like a bad (and unused) idea */
/*
* Check for alternate resource loader.
*/
if ((pgrm = getenv("DTLOADRESOURCES")) == NULL)
{
pgrm = CDE_INSTALLATION_TOP "/bin/dtsession_res";
}
#else
pgrm = CDE_INSTALLATION_TOP "/bin/dtsession_res";
#endif
/*
* By convention, exec() wants arg0 to be the program name. Ex: if pgrm
* is /usr/dt/bin/dtsession_res, the program name is dtsession_res.
* If all else fails, use pgrm.
*/
argv[0] = (p = strrchr(pgrm, '/')) != NULL && *(p+1) != '\0' ? p+1 : pgrm;
i = 0;
Va_start(args,errorHandlerInstalled);
do
{
i++;
argv[i] = va_arg(args, char *);
}
while(argv[i]);
va_end(args);
/*
* if an error handler is installed - remove it
*/
if(errorHandlerInstalled)
{
sigaction(SIGCHLD, &smGD.defvec, (struct sigaction *) NULL);
}
/*
* Fork and exec the xrdb process to load in the file created by
* writing out the resource manager string generated by the last
* session termination.
*/
for(i = 0;(i < 10) && ((forkrc = vfork()) < 0);i++)
{
if(errno != EAGAIN)
{
break;
}
sleep(2);
}
if(forkrc < 0)
{
PrintErrnoError(DtError, smNLS.cantForkClientString);
return(-1);
}
/*
* Fork succeeded - now do the exec
*/
if(forkrc == 0)
{
SetSIGPIPEToDefault ();
/*
* Set the gid of the process back from bin
*/
#ifndef SVR4
setregid(smGD.runningGID, smGD.runningGID);
#else
setgid(smGD.runningGID);
setegid(smGD.runningGID);
#endif
#if defined(CSRG_BASED)
setsid();
#else
(void) setpgrp();
#endif /* CSRG_BASED */
MarkFileDescriptors (3, F_SETFD, 1);
execStatus = execv(pgrm, argv);
if(execStatus != 0)
{
char clientMessage[MAXPATHLEN + 256];
memset(clientMessage, 0, MAXPATHLEN + 256);
snprintf(clientMessage, (MAXPATHLEN + 256) - 1,
((char *)GETMESSAGE(16, 1, "Unable to exec process %s. No session resources will be restored.")), pgrm);
PrintErrnoError(DtError, clientMessage);
SM_EXIT(-1);
}
}
while(wait(&childStatus) != forkrc);
/*
* if an error handler is installed - remove it
*/
if(errorHandlerInstalled)
{
sigaction(SIGCHLD, &smGD.childvec, (struct sigaction *) NULL);
}
return(0);
}
/*************************************<->*************************************
*
* RestorePreferences ( filename)
*
*
* Description:
* -----------
*
* This routine has two roles:
*
* 1) If 'filename' specified, the content of filename is read, and
* _DT_SM_PREFERENCES is populated with its content. This is used
* at session startup to set the initial state of _DT_SM_PREFERENCES.
*
* 2) If 'filename' is NULL, the content of _DT_SM_PREFERENCES is
* merged into RESOURCE_MANAGER. This is used when resources are
* reloaded at user request during a session.
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
int
RestorePreferences(
char *filename )
{
char *data;
if (filename)
{
FILE *fp;
int size;
struct stat statinfo;
if(access(filename,R_OK) != 0)
{
return(0);
}
/*
* Determine size of file.
*/
if (stat(filename, &statinfo) == -1)
{
return(0);
}
/*
* Get some memory.
*/
if ((data = (char *)SM_MALLOC(statinfo.st_size + 1)) == NULL)
{
return(0);
}
/*
* Read file into memory.
*/
if ((fp = fopen(filename, "r")) == NULL)
{
SM_FREE(data);
return(0);
}
size = fread(data, 1, statinfo.st_size, fp);
if (size == statinfo.st_size)
{
/*
* Merge .Xdefaults string into RESOURCE_MANAGER database, and
* also convert to Xrm database form for later subtraction.
*/
data[size] = '\0';
_DtAddResString(smGD.display, data, _DT_ATR_PREFS);
}
fclose(fp);
SM_FREE(data);
}
else
{
/*
* Read string from _DT_SM_PREFERENCES
*/
data = _DtGetResString(smGD.display, _DT_ATR_PREFS);
/*
* Merge string into RESOURCE_MANAGER
*/
_DtAddResString(smGD.display, data, _DT_ATR_RESMGR);
XFree(data);
}
return(0);
}
/*************************************<->*************************************
*
* RestoreSettings ()
*
*
* Description:
* -----------
* In charge of restoring all settings. Settings are stored in resource
* format so it gets the values by getting the resource values stored in
* a resource file that was created by the session manager.
*
*
* Inputs:
* ------
* smGD.settingPath = path that points to the settings resource file.
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
* This routine messes with the actual strings returned by the resource
* manager by tokenizing them, so these session settings resources should
* not be accessed again.
*
*************************************<->***********************************/
static int
RestoreSettings( void )
{
XrmDatabase smBase = NULL;
XKeyboardControl kbdControl;
int kbdControlMask;
char **restorePtrArray, **tmpRestore;
char *restoreCharArray;
int numArgs, ptrSize, charSize;
int i;
char *tmpKey;
KeySym *tmpSyms, codeSym;
int symSize;
KeyCode *tmpCode;
XModifierKeymap restoreMod;
ptrSize = 50;
charSize = 5000;
restorePtrArray = (char **) SM_MALLOC (ptrSize * sizeof(char *));
restoreCharArray = (char *) SM_MALLOC (charSize * sizeof(char));
if((restorePtrArray == NULL) || (restoreCharArray == NULL))
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
if(restorePtrArray != NULL)
{
SM_FREE((char *) restorePtrArray);
}
else
{
if(restoreCharArray != NULL)
{
SM_FREE(restoreCharArray);
}
}
return(-1);
}
/*
* Load the resources from the SM database file
*/
if (smGD.settingPath[0] != 0)
{
smBase = XrmGetFileDatabase(smGD.settingPath);
if(smBase == NULL)
{
PrintError(DtError, GETMESSAGE(16, 2, "Invalid client settings file. No settings restored."));
return(-1);
}
else
{
XrmMergeDatabases(smBase, &(smGD.display->db));
}
}
/*
* Retrieve the session settings file from the database
*/
XtGetApplicationResources(smGD.topLevelWid, (XtPointer) &smSettings,
settingsResources, XtNumber(settingsResources),
NULL, 0);
/*
* Copy any string resources since they may be overwritten in
* Xrm calls.
*/
smGD.fontDirs = SmNewString(smSettings.fontDirs);
smGD.autoRepeats = SmNewString(smSettings.autoRepeats);
smGD.buttonMap = SmNewString(smSettings.buttonMap);
smGD.keySyms = SmNewString(smSettings.keySyms);
smGD.modSyms = SmNewString(smSettings.modSyms);
/*
* This is provided for backward compatibility sake. The values that
* confirmMode can take have changed
*/
if(smSettings.confirmMode == DtSM_ASK_STATE)
{
smSettings.confirmMode = DtSM_VERBOSE_MODE;
}
/*
* If the user has previously used the "query" method, and now wishes
* to use "only what I've customized" method, then we have to start
* from scratch. So don't set anything until customizer tells me to
*/
if((smSettings.didQuery == True) && (smRes.querySettings == False))
{
SM_FREE((char *) restorePtrArray);
SM_FREE(restoreCharArray);
return(0);
}
/*
* Restore pointer control settings
*/
if((smSettings.accelNum > -1 ) || (smSettings.threshold > -1))
{
XChangePointerControl(smGD.display, True, True,
smSettings.accelNum,
smSettings.accelDenom,
smSettings.threshold);
smToSet.pointerChange = True;
}
else
{
smToSet.pointerChange = False;
}
/*
* Restore screen saver settings if any are set to non-default
* values.
*/
if ((smSettings.timeout > -1) || (smSettings.interval > -1) ||
(smSaverRes.saverTimeout > -1) || (smSaverRes.lockTimeout > -1) ||
(smSaverRes.cycleTimeout > -1))
{
/*
* For the time between Screen Savers, use the cycleTimeout
* if the user has set this value. Otherwise, use the interval
* value that was set when the session was saved.
*/
if (smSaverRes.cycleTimeout < 0)
{
screenSaverVals.smInterval = smSettings.interval;
}
else
{
screenSaverVals.smInterval = smSaverRes.cycleTimeout;
}
/*
* For the screen saver time, use the minimum of the values set for
* saverTimeout or lockTimeout if the user has set one of these
* values.
*
* Otherwise, use the Timeout value that was set when the
* session was saved.
*
* If it is not set, then use the minimum of the values set for
* saverTimeout or lockTimeout. Set timeout to the Timeout value
* that was saved.
*/
if ((smSaverRes.saverTimeout > -1) ||
(smSaverRes.lockTimeout > -1))
{
if (smSaverRes.saverTimeout > -1)
{
if ((smSaverRes.lockTimeout > -1) &&
(smSaverRes.lockTimeout < smSaverRes.saverTimeout))
{
screenSaverVals.smTimeout = smSaverRes.lockTimeout;
}
else
{
screenSaverVals.smTimeout = smSaverRes.saverTimeout;
}
}
else
{
screenSaverVals.smTimeout = smSaverRes.lockTimeout;
}
}
else
{
screenSaverVals.smTimeout = smSettings.timeout;
}
screenSaverVals.smPreferBlank = smSettings.preferBlank;
screenSaverVals.smAllowExp = smSettings.allowExp;
/* Notify X of the new screen saver values */
XSetScreenSaver(smGD.display, screenSaverVals.smTimeout,
screenSaverVals.smInterval,
screenSaverVals.smPreferBlank,
screenSaverVals.smAllowExp);
/*
* If using timeout or interval values that were
* previously saved, then set flag to indicate that they
* should be saved again when the state for the session
* is saved.
*/
if ((smSettings.timeout > -1) || (smSettings.interval > -1))
{
smToSet.screenSavChange = True;
}
else
{
smToSet.screenSavChange = False;
}
}
else
{
smToSet.screenSavChange = False;
}
/*
* Get the font path. Then set it.
*/
tmpRestore = restorePtrArray;
numArgs = 0;
*tmpRestore = strtok(smGD.fontDirs, ",");
while(*tmpRestore != NULL)
{
numArgs++; tmpRestore++;
*tmpRestore = strtok(NULL, ",");
if((numArgs >= ptrSize) && (*tmpRestore != NULL))
{
ptrSize += 50;
restorePtrArray = (char **)SM_REALLOC((char *)
restorePtrArray, ptrSize *
sizeof(char *));
if(restorePtrArray == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
SM_FREE(restoreCharArray);
return(-1);
}
}
}
if(numArgs > 0)
{
XSetFontPath(smGD.display, restorePtrArray, numArgs);
}
/*
* Restore the keyboard control information. In order for it
* to be restored it has to be changed from a XKeyboardState
* format to an XKeyboardControl format.
*/
if((smSettings.kbdState.key_click_percent > -1) ||
(smSettings.kbdState.bell_percent > -1) ||
(smSettings.kbdState.bell_pitch > -1) ||
(smSettings.kbdState.bell_duration > -1))
{
kbdControlMask = 0;
if((smSettings.kbdState.bell_percent > -1) ||
(smSettings.kbdState.bell_pitch > -1) ||
(smSettings.kbdState.bell_duration > -1))
{
kbdControl.bell_percent = smSettings.kbdState.bell_percent;
kbdControl.bell_pitch = smSettings.kbdState.bell_pitch;
kbdControl.bell_duration = smSettings.kbdState.bell_duration;
kbdControlMask |= (KBBellPercent | KBBellPitch | KBBellDuration);
smToSet.audioChange = True;
audioVals.smBellPercent = smSettings.kbdState.bell_percent;
audioVals.smBellPitch = smSettings.kbdState.bell_pitch;
audioVals.smBellDuration = smSettings.kbdState.bell_duration;
}
else
{
smToSet.audioChange = False;
}
if((smSettings.kbdState.key_click_percent > -1) ||
(smSettings.kbdState.global_auto_repeat != AutoRepeatModeOn))
{
kbdControl.key_click_percent =
smSettings.kbdState.key_click_percent;
kbdControlMask |= KBKeyClickPercent;
smToSet.keyboardChange = True;
keyboardVals.smKeyClickPercent = kbdControl.key_click_percent;
}
else
{
smToSet.keyboardChange = False;
}
/*
* NOTICE THAT THE LED'S DON'T GET RESET. THIS IS BECAUSE LED STUFF
* IS MACHINE DEPENDENT.
*/
/*
* Set the auto repeat stuff
*/
tmpKey = strtok(smGD.autoRepeats, ",");
if((tmpKey == NULL) &&
((smSettings.kbdState.global_auto_repeat == AutoRepeatModeOff) ||
(smSettings.kbdState.global_auto_repeat == AutoRepeatModeOn)))
{
smToSet.keyboardChange = True;
kbdControl.auto_repeat_mode =
smSettings.kbdState.global_auto_repeat;
kbdControlMask |= KBAutoRepeatMode;
XChangeKeyboardControl(smGD.display, kbdControlMask, &kbdControl);
keyboardVals.smGlobalAutoRepeat =
smSettings.kbdState.global_auto_repeat;
}
else
{
if(tmpKey != NULL)
{
smToSet.keyboardChange = True;
kbdControl.auto_repeat_mode = smSettings.kbdState.global_auto_repeat;
kbdControlMask |= KBAutoRepeatMode;
XChangeKeyboardControl(smGD.display,
kbdControlMask, &kbdControl);
kbdControl.auto_repeat_mode = AutoRepeatModeOn;
kbdControlMask = KBAutoRepeatMode | KBKey;
/*
* This is only involked when there is auto repeats set for
* specific keys only. It is VERY SLOW code so unless you
* have to save off auto repeats for single keys - DON'T
*/
while(tmpKey != NULL)
{
kbdControl.key = atoi(tmpKey);
XChangeKeyboardControl(smGD.display,
kbdControlMask, &kbdControl);
tmpKey = strtok(NULL, ",");
}
}
else
{
if(kbdControlMask != 0)
{
XChangeKeyboardControl(smGD.display,
kbdControlMask, &kbdControl);
}
}
}
}
else
{
smToSet.audioChange = False;
smToSet.keyboardChange = False;
}
/*
* Restore the button mappings
*/
numArgs = 0;
tmpKey = strtok(smGD.buttonMap, ",");
if(tmpKey != NULL)
{
smToSet.pointerMapChange = True;
}
else
{
smToSet.pointerMapChange = False;
}
while(tmpKey != NULL)
{
restoreCharArray[numArgs] = (char) atoi(tmpKey);
numArgs++;
tmpKey = strtok(NULL, ",");
if((numArgs >= charSize) && (tmpKey != NULL))
{
charSize += 500;
restoreCharArray = (char *) SM_REALLOC(restoreCharArray,
charSize * sizeof(char));
if(restoreCharArray == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
SM_FREE((char *)restorePtrArray);
return(-1);
}
}
}
if(numArgs > 0)
{
XSetPointerMapping(smGD.display, (unsigned char *)restoreCharArray, numArgs);
/*
* Copy the pointer map into the saved map for logout
*/
smToSet.numButton = ((numArgs > 5) ? 5 : numArgs);
for(i = 0; i < smToSet.numButton;i++)
{
smToSet.pointerMap[i] = restoreCharArray[i];
}
}
/*
* Restore the key mappings
*/
if(smSettings.numKeyCode > 0)
{
tmpSyms = (KeySym *) restoreCharArray;
symSize = (charSize * sizeof(char)) / sizeof(KeySym);
tmpKey = strtok(smGD.keySyms, ",");
for(i = 0;tmpKey != NULL;i++)
{
tmpSyms[i] = (KeySym) atol(tmpKey);
tmpKey = strtok(NULL, ",");
numArgs = i + 1;
if((numArgs >= symSize) && (tmpKey != NULL))
{
charSize += 1000;
symSize = (charSize * sizeof(char))/sizeof(KeySym);
restoreCharArray = (char *) SM_REALLOC(restoreCharArray,
(charSize * sizeof(char)));
if(restoreCharArray == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
SM_FREE((char *) restorePtrArray);
return(-1);
}
tmpSyms = (KeySym *) restoreCharArray;
}
}
numArgs /= smSettings.keySymPerCode;
XChangeKeyboardMapping(smGD.display, (KeyCode)
smGD.display->min_keycode,
smSettings.keySymPerCode, tmpSyms,
numArgs);
}
/*
* Restore the modifier mappings
*/
tmpCode = (KeyCode *) restoreCharArray;
tmpKey = strtok(smGD.modSyms, ",");
if(tmpKey != NULL)
{
for(i = 0;i < (8 * smSettings.maxKeyPerMod);i++)
{
if(tmpKey != NULL)
{
codeSym = (KeySym) atol(tmpKey);
if(codeSym != 0)
{
tmpCode[i] = XKeysymToKeycode(smGD.display, codeSym);
}
else
{
tmpCode[i] = (KeyCode) 0;
}
}
else
{
tmpCode[i] = (KeyCode) 0;
}
tmpKey = strtok(NULL, ",");
}
restoreMod.max_keypermod = smSettings.maxKeyPerMod;
restoreMod.modifiermap = tmpCode;
XSetModifierMapping(smGD.display, &restoreMod);
}
SM_FREE((char *) restorePtrArray);
SM_FREE(restoreCharArray);
return(0);
}
/*************************************<->*************************************
*
* RestoreIndependentResources ()
*
*
* Description:
* -----------
* In charge of restoring the resources that help make the session more
* resolution and language independent - only restored if they are
* necessary (lang || resolution has changed) and exist
*
*
* Inputs:
* ------
* smResources = global pointer to the resources to be restored by the SM
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
void
RestoreIndependentResources( void )
{
Atom actualType;
int actualFormat;
unsigned long nitems, leftover;
unsigned char *data = NULL;
XrmDatabase smBase;
XrmValue fontResourceReturn;
char *currentLangPtr, *resValRet, *sessionType;
float fltYRes;
int intYRes[2], status,i;
char *sessionRes;
struct stat buf;
Boolean resIndep = False, resRet;
char *resdata;
if(((smGD.sessionLang == NULL) || (*smGD.sessionLang == 0)) &&
(smRes.displayResolution == 0))
{
/*
* No saved info to draw from - nothing new is added
*/
return;
}
currentLangPtr = getenv("LANG");
fltYRes = ((float) DisplayHeight(smGD.display, 0) /
(float) DisplayHeightMM(smGD.display, 0)) * 1000;
if(fltYRes < MED_RES_Y_RES)
{
intYRes[0] = LOW_RES_Y_RES;
sessionRes = SM_LOW_RES_EXT;
}
else
{
if(fltYRes >= HIGH_RES_Y_RES)
{
intYRes[0] = HIGH_RES_Y_RES;
sessionRes = SM_HIGH_RES_EXT;
}
else
{
intYRes[0] = MED_RES_Y_RES;
sessionRes = SM_MED_RES_EXT;
}
}
if(smRes.displayResolution < MED_RES_Y_RES)
{
intYRes[1] = LOW_RES_Y_RES;
}
else
{
if(smRes.displayResolution >= HIGH_RES_Y_RES)
{
intYRes[1] = HIGH_RES_Y_RES;
}
else
{
intYRes[1] = MED_RES_Y_RES;
}
}
/*
* If the resolution or the language has changed -
* load the language/resolution independent fonts if
* they exist in the users home directory or in the system
*/
if((strcmp(currentLangPtr, smGD.sessionLang)) ||
(intYRes[0] != intYRes[1]))
{
char *fontPath = SM_MALLOC(MAXPATHLEN + 1);
if(smGD.sessionType == HOME_SESSION)
{
sessionType = SM_HOME_FONT_DIRECTORY;
}
else
{
sessionType = SM_CURRENT_FONT_DIRECTORY;
}
memset(fontPath, 0, MAXPATHLEN + 1);
snprintf(fontPath, MAXPATHLEN, "%s/%s/%s/%s.%s",
smGD.savePath, sessionType,
currentLangPtr, SM_FONT_FILE, sessionRes);
status = stat(fontPath, &buf);
if(status == -1)
{
/*
* User has nothing there - look in the system defaults
* first in the language dep -then in lang independent
*/
memset(fontPath, 0, MAXPATHLEN + 1);
if((currentLangPtr != NULL) && (*currentLangPtr != 0))
{
strcat(fontPath, "/");
strncat(fontPath, currentLangPtr, MAXPATHLEN);
}
strncat(fontPath, "/", MAXPATHLEN);
strncat(fontPath, SM_SYSTEM_FONT_FILE, MAXPATHLEN);
FixPath(fontPath);
status = stat(fontPath, &buf);
if(status == -1)
{
if((currentLangPtr != NULL) && (*currentLangPtr != 0) &&
(strcmp(currentLangPtr, "C")))
{
memset(fontPath, 0, MAXPATHLEN + 1);
strcpy(fontPath, "/C/");
strncat(fontPath, SM_SYSTEM_FONT_FILE, MAXPATHLEN);
FixPath(fontPath);
status = stat(fontPath, &buf);
if(status != -1)
{
resIndep = True;
}
}
}
else
{
resIndep = True;
}
}
else
{
resIndep = True;
}
strncpy(smGD.fontPath, fontPath, MAXPATHLEN);
if(resIndep == True)
{
/*
* add the auxillary resources onto the root window
*/
RestoreResources(True, "-merge", "-file", smGD.fontPath, NULL);
/*
* Load the resources from the RESOURCE_MANAGER
* property on the root window
*/
if(XGetWindowProperty(smGD.display, RootWindow(smGD.display, 0),
XA_RESOURCE_MANAGER,0L,
100000000L,False,XA_STRING,&actualType,
&actualFormat,&nitems,&leftover,
(unsigned char**) &data) == Success)
{
smBase = XrmGetStringDatabase((char *)data);
}
else
{
smBase = NULL;
}
if(smBase == NULL)
{
PrintError(DtError, GETMESSAGE(16, 6, "Invalid display/language independent resource file. No display/language independent resources will be restored."));
SM_FREE((char *)data);
return;
}
else
{
/*
* Get the new fontlist from the resources and
* Put it on the application shell. Then add
* the auxillary resources into the display struct
*/
resRet = XrmGetResource(smBase, "*fontList", "*FontList",
&resValRet, &fontResourceReturn);
i = 0;
XtSetArg(uiArgs[i], XmNdefaultFontList,
(XmFontList) fontResourceReturn.addr);i++;
XtSetValues(smGD.topLevelWid, uiArgs, i);
/*
* Overwrite the old font preferences, otherwise,
* they'll come back to haunt us if the user logs in again
* under the current language. We need to get the font
* resources which have just been loaded, then overlay
* them onto the _DT_SM_PREFERENCES root property to make
* sure we get them back when we login again.
*/
for (i = 0; i < XtNumber(fonttype); i++)
{
resRet = XrmGetResource(smBase, fonttype[i], fontclass[i],
&resValRet, &fontResourceReturn);
if (resRet)
{
resdata =
(char *)SM_MALLOC(fontResourceReturn.size + 30);
bzero(resdata, fontResourceReturn.size + 30);
strcat(resdata, fonttype[i]);
strcat(resdata, ": ");
strcat(resdata, fontResourceReturn.addr);
strcat(resdata, "\n");
_DtAddResString(smGD.display, resdata, _DT_ATR_PREFS);
SM_FREE(resdata);
}
}
XrmMergeDatabases(smBase, &(smGD.display->db));
SM_FREE((char *)data);
}
}
SM_FREE((char*) fontPath);
}
return;
}
/*************************************<->*************************************
*
* RestoreClients ()
*
*
* Description:
* -----------
* Reads through the client file and restores its contents. A client file
* consists of hints for the workspace manager, actual client commands, and
* remote execution commands. All commands are processed accordingly.
* If this is the first DT 3.0 session for a DT 2.0 user then we will
* also launch the helpviewer. If this is the first DT 3.0 session for a
* DT 2.0 user then we will also run convertVS.sh to change all
* occurrences of /usr/bin/X11/hpterm to .../dt/bin/hpterm,
* /usr/bin/X11/xterm to .../dt/bin/xterm and
* /usr/bin/X11/xload to .../dt/bin/xload.
*
*
* Inputs:
* ------
*
* Outputs:
* -------
*
* Comments:
* --------
* Any information read from the client file will be mucked with during
* processing, and should not try to be mucked with again.
*
* WARNING: This routine closes cfileP - not the calling routine
* DOUBLE-WARNING: This routine starts the window manager
*
*************************************<->***********************************/
static int
RestoreClients( void )
{
unsigned char *lineP, *string;
char *pch, *dispPtr = NULL;
char *dispEnv, *dispSav, *dispEnvHelpview, *dispSavHelpview;
unsigned char *hostPtr=NULL, *cmdPtr=NULL, *hintPtr = NULL;
unsigned char *remoteDisplay;
char *displayName;
char *envVal;
unsigned char tmpChar[35];
int screenNum = 0, i, j, chlen, numClientsExec;
int numRemoteDone = 0;
Window dtwmWin = 0;
Boolean clientsDone = False, wmHandshake = False, cmdInvInit = False;
XClientMessageEvent smToWmMessage;
/*
* These variables are needed to buffer up the commands and then
* execute them (also buffer up hints then put them on the root window
*/
unsigned char *hintsBuf[MAX_SCREENS_SAVED];
unsigned char *cmdBuf[MAX_SCREENS_SAVED];
unsigned int maxHintsSize[MAX_SCREENS_SAVED];
unsigned int actHintsSize[MAX_SCREENS_SAVED];
unsigned int numHints[MAX_SCREENS_SAVED];
unsigned int maxCmdSize[MAX_SCREENS_SAVED];
unsigned int actCmdSize[MAX_SCREENS_SAVED];
unsigned int numCmd[MAX_SCREENS_SAVED];
unsigned int maxRemoteSize[MAX_SCREENS_SAVED];
/*
* Initialize the buffers and their sizes to null and 0. Because of
* all possible combinations - buffers aren't malloc'd until they're
* needed
*/
for(i = 0;i<smGD.numSavedScreens;i++)
{
hintsBuf[i] = NULL;
cmdBuf[i] = NULL;
remoteBuf[i] = NULL;
maxHintsSize[i] = 0;
actHintsSize[i] = 0;
numHints[i] = 0;
maxCmdSize[i] = 0;
actCmdSize[i] = 0;
numCmd[i] = 0;
maxRemoteSize[i] = 0;
actRemoteSize[i] = 0;
}
/*
* Save the contents of the DISPLAY environment variable so that it
* can be restored when we're through
*/
dispEnv = getenv(DISPLAY_NAME);
if(dispEnv != NULL)
{
dispSav = (char *) SM_MALLOC(((strlen(dispEnv) +
strlen(DISPLAY_NAME_EQUAL)) * sizeof(char) + 1));
sprintf(dispSav, "%s%s", DISPLAY_NAME_EQUAL, dispEnv);
}
else
{
dispSav = NULL;
}
linec = 0;
displayName = strdup(smGD.display->display_name);
remoteDisplay = (unsigned char *)
SM_MALLOC(sizeof(unsigned char) * (strlen(displayName) + 101));
/*
* Create the display name for locally executing clients
*/
pch = displayName;
while (*pch)
{
if (*pch == ':')
{
dispPtr = pch;
pch++;
break;
}
pch++;
}
while (*pch)
{
if (*pch == '.')
{
pch++;
*pch = '\0';
break;
}
pch++;
}
/*
* Create the display name for remotely executing clients.
* These two may or may not be the same
*/
DtGetShortHostname((char *)remoteDisplay, 100);
/*
* Add the display qualifications to the host name
* screen is added at execution time
*/
strcat((char *)remoteDisplay, (char *)dispPtr);
/*
* Intern the atom needed to put the hints on the root window
* This has to be done here because InitProtocol has not been called yet
*/
XaWmDtHints = XInternAtom(smGD.display, _XA_DT_SESSION_HINTS, False);
while(GetNextLine() != NULL)
{
lineP = line;
string = GetSmartString(&lineP);
if( string != NULL && !strcmp((char *)string, "dtsmcmd"))
{
while((string = GetSmartString(&lineP)) != NULL )
{
if(!strcmp((char *)string, "-host"))
{
/*
* Extract a host pointer - host pointers
* only exist on remote executions
*/
string = GetSmartString(&lineP);
hostPtr = string;
}
else
{
if(!strcmp((char *)string, "-cmd"))
{
/*
* Extract the command pointer from the
* hints string
*/
string = GetSmartString(&lineP);
cmdPtr = string;
}
else
{
if(!strcmp((char *)string, "-screen"))
{
/*
* Extract the screen number from the command
*/
string = GetSmartString(&lineP);
screenNum = atoi((char *)string);
}
else
{
if(!strcmp((char *)string, "-hints"))
{
/*
* Extract the hints string
*/
string = GetSmartString(&lineP);
hintPtr = string;
}
}
}
}
}
/*
* Now put our information in buffers and reinitialize the pointers
*/
if(hintPtr != NULL)
{
if(FillHintBuf(hintPtr, hintsBuf, maxHintsSize,
actHintsSize, screenNum, numHints) != 0)
{
/*
* Free all malloc'd buffers and exit
*/
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(actHintsSize[i] > 0)
{
SM_FREE((char *) hintsBuf[i]);
}
if(actCmdSize[i] > 0)
{
SM_FREE((char *) cmdBuf[i]);
}
if(actRemoteSize[i] > 0)
{
SM_FREE((char *) remoteBuf[i]);
}
}
free(displayName);
return(-1);
}
hintPtr = NULL;
}
if((cmdPtr != NULL) && (hostPtr == NULL))
{
if(FillCmdBuf(cmdPtr, cmdBuf, maxCmdSize,
actCmdSize,screenNum, &numCmd[screenNum]) != 0)
{
/*
* Free all malloc'd buffers and exit
*/
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(actHintsSize[i] > 0)
{
SM_FREE((char *) hintsBuf[i]);
}
if(actCmdSize[i] > 0)
{
SM_FREE((char *) cmdBuf[i]);
}
if(actRemoteSize[i] > 0)
{
SM_FREE((char *) remoteBuf[i]);
}
}
return(-1);
}
cmdPtr = NULL;
}
else
{
if((cmdPtr != NULL) && (hostPtr != NULL))
{
if(FillRemoteBuf(cmdPtr, hostPtr, remoteDisplay,
remoteBuf, maxRemoteSize,
actRemoteSize, screenNum) != 0)
{
/*
* Free all malloc'd buffers and exit
*/
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(actHintsSize[i] > 0)
{
SM_FREE((char *) hintsBuf[i]);
}
if(actCmdSize[i] > 0)
{
SM_FREE((char *) cmdBuf[i]);
}
if(actRemoteSize[i] > 0)
{
SM_FREE((char *) remoteBuf[i]);
}
}
free(displayName);
return(-1);
}
cmdPtr = NULL;
hostPtr = NULL;
}
}
screenNum = XDefaultScreen(smGD.display);
}
}
/*
* All done with file so close it off and set descriptor to NULL -
* This is done so that parsing routines can be used with a buffer later
*/
fclose(cfileP);
cfileP = NULL;
/*
* Now execute all the buffers, put all hints on the root windows
* Do all remote executions
*/
for(i = 0;i < smGD.numSavedScreens;i++)
{
/*
* Put the root window property on each root window
*/
if(actHintsSize[i] > 0)
{
/*
* Append number of hints to front of buffer
*/
sprintf((char *)tmpChar, "%d", numHints[i]);
strncpy((char *)hintsBuf[i], (char *)tmpChar,
strlen((char *)tmpChar));
XChangeProperty(smGD.display, RootWindow(smGD.display, i),
XaWmDtHints, XA_STRING, 8, PropModeReplace,
hintsBuf[i], actHintsSize[i]);
SM_FREE((char *) hintsBuf[i]);
XSync(smGD.display, 0);
}
}
StartWM();
/*
* Now exec on the local clients - we're doing contention management
* to make sure the system doesn't get swamped
*/
i = 0;
while((actCmdSize[i] == 0) && (i < smGD.numSavedScreens))
{
i++;
}
envVal = SM_MALLOC(BUFSIZ);
if(i >= smGD.numSavedScreens)
{
clientsDone = True;
}
else
{
sprintf(envVal,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, i);
putenv(envVal);
linec = 0;
parseP = cmdBuf[i];
}
/*
* Keep forking one client after the other until the
* memory utilization gets beyond the threshold -
* (but only if the capability exists) Then go to
* window manager handshaking
*/
#ifdef DEBUG_CONT_MANAGEMENT
if(smRes.contManagement & SM_CM_SYSTEM)
{
fprintf(stderr, "SM_CM_SYSTEM flag set in smRes.contManagement\n");
}
if(smRes.contManagement & SM_CM_HANDSHAKE)
{
fprintf(stderr, "SM_CM_HANDSHAKE flag set in smRes.contManagement\n");
}
#endif /* DEBUG_CONT */
numClientsExec = 0;
if((smRes.contManagement & SM_CM_SYSTEM) &&
((GetMemoryUtilization() != MEM_NOT_AVAILABLE) &&
(clientsDone == False)))
{
while((GetMemoryUtilization() == MEM_NOT_FULL) &&
(clientsDone == False))
{
GetNextLine();
lineP = line;
CreateExecString((char *) lineP);
if(smExecArray[0] != NULL)
{
(void) StartClient(smExecArray[0], (char **)smExecArray, NULL,
NULL, NULL, False, False, -1);
}
numClientsExec++;
/*
* When all the clients have been exec'd for this screen
* go on to the next
*/
if(numClientsExec >= numCmd[i])
{
ResetScreenInfo(cmdBuf, &i, actCmdSize, &clientsDone,
envVal, displayName);
numClientsExec = 0;
}
}
}
/*
* After we've checked memory utilization - finish up
* by handshaking with the worksapce manager - if it's there
*/
if(clientsDone == False)
{
if((smGD.dtwmRunning) && (smRes.contManagement & SM_CM_HANDSHAKE))
{
/*
* Get the window id of the workspace manager and tell it
* to start messaging
*/
_DtGetMwmWindow(smGD.display, RootWindow(smGD.display, 0),
&dtwmWin);
smToWmMessage.type = ClientMessage;
smToWmMessage.window = dtwmWin;
smToWmMessage.message_type = XaSmWmProtocol;
smToWmMessage.format = 32;
smToWmMessage.data.l[0] = XaSmStartAckWindow;
smToWmMessage.data.l[1] = CurrentTime;
if (XSendEvent(smGD.display, dtwmWin,False,NoEventMask,
(XEvent *) &smToWmMessage) != 0)
{
wmHandshake = True;
XSync(smGD.display, 0);
}
}
/*
* Start a client - and wait for the workspace manager to
* map a window to start a new client
*/
while(clientsDone == False)
{
GetNextLine();
lineP = line;
CreateExecString((char *) lineP);
if(smExecArray[0] != NULL)
{
(void) StartClient(smExecArray[0], smExecArray,
NULL, NULL, NULL, False, False, -1);
}
/*
* If we're handshaking with the workspace manager
* wait for the client to be mapped before starting
* the next one
*/
if(wmHandshake == True)
{
WaitForClientMap();
}
numClientsExec++;
/*
* When all the clients have been exec'd for this screen
* go on to the next
*/
if(numClientsExec >= numCmd[i])
{
ResetScreenInfo(cmdBuf, &i, actCmdSize, &clientsDone,
envVal, displayName);
numClientsExec = 0;
}
}
if(wmHandshake == True)
{
/*
* If we are handshaking - tell the workspace manager to
* stop
*/
smToWmMessage.type = ClientMessage;
smToWmMessage.window = dtwmWin;
smToWmMessage.message_type = XaSmWmProtocol;
smToWmMessage.format = 32;
smToWmMessage.data.l[0] = XaSmStopAckWindow;
smToWmMessage.data.l[0] = CurrentTime;
XSendEvent(smGD.display, dtwmWin,False,NoEventMask,
(XEvent *) &smToWmMessage);
}
}
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(numRemoteDone == MAX_REMOTE_CLIENTS)
{
break;
}
/*
* Send out all the remote execution commands for the screen to
* the command invoker. On failure - do a remsh instead
*/
if(actRemoteSize[i] > 0)
{
/*
* Initialize the command invoker - if not done
*/
if(cmdInvInit == False)
{
_DtInitializeCommandInvoker(smGD.display,
DtSM_TOOL_CLASS,
SM_RESOURCE_CLASS,
NULL, smGD.appCon);
cmdInvInit = True;
}
/*
* Set up the display environment variable so that the
* application comes back to the right screen
*/
sprintf(envVal,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, i);
putenv(envVal);
linec = 0;
parseP = remoteBuf[i];
while(numRemoteExecs > 0 && GetNextLine() != NULL)
{
/*
* Get the host and the command and send them off
* On failure of the command invoker do a remsh
*/
lineP = line;
string = GetSmartString(&lineP);
hostPtr = string;
string = GetSmartString(&lineP);
cmdPtr = string;
remoteBufPtr[numRemoteDone].cmdPtr = cmdPtr;
remoteBufPtr[numRemoteDone].hostPtr = hostPtr;
_DtCommandInvokerExecute(DtSTART_SESSION, NULL, NULL, NULL,
"-", (char *) hostPtr, (char *) cmdPtr,
RemoteRequestSucceeded, NULL,
RemoteRequestFailed,
&remoteBufPtr[numRemoteDone]);
numRemoteDone++;
/*
* If there is no more room in the remote client
* array - quit exec'ing remote clients
*/
if(numRemoteDone == MAX_REMOTE_CLIENTS)
{
PrintError(DtError, GETMESSAGE(16, 5, "You have reached the maximum allowed number of remote clients. No further remote clients will be restored."));
break;
}
}
}
}
/*
* Now return the display variable back to the display that was
* originally opened (the default display)
*/
if(dispSav != NULL)
{
putenv(dispSav);
}
else
{
FixEnvironmentData();
}
free(displayName);
return(0);
} /* END OF FUNCTION RestoreClients */
/*************************************<->*************************************
*
* StartEtc ( exiting )
*
*
* Description:
* -----------
* Call the StartClient routine to fork and exec either the sessionetc file
* (if exiting==False) or the sessionexit file (if exiting==True).
*
*
* Inputs:
* ------
*
* Outputs:
* -------
*
* Comments:
* --------
*
*************************************<->***********************************/
void
StartEtc( Boolean exiting )
{
int status;
struct stat buf;
char *execArray[3];
if (exiting) {
execArray[0] = smGD.exitPath;
execArray[1] = smExitFile;
} else {
execArray[0] = smGD.etcPath;
execArray[1] = smEtcFile;
}
execArray[2] = '\0';
if ((status=stat(execArray[0], &buf)) != -1)
{
StartClient(execArray[0], execArray, NULL, NULL, NULL, False, False, -1);
}
}
/*************************************<->*************************************
*
* GetNextLine ()
*
*
* Description:
* -----------
* Returns the next line from an fopened configuration file or a newline-
* embedded configuration string.
*
*
* Inputs:
* ------
* cfileP = (global) file pointer to fopened configuration file or NULL
* line = (global) line buffer
* linec = (global) line count
* parseP = (global) parse string pointer if cfileP == NULL
*
*
* Outputs:
* -------
* line = (global) next line
* linec = (global) line count incremented
* parseP = (global) parse string pointer incremented
* Return = line or NULL if file or string is exhausted.
*
*
* Comments:
* --------
* If there are more than MAXLINE characters on a line in the file cfileP the
* excess are truncated.
* Assumes the line buffer is long enough for any parse string line.
* Code stolen from dtmwm
*
*************************************<->***********************************/
static unsigned char *
GetNextLine( void )
{
unsigned char *string;
#ifdef MULTIBYTE
int chlen;
#endif
if (cfileP != NULL)
/* read fopened file */
{
string = (unsigned char *) fgets((char *)line, fileSize, cfileP);
}
else if ((parseP != NULL) && (*parseP != 0))
/* read parse string */
{
string = line;
#ifdef MULTIBYTE
while ((*parseP != 0) &&
((chlen = mblen ((char *) parseP, MB_CUR_MAX)) > 0) &&
(*parseP != '\n'))
/* copy all but NULL and newlines to line buffer */
{
while (chlen--)
{
*(string++) = *(parseP++);
}
}
#else
while ((*parseP != NULL) && (*parseP != '\n'))
/* copy all but NULL and newlines to line buffer */
{
*(string++) = *(parseP++);
}
#endif
*string = 0;
if (*parseP == '\n')
{
parseP++;
}
}
else
{
string = NULL;
}
linec++;
return (string);
} /* END OF FUNCTION GetNextLine */
/*************************************<->*************************************
*
* PeekAhead (currentChar, currentLev)
*
*
* Description:
* -----------
* Returns a new level value if this is a new nesting level of quoted string
* Otherwise it returns a zero
*
*
* Inputs:
* ------
* currentChar = current position in the string
* currentLev = current level of nesting
*
*
* Outputs:
* -------
* Returns either a new level of nesting or zero if the character is copied in
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static unsigned int
PeekAhead(
unsigned char *currentChar,
unsigned int currentLev )
{
Boolean done = False;
unsigned int tmpLev = 1;
#ifdef MULTIBYTE
unsigned int chlen;
while (((chlen = mblen ((char *) currentChar, MB_CUR_MAX)) > 0) &&
(chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
&& (done == False))
{
currentChar++;
if(((chlen = mblen ((char *) currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) &&
((*currentChar == '"') || (*currentChar == '\\')))
{
tmpLev++;
if(*currentChar == '"')
{
done = True;
}
else
{
currentChar++;
}
}
}
#else
while((*currentChar != NULL) && (done == False) &&
((*currentChar == '"') || (*currentChar == '\\')))
{
currentChar++;
if((*currentChar != NULL) &&
((*currentChar == '"') || (*currentChar == '\\')))
{
tmpLev++;
if(*currentChar == '"')
{
done = True;
}
else
{
currentChar++;
}
}
}
#endif /*MULTIBYTE*/
/*
* Figure out if this is truly a new level of nesting - else ignore it
* This section probably could do some error checking and return -1
* If so, change type of routine from unsigned int to int
*/
if(done == True)
{
return(tmpLev);
}
else
{
return(0);
}
}
/*************************************<->*************************************
*
* GetSmartString (linePP)
*
*
* Description:
* -----------
* Returns the next quoted or whitespace-terminated nonquoted string in the
* line buffer.
* Additional functionality added to GetString in that anything in a
* quoted string is considered sacred and nothing will be stripped from
* the middle of a quoted string.
*
*
* Inputs:
* ------
* linePP = pointer to current line buffer pointer.
*
*
* Outputs:
* -------
* linePP = pointer to revised line buffer pointer.
* Return = string
*
*
* Comments:
* --------
* May alter the line buffer contents.
* Handles quoted strings and characters, removing trailing whitespace from
* quoted strings.
* Returns NULL string if the line is empty or is a comment.
* Code stolen from dtmwm.
*
*************************************<->***********************************/
static unsigned char *
GetSmartString(
unsigned char **linePP )
{
unsigned char *lineP = *linePP;
unsigned char *endP;
unsigned char *curP;
unsigned char *lnwsP;
unsigned int level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH];
#ifdef MULTIBYTE
int chlen;
/* get rid of leading white space */
ScanWhitespace (&lineP);
/*
* Return NULL if line is empty, whitespace, or begins with a comment.
*/
if((chlen = mblen ((char *) lineP, MB_CUR_MAX)) < 1)
{
*linePP = lineP;
return (NULL);
}
if ((chlen == 1) && (*lineP == '"'))
/* Quoted string */
{
quoteLevel[level] = 1;
/*
* Start beyond double quote and find the end of the quoted string.
* '\' quotes the next character - but is not stripped out.
* Otherwise, matching double quote or NULL terminates the string.
*
* We use lnwsP to point to the last non-whitespace character in the
* quoted string. When we have found the end of the quoted string,
* increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
* This removes any trailing whitespace without overwriting the
* matching quote, needed later. If the quoted string was all
* whitespace, then this will write a NULL at the beginning of the
* string that will be returned -- OK.
*/
lnwsP = lineP++; /* lnwsP points to first '"' */
curP = endP = lineP; /* other pointers point beyond */
while ((*endP = *curP) &&
((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0) &&
((chlen > 1) || (*curP != '"')))
/* Haven't found matching quote yet.
* First byte of next character has been copied to endP.
*/
{
curP++;
if ((chlen == 1) && (*endP == '\\') &&
((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0))
{
/*
* Check to see if this is a quoted quote - if it is
* strip off a level - if not - it's sacred leave it alone
*/
checkLev = PeekAhead((curP - 1), quoteLevel[level]);
if(checkLev > 0)
{
if(quoteLevel[level] >= checkLev)
{
if (level > 0) level--;
}
else if (level < MAX_QUOTE_DEPTH)
{
level++;
quoteLevel[level] = checkLev;
}
for(i = 0;i < (checkLev - 2);i++)
{
*endP++ = *curP++;curP++;
}
*endP = *curP++;
}
}
if (chlen == 1)
/* Singlebyte character: character copy finished. */
{
if (isspace (*endP))
/* whitespace character: leave lnwsP unchanged. */
{
endP++;
}
else
/* non-whitespace character: point lnwsP to it. */
{
lnwsP = endP++;
}
}
else if (chlen > 1)
/* Multibyte (nonwhitespace) character: point lnwsP to it.
* Finish character byte copy.
*/
{
lnwsP = endP++;
while (--chlen)
{
*endP++ = *curP++;
lnwsP++;
}
}
}
#else
/* get rid of leading white space */
ScanWhitespace (&lineP);
/* Return NULL if line is empty, or whitespace */
if(*lineP == NULL)
{
*linePP = lineP;
return (NULL);
}
if (*lineP == '"')
/* Quoted string */
{
quoteLevel[level] = 1;
/*
* Start beyond double quote and find the end of the quoted string.
* '\' quotes the next character.
* Otherwise, matching double quote or NULL terminates the string.
*
* We use lnwsP to point to the last non-whitespace character in the
* quoted string. When we have found the end of the quoted string,
* increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
* This removes any trailing whitespace without overwriting the
* matching quote, needed later. If the quoted string was all
* whitespace, then this will write a NULL at the beginning of the
* string that will be returned -- OK.
*/
lnwsP = lineP++; /* lnwsP points to first '"' */
curP = endP = lineP; /* other pointers point beyond */
while ((*endP = *curP) && (*endP != '"'))
/* haven't found matching quote yet */
{
/* point curP to next character */
curP++;
if ((*endP == '\\') && (*curP != NULL))
/* shift quoted nonNULL character down and curP ahead */
{
/*
* Check to see if this is a quoted quote - if it is
* strip off a level - if not - it's sacred leave it alone
*/
checkLev = PeekAhead((curP - 1), quoteLevel[level]);
if(checkLev > 0)
{
if(quoteLevel[level] >= checkLev)
{
if (level > 0) level--;
}
else if (level < MAX_QUOTE_DEPTH)
{
level++;
quoteLevel[level] = checkLev;
}
for(i = 0;i < (checkLev - 2);i++)
{
*endP++ = *curP++;curP++;
}
*endP = *curP++;
}
}
if (isspace (*endP))
/* whitespace character: leave lnwsP unchanged. */
{
endP++;
}
else
/* non-whitespace character: point lnwsP to it. */
{
lnwsP = endP++;
}
}
#endif
/*
* Found matching quote or NULL.
* NULL out any trailing whitespace.
*/
lnwsP++;
if (lnwsP < endP)
{
*lnwsP = 0;
}
}
else
/* Unquoted string */
{
/*
* Find the end of the nonquoted string.
* '\' quotes the next character.
* Otherwise, whitespace, NULL, terminates the string.
*/
curP = endP = lineP;
#ifdef MULTIBYTE
while ((*endP = *curP) &&
((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0) &&
((chlen > 1) || (!isspace (*curP))))
/* Haven't found whitespace yet.
* First byte of next character has been copied to endP.
*/
{
curP++;
if ((chlen == 1) && (*endP == '\\') &&
((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0))
/* character quote:
* copy first byte of quoted nonNULL character down.
* point curP to next byte
*/
{
*endP = *curP++;
}
endP++;
if (chlen > 1)
/* Multibyte character: finish character copy. */
{
while (--chlen)
{
*endP++ = *curP++;
}
}
}
#else
while ((*endP = *curP) && !isspace (*endP))
{
/* point curP to next character */
curP++;
if ((*endP == '\\') && (*curP != NULL))
/* shift quoted nonNULL character down and curP ahead */
{
*endP = *curP++;
}
endP++;
}
#endif
}
/*
* Two cases for *endP:
* whitespace or
* matching quote -> write NULL over char and point beyond
* NULL -> point to NULL
*/
if (*endP != 0)
{
*endP = 0; /* write NULL over terminator */
*linePP = ++curP; /* point beyond terminator */
}
else
{
*linePP = endP;
}
return ((unsigned char *)lineP);
} /* END OF FUNCTION GetString */
/*************************************<->*************************************
*
* ScanWhitespace(linePP)
*
*
* Description:
* -----------
* Scan the string, skipping over all white space characters.
*
*
* Inputs:
* ------
* linePP = nonNULL pointer to current line buffer pointer
*
*
* Outputs:
* -------
* linePP = nonNULL pointer to revised line buffer pointer
*
*
* Comments:
* --------
* Assumes linePP is nonNULL
* Code Stolen from dtmwm
*
*************************************<->***********************************/
void
ScanWhitespace(
unsigned char **linePP )
{
#ifdef MULTIBYTE
while (*linePP && (mblen ((char *) *linePP, MB_CUR_MAX) == 1) && isspace (**linePP))
#else
while (*linePP && isspace (**linePP))
#endif
{
(*linePP)++;
}
} /* END OF FUNCTION ScanWhitespace */
/*************************************<->*************************************
*
* FillHintBuf(newHint, hintBuf, maxSize, actSize, screen, numHints)
*
*
* Description:
* -----------
* Put the new hint into the hint buffer. Each hint is separated by a
* newline.
*
*
* Inputs:
* ------
* newHint = hint to add to the buffer
* hintBuf = an array of buffers - one for each screen
* maxSize = array of buffers of the current malloced size of each hintBuf
* actSize = array of space currently used by each hintBuf
* screen = screen number for this hint
* numHints = array of the number of hints for each screen
* smGD.numSavedScreens = (global) checked to make sure this hint should be
* added.
*
* Outputs:
* -------
* hintBuf[screen] = updated hint buf for this screen (newHint added)
* maxSize[screen] = enlarged if not big enough or malloced if not done before
* actSize[screen] = updated size of the hints buffer
* numHints[screen] = updated by 1 if this hint is added
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static int
FillHintBuf(
unsigned char *newHint,
unsigned char **hintBuf,
unsigned int *maxSize,
unsigned int *actSize,
unsigned int screen,
unsigned int *numHints)
{
static int hintBufSize = 5000;
/*
* If the screen that this hint was meant for is not in the current
* set of available screens, don't save it
*/
if(screen >= smGD.numSavedScreens)
{
return(0);
}
/*
* Check to see if this buffer has been malloc'd before - if it hasn't
* malloc it. If it has - check to make sure it's big enough to hold the
* new information.
*/
if(maxSize[screen] == 0)
{
hintBuf[screen] = (unsigned char *) SM_MALLOC(hintBufSize * sizeof(char));
if(hintBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = hintBufSize * sizeof(char);
/*
* Now reserve 4 bytes for the length
*/
strcpy((char *)hintBuf[screen], " \n");
}
else
{
if((actSize[screen] + strlen((char *)newHint) + 2) >= maxSize[screen])
{
hintBuf[screen] = (unsigned char *)
SM_REALLOC((char *) hintBuf[screen],
maxSize[screen] +
(hintBufSize *
sizeof(char)));
if(hintBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = maxSize[screen] + (hintBufSize * sizeof(char));
}
}
/*
* add the new hint AFTER the last newline
*/
strcat((char *)hintBuf[screen], (char *)newHint);
strcat((char *)hintBuf[screen], "\n");
actSize[screen] = strlen((char *)hintBuf[screen]);
numHints[screen] += 1;
return(0);
}
/*************************************<->*************************************
*
* FillCmdBuf(newCmd, cmdBuf, maxSize, actSize, screen)
*
*
* Description:
* -----------
* Put a new command into the command buffer. The command buffer is just
* one big long string of stuff to be executed.
*
*
* Inputs:
* ------
* newCmd = command to add to the buffer
* cmdBuf = an array of buffers - one for each screen
* maxSize = array of buffers of the current malloced size of each cmdBuf
* actSize = array of space currently used by each cmdBuf
* screen = screen number for this command
* smGD.numSavedScreens = (global) checked to make sure this hint should be
* added.
*
* Outputs:
* -------
* cmdBuf[screen] = updated command buf for this screen (newCmd added)
* maxSize[screen] = enlarged if not big enough or malloced if not done before
* actSize[screen] = updated size of the command buffer
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static int
FillCmdBuf(
unsigned char *newCmd,
unsigned char **cmdBuf,
unsigned int *maxSize,
unsigned int *actSize,
unsigned int screen,
unsigned int *numCmd )
{
static int cmdBufSize = 5000;
/*
* If the screen that this command was meant for is not in the current
* set of available screens, don't save it
*/
if(screen >= smGD.numSavedScreens)
{
return(0);
}
/*
* Check to see if this buffer has been malloc'd before - if it hasn't
* malloc it. If it has - check to make sure it's big enough to hold the
* new information.
*/
if(maxSize[screen] == 0)
{
cmdBuf[screen] = (unsigned char *) SM_MALLOC(cmdBufSize * sizeof(char));
if(cmdBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = cmdBufSize * sizeof(char);
}
else
{
if((actSize[screen] + strlen((char *)newCmd)) >= maxSize[screen])
{
cmdBuf[screen] = (unsigned char *) SM_REALLOC((char *)cmdBuf[screen],
maxSize[screen] +
(cmdBufSize *
sizeof(char)));
if(cmdBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = maxSize[screen] + (cmdBufSize * sizeof(char));
}
}
if(actSize[screen] == 0)
{
strcpy((char *)cmdBuf[screen], (char *)newCmd);
}
else
{
strcat((char *)cmdBuf[screen], (char *)newCmd);
}
*numCmd = *numCmd + 1;
strcat((char *)cmdBuf[screen], "\n");
actSize[screen] = strlen((char *)cmdBuf[screen]);
return(0);
}
/*************************************<->*************************************
*
* FillRemoteBuf(newCmd, hostName, displayName, remoteBuf,
* maxSize, actSize, screen)
*
*
* Description:
* -----------
* Put a new command into the remote execution buffer. The command buffer is
* just one big long string of stuff to be executed.
*
*
* Inputs:
* ------
* newCmd = command to add to the buffer
* hostName = host where command is to be executed from
* displayName = display where host is to be executed to
* remoteBuf = an array of buffers - one for each screen
* maxSize = array of buffers of the current malloced size of each cmdBuf
* actSize = array of space currently used by each cmdBuf
* screen = screen number for this command
* smGD.numSavedScreens = (global) checked to make sure this hint should be
* added.
*
* Outputs:
* -------
* cmdBuf[screen] = updated command buf for this screen (newCmd added)
* in remote format (host name and display name)
* maxSize[screen] = enlarged if not big enough or malloced if not done before
* actSize[screen] = updated size of the command buffer
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static int
FillRemoteBuf(
unsigned char *newCmd,
unsigned char *hostName,
unsigned char *displayName,
unsigned char *remoteBuf[] ,
unsigned int *maxSize ,
unsigned int *actSize ,
unsigned int screen )
{
unsigned char *string;
static int remoteBufSize = 5000;
/*
* If the screen that this command was meant for is not in the current
* set of available screens, don't save it
*/
if(screen >= smGD.numSavedScreens)
{
return(0);
}
/*
* Check to see if this buffer has been malloc'd before - if it hasn't
* malloc it. If it has - check to make sure it's big enough to hold the
* new information.
*/
if(maxSize[screen] == 0)
{
remoteBuf[screen] = (unsigned char *)
SM_MALLOC(remoteBufSize * sizeof(char));
if(remoteBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = remoteBufSize * sizeof(char);
}
else
{
if((actSize[screen] + strlen((char *)newCmd) +
strlen((char *)hostName) +
strlen((char *)displayName) +
strlen("-display ") + 5) >= maxSize[screen])
{
remoteBuf[screen] = (unsigned char *)
SM_REALLOC((char *)remoteBuf[screen],
maxSize[screen] +
(remoteBufSize * sizeof(char)));
if(remoteBuf[screen] == NULL)
{
actSize[screen] = 0;
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return(-1);
}
maxSize[screen] = maxSize[screen] + (remoteBufSize * sizeof(char));
}
}
if(actSize[screen] == 0)
{
/*
* If the buffer is empty fill it with the initial contents
*/
strcpy((char *)remoteBuf[screen], (char *)hostName);
strcat((char *)remoteBuf[screen], " ");
}
else
{
/*
* if this buffer is not emtpy
* add the new command BEFORE the last null terminator
* Commands for remote executions are separated by newlines
*/
strcat((char *)remoteBuf[screen], "\n");
strcat((char *)remoteBuf[screen], (char *)hostName);
}
/*
* Copy the command in - quote it
*/
strcat((char *)remoteBuf[screen], " \"");
string = GetSmartString(&newCmd);
strcat((char *)remoteBuf[screen], (char *)string);
strcat((char *)remoteBuf[screen], " ");
/*
* Once display name has been put in place - concatenate the
* rest of the command
*/
while((string = GetSmartString(&newCmd)) != NULL )
{
strcat((char *)remoteBuf[screen], " ");
strcat((char *)remoteBuf[screen], (char *)string);
}
/*
* Now close off the command with a quote
*/
strcat((char *)remoteBuf[screen], "\"");
actSize[screen] = strlen((char *)remoteBuf[screen]);
/*
* Bump the remote command counter
*/
numRemoteExecs++;
return(0);
}
/*************************************<->*************************************
*
* CreateExecString(execString)
*
*
* Description:
* -----------
* Create a string that can be fed to a fork and exec by breaking it up
* into argc and argv
*
*
* Inputs:
* ------
* execString = whole command
*
* Outputs:
* -------
* smExecArray = global modified to contain pointers to argc and argv
*
*
* Comments:
* --------
*
*************************************<->***********************************/
void
CreateExecString(
char *execString)
{
#define ARG_AMT 100
static int iSizeArgv = ARG_AMT;
char *string;
int argc = 0;
if (smExecArray == NULL)
{
smExecArray = (char **) XtMalloc (ARG_AMT * sizeof(char *));
}
string = (char *) GetSmartString((unsigned char **) &execString);
while(string != NULL)
{
smExecArray[argc] = string;
argc++;
if (argc >= iSizeArgv)
{
iSizeArgv += ARG_AMT;
smExecArray = (char **)
XtRealloc ((char *)smExecArray, (iSizeArgv * sizeof(char *)));
}
string = (char *) GetSmartString((unsigned char **) &execString);
}
/*
* If the last string is a background character
* get rid of it
*/
if(argc > 0)
{
if(!strcmp((char *)smExecArray[argc - 1], "&"))
{
smExecArray[argc - 1] = '\0';
}
}
smExecArray[argc] = '\0';
} /* END OF FUNCTION CreateExecString */
/*
* SetTemporaryDisplay - does a putenv of the current value of the
* DISPLAY environment variable but with the given screen number.
*
* GLOBALS MODIFIED:
* savedDisplay
*/
static void
SetTemporaryDisplay (
int screenNum)
{
static char * tmpDisplay = NULL;
static int lastScreen = -1;
char * pch;
if (screenNum == -1)
return;
if (!savedDisplay) {
char * dispEnv;
if ((dispEnv = getenv (DISPLAY_NAME)) == NULL)
return;
savedDisplay = XtMalloc (strlen (DISPLAY_NAME_EQUAL) +
strlen (dispEnv) + 2);
if (!savedDisplay)
return;
sprintf (savedDisplay, "%s%s", DISPLAY_NAME_EQUAL, dispEnv);
}
if (lastScreen == screenNum && tmpDisplay != NULL) {
putenv (tmpDisplay);
return;
}
lastScreen = screenNum;
if (!tmpDisplay) {
if (!savedDisplay)
return;
tmpDisplay = XtMalloc (strlen (savedDisplay) + 4);
if (!tmpDisplay)
return;
strcpy (tmpDisplay, savedDisplay);
}
if (pch = strrchr (tmpDisplay, ':')) {
char *pch2, *pch3;
if (pch2 = strchr (pch, '.'))
*pch2 = '\000';
pch3 = XtMalloc (strlen (tmpDisplay) + 4);
if (!pch3)
return;
sprintf (pch3, "%s.%d", tmpDisplay, screenNum);
strcpy (tmpDisplay, pch3);
XtFree ((char *) pch3);
putenv (tmpDisplay);
}
}
/*
* RestoreDisplay - does a putenv of the global variable savedDisplay
*/
static void
RestoreDisplay (
int screenNum)
{
if (screenNum != -1 && savedDisplay)
putenv (savedDisplay);
}
/*************************************<->*************************************
*
* StartClient - calls StartLocalClient or StartRemoteClient depending
* on the value of hostName.
*
* Description:
* -----------
* Starts a local or remote application
*
* Inputs:
* ------
* program = execArray[0]
* execArray = command to fork and exec
* hostName = the name of the host where program should be executed
* cwd = directory to chdir to before doing the exec
* envp = the envrironment variables to add to the child processes env
* checkCwd = if True and cwd is NULL, a message will be logged; if
* False, cwd will not be checked and the cwd will be set to $HOME
* useIgnoreEnvironmentResource = if True, the variables listed in the
* IgnoreEnvironment resource will be removed from 'environ' before
* execArray is exec'd
* screen = if set to -1, it will be ignored; otherwise, the screen
* number will be used to define DISPLAY for the duration of this
* function - DISPLAY will be reset before the function returns.
*
* Outputs:
* -------
* Returns True if the command is successfully executed; False otherwise.
*
* Comments:
* --------
* localHost - is modified
*
*************************************<->***********************************/
Boolean
StartClient(
char * program,
char * execArray[],
char * hostName,
char * cwd,
char ** envp,
Boolean checkCwd,
Boolean useIgnoreEnvironmentResource,
int screen)
{
static char * defaultCwd = NULL;
Boolean cwdNull = False;
Boolean startStatus;
SetTemporaryDisplay (screen);
if (!ignoreEnvPtr && useIgnoreEnvironmentResource) {
if (smRes.ignoreEnvironment)
ignoreEnvPtr = _DtVectorizeInPlace (
smRes.ignoreEnvironment, ',');
}
if (!defaultCwd)
{
char *tstr = getenv("HOME");
if (tstr)
{
int slen = strlen(tstr) + 1;
defaultCwd = XtCalloc(1, slen);
snprintf(defaultCwd, slen, "%s", tstr);
}
else
defaultCwd = getcwd (NULL, MAXPATHLEN + 1);
(void) gethostname (localHost, MAXHOSTNAMELEN);
}
if (!cwd) {
cwdNull = True;
cwd = defaultCwd;
}
if (!hostName || (_DtIsSameHost (localHost, hostName)))
startStatus = StartLocalClient (program, execArray,
cwd, envp, checkCwd,
useIgnoreEnvironmentResource);
else
startStatus = StartRemoteClient (program, execArray, hostName,
cwd, envp,
useIgnoreEnvironmentResource);
RestoreDisplay (screen);
return (startStatus);
}
/*************************************<->*************************************
*
* StartLocalClient
*
* Description:
* -----------
* Starts a local application.
*
* -------
* Returns True if the command is successfully executed; False otherwise.
*
*************************************<->***********************************/
static Boolean
StartLocalClient (
char *program,
char *execArray[],
char *cwd,
char **envp,
Boolean doChdir,
Boolean useIgnoreEnvironmentResource)
{
pid_t clientFork;
int execStatus, i;
char clientMessage[MAXPATHLEN + 30];
char **tmpEnv, **ppchar;
/*
* Fork and exec the client process
*/
clientFork = vfork();
/*
* If the fork fails - Send out an error and return
*/
if(clientFork < 0)
{
PrintErrnoError(DtError, smNLS.cantForkClientString);
return (False);
}
/*
* Fork succeeded - now do the exec
*/
if(clientFork == 0)
{
SetSIGPIPEToDefault ();
/*
* Log a warning if the given cwd is not valid
*/
if (doChdir && cwd)
{
if ((chdir (cwd)) == -1)
{
char *tmpCwd;
tmpCwd = getcwd (NULL, MAXPATHLEN + 1);
LogCWDMessage (cwd, program, tmpCwd);
}
}
/*
* Add envp to the client's environ if the variable
* is not in the ignoreEnvironment list
*/
if (useIgnoreEnvironmentResource && envp) {
if (ignoreEnvPtr)
tmpEnv = RemoveEnvironmentVars (envp);
else
tmpEnv = envp;
for (ppchar = tmpEnv; ppchar && *ppchar; ppchar++)
putenv (strdup (*ppchar));
}
/*
* Set the gid of the process back from bin
*/
#ifndef SVR4
setregid(smGD.runningGID, smGD.runningGID);
#else
setgid(smGD.runningGID);
setegid(smGD.runningGID);
#endif
_DtEnvControl(DT_ENV_RESTORE_PRE_DT);
#if defined(CSRG_BASED)
setsid();
#else
(void)setpgrp();
#endif /* CSRG_BASED */
MarkFileDescriptors (3, F_SETFD, 1);
execStatus = execvp(program, execArray);
if(execStatus != 0)
{
sprintf(clientMessage, ((char *)GETMESSAGE(16, 3, "Unable to exec %s.")), execArray[0]);
PrintErrnoError(DtError, clientMessage);
SM_EXIT(-1);
}
}
return (True);
}
/*************************************<->*************************************
*
* StartRemoteClient
*
* Description:
* -----------
* Starts a remote application.
*
* -------
* Returns True if the command is successfully executed; False otherwise.
*
*************************************<->***********************************/
static Boolean
StartRemoteClient (
char * program,
char * execArray[],
char * hostName,
char * cwd,
char ** envp,
Boolean useIgnoreEnvironmentResource)
{
int ioMode;
SPC_Channel_Ptr channel;
char * netfile;
char errorMessage[1024];
char * message;
static Boolean cmdInvokerInitialized = False;
char ** tmpEnv = envp;
ioMode = SPCIO_NOIO | SPCIO_FORCE_CONTEXT;
if (!cmdInvokerInitialized) {
_DtInitializeCommandInvoker(smGD.display,
DtSM_TOOL_CLASS,
SM_RESOURCE_CLASS,
NULL, smGD.appCon);
cmdInvokerInitialized = True;
}
(void) strcpy (errorMessage, "");
channel = (SPC_Channel_Ptr) _DtSPCOpen (hostName, ioMode, errorMessage);
if (channel == SPC_ERROR) {
message = strdup ((char *) GETMESSAGE (40, 13,
"The following application cannot be started on host '%s'\nbecause this host cannot be reached from host '%s':\n\n %s"));
if (message) {
DtMsgLogMessage (smGD.programName, DtMsgLogError,
message, hostName, localHost, program);
free (message);
}
return (False);
}
netfile = tt_host_file_netfile (hostName, cwd);
if (tt_pointer_error (netfile) != TT_OK) {
message = strdup ((char *) GETMESSAGE (40, 14,
"An attempt to start application '%s'\non host '%s' failed because the following directory\ncould not be translated into cannonical form:\n\n %s\n\n[%s]"));
if (message) {
DtMsgLogMessage (smGD.programName, DtMsgLogError,
message, program, hostName, cwd,
tt_status_message (tt_pointer_error (
netfile)));
free (message);
}
return (False);
}
/*
* Add envp to the client's environ if the variable
* is not in the ignoreEnvironment list
*/
if (useIgnoreEnvironmentResource && ignoreEnvPtr && envp)
tmpEnv = RemoveEnvironmentVars (envp);
if ((_DtSPCSpawn (program, netfile, execArray, tmpEnv, channel,
hostName, NULL, cwd, errorMessage)) == SPC_ERROR) {
DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMessage);
if (tmpEnv)
XtFree ((char *) tmpEnv);
return (False);
}
tt_free (netfile);
if (tmpEnv)
XtFree ((char *) tmpEnv);
return (True);
}
/*************************************<->*************************************
*
* ForkWM()
*
*
* Description:
* -----------
* Fork and exec the default window manager
*
*
* Inputs:
* ------
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
ForkWM( void )
{
pid_t clientFork;
int execStatus, i;
strcpy(tmpExecWmFile,CDE_INSTALLATION_TOP "/bin/dtwm");
/*
* Fork and exec the client process
*/
clientFork = vfork();
/*
* If the fork fails - Send out an error and return
*/
if(clientFork < 0)
{
PrintErrnoError(DtError, smNLS.cantForkClientString);
return;
}
/*
* Fork succeeded - now do the exec
*/
if(clientFork == 0)
{
SetSIGPIPEToDefault ();
/*
* Set the gid of the process back from bin
*/
#ifndef SVR4
setregid(smGD.runningGID, smGD.runningGID);
#else
setgid(smGD.runningGID);
setegid(smGD.runningGID);
#endif
_DtEnvControl(DT_ENV_RESTORE_PRE_DT);
#if defined(CSRG_BASED)
setsid();
#else
(void)setpgrp();
#endif /* CSRG_BASED */
MarkFileDescriptors (3, F_SETFD, 1);
/*
* These lines were added to support the builtin
* panacomm dtwm.
* This used to be
* execStatus = execlp(".../dt/bin/dtwm", "dtwm", (char *) 0);
*/
execStatus = execlp(tmpExecWmFile, "dtwm", (char *) 0);
/*
* ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^
* End of lines were added to support the builtin
* panacomm dtwm.
*/
if(execStatus != 0 && (!localWmLaunched))
{
PrintErrnoError(DtError, GETMESSAGE(16, 4, "Unable to exec process /usr/dt/bin/dtwm. No window manager will be started."));
SM_EXIT(-1);
}
}
}
/*************************************<->*************************************
*
* KillParent()
*
*
* Description:
* -----------
* Fork a copy of ourselves and kill the parent off so that scripts starting
* up the session manager can continue.
*
* Inputs:
* ------
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
void
KillParent( void )
{
pid_t clientFork;
/*
* Fork and exec the client process
*/
clientFork = fork();
/*
* If the fork fails - We have to exit so that the rest of the
* script can continue
*/
if(clientFork < 0)
{
PrintErrnoError(DtError, smNLS.cantForkClientString);
SM_EXIT(-1);
}
/*
* Fork succeeded - now kill the parent
*/
if(clientFork != 0)
{
SM_EXIT(0);
}
/*
* Disassociate from parent
*/
#if defined(CSRG_BASED)
setsid();
#else
setpgrp();
#endif /* CSRG_BASED */
}
/*************************************<->*************************************
*
* WaitForWM ()
*
*
* Description:
* -----------
* This routine waits for the window manager to start. It uses a
* resource (waitWmTimeout) with a dynamic default to determine how many
* seconds to wait for WM start and then starts clients.
*
*
* Inputs:
* ------
* appContext = application context for the window
* window = window id for the
*
*
* Outputs:
* -------
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
WaitForWM( void )
{
XEvent event;
XtIntervalId wmTimerId;
XtAddEventHandler(smGD.topLevelWid,
0,
True,
(XtEventHandler)HandleWMClientMessage,
(XtPointer) NULL);
/*
* Set a timer which stops the block on waiting for the
* window manager to start
*/
wmTimeout = False;
wmTimerId = XtAppAddTimeOut(smGD.appCon,
smRes.waitWmTimeout,
WaitWMTimeout, NULL);
while((smGD.dtwmRunning == False) && (wmTimeout == False))
{
XtAppProcessEvent(smGD.appCon, XtIMAll);
}
XtRemoveTimeOut(wmTimerId);
XtRemoveEventHandler(smGD.topLevelWid,
0,
True,
(XtEventHandler)HandleWMClientMessage,
(XtPointer) NULL);
return;
} /* END OF FUNCTION WaitForWM */
/*************************************<->*************************************
*
* WaitWMTimeout
*
*
* Description:
* -----------
* Timeout procedure the WaitForCommand routine. It stops a loop waiting
* for the window manager to get started.
*
*
* Inputs:
* ------
*
*
* Outputs:
* -------
* wmTimeout = (global) flag that stops the loop
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
WaitWMTimeout(
XtPointer client_data,
XtIntervalId *id )
{
wmTimeout = True;
return;
} /* END OF FUNCTION WaitWMTimeout */
/*************************************<->*************************************
*
* HandleWMClientMessage
*
*
* Description:
* -----------
* This is the event handler registered to receive the client message
* from dtwm when dtwm is ready for business
*
*
*************************************<->***********************************/
static void
HandleWMClientMessage( Widget smWidget,
XtPointer dummy,
XEvent *event)
{
if (event->type == ClientMessage)
{
ProcessClientMessage(event);
}
return;
} /* END OF FUNCTION HandleWMClientMessage */
/*************************************<->*************************************
*
* FixEnvironmentData
*
*
* Description:
* -----------
* If DISPLAY variable exists in the environment - remove it
*
*
* Inputs:
* ------
*
*
* Outputs:
* -------
* wmTimeout = (global) flag that stops the loop
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
FixEnvironmentData( void )
{
char **ppchar;
int i;
extern char **environ; /* MODIFIED - DISPLAY is remove if found. */
for (i=0, ppchar = environ; *ppchar; ppchar++, i++)
{
if ((strncmp (*ppchar, DISPLAY_NAME_EQUAL, strlen(DISPLAY_NAME_EQUAL))) == 0)
{
/*
* Change the DISPLAY environment variable.
*/
for (; *ppchar; ppchar++, i++)
{
environ[i]=environ[i+1];
}
break;
}
}
}
/*************************************<->*************************************
*
* ResetScreenInfo()
*
*
* Description:
* -----------
* After one screen is finished - set up the info for the next
*
*
* Inputs:
* ------
* cmdBuf - Buffer that holds all the invocation information
* screen - Pointer to the screen number that we're currently working on
* env - used to set up the environment for changing the display var
* displayName - name of the current display
*
* Outputs:
* -------
* cmdBuf - old buffers are freed
* screen - updated to point to the new screen info
* done - tells whether the clients are done being exec'd
* linec - *GLOBAL* sets line being read from
* parseP - *GLOBAL*
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
ResetScreenInfo(unsigned char **cmdBuf,
int *screen,
unsigned int *cmdSize,
Boolean *done,
char *env,
char *displayName)
{
SM_FREE((char *) cmdBuf[*screen]);
(*screen)++;
while((cmdSize[*screen] == 0) && (*screen < smGD.numSavedScreens))
{
(*screen)++;
}
if(*screen >= smGD.numSavedScreens)
{
*done = True;
}
else
{
sprintf((char *)env,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, *screen);
putenv(env);
linec = 0;
parseP = cmdBuf[*screen];
}
}
/*************************************<->*************************************
*
* RemoteRequestFailed ()
*
*
* Description:
* -----------
* If a request to the command invoker fails, this callback will be called.
* It will then try to execute the command by performing a remsh on it.
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
RemoteRequestFailed(char *message,
void *client_data)
{
static char *cmdBuf = NULL;
static char *tmpCmdBuf = NULL;
char *errorString = NULL;
String tmpString;
static int cmdBufSize = 0;
int i;
int tmpSize;
RemoteReq *tmpReq = (RemoteReq *) client_data;
/*
* If the memory for the buffer has not been malloced - do so
*/
if(cmdBuf == NULL)
{
cmdBuf = SM_MALLOC((200 * sizeof(char)) + 1 );
if(cmdBuf == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
return;
}
cmdBufSize = 200 + 1;
tmpCmdBuf = SM_MALLOC((200 * sizeof(char)) + 1 );
if(tmpCmdBuf == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
}
}
/*
* Copy in the host and command field and execute the command
*/
tmpSize = (strlen(REMOTE_CMD_STRING) +
strlen((char *) tmpReq->hostPtr) +
strlen((char *) tmpReq->cmdPtr) + 1);
if(tmpSize >= cmdBufSize)
{
cmdBuf = SM_REALLOC(cmdBuf, (tmpSize) * sizeof(char));
if(cmdBuf == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
cmdBufSize = 0;
return;
}
cmdBufSize = tmpSize;
if(tmpCmdBuf != NULL)
{
tmpCmdBuf = SM_REALLOC(tmpCmdBuf, (tmpSize) * sizeof(char));
if(tmpCmdBuf == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
}
}
}
sprintf(cmdBuf, REMOTE_CMD_STRING, tmpReq->hostPtr, tmpReq->cmdPtr);
/*
* save cmdBuf for error message, cmdBuf is changed
* by CreateExecString
*/
if (tmpCmdBuf != NULL)
{
strcpy(tmpCmdBuf,cmdBuf);
}
CreateExecString(cmdBuf);
if(smExecArray[0] != NULL)
{
(void) StartClient(smExecArray[0], smExecArray, NULL, NULL,
NULL, False, False, -1);
if (tmpCmdBuf != NULL)
{
tmpString = GETMESSAGE(16, 8,
"An attempt to restore the following\ncommand (using the DT remote execution process)\non host \"%s\" failed:\n\n %s\n\nThe following execution string will be tried:\n\n %s\n\n");
errorString =
(char *)SM_MALLOC((strlen(tmpString) +
strlen((char *)tmpReq->hostPtr) +
strlen((char *)tmpReq->cmdPtr) +
strlen(tmpCmdBuf) + 1 ) *
sizeof(char));
if(errorString == NULL)
{
PrintErrnoError(DtError, smNLS.cantMallocErrorString);
}
else
{
sprintf(errorString, tmpString, tmpReq->hostPtr,
tmpReq->cmdPtr, tmpCmdBuf );
PrintError(DtError, errorString);
SM_FREE(errorString);
}
}
}
/*
* Now check to make sure that this isn't the last remote request.
* If so, free the data
*/
numRemoteExecs--;
if(numRemoteExecs == 0)
{
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(actRemoteSize[i] > 0)
{
SM_FREE((char *) remoteBuf[i]);
}
}
}
return;
}
/*************************************<->*************************************
*
* RemoteRequestSucceeded ()
*
*
* Description:
* -----------
* If a request to the command invoker succeeds, this callback will be called.
* It decrements the remote execution counter, and frees the info if
* remote executions are finished
*
* Inputs:
* ------
*
*
* Outputs:
* -------
*
*
* Comments:
* --------
*
*************************************<->***********************************/
static void
RemoteRequestSucceeded(char *message,
void *client_data)
{
int i;
numRemoteExecs--;
if(numRemoteExecs == 0)
{
for(i = 0;i < smGD.numSavedScreens;i++)
{
if(actRemoteSize[i] > 0)
{
SM_FREE((char *) remoteBuf[i]);
}
}
}
}
/**************************************************************************
*
* XSMP code follows
*
**************************************************************************/
Boolean
StartXSMPSession (
char * databaseName)
{
ClientDB inputDB;
XSMPClientDBRecPtr pXSMPRec;
ProxyClientDBRecPtr pProxyRec;
int i;
StartWM ();
if ((inputDB = OpenInputClientDB (databaseName,
&smXSMP.dbVersion,
&smXSMP.dbSessionId)) == NULL) {
LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogError, 1);
return (False);
}
if (!smXSMP.dbVersion) {
LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogWarning, 2);
smXSMP.dbVersion = SM_VENDOR_NAME;
}
if (!smXSMP.dbSessionId) {
LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogWarning, 3);
smXSMP.dbSessionId = SM_RELEASE_NAME;
}
/*
* First start the XSMP clients
*/
for (;;) {
if ((pXSMPRec = GetXSMPClientDBRec (inputDB)) == NULL)
break;
if (!CheckRequiredProperties (pXSMPRec, databaseName)) {
FreeXSMPClientDBRec (pXSMPRec);
continue;
}
if (StartXSMPClient (pXSMPRec, databaseName)) {
XSMPClientDBRecPtr tmpRecPtr;
pXSMPRec->next = NULL;
if (!smXSMP.xsmpDbList) {
smXSMP.xsmpDbList = pXSMPRec;
continue;
}
/*
* Find the end of the list
*/
for (tmpRecPtr = smXSMP.xsmpDbList;
tmpRecPtr && tmpRecPtr->next != NULL;
tmpRecPtr = tmpRecPtr->next);
tmpRecPtr->next = pXSMPRec;
}
else
FreeXSMPClientDBRec (pXSMPRec);
}
/*
* Now start the Proxy clients
*/
for (i = 0; ; i++) {
if ((pProxyRec = GetProxyClientDBRec (inputDB)) == NULL)
break;
if (!CheckRequiredFields (pProxyRec, databaseName, i)) {
FreeProxyClientDBRec (pProxyRec);
continue;
}
(void) StartProxyClient (pProxyRec);
FreeProxyClientDBRec (pProxyRec);
}
(void) CloseClientDB (inputDB, False);
return (True);
}
Boolean
StartXSMPClient (
XSMPClientDBRecPtr pDbRec,
char * databaseName)
{
return (StartClient (pDbRec->restartCommand[0],
pDbRec->restartCommand,
pDbRec->clientHost,
pDbRec->cwd,
pDbRec->environment,
True,
True,
pDbRec->screenNum));
}
Boolean
StartProxyClient (
ProxyClientDBRecPtr pDbRec)
{
return (StartClient (pDbRec->command[0],
pDbRec->command,
pDbRec->clientHost,
NULL,
NULL,
False,
False,
pDbRec->screenNum));
}
Boolean
ExecuteCommandProperty (
char * commandName,
ClientRecPtr pClientRec)
{
char ** argv;
char ** envp = NULL;
char * cwd;
PropertyRecPtr pPropRec;
int i;
Boolean retValue;
if ((pPropRec = GetPropertyRec (pClientRec, commandName)) == NULL)
return (False);
argv = (char **) XtMalloc ((pPropRec->prop.num_vals + 1) *
sizeof (char *));
if (!argv)
return (False);
for (i = 0; i < pPropRec->prop.num_vals; i++)
argv[i] = pPropRec->prop.vals[i].value;
argv[pPropRec->prop.num_vals] = NULL;
cwd = GetArrayPropertyValue (pClientRec, SmCurrentDirectory);
if ((pPropRec = GetPropertyRec (pClientRec, SmEnvironment)) != NULL) {
envp = (char **) XtMalloc ((pPropRec->prop.num_vals + 1) *
sizeof (char *));
if (!envp)
return (False);
for (i = 0; i < pPropRec->prop.num_vals; i++)
envp[i] = pPropRec->prop.vals[i].value;
envp[pPropRec->prop.num_vals] = NULL;
}
retValue = StartClient (argv[0], argv,
pClientRec->clientHost,
cwd, envp,
True, True,
pClientRec->screenNum);
XtFree ((char *) argv);
if (envp)
XtFree ((char *) envp);
return (retValue);
}
/*************************************<->*************************************
*
* ExecuteDiscardCommands -
*
* Description: Executes all of the DiscardCommand properties in the
* given client database
*
* Inputs: None
*
*************************************<->***********************************/
void
ExecuteDiscardCommands (
char * db)
{
ClientDB inputDB;
XSMPClientDBRecPtr pXSMPRec;
char * version = NULL;
char * id = NULL;
char * str;
if ((inputDB = OpenInputClientDB (db, &version, &id )) == NULL) {
str = strdup ((char *) GETMESSAGE (40, 26,
"The following client database cannot be opened:\n\n %s\n\nThe 'DiscardCommand' properties cannot be run."));
if (!str)
return;
DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str, db);
free (str);
return;
}
if (version)
XtFree ((char *) version);
if (id)
XtFree ((char *) id);
for (;;) {
if ((pXSMPRec = GetXSMPClientDBRec (inputDB)) == NULL)
break;
if (!pXSMPRec->discardCommand)
continue;
if (!StartClient (pXSMPRec->discardCommand[0],
pXSMPRec->discardCommand,
pXSMPRec->clientHost,
pXSMPRec->cwd,
pXSMPRec->environment,
True,
True,
pXSMPRec->screenNum)) {
str = strdup ((char *) GETMESSAGE (40, 27,
"An attempt to execute the 'DiscardCommand' property for\napplication '%s' failed."));
if (!str)
return;
DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str,
pXSMPRec->program);
free (str);
}
FreeXSMPClientDBRec (pXSMPRec);
}
(void) CloseClientDB (inputDB, False);
}
static Boolean
CheckRequiredProperties (
XSMPClientDBRecPtr pDbRec,
char * databaseName)
{
Boolean propsOK = True;
if (!pDbRec->program) {
LogMissingPropertyMessage (pDbRec, SmProgram,
databaseName, DtMsgLogError);
propsOK = False;
}
if (!pDbRec->restartCommand) {
LogMissingPropertyMessage (pDbRec, SmRestartCommand,
databaseName, DtMsgLogError);
propsOK = False;
}
return (propsOK);
}
static Boolean
CheckRequiredFields (
ProxyClientDBRecPtr pDbRec,
char * databaseName,
int clientNum)
{
char * message;
if (!pDbRec->command) {
message = strdup ((char *) GETMESSAGE (40, 11,
"The required resource '%s' is missing for client '%d'\nin the file '%s'."));
if (!message)
return (False);
DtMsgLogMessage (smGD.programName, DtMsgLogError, message,
SmProgram, clientNum, databaseName);
free (message);
return (False);
}
return (True);
}
static void
LogXSMPOpenDatabaseFailure (
char * databaseName,
DtMsgLogType msgType,
int errorNum)
{
char * message = NULL;
char * data;
int msgNum;
switch (errorNum) {
case 1: data = databaseName;
msgNum = 8;
message = strdup ((char *) GETMESSAGE (40, msgNum,
"The following session database could not be opened:\n\n '%s'"));
break;
case 2: data = versionStr;
msgNum = 9;
message = strdup ((char *) GETMESSAGE (40, msgNum,
"The following session database does not contain\nthe required resource '%s':\n\n %s"));
break;
case 3: data = dtsessionIDStr;
msgNum = 9;
message = strdup ((char *) GETMESSAGE (40, msgNum,
"The following session database does not contain\nthe required resource '%s':\n\n %s"));
break;
}
if (!message)
return;
if (errorNum == 1)
DtMsgLogMessage (smGD.programName, msgType, message, data);
else
DtMsgLogMessage (smGD.programName, msgType, message,
data, databaseName);
free (message);
}
static void
LogMissingPropertyMessage (
XSMPClientDBRecPtr pDbRec,
char * propName,
char * databaseName,
DtMsgLogType msgType)
{
char * message;
message = strdup ((char *) GETMESSAGE (40, 10,
"The required property '%s' is missing for client\n\n %s\n\nin the file '%s'."));
if (!message)
return;
DtMsgLogMessage (smGD.programName, msgType, message,
propName, pDbRec->clientId, databaseName);
free (message);
}
static void
LogCWDMessage (
char * badDir,
char * appName,
char * goodDir)
{
char * message;
message = strdup ((char *) GETMESSAGE (40, 12,
"The directory '%s'\nis not available for application '%s'.\n\nThe following directory will be used:\n\n %s"));
if (!message)
return;
DtMsgLogMessage (smGD.programName, DtMsgLogWarning, message,
badDir, appName, goodDir);
free (message);
}
static
char ** RemoveEnvironmentVars (
char **envp)
{
char ** retEnv = NULL;
char **ppchar, **ppchar2;
int count;
Boolean found;
if (!envp)
return (NULL);
for (count = 0, ppchar = envp; ppchar && *ppchar; count++, ppchar++) ;
retEnv = (char **) XtMalloc ((count + 1) * sizeof (char *));
if (!retEnv)
return (NULL);
if (!ignoreEnvPtr) {
for (count = 0, ppchar = envp; ppchar && *ppchar;
count++, ppchar++) {
retEnv[count] = *ppchar;
}
retEnv[count] = NULL;
return (retEnv);
}
for (count = 0, ppchar = envp; ppchar && *ppchar; ppchar++) {
found = False;
for (ppchar2 = ignoreEnvPtr; ppchar2 && *ppchar2; ppchar2++) {
if ((!strncmp (*ppchar, *ppchar2, strlen (*ppchar2))) &&
(((*ppchar)[strlen(*ppchar2)]) == '=')) {
found = True;
break;
}
}
if (!found) {
retEnv[count] = *ppchar;
count++;
}
}
retEnv[count] = NULL;
return (retEnv);
}
/*
* MarkFileDescriptors - mark file descriptiors start_fd through open_max
* with the given "cmd" and "data".
*
* The code for calculating open_max was taken from DtSvc/DtUtil1/CmdMain.c
*/
static void
MarkFileDescriptors (
int start_fd,
int cmd,
int data)
{
int i;
long open_max;
open_max = sysconf(_SC_OPEN_MAX);
if (open_max == -1) {
#ifdef _SUN_OS
open_max = NOFILE;
#else
#if defined(_AIX)
open_max = FOPEN_MAX;
#else
open_max = FD_SETSIZE;
#endif
#endif /* _SUN_OS */
}
for (i = start_fd; i < open_max; i++)
(void) fcntl (i, cmd, data);
}