777 lines
19 KiB
C
777 lines
19 KiB
C
/*
|
|
* 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
|
|
*/
|
|
/* *
|
|
* (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. *
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#ifdef TERMINAL_SERVER
|
|
#include "TermHeader.h"
|
|
#include "TermPrimDebug.h"
|
|
#include "TermView.h"
|
|
#include "DtTermServer.h"
|
|
#include "TermPrimSetPty.h"
|
|
#ifdef LOG_USAGE
|
|
#include "DtTermLogit.h"
|
|
#endif /* LOG_USAGE */
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <Dt/Service.h>
|
|
|
|
/* defines for types of service requests. Upper case for the requestor
|
|
* types, lower case for the server types...
|
|
*/
|
|
#define SVC_SUCCESS 'S'
|
|
#define SVC_FAIL 'F'
|
|
#define SVC_NOTIFY 'N'
|
|
|
|
#define SVC_REQUEST 'r'
|
|
#define SVC_LOSE 'l'
|
|
|
|
#define DTTERM_SVC_CLASS "DTTERM"
|
|
#define DTTERM_SVC_START_MSG "DTTERM-START"
|
|
#define DTTERM_SVC_TERMINATE_MSG "DTTERM-TERMINATE"
|
|
#define DTTERM_SVC_TERMINATION_MSG "DTTERM-TERMINATION"
|
|
|
|
static XtIntervalId pingId = (XtIntervalId) 0;
|
|
int PingInterval = 5;
|
|
|
|
#ifdef TIMEOUT
|
|
#define STICKAROUND 15 /* 15 minutes... */
|
|
static XtIntervalId waitId = (XtIntervalId) 0;
|
|
#endif /* TIMEOUT */
|
|
|
|
static Boolean ExitOnLastClose;
|
|
|
|
static char *serviceName = (char *) 0;
|
|
static DtSvcHandle serviceHandle;
|
|
static Boolean iAmTheServer = False;
|
|
static Boolean waitingForReply = False;
|
|
static Boolean waitedForReply = False;
|
|
static Widget refWidget;
|
|
char *ServerFailureMessage = (char *) 0;
|
|
int ServerFailureErrno = 0;
|
|
int InstanceCount = 0;
|
|
|
|
typedef struct _ServiceClientInfoRec {
|
|
pid_t pid;
|
|
Widget shellWidget;
|
|
struct _ServiceClientInfoRec *prev;
|
|
struct _ServiceClientInfoRec *next;
|
|
} ServiceClientInfoRec, *ServiceClientInfo;
|
|
|
|
static ServiceClientInfoRec serviceClientInfoHeadRec;
|
|
static ServiceClientInfo serviceClientInfoHead = &serviceClientInfoHeadRec;
|
|
static Boolean initFlag = False;
|
|
|
|
static void Initialize(
|
|
Widget topLevel,
|
|
int argc,
|
|
char **argv,
|
|
char *serverId
|
|
);
|
|
|
|
static void clientMessageProc(
|
|
DtSvcHandle service,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
);
|
|
|
|
static void serverRequestProc(
|
|
DtSvcHandle service,
|
|
DtSvcMsgContext replyContext,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
);
|
|
|
|
static void serverMessageProc(
|
|
DtSvcHandle service,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
);
|
|
|
|
static void Ping(
|
|
XtPointer clientData,
|
|
XtIntervalId *id
|
|
);
|
|
|
|
#ifdef TIMEOUT
|
|
static void TimeOut(
|
|
XtPointer clientData,
|
|
XtIntervalId *id
|
|
);
|
|
#endif /* TIMEOUT */
|
|
|
|
static void CleanUp(
|
|
int sig
|
|
);
|
|
|
|
|
|
static const int trapSignalList[] = {
|
|
SIGINT,
|
|
SIGQUIT,
|
|
SIGTERM,
|
|
SIGUSR1,
|
|
SIGUSR2,
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
Initialize(
|
|
Widget topLevel,
|
|
int argc,
|
|
char **argv,
|
|
char *serverId
|
|
)
|
|
{
|
|
char hostname[BUFSIZ];
|
|
int i;
|
|
pid_t pid;
|
|
struct sigaction sa;
|
|
|
|
if (initFlag) {
|
|
/* already initialized... */
|
|
return;
|
|
}
|
|
|
|
refWidget = topLevel;
|
|
|
|
#ifdef NOTDEF
|
|
/* build a service name. The service name needs to be application,
|
|
* host, and username specific. Since we are talking through the
|
|
* display connection, it will already be display specific.
|
|
* The format of the service name will be "DTTERM-hostname-uid"
|
|
* (i.e., "DTTERM-hpcvxds.cv.hp.com-201")...
|
|
*/
|
|
char *buffer = (char*) malloc(BUFSIZ);
|
|
if (gethostname(hostname, sizeof(hostname))) {
|
|
(void) strcpy(hostname, "unknown");
|
|
}
|
|
(void) sprintf(buffer, "%s-%s-%ld", DTTERM_SVC_CLASS, hostname, (long)getuid());
|
|
serviceName = XtMalloc(strlen(buffer) + 1);
|
|
(void) strcpy(serviceName, buffer);
|
|
free(buffer);
|
|
#endif /* NOTDEF */
|
|
|
|
/* we will use serverId as the service name... */
|
|
serviceName = XtMalloc(strlen(serverId) + 1);
|
|
(void) strcpy(serviceName, serverId);
|
|
|
|
/* get a handle... */
|
|
serviceHandle = _DtSvcNewHandle(serviceName, refWidget);
|
|
|
|
/* register with the server... */
|
|
if (DT_SVC_SUCCESS == _DtSvcRegister(
|
|
serviceHandle,
|
|
False,
|
|
serverRequestProc,
|
|
(XtPointer) SVC_REQUEST,
|
|
serverMessageProc,
|
|
(XtPointer) SVC_LOSE)) {
|
|
|
|
/* We are the new server. We need to do several things:
|
|
*
|
|
* -fork ourself off. The server needs to run as a child of
|
|
* our application so that it can stay around when our session
|
|
* is done.
|
|
*
|
|
* -dissassociate ourself from our parent.
|
|
*
|
|
* -have the child re-exec ourself. This will allow the child
|
|
* to request a session and talk to us as any other normal
|
|
* requestor process.
|
|
*/
|
|
/* if the 'n' flag is set, we will not daemonize ourself (i.e.,
|
|
* fork off and run as a child of the current process)...
|
|
*/
|
|
if (!isDebugSet('n')) {
|
|
for (i = 0; (i < 10) && ((pid = fork()) < 0); i++) {
|
|
/* if we are out of process slots, then let's sleep
|
|
* a bit and try again...
|
|
*/
|
|
if (errno != EAGAIN) {
|
|
break;
|
|
}
|
|
|
|
/* give it a chance to clear up... */
|
|
(void) sleep((unsigned long) 2);
|
|
}
|
|
} else {
|
|
pid = 0;
|
|
}
|
|
|
|
if (pid < 0) {
|
|
/* can't do much of anything and we haven't done much of
|
|
* anything. Let's just error out...
|
|
*/
|
|
(void) perror("fork()");
|
|
(void) exit(1);
|
|
} else if (pid > 0) {
|
|
/* parent. Let's clean up, restart, and let the new process
|
|
* try again...
|
|
*/
|
|
/* close the server connection... */
|
|
(void) close(ConnectionNumber(XtDisplay(refWidget)));
|
|
(void) execvp(argv[0], argv);
|
|
(void) perror(argv[0]);
|
|
(void) _exit(1);
|
|
}
|
|
|
|
/* child server process...
|
|
*/
|
|
/* set the iAmTheServer flag to True. This flag will remain True
|
|
* until we lose ownership of the service...
|
|
*/
|
|
iAmTheServer = True;
|
|
|
|
/* set up signal handlers so that we can clean up nicely... */
|
|
(void) sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = CleanUp;
|
|
|
|
for (i = 0; i < (sizeof(trapSignalList) / sizeof(trapSignalList[0]));
|
|
i++) {
|
|
(void) sigaction(trapSignalList[i], &sa, (struct sigaction *) 0);
|
|
}
|
|
|
|
/* register for service. This will allow us to deal with the
|
|
* case where we lose ownership of the service. We will then
|
|
* be able to listen to termination requests from our client
|
|
* applications and shut down the sessions when requested to
|
|
* do so...
|
|
*/
|
|
(void) _DtSvcNotifyGroupRegister(
|
|
serviceHandle,
|
|
serverMessageProc,
|
|
(XtPointer) SVC_NOTIFY);
|
|
|
|
/* get our initial tty modes before we go and create a new
|
|
* session id...
|
|
*/
|
|
(void) _DtTermPrimPtyGetDefaultModes();
|
|
|
|
/* new session group... */
|
|
(void) setsid();
|
|
} else {
|
|
|
|
/* we are not the server. We need to register for messages. Then
|
|
* we are done and the service world is now for us...
|
|
*/
|
|
(void) _DtSvcNotifyGroupRegister(
|
|
serviceHandle,
|
|
clientMessageProc,
|
|
(XtPointer) SVC_NOTIFY);
|
|
}
|
|
|
|
/* install a ping timeout... */
|
|
if (PingInterval > 0) {
|
|
pingId = XtAppAddTimeOut(XtWidgetToApplicationContext(topLevel),
|
|
1000 * 60 * PingInterval, Ping, (XtPointer) topLevel);
|
|
}
|
|
|
|
/* make sure we are never called again... */
|
|
initFlag = True;
|
|
}
|
|
|
|
|
|
static void
|
|
NiceCleanUp(
|
|
XtPointer clientData,
|
|
XtIntervalId *id
|
|
)
|
|
{
|
|
ServiceClientInfo serviceClientInfo;
|
|
char buffer[BUFSIZ];
|
|
String args[20];
|
|
int argcnt;
|
|
|
|
/* find the serviceClientInfoRec for this widget... */
|
|
for (serviceClientInfo = serviceClientInfoHead->next; serviceClientInfo;
|
|
serviceClientInfo = serviceClientInfo->next) {
|
|
|
|
/* notify each client that the session (is being) terminated... */
|
|
argcnt = 0;
|
|
(void) sprintf(buffer, "%ld", (long)serviceClientInfo->pid);
|
|
args[argcnt] = buffer; argcnt++;
|
|
(void) _DtSvcNotifySend(
|
|
serviceHandle,
|
|
DTTERM_SVC_TERMINATION_MSG,
|
|
args,
|
|
argcnt);
|
|
(void) XSync(XtDisplay(refWidget), 0);
|
|
}
|
|
|
|
/* we can now exit... */
|
|
(void) exit(1);
|
|
}
|
|
|
|
static void
|
|
CleanUp(
|
|
int sig
|
|
)
|
|
{
|
|
static Boolean firstTime = True;
|
|
|
|
if (firstTime) {
|
|
/* let's try to do this nicely and invoke our cleanup routine
|
|
* via the toolkit (i.e., outside of a signal handler)...
|
|
*/
|
|
(void) XtAppAddTimeOut(XtWidgetToApplicationContext(refWidget),
|
|
0, NiceCleanUp, (XtPointer) refWidget);
|
|
firstTime = False;
|
|
} else {
|
|
/* we have received multiple attempts to kill ourself. Just
|
|
* exit...
|
|
*/
|
|
(void) exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
serverMessageProc(
|
|
DtSvcHandle service,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
)
|
|
{
|
|
switch ((int) clientData) {
|
|
case SVC_LOSE:
|
|
/* we lost control of the service... */
|
|
iAmTheServer = False;
|
|
|
|
if (InstanceCount <= 0) {
|
|
/* no reason to stay around... */
|
|
(void) _DtSvcDestroyHandle(serviceHandle);
|
|
(void) exit(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
serverRequestProc(
|
|
DtSvcHandle service,
|
|
DtSvcMsgContext replyContext,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
)
|
|
{
|
|
Widget shellWidget;
|
|
ServiceClientInfo serviceClientInfo;
|
|
char buffer[BUFSIZ];
|
|
String reply[20];
|
|
pid_t pid = -1;
|
|
Arg arglist[20];
|
|
int i1;
|
|
int i2;
|
|
int argcnt = 0;
|
|
char **commandToExecute = (char **) 0;
|
|
|
|
switch ((int) clientData) {
|
|
case SVC_REQUEST:
|
|
if (!strcmp(messageFields[0], DTTERM_SVC_START_MSG)) {
|
|
/* create our shell widget... */
|
|
argcnt = 0;
|
|
(void) XtSetArg(arglist[argcnt], XmNallowShellResize, True);
|
|
argcnt++;
|
|
shellWidget = XtAppCreateShell((char *) 0, "Dtterm",
|
|
applicationShellWidgetClass, XtDisplay((Widget) refWidget),
|
|
arglist, argcnt);
|
|
|
|
/* parse off messageFields and build the dttermview arglist... */
|
|
argcnt = 0;
|
|
|
|
for (i2 = 1; i2 < numFields; i2++) {
|
|
if (!strcmp(messageFields[i2], "-pid")) {
|
|
(void) i2++;
|
|
if (i2 < numFields) {
|
|
pid = (pid_t) strtol(messageFields[i2], (char **) 0, 0);
|
|
}
|
|
|
|
} else if (!strcmp(messageFields[i2], "-ls")) {
|
|
(void) XtSetArg(arglist[argcnt], XmNloginShell,
|
|
True); argcnt++;
|
|
|
|
} else if (!strcmp(messageFields[i2], "+ls")) {
|
|
(void) XtSetArg(arglist[argcnt], XmNloginShell,
|
|
False); argcnt++;
|
|
|
|
} else if (!strcmp(messageFields[i2], "-e")) {
|
|
(void) i2++;
|
|
if (i2 < numFields) {
|
|
/* DKS: somewhere we will need to free this... */
|
|
commandToExecute = (char **)
|
|
XtMalloc((numFields - i2 + 1) *
|
|
sizeof(char *));
|
|
for (i1 = 0; i2 < numFields; i1++, i2++) {
|
|
commandToExecute[i1] = messageFields[i2];
|
|
}
|
|
/* null term commandToExecute... */
|
|
commandToExecute[i1] = (char *) 0;
|
|
(void) XtSetArg(arglist[argcnt], XmNsubprocessArgv,
|
|
commandToExecute); argcnt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* create the dtterm... */
|
|
(void) CreateInstance(shellWidget, "Dtterm",
|
|
arglist, argcnt);
|
|
|
|
/* create the ServiceClientInfoRec for this instance...
|
|
*/
|
|
serviceClientInfo =
|
|
(ServiceClientInfo) XtMalloc(sizeof(ServiceClientInfoRec));
|
|
serviceClientInfo->pid = pid;
|
|
serviceClientInfo->shellWidget = shellWidget;
|
|
/* insert it at the head of the list... */
|
|
serviceClientInfo->next = serviceClientInfoHead->next;
|
|
serviceClientInfo->prev = serviceClientInfoHead;
|
|
if (serviceClientInfoHead->next) {
|
|
serviceClientInfoHead->next->prev = serviceClientInfo;
|
|
}
|
|
serviceClientInfoHead->next = serviceClientInfo;
|
|
|
|
(void) XtRealizeWidget(shellWidget);
|
|
|
|
InstanceCount++;
|
|
/* since we now have active instances, we can remove our
|
|
* wait timeout...
|
|
*/
|
|
#ifdef TIMEOUT
|
|
if (waitId) {
|
|
(void) XtRemoveTimeOut(waitId);
|
|
waitId = (XtIntervalId) 0;
|
|
}
|
|
#endif /* TIMEOUT */
|
|
|
|
/* ack the reply... */
|
|
i2 = 0;
|
|
(void) sprintf(buffer, "0x%lx", shellWidget);
|
|
reply[i2] = buffer; i2++;
|
|
(void) _DtSvcRequestReply(
|
|
serviceHandle,
|
|
replyContext,
|
|
reply,
|
|
i2,
|
|
True);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
clientMessageProc(
|
|
DtSvcHandle service,
|
|
Pointer clientData,
|
|
String *messageFields,
|
|
int numFields
|
|
)
|
|
{
|
|
int i1;
|
|
pid_t pid;
|
|
char buffer[BUFSIZ];
|
|
|
|
switch ((int) clientData) {
|
|
case SVC_NOTIFY:
|
|
/* process the notify message... */
|
|
if (!strcmp(messageFields[0], DTTERM_SVC_TERMINATION_MSG)) {
|
|
if (numFields >= 2) {
|
|
pid = (pid_t) strtol(messageFields[1], (char **) 0, 0);
|
|
} else {
|
|
pid = -1;
|
|
}
|
|
|
|
if (pid == getpid()) {
|
|
/* our session terminated -- exit... */
|
|
(void) _DtSvcDestroyHandle(serviceHandle);
|
|
(void) exit(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SVC_FAIL:
|
|
/* turn on the waitingForReply flag... */
|
|
waitingForReply = False;
|
|
/* set the waitedForReply flag to True (i.e., failure)... */
|
|
waitedForReply = True;
|
|
|
|
/* get errno (if returned)... */
|
|
if (numFields >= 2) {
|
|
errno = (int) strtol(messageFields[1], (char **) 0, 0);
|
|
}
|
|
/* build any failure message... */
|
|
*buffer = '\0';
|
|
for (i1 = 2; i1 < numFields; i1++) {
|
|
if (*buffer) {
|
|
(void) strcat(buffer, " ");
|
|
}
|
|
(void) strcat(buffer, messageFields[i1]);
|
|
}
|
|
ServerFailureMessage =
|
|
XtRealloc(ServerFailureMessage,
|
|
strlen(buffer));
|
|
(void) strcpy(ServerFailureMessage, buffer);
|
|
break;
|
|
|
|
case SVC_SUCCESS:
|
|
/* turn on the waitingForReply flag... */
|
|
waitingForReply = False;
|
|
/* set the waitedForReply flag to False (i.e., success)... */
|
|
waitedForReply = False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
Boolean
|
|
ServerStartSession(
|
|
Widget topLevel,
|
|
int argc,
|
|
char **argv,
|
|
Boolean server,
|
|
char *serverId,
|
|
Boolean exitOnLastClose,
|
|
Boolean block,
|
|
Boolean loginShell,
|
|
char **commandToExec
|
|
)
|
|
{
|
|
char buffer[BUFSIZ];
|
|
String args[20];
|
|
int argcnt;
|
|
int i1;
|
|
XEvent event;
|
|
XtAppContext appContext;
|
|
|
|
ExitOnLastClose = exitOnLastClose;
|
|
|
|
(void) Initialize(topLevel, argc, argv, serverId);
|
|
if (iAmTheServer) {
|
|
/* we are the server. We need to wait for our clients to make
|
|
* a request of us.
|
|
*/
|
|
|
|
#ifdef LOG_USAGE
|
|
/* log our startup... */
|
|
(void) LogStart(0, argc, argv);
|
|
#endif /* LOG_USAGE */
|
|
|
|
return(True);
|
|
}
|
|
|
|
/* if we go to this point and the -server option was specified, we
|
|
* should go away. Otherwise we should request service...
|
|
*/
|
|
if (server) {
|
|
/* all that was requested was creation of a server. We can go
|
|
* away now...
|
|
*/
|
|
(void) exit(0);
|
|
}
|
|
|
|
/* make a request of the server to start a session...
|
|
*/
|
|
/* need 2 for "-pid" and "<pid>"... */
|
|
argcnt = 2;
|
|
if (commandToExec && *commandToExec) {
|
|
/* need one for "-e"... */
|
|
(void) argcnt++;
|
|
|
|
/* need one for each string in the command... */
|
|
/*EMPTY*/
|
|
for (i1 = 0; commandToExec[i1]; i1++) {
|
|
;
|
|
}
|
|
argcnt += i1;
|
|
}
|
|
|
|
argcnt = 0;
|
|
args[argcnt] = "-pid"; argcnt++;
|
|
(void) sprintf(buffer, "%ld", (long)getpid());
|
|
args[argcnt] = buffer; argcnt++;
|
|
|
|
if (loginShell) {
|
|
args[argcnt] = "-ls"; argcnt++;
|
|
} else {
|
|
args[argcnt] = "+ls"; argcnt++;
|
|
}
|
|
|
|
if (commandToExec && *commandToExec) {
|
|
args[argcnt] = "-e"; argcnt++;
|
|
for (i1 = 0; commandToExec[i1]; i1++) {
|
|
args[argcnt] = commandToExec[i1]; argcnt++;
|
|
}
|
|
}
|
|
|
|
if (DT_SVC_FAIL == _DtSvcRequestSend(
|
|
serviceHandle,
|
|
DTTERM_SVC_START_MSG,
|
|
args,
|
|
argcnt,
|
|
clientMessageProc,
|
|
(XtPointer) SVC_SUCCESS,
|
|
clientMessageProc,
|
|
(XtPointer) SVC_FAIL)) {
|
|
(void) fprintf(stderr, "request to server failed\n");
|
|
return(True);
|
|
}
|
|
|
|
/* dispatch locally until we get back the results from our server... */
|
|
appContext = XtWidgetToApplicationContext(topLevel);
|
|
for (waitingForReply = True; waitingForReply; ) {
|
|
(void) XtAppNextEvent(appContext, &event);
|
|
(void) XtDispatchEvent(&event);
|
|
}
|
|
|
|
if (!block) {
|
|
/* we succeeded, we can exit now... */
|
|
(void) _DtSvcDestroyHandle(serviceHandle);
|
|
(void) exit(0);
|
|
}
|
|
|
|
return(waitedForReply);
|
|
}
|
|
|
|
void
|
|
ServerInstanceTerminated(
|
|
Widget w
|
|
)
|
|
{
|
|
ServiceClientInfo serviceClientInfo;
|
|
char buffer[BUFSIZ];
|
|
String args[20];
|
|
int argcnt;
|
|
|
|
/* find the serviceClientInfoRec for this widget... */
|
|
for (serviceClientInfo = serviceClientInfoHead->next; serviceClientInfo;
|
|
serviceClientInfo = serviceClientInfo->next) {
|
|
if (serviceClientInfo->shellWidget == w) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (serviceClientInfo && (serviceClientInfo->shellWidget == w)) {
|
|
/* notify the client that the session terminated... */
|
|
argcnt = 0;
|
|
(void) sprintf(buffer, "%ld", (long)serviceClientInfo->pid);
|
|
args[argcnt] = buffer; argcnt++;
|
|
(void) _DtSvcNotifySend(
|
|
serviceHandle,
|
|
DTTERM_SVC_TERMINATION_MSG,
|
|
args,
|
|
argcnt);
|
|
|
|
/* free up the serviceClientInfoRec... */
|
|
serviceClientInfo->prev->next = serviceClientInfo->next;
|
|
if (serviceClientInfo->next) {
|
|
serviceClientInfo->next->prev = serviceClientInfo->prev;
|
|
}
|
|
(void) XtFree((char *) serviceClientInfo);
|
|
}
|
|
|
|
if ((--InstanceCount <= 0) && (!iAmTheServer)) {
|
|
(void) _DtSvcDestroyHandle(serviceHandle);
|
|
(void) exit(0);
|
|
} else
|
|
#ifdef TIMEOUT
|
|
if ((InstanceCount <= 0) && !waitId) {
|
|
/* set up a wait timeout and stick around for a while before
|
|
* we exit...
|
|
*/
|
|
waitId = XtAppAddTimeOut(XtWidgetToApplicationContext(refWidget),
|
|
1000 * 60 * STICKAROUND, TimeOut, (XtPointer) refWidget);
|
|
}
|
|
#endif /* TIMEOUT */
|
|
|
|
if ((InstanceCount <= 0) && ExitOnLastClose) {
|
|
(void) exit(0);
|
|
}
|
|
}
|
|
|
|
#ifdef TIMEOUT
|
|
static void
|
|
TimeOut(
|
|
XtPointer clientData,
|
|
XtIntervalId *id
|
|
)
|
|
{
|
|
/* if we have no instances active, go away... */
|
|
if (InstanceCount <= 0) {
|
|
(void) exit(0);
|
|
}
|
|
|
|
/* otherwise, clear the waitId... */
|
|
if (*id == waitId) {
|
|
waitId = (XtIntervalId) 0;
|
|
}
|
|
}
|
|
#endif /* TIMEOUT */
|
|
|
|
static void
|
|
Ping(
|
|
XtPointer clientData,
|
|
XtIntervalId *id
|
|
)
|
|
{
|
|
Widget w = (Widget) clientData;
|
|
Window root;
|
|
Window child;
|
|
int rootX;
|
|
int rootY;
|
|
int winX;
|
|
int winY;
|
|
unsigned int mask;
|
|
|
|
if (*id != pingId) {
|
|
return;
|
|
}
|
|
|
|
/* cause a round trip to the server... */
|
|
(void) XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
|
|
&rootX, &rootY, &winX, &winY, &mask);
|
|
|
|
/* reset the timeout... */
|
|
if (PingInterval > 0) {
|
|
pingId = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
|
|
1000 * 60 * PingInterval, Ping, clientData);
|
|
}
|
|
}
|
|
#else
|
|
/* dummy variable to get pass compilation phase */
|
|
static char *foo;
|
|
#endif /* TERMINAL_SERVER */
|