1 /* $TOG: CmdMain.c /main/15 1998/04/20 12:46:37 mgreess $ */
3 * (c) Copyright 1997, The Open Group
5 /***************************************************************************
8 * Description: Command execution system
11 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
12 ** (c) Copyright 1993, 1994 International Business Machines Corp.
13 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
14 ** (c) Copyright 1993, 1994 Novell, Inc.
15 ***************************************************************************/
18 #include <Dt/CmdInv.h>
22 #include "/sys5/usr/include/sys/termio.h"
29 #ifdef _SUN_OS /* to get the define for NOFILE */
30 #include <sys/param.h>
32 #define X_INCLUDE_PWD_H
33 #define XOS_USE_XT_LOCKING
34 #include <X11/Xos_r.h>
36 #include <Dt/CommandM.h>
37 #include <Dt/EnvControlP.h>
38 #include <Dt/DtNlUtils.h>
40 #include <Dt/ActionDb.h>
41 #include <Dt/ActionUtilP.h>
42 #include "myassertP.h"
43 #include "DtSvcLock.h"
47 #include <SPC/spc-proto.h>
50 #define MAX_EXEC_ARGS 1000 /* Maximum number of arguments for */
53 * Dtexec return status:
55 #define COMMAND_CHECK_FAILURE 1
59 #define INETD_SECURITY_FILE "/var/adm/inetd.sec"
61 #define INETD_SECURITY_FILE "/usr/adm/inetd.sec"
65 #define Cmd_FreeAllocatedStringVector(sv) \
66 _DtCmdFreeStringVector(sv);\
70 * Global variables for the Command Invoker.
72 static char _cmdClientHost[MAXHOSTNAMELEN];
75 * Static variables for the Command Invoker.
77 static Cmd_RequestQueue *requestQueue = NULL;
80 * Static function declarations:.
83 static void QueueRequest (
84 SPC_Channel_Ptr channel,
90 unsigned long requestNum,
91 DtSvcMsgContext replyContext,
92 DtCmdInvExecuteProc success_proc,
94 DtCmdInvExecuteProc failure_proc,
96 static void ExecuteQueuedRequest (
97 unsigned long requestNum);
99 static void FreeRequest (Cmd_RequestQueue *pNode);
101 static void DtexecTerminator (
102 SPC_Channel_Ptr cmdChannel,
107 static void CheckCommandTerminator (
108 SPC_Channel_Ptr cmdChannel,
113 static int DtCmdGetWindowType(
114 unsigned long windowTypeMask);
115 static void _DtCmdInitializeErrorMessages(void);
118 * Command invocatin error messages.
120 static char *errorExec,
127 *errorRemoteSubprocess,
131 *errorRegisterHandshake,
132 *errorRegisterUsername,
139 /*******************************************************************************
142 * This is a wrapper around DtSPCSpawn (i.e. XeSPCSPawn) that makes sure
143 * the original environment is restored before the spawn and the DT
144 * environment is reinstated after the spawn. It returns the value
145 * originally returned by DtSPCSpawn.
147 ******************************************************************************/
155 SPC_Channel_Ptr chan,
164 * Restore the original environment
166 (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
169 * Map some env var paths to execHost.
171 (void) _DtEnvMapForRemote(execHost);
173 if ((retVal = XeSPCSpawn(path,
179 switch (DtSPCErrorNumber)
181 case SPC_cannot_Chdir:
182 (void) sprintf (errorMessage,
187 case SPC_Cannot_Fork:
188 (void) sprintf (errorMessage,
192 case SPC_Env_Too_Big:
193 case SPC_Arg_Too_Long:
194 (void) sprintf (errorMessage,
202 (void) sprintf (errorMessage,
210 * Restore some env var paths.
212 (void) _DtEnvRestoreLocal();
215 * Restore the DT environment
217 (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
220 * Return the result of DtSPCSpawn
225 /*******************************************************************************
228 * This is a wrapper around DtSPCOpen (i.e. XeSPCOpen) that makes sure
229 * the original environment is restored before the spawn and the DT
230 * environment is reinstated after the spawn. It returns the value
231 * originally returned by DtSPCOpen.
233 ******************************************************************************/
240 SPC_Channel_Ptr chan;
241 _Xgetpwparams pwd_buf;
242 struct passwd * pwd_ret;
245 * Restore the original environment
247 (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
250 * Map some env var paths to execHost.
252 (void) _DtEnvMapForRemote(hostname);
254 if ((chan = XeSPCOpen(hostname, iomode)) == SPC_ERROR)
259 switch (DtSPCErrorNumber)
261 case SPC_Unknown_Host:
262 (void) sprintf (errorMessage,
266 case SPC_Bad_Connect:
267 (void) sprintf (errorMessage,
273 case SPC_Bad_Service:
274 (void) sprintf (errorMessage,
279 case SPC_Register_Handshake:
281 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) ==
285 username = pwd_ret->pw_name;
286 (void) sprintf (errorMessage,
287 errorRegisterHandshake,
294 case SPC_Register_Username:
296 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) ==
300 username = pwd_ret->pw_name;
301 (void) sprintf (errorMessage,
302 errorRegisterUsername,
306 case SPC_Register_Netrc:
307 (void) sprintf (errorMessage,
311 case SPC_Env_Too_Big:
312 (void) sprintf (errorMessage,
317 case SPC_Connection_EOF:
319 (void) sprintf (errorMessage,
330 (void) sprintf (errorMessage,
341 (void) sprintf (errorMessage,
348 * Restore some env var paths.
350 (void) _DtEnvRestoreLocal();
353 * Restore the DT environment
355 (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
361 /******************************************************************************
363 * QueueRequest - takes the "state" from a request and puts it on the
368 * SPC_Channel_Ptr channel; - Spcd channel id.
369 * char *context; - Context for SPCSpawn.
370 * char *execHost; - The execution host.
371 * char *execString; - The execution string.
372 * char **argv; - Arg vector for SPCSpawn.
373 * (Arg vector is XtFree'd)
374 * int windowType; - window type of queued command.
375 * unsigned long requestNum; - Id number into the queue.
376 * DtSvcMsgContext replyContext; - Reply info.
377 * DtCmdInvExecuteProc success_proc; - Success callback.
378 * void *success_data; - Success client_data.
379 * DtCmdInvExecuteProc failure_proc; - Failure callback.
380 * void *failure_data; - Failure client_data.
384 * Cmd_RequestQueue *requestQueue; - This request to added.
386 *****************************************************************************/
390 SPC_Channel_Ptr channel,
396 unsigned long requestNum,
397 DtSvcMsgContext replyContext,
398 DtCmdInvExecuteProc success_proc,
400 DtCmdInvExecuteProc failure_proc,
404 Cmd_RequestQueue *pNode;
405 Cmd_RequestQueue *pNewNode;
407 pNewNode = (Cmd_RequestQueue *) XtMalloc (sizeof (Cmd_RequestQueue));
409 pNewNode->next = (Cmd_RequestQueue *) NULL;
410 pNewNode->channel = channel;
411 pNewNode->context = XtNewString (context);
412 pNewNode->exec_host = XtNewString (execHost);
413 pNewNode->exec_string = XtNewString (execString);
414 pNewNode->argv = argv;
415 pNewNode->winType = winType;
416 pNewNode->request_num = requestNum;
417 if (replyContext == NULL)
418 pNewNode->replyContext = NULL;
420 pNewNode->replyContext = replyContext;
421 pNewNode->success_proc = success_proc;
422 pNewNode->success_data = success_data;
423 pNewNode->failure_proc = failure_proc;
424 pNewNode->failure_data = failure_data;
426 if (requestQueue == NULL)
428 requestQueue = pNewNode;
433 * Find the End Of the Queue and link in the NewNode.
435 for (pNode = requestQueue; pNode->next != NULL; pNode = pNode->next);
437 pNode->next = pNewNode;
441 /******************************************************************************
443 * ExecuteQueuedRequest - given a key into the requestQueue (requestNum)
444 * find the appropriate request and execute it.
448 * unsigned long requestNum; - Key into the requestQueue.
452 * Cmd_RequestQueue *requestQueue; - The executed request gets
455 *****************************************************************************/
458 ExecuteQueuedRequest (
459 unsigned long requestNum)
462 Boolean success = True;
463 Cmd_RequestQueue *prev = NULL;
464 Cmd_RequestQueue *pNode = requestQueue;
465 unsigned long iomode;
467 for (; pNode != NULL; pNode = pNode->next)
469 if ( pNode->request_num == requestNum )
472 * Pluck pNode out of the queue
475 prev->next = pNode->next;
477 requestQueue = pNode->next;
483 * Move alone to the next node
491 errorMessage = XtMalloc (MAX_BUF_SIZE * sizeof (char));
498 iomode = ( SPCIO_NOIO
499 | SPCIO_SYNC_TERMINATOR
500 | SPCIO_FORCE_CONTEXT );
503 if ((pNode->channel = (_DtSPCOpen(pNode->exec_host,
505 errorMessage))) == SPC_ERROR)
511 if ((_DtSPCSpawn(pNode->argv[0], pNode->context, pNode->argv, NULL,
512 pNode->channel, pNode->exec_host, NULL, NULL,
513 errorMessage)) == SPC_ERROR)
516 if (DtSPCErrorNumber != SPC_Arg_Too_Long)
517 DtSPCClose(pNode->channel);
520 if (success && pNode->success_proc != NULL)
522 if (cmd_Resources.executionHostLogging && pNode->success_data != NULL)
525 data = (CallbackData *) pNode->success_data;
526 (void) sprintf (errorMessage, successHost,
527 data->actionLabel, pNode->exec_host);
528 _DtCmdLogErrorMessage (errorMessage);
531 (*pNode->success_proc) (NULL, pNode->success_data);
535 if (cmd_Resources.executionHostLogging)
537 if (DtSPCErrorNumber == SPC_Arg_Too_Long)
540 char *cmdp; /* pointer to complete command string */
544 * The message should include all of the command because
545 * the problem may be with some on the internally generated
546 * parts of the command (e.g. the terminal emulator and args).
547 * This means going through all of argv to determine the
548 * length of the string.
550 for (cmdlen = 0, i = 0; pNode->argv[i]; i++) {
551 cmdlen+=strlen(pNode->argv[i]);
552 cmdlen+=2; /* make room for a space + string terminator */
555 tmp_message = (char *) XtMalloc (strlen (errorSpawn) +
556 strlen (pNode->exec_host) +
558 cmdp = (char *) XtMalloc(cmdlen + 1);
560 for (i = 0; pNode->argv[i]; i++) {
561 strcat(cmdp,pNode->argv[i]);
564 (void) sprintf (tmp_message, errorSpawn, pNode->exec_host, cmdp);
565 _DtCmdLogErrorMessage (tmp_message);
570 if (pNode->failure_proc != NULL)
571 (*pNode->failure_proc) (errorMessage, pNode->failure_data);
574 XtFree ((char *)errorMessage);
579 _DtCmdGetQueueHead(void)
584 /******************************************************************************
586 * FreeRequest - Frees the malloced data associated with the node.
587 * and frees the node.
591 * Cmd_RequestQueue *pNode
594 *****************************************************************************/
597 FreeRequest (Cmd_RequestQueue *pNode)
603 XtFree (pNode->context);
604 XtFree (pNode->exec_host);
605 XtFree (pNode->exec_string);
606 Cmd_FreeAllocatedStringVector (pNode->argv);
608 XtFree ((char *) pNode);
611 /******************************************************************************
613 * _DtCmdCommandInvokerExecute - executes a request on the specified host.
617 * _CMD_EXECUTE_SUCCESS - successful execution
618 * _CMD_EXECUTE_FAILURE - execution failed
619 * _CMD_EXECUTE_QUEUED - the request was queued
620 * _CMD_EXECUTE_FATAL - the request contains invalid information
623 *****************************************************************************/
626 _DtCmdCommandInvokerExecute (
627 char *errorMessage, /* MODIFIED */
628 DtSvcMsgContext replyContext, /* OBSOLETE -- always NULL */
632 char *contextFile, /* OBSOLETE -- always NULL */
638 DtCmdInvExecuteProc success_proc,
640 DtCmdInvExecuteProc failure_proc,
644 int ioMode, i, index1;
647 char context[MAXPATHLEN];
648 char tmpDir [MAXPATHLEN];
650 SPC_Channel_Ptr cmdChannel;
651 char *theCommand = NULL;
652 Boolean terminalRequest = False;
653 char *commandArray2[MAX_EXEC_ARGS];
654 Boolean localExecution = True;
656 static unsigned long requestNum = 0;
657 char *toolRequest = NULL; /* backward compatibility kludge */
660 myassert( !(contextFile && replyContext) );
663 * Check for a valid window-type.
664 * This check is probably redundant but it converts the mask bits into
665 * small integer values used by the rest of the command invoker code.
668 DtCmdGetWindowType(winMask))== -1)
670 (void) sprintf (errorMessage, errorRequest, toolRequest,
671 DtTERMINAL, DtPERM_TERMINAL, DtOUTPUT_ONLY,
672 DtSHARED_OUTPUT, "" /* Obsolete shell window */,
674 return (_CMD_EXECUTE_FATAL);
678 * Create the command to be exec'ed.
680 if (windowType == PERM_TERMINAL || windowType == TERMINAL)
682 _DtCmdCreateTerminalCommand (&theCommand, windowType, execString,
683 execParms, execHost, procId, tmpFiles);
684 terminalRequest = True;
689 * NO-STDIO || START-SESSION request.
692 theCommand = XtMalloc(
693 + strlen (cmd_Resources.dtexecPath)
694 + strlen(" -open ") + 4 /* waitTime len */
695 + strlen(" -ttprocid ") + strlen(_DtActNULL_GUARD(procId))
696 + strlen(_DtActNULL_GUARD(tmpFiles))
697 + strlen (execString)
698 + 5 /* for 2 quotes,2 blanks,null */);
700 sprintf(theCommand,"%s -open %d -ttprocid '%s' %s %s",
701 cmd_Resources.dtexecPath,
702 0 /* wait time zero for NO_STDIO */,
703 _DtActNULL_GUARD(procId),
704 _DtActNULL_GUARD(tmpFiles),
710 * See if the request requires Remote Execution.
712 localExecution = _DtIsSameHost(execHost,NULL);
715 * If this is a terminalRequest and the Command Invoker subprocess
716 * is not executable, return now.
718 if (localExecution && terminalRequest && !cmd_Globals.subprocess_ok)
720 if (!(_DtCmdCheckForExecutable (cmd_Resources.dtexecPath)))
722 (void) sprintf (errorMessage, cmd_Globals.error_subprocess,
723 cmd_Resources.dtexecPath);
724 XtFree ((char *) theCommand);
725 return (_CMD_EXECUTE_FAILURE);
728 cmd_Globals.subprocess_ok = True;
732 * If this is a terminalRequest and the terminal emulator
733 * is not executable, return now.
735 if (localExecution && terminalRequest && !cmd_Globals.terminal_ok)
737 if (!(_DtCmdCheckForExecutable (cmd_Resources.localTerminal)))
739 (void) sprintf (errorMessage, cmd_Globals.error_terminal,
740 cmd_Resources.localTerminal);
741 XtFree ((char *) theCommand);
742 return (_CMD_EXECUTE_FAILURE);
745 cmd_Globals.terminal_ok = True;
749 * Break the command into something execvp or SPCSpawn can handle
750 * and then free "theCommand" if this is a termianl-based request.
752 commandArray = (char **) XtMalloc (MAX_EXEC_ARGS * sizeof (char *));
753 _DtCmdStringToArrayOfStrings (theCommand, commandArray);
763 /* REMOTE Execution */
765 ioMode = SPCIO_NOIO | SPCIO_SYNC_TERMINATOR | SPCIO_FORCE_CONTEXT;
767 if ((cmdChannel = (_DtSPCOpen(execHost,
769 errorMessage))) == SPC_ERROR)
771 Cmd_FreeAllocatedStringVector (commandArray);
772 return (_CMD_EXECUTE_FAILURE);
775 /* Old syntax should no longer appear in contextHost/Dir */
776 myassert( (contextHost?*contextHost != '*':1) &&
777 (contextDir?*contextDir != '*':1) );
779 * Create a "netfile" for the cwd to be used.
781 netfile = (char *) tt_host_file_netfile (
782 ((contextHost == NULL) ? execHost : contextHost),
783 ((contextDir == NULL) ? (char *) getenv ("HOME") : contextDir));
785 if (tt_pointer_error (netfile) != TT_OK) {
786 (void) sprintf (errorMessage, cmd_Globals.error_directory_name_map,
787 ((contextDir == NULL) ? (char *) getenv ("HOME") : contextDir),
788 ((contextHost == NULL) ? execHost : contextHost),
789 tt_status_message (tt_pointer_error(netfile)));
790 Cmd_FreeAllocatedStringVector (commandArray);
791 return (_CMD_EXECUTE_FAILURE);
793 (void) strcpy (context, netfile);
797 * First check to see if the "dtexecPath" is executable on
798 * the remote execution host by executing it with no
799 * options which will cause it to immediately die.
801 * There is no need to set up termination handler for this
802 * because we don't care when it dies, we only care about
803 * whether or not it can be executed.
806 argv[0] = cmd_Resources.dtexecPath;
807 argv[1] = (char *) NULL;
809 if ((_DtSPCSpawn(argv[0], context, argv, NULL, cmdChannel,
810 execHost, contextHost, contextDir, errorMessage))
813 if (DtSPCErrorNumber != SPC_cannot_Chdir &&
814 DtSPCErrorNumber != SPC_Cannot_Fork &&
815 DtSPCErrorNumber != SPC_Env_Too_Big &&
816 DtSPCErrorNumber != SPC_Arg_Too_Long)
818 * The Error message must mention that the dtexec
819 * process is not executable so must overwrite the
820 * error message returned by the Spawn function with
821 * an appropriate message.
823 (void) sprintf (errorMessage, errorRemoteSubprocess, execHost,
824 cmd_Resources.dtexecPath);
825 DtSPCClose(cmdChannel);
826 Cmd_FreeAllocatedStringVector (commandArray);
827 return (_CMD_EXECUTE_FAILURE);
830 /* The dtexec process is now known to exist on the remote host */
833 * Now run a test to see if the command is executable
836 _DtCmdStringToArrayOfStrings (execString, commandArray2);
838 tmp = (char *) XtMalloc (strlen (commandArray2[0]) +
839 strlen ("whence ") + 2);
840 (void) sprintf (tmp, "whence %s", commandArray2[0]);
842 _DtCmdFreeStringVector (commandArray2);
847 argv[3] = (char *) NULL;
852 if ((cmdChannel = (_DtSPCOpen(execHost,
854 errorMessage))) == SPC_ERROR)
856 Cmd_FreeAllocatedStringVector (commandArray);
857 return (_CMD_EXECUTE_FAILURE);
861 * Set up a callback to be invoked when the test command
865 if ((DtSPCRegisterTerminator(cmdChannel,
866 (SPC_TerminateHandlerType) CheckCommandTerminator,
867 (void *) ++requestNum)) == SPC_ERROR)
869 DtSPCClose(cmdChannel);
870 Cmd_FreeAllocatedStringVector (commandArray);
871 (void) strcpy (errorMessage, errorSpcTerminator);
872 XtFree ((char *) tmp);
873 _DtSvcProcessUnlock();
874 return (_CMD_EXECUTE_FAILURE);
877 if ((_DtSPCSpawn(argv[0], context, argv, NULL, cmdChannel,
878 execHost, contextHost, contextDir, errorMessage))
881 DtSPCClose(cmdChannel);
882 (void) sprintf (errorMessage, errorRemoteSubprocess, execHost,
884 Cmd_FreeAllocatedStringVector (commandArray);
885 XtFree ((char *) tmp);
886 _DtSvcProcessUnlock();
887 return (_CMD_EXECUTE_FAILURE);
890 * The command line checking process has been spawned.
891 * There is nothing left to do but to queue the request
892 * and return to the client's main loop. The command
893 * line will be executed after the above spawned process
896 QueueRequest (cmdChannel, context, execHost, execString,
897 commandArray, windowType, requestNum, replyContext,
898 success_proc, success_data, failure_proc, failure_data);
899 _DtSvcProcessUnlock();
901 return (_CMD_EXECUTE_QUEUED);
905 /* LOCAL Execution */
908 * Must first check to see if the execvp will potentially fail.
910 * Since the terminal emulator is pre-appended onto the execution
911 * string, don't want to check it (should have been done during
912 * startup (in _DtInitializeCommandInvoker)) but must check the
913 * execution string that was passed in as part of the message.
915 /* Break the command into something execvp can handle */
916 _DtCmdStringToArrayOfStrings (execString, commandArray2);
918 if (!_DtCmdCheckForExecutable (commandArray2[0]))
920 (void) sprintf (errorMessage, errorExec, commandArray2[0]);
921 Cmd_FreeAllocatedStringVector (commandArray);
922 _DtCmdFreeStringVector (commandArray2);
923 return (_CMD_EXECUTE_FAILURE);
925 _DtCmdFreeStringVector (commandArray2);
928 * Save the current directory and then "chdir" to the directory
929 * to do the execution. If the chdir fails, return.
931 (void) getcwd (tmpDir, MAXPATHLEN);
933 if (!_DtCmdValidDir (_cmdClientHost, contextDir, contextHost))
935 Cmd_FreeAllocatedStringVector (commandArray);
936 (void) sprintf (errorMessage, errorChdir, contextDir, execHost);
937 (void) chdir (tmpDir);
938 return (_CMD_EXECUTE_FAILURE);
942 * Restore the original environment and remove any DT
943 * specific environment variables that were added.
945 (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
947 /* Fork and then execvp the execution string */
948 for (index1 = 0; (index1 < 10) &&
949 ((commandPid = fork ()) < 0); index1++)
951 /* Out of resources ? */
954 /* If not out of resources, sleep and try again */
955 (void) sleep ((unsigned long) 2);
960 Cmd_FreeAllocatedStringVector (commandArray);
961 (void) chdir (tmpDir);
962 (void) sprintf(errorMessage, errorFork, execHost);
963 (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
964 return (_CMD_EXECUTE_FAILURE);
970 #if defined(__hp_osf) || defined(__osf__)
976 if (!terminalRequest )
981 * Close stdout and redirect it to /dev/null. If this
982 * is not done and the request writes to stdout, the
983 * output will be queued in an "unlinked" file in
984 * /tmp until the client using this code terminates.
986 if ((fd = open ("/dev/null", O_RDWR)) > 0)
987 (void) dup2 (fd, fileno (stdout));
991 * Mark file descriptiors >=3 as "Close on Exec".
996 open_max = sysconf(_SC_OPEN_MAX);
1002 #if defined(USL) || defined(__uxp__) || defined(_AIX)
1003 open_max = FOPEN_MAX;
1005 open_max = FD_SETSIZE;
1007 #endif /* _SUN_OS */
1010 for (i=3; i < open_max; i++)
1011 (void) fcntl (i, F_SETFD, 1);
1015 (void) execvp (commandArray[0], commandArray);
1017 /* Should never get here, but if you do, must exit */
1020 * The following message will be written to the errorlog
1021 * file if the request is not a terminal requests or
1022 * to the terminal window if the request requires a
1025 (void) sprintf (errorMessage, errorExec, commandArray[0]);
1026 (void) printf ("%s\n", errorMessage);
1031 * Restore the pre-fork environment.
1033 (void) chdir (tmpDir);
1034 (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
1037 Cmd_FreeAllocatedStringVector (commandArray);
1039 return (_CMD_EXECUTE_SUCCESS);
1042 /******************************************************************************
1044 * CheckCommandTerminator - this is the SPC termination callback
1045 * that is invoked when the command line checking process terminates.
1047 * When this callback is invoked, the next step is to check the
1048 * exit status of the remote checking process and if the "command_
1049 * line" is executable, execute the QueuedRequest. Otherwise,
1052 * PARAMETERS: This parameters for this callback are those defined by
1053 * the type "SPC_TerminateHandlerType". Most are not used.
1055 *****************************************************************************/
1058 CheckCommandTerminator(
1059 SPC_Channel_Ptr cmdChannel,
1060 int pid, /* NOT USED */
1061 int type, /* NOT USED */
1062 int cause, /* Exit value of the remote process. */
1063 unsigned long requestNum) /* Specifies the request number. */
1066 char errorMessage[MAX_BUF_SIZE];
1067 Cmd_RequestQueue *prev = NULL;
1068 Cmd_RequestQueue *pNode = requestQueue;
1070 DtSPCClose(cmdChannel);
1073 * Must find the node in the queue.
1075 for (; pNode != NULL; pNode = pNode->next)
1077 if ( pNode->request_num == requestNum )
1080 * Pluck pNode out of the queue
1083 prev->next = pNode->next;
1085 requestQueue = pNode->next;
1091 * Move alone to the next node
1100 * Check the exit status of the remote process.
1102 if (cause == COMMAND_CHECK_FAILURE)
1104 if (pNode->failure_proc != NULL)
1106 (void) sprintf (errorMessage, errorSpawn, pNode->exec_host,
1107 pNode->exec_string);
1108 if (cmd_Resources.executionHostLogging)
1109 _DtCmdLogErrorMessage (errorMessage);
1110 (*pNode->failure_proc) (errorMessage, pNode->failure_data);
1113 FreeRequest (pNode);
1119 * Re-queue this node -- we will execute the command
1121 pNode->next = requestQueue;
1122 requestQueue = pNode;
1124 ExecuteQueuedRequest (requestNum);
1127 /******************************************************************************
1129 * DtCmdGetWindowType - given a window-type mask, determine its'
1130 * internal window type number.
1132 * It should not be possible for this to be called with a bogus mask,
1136 * unsigned long mask; - The request window type mask
1138 * RETURNS: The window type if one if found, otherwise "-1".
1140 *****************************************************************************/
1144 unsigned long windowTypeMask)
1146 int winTypeNum = -1;
1149 * Determine the winType number recognized by dtexec
1150 * The expected wintype input here is the value of the
1151 * wintype bits in the action mask. Convert this to the
1152 * simple integers expected by dtexec.
1155 switch ( windowTypeMask )
1157 case _DtAct_NO_STDIO_BIT:
1160 case _DtAct_TERMINAL_BIT:
1161 winTypeNum = TERMINAL;
1163 case _DtAct_PERM_TERM_BIT:
1164 winTypeNum = PERM_TERMINAL;
1167 myassert(0); /* should never get here */
1168 winTypeNum = PERM_TERMINAL;
1176 /******************************************************************************
1178 * _DtActionCommandInvoke
1179 * ----------------------
1180 * This is the primary entry point into the command invoker portion
1181 * of the Dt Services library. Command Actions are routed to this
1182 * entry point. This function is used to invoke both local and remote
1185 * If logging is turned on, the success or failure message is logged.
1186 ******************************************************************************/
1188 _DtActionCommandInvoke(
1197 void (*success_proc)(),
1199 void (*failure_proc)(),
1203 char errorMessage[MAX_BUF_SIZE * 2];
1205 status = _DtCmdCommandInvokerExecute (errorMessage, NULL,
1207 cwdHost, cwdDir, NULL,
1208 termOpts, execHost, execString,
1210 success_proc, success_data,
1211 failure_proc, failure_data);
1214 case _CMD_EXECUTE_SUCCESS :
1215 if (cmd_Resources.executionHostLogging && success_data != NULL)
1218 data = (CallbackData *) success_data;
1219 (void) sprintf (errorMessage, successHost,
1220 data->actionLabel, execHost);
1221 _DtCmdLogErrorMessage (errorMessage);
1223 if (success_proc != NULL)
1224 (*success_proc) (NULL, success_data);
1226 case _CMD_EXECUTE_QUEUED :
1228 * Return for now and when the termination handler
1229 * gets hit, the queued request will be executed.
1234 * _CMD_EXECUTE_FAILURE or _CMD_EXECUTE_FATAL
1236 if (cmd_Resources.executionHostLogging)
1237 _DtCmdLogErrorMessage (errorMessage);
1238 if (failure_proc != NULL)
1239 (*failure_proc) (errorMessage, failure_data);
1243 return (status == _CMD_EXECUTE_QUEUED) ? 1 : 0;
1246 /******************************************************************************
1248 * _DtCommandInvokerExecute -
1250 * This function allows a client to use the DT "Command Invoker"
1251 * Library for its' process execution. This function is intended
1252 * for processes which do not use the Action Library.
1254 * For local execution, the "fork" and "execvp" system calls are
1255 * used. For remote execution, the "SPCD" is used.
1257 * RETURNS: Nothing directly. However, if the command is successfully
1258 * executed, the "success_proc" function is executed; otherwise,
1259 * the "failure_proc" function is executed.
1261 * NOTE: This API is NOT public it is only here for use by the Session
1262 * manager which uses to start up remote clients at session restore
1263 * time (see SmRestore.c).
1265 *****************************************************************************/
1268 _DtCommandInvokerExecute(
1273 char *exec_parameters,
1276 DtCmdInvExecuteProc success_proc,
1278 DtCmdInvExecuteProc failure_proc,
1282 _DtSvcAppLock(cmd_Globals.app_context);
1284 _DtActionCommandInvoke(_DtAct_NO_STDIO_BIT,context_host,
1285 context_dir, exec_string, exec_parameters, exec_host,
1287 success_proc,success_data, failure_proc,failure_data);
1288 _DtSvcAppUnlock(cmd_Globals.app_context);
1292 /******************************************************************************
1294 * _DtInitializeCommandInvoker - initialize some global variables and
1295 * and call the appropriate initialization routines.
1299 * Display *display; - The X server connection.
1301 * char *toolClass; - The client's tool class.
1303 * char *appClass; - The client's application class.
1305 * DtSvcMessageProc reloadDBHandler; - The callback function for handling
1306 * a "RELOAD-TYPES-DB" request. (OBSOLETE)
1308 * XtAppContext appContext; - The client's application context.
1312 * SbInputId (*SbAddInput_hookfn); - Set to _DtCmdSPCAddInputHandler
1314 * SbInputId (*SbRemoveInput_hookfn); - Set to XtRemoveInput
1316 * SbInputId (*SbAddException_hookfn); - Set to _DtCmdSPCAddExceptionHandler
1317 * SbInputId (*SbRemoveException_hookfn); - Set to XtRemoveInput
1319 *****************************************************************************/
1322 _DtInitializeCommandInvoker(
1324 char *toolClass, /* ignored */
1325 char *appClass, /* ignored */
1326 DtSvcMessageProc reloadDBHandler, /* OBSOLETE -- ignored */
1327 XtAppContext appContext)
1329 static int beenCalled = 0;
1331 _DtSvcAppLock(appContext);
1334 * Prevent repeat calls
1336 _DtSvcProcessLock();
1338 _DtSvcProcessUnlock();
1344 cmd_Globals.app_context = appContext;
1346 SbAddInput_hookfn = _DtCmdSPCAddInputHandler;
1348 SbRemoveInput_hookfn = XtRemoveInput;
1350 SbAddException_hookfn = _DtCmdSPCAddExceptionHandler;
1352 SbRemoveException_hookfn = XtRemoveInput;
1354 _DtCmdBuildPathList ();
1356 _DtCmdInitializeErrorMessages ();
1359 * Must get the name of the invoking host, so that requests
1360 * can be checked for remote execution.
1362 if ((DtGetShortHostname(_cmdClientHost, MAXHOSTNAMELEN)) == -1) {
1363 _DtCmdLogErrorMessage ("Cannot determine the local host name.\n");
1366 _DtCmdGetResources (display);
1368 _DtSvcProcessUnlock();
1369 _DtSvcAppUnlock(appContext);
1372 /*****************************************************************************
1374 * _DtCmdInitializeErrorMessages - initializes all of the command invoker's
1379 * MODIFIED: all of the Command Invoker's error messages are initialized.
1381 *****************************************************************************/
1384 _DtCmdInitializeErrorMessages( void )
1388 * Non-Fatal -> Abort the request
1390 errorChdir = strdup (((char *)Dt11GETMESSAGE(3, 2, "An attempt to change to the following directory:\n\n %s\n\nfrom host \"%s\" failed.\n\nCheck the spelling and permissions and make sure the directory exists.")));
1392 errorSpawn = strdup (((char *)Dt11GETMESSAGE(3, 5, "An attempt to execute the following command on host\n\"%s\" failed:\n\n %s\n\nCheck that the program exists, has the correct\npermissions and is executable.")));
1394 errorExec = strdup (((char *)Dt11GETMESSAGE(3, 6, "An attempt to execute the following command failed:\n\n %s\n\nCheck that the program exists, has the correct\npermissions and is executable.")));
1396 cmd_Globals.error_terminal = strdup (((char *)Dt11GETMESSAGE(3, 7, "This action cannot be started because the following\nterminal emulator cannot be executed:\n\n %s\n\nCheck that the program exists, has the correct permissions\nand is executable. This problem may have occurred because the\nprogram is not in your \"PATH\".")));
1398 errorLength = strdup (((char *)Dt11GETMESSAGE(3, 9, "The total number of characters in this action exceeds the limit of \"%d\".\n\nYou may need to break the action into more than one action.")));
1400 errorFork = strdup (((char *)Dt11GETMESSAGE(3, 11, "An attempt to start a new process on host \"%s\" failed.\n\nTo continue, you may need to stop an unneeded process on this host.")));
1402 errorRequest = strdup (((char *)Dt11GETMESSAGE(3, 17, "This action's WINDOW_TYPE \"%s\" is un-recognized.\n\nThe WINDOW_TYPE should be one of the following:\n\n %s, %s, %s,\n %s, %s, or %s\n")));
1404 cmd_Globals.error_subprocess = strdup (((char *)Dt11GETMESSAGE(3, 18, "This action cannot be started because the DT subprocess program:\n\n %s\n\ncannot be executed. Check that the program has the correct\npermissions and is executable.")));
1406 errorRemoteSubprocess = strdup (((char *)Dt11GETMESSAGE(3, 20, "This action cannot be executed on host \"%s\"\nbecause the following required program either\ndoes not exist or it is not executable:\n\n %s\n")));
1409 * The following errors may occur when a SPC
1410 * channel is opened.
1412 errorUnknownHost = XtNewString (((char *)Dt11GETMESSAGE(3, 24, "This action cannot be executed because\nhost \"%s\" cannot be reached.")));
1414 errorBadConnect = XtNewString (((char *)Dt11GETMESSAGE(3, 25, "This action cannot be executed on host \"%s\" because the\n\"%s\" service is not properly configured on this host.")));
1416 errorBadService = XtNewString (((char *)Dt11GETMESSAGE(3, 26, "This action cannot be executed because the \"%s\"\nservice is not configured on host \"%s\".")));
1418 errorRegisterHandshake = XtNewString (((char *)Dt11GETMESSAGE(3, 27, "This action cannot be executed on host \"%s\" because user\n\"%s\" has a user id of \"%d\" on host \"%s\" and this does\nnot match the username and user id on the action\ninvocation host \"%s\".")));
1420 errorRegisterUsername = XtNewString (((char *)Dt11GETMESSAGE(3, 28, "This action cannot be executed on host \"%s\" because\nuser \"%s\" does not have an account on this host.")));
1422 errorRegisterNetrc = XtNewString (((char *)Dt11GETMESSAGE(3, 29, "This action cannot be executed on host \"%s\" because\na pathname to the authentication file cannot be created.")));
1424 errorRegisterOpen = XtNewString (((char *)Dt11GETMESSAGE(3, 30, "This action cannot be executed on host \"%s\" because\nthe authentication file on this host cannot be opened.\n\nThis may be caused by your network home not being\nproperly configured.")));
1426 errorEnvTooBig = XtNewString (((char *)Dt11GETMESSAGE(3, 31, "This action cannot be executed on host \"%s\" because\nthe environment exceeds \"%d\" bytes.")));
1428 errorInetSecurity = XtNewString (((char *)Dt11GETMESSAGE(3, 32, "This action cannot be executed on host \"%s\" because\nhost \"%s\" is not authorized to use the \"%s\" service.\n\nTo fix this, add host \"%s\" to the \"%s\" service\nentry in file \"%s\" on host \"%s\".")));
1431 * Do not post a dialog, write to the error log file only.
1434 errorSpcTerminator = strdup (((char *)Dt11GETMESSAGE(3, 15, "An attempt to register the output log from a remote host failed.\n\nTo continue, you may need to stop an existing process.")));
1436 successHost = strdup (((char *)Dt11GETMESSAGE(3, 21, "The action \"%s\" was successfully executed on host \"%s\".")));
1438 cmd_Globals.error_directory_name_map = strdup (((char *)Dt11GETMESSAGE(3, 22, "The directory \"%s\" on host \"%s\"\ncould not be converted to a network path.\n(%s)")));