Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / CmdMain.c
1 /* $TOG: CmdMain.c /main/15 1998/04/20 12:46:37 mgreess $ */
2 /* 
3  * (c) Copyright 1997, The Open Group 
4  */
5 /***************************************************************************
6 *
7 * File:         CmdMain.c
8 * Description:  Command execution system
9 * Language:     C
10 *
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 ***************************************************************************/
16
17 #include "CmdInvP.h"
18 #include <Dt/CmdInv.h>
19
20 #include <fcntl.h>
21 #ifdef __apollo
22 #include "/sys5/usr/include/sys/termio.h"
23 #else
24 #include <termio.h>
25 #endif
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #ifdef _SUN_OS   /* to get the define for NOFILE */
30 #include <sys/param.h>
31 #endif /* _SUN_OS */
32 #define X_INCLUDE_PWD_H
33 #define XOS_USE_XT_LOCKING
34 #include <X11/Xos_r.h>
35
36 #include <Dt/CommandM.h>
37 #include <Dt/EnvControlP.h>
38 #include <Dt/DtNlUtils.h>
39
40 #include <Dt/ActionDb.h>
41 #include <Dt/ActionUtilP.h>
42 #include "myassertP.h"
43 #include "DtSvcLock.h"
44
45 #include <SPC/spcE.h>
46 #include <SPC/spcP.h>
47 #include <SPC/spc-proto.h>
48 #include <Tt/tt_c.h>
49
50 #define MAX_EXEC_ARGS           1000    /* Maximum number of arguments for */
51                                         /* execvp call. */
52 /*
53  * Dtexec return status:
54  */
55 #define COMMAND_CHECK_FAILURE           1
56
57 #ifdef __hpux
58 #ifdef hpV4
59 #define INETD_SECURITY_FILE     "/var/adm/inetd.sec"
60 #else /* hpV4 */
61 #define INETD_SECURITY_FILE     "/usr/adm/inetd.sec"
62 #endif /* hpV4 */
63 #endif /* __hpux */
64
65 #define Cmd_FreeAllocatedStringVector(sv) \
66                 _DtCmdFreeStringVector(sv);\
67                 XtFree((char *)sv);
68
69 /*
70  * Global variables for the Command Invoker.
71  */
72 static char _cmdClientHost[MAXHOSTNAMELEN];
73
74 /*
75  * Static variables for the Command Invoker.
76  */
77 static Cmd_RequestQueue *requestQueue = NULL;
78
79 /*
80  * Static function declarations:.
81  */
82
83 static void QueueRequest (
84                         SPC_Channel_Ptr channel,
85                         char *context,
86                         char *execHost,
87                         char *execString,
88                         char **argv,
89                         int  windowType,
90                         unsigned long requestNum,
91                         DtSvcMsgContext replyContext,
92                         DtCmdInvExecuteProc success_proc,
93                         void *success_data,
94                         DtCmdInvExecuteProc failure_proc,
95                         void *failure_data);
96 static void ExecuteQueuedRequest ( 
97                         unsigned long requestNum);
98
99 static void FreeRequest (Cmd_RequestQueue *pNode);
100                         
101 static void DtexecTerminator (
102                         SPC_Channel_Ptr cmdChannel,
103                         int pid,
104                         int type,
105                         int cause,
106                         unsigned long ind) ;
107 static void CheckCommandTerminator (
108                         SPC_Channel_Ptr cmdChannel,
109                         int pid,
110                         int type,
111                         int cause,
112                         unsigned long ind) ;
113 static int DtCmdGetWindowType(
114         unsigned long windowTypeMask);
115 static void _DtCmdInitializeErrorMessages(void);
116
117 /*
118  * Command invocatin error messages.
119  */
120 static char     *errorExec,
121                 *errorSpawn,
122                 *errorFork,
123                 *errorSpcTerminator,
124                 *errorLength,
125                 *errorRequest,
126                 *errorChdir,
127                 *errorRemoteSubprocess,
128                 *errorUnknownHost,
129                 *errorBadConnect,
130                 *errorBadService,
131                 *errorRegisterHandshake,
132                 *errorRegisterUsername,
133                 *errorRegisterNetrc,
134                 *errorRegisterOpen,
135                 *errorEnvTooBig,
136                 *errorInetSecurity,
137                 *successHost;
138
139 /*******************************************************************************
140  *
141  * _DtSPCSpawn()
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.
146  *
147  ******************************************************************************/
148
149 int
150 _DtSPCSpawn( 
151         char            *path, 
152         char            *cwd,
153         char            **args,
154         char            **env,
155         SPC_Channel_Ptr chan,
156         char            *execHost,
157         char            *contextHost,
158         char            *contextDir,
159         char            *errorMessage)
160 {
161         int     retVal;
162
163         /*
164          * Restore the original environment
165          */
166         (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
167
168         /*
169          * Map some env var paths to execHost.
170          */
171         (void) _DtEnvMapForRemote(execHost);
172
173         if ((retVal = XeSPCSpawn(path,
174                                  cwd,
175                                  args,
176                                  env,
177                                  chan)) == SPC_ERROR)
178         {
179                 switch (DtSPCErrorNumber) 
180                 {
181                         case SPC_cannot_Chdir:
182                                 (void) sprintf (errorMessage, 
183                                                 errorChdir, 
184                                                 contextDir, 
185                                                 execHost);
186                                 break;
187                         case SPC_Cannot_Fork:
188                                 (void) sprintf (errorMessage, 
189                                                 errorFork, 
190                                                 execHost);
191                                 break;
192                         case SPC_Env_Too_Big:
193                         case SPC_Arg_Too_Long:
194                                 (void) sprintf (errorMessage, 
195                                                 errorLength, 
196                                                 SPC_BUFSIZ);
197                                 break;
198                         default:
199                                 /*
200                                  * SPC_Cannot_Exec
201                                  */
202                                 (void) sprintf (errorMessage, 
203                                                 errorSpawn,
204                                                 execHost,
205                                                 path);
206                 }
207         }
208
209         /*
210          * Restore some env var paths.
211          */
212         (void) _DtEnvRestoreLocal();
213
214         /*
215          * Restore the DT environment
216          */
217         (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
218
219         /*
220          * Return the result of DtSPCSpawn
221          */
222         return retVal;
223 }
224
225 /*******************************************************************************
226  *
227  * _DtSPCOpen()
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.
232  *
233  ******************************************************************************/
234 SPC_Channel_Ptr
235 _DtSPCOpen(
236         char *hostname, 
237         int iomode, 
238         char *errorMessage)
239 {
240         SPC_Channel_Ptr chan;
241         _Xgetpwparams   pwd_buf;
242         struct passwd * pwd_ret;
243
244         /*
245          * Restore the original environment
246          */
247         (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
248
249         /*
250          * Map some env var paths to execHost.
251          */
252         (void) _DtEnvMapForRemote(hostname);
253
254         if ((chan = XeSPCOpen(hostname, iomode)) == SPC_ERROR)
255         {
256                 uid_t           this_uid;
257                 char            *username;
258
259                 switch (DtSPCErrorNumber) 
260                 {
261                         case SPC_Unknown_Host:
262                                 (void) sprintf (errorMessage, 
263                                                 errorUnknownHost,
264                                                 hostname);
265                                 break;
266                         case SPC_Bad_Connect:
267                                 (void) sprintf (errorMessage, 
268                                                 errorBadConnect,
269                                                 hostname,
270                                                 SPC_SERVICE,
271                                                 _cmdClientHost);
272                                 break;
273                         case SPC_Bad_Service:
274                                 (void) sprintf (errorMessage, 
275                                                 errorBadService,
276                                                 SPC_SERVICE,
277                                                 _cmdClientHost);
278                                 break;
279                         case SPC_Register_Handshake:
280                                 this_uid = getuid();
281                                 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == 
282                                    NULL)
283                                         username = NULL;
284                                 else
285                                         username = pwd_ret->pw_name;
286                                 (void) sprintf (errorMessage, 
287                                                 errorRegisterHandshake,
288                                                 hostname,
289                                                 username,
290                                                 this_uid,
291                                                 _cmdClientHost,
292                                                 hostname);
293                                 break;
294                         case SPC_Register_Username:
295                                 this_uid = getuid();
296                                 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == 
297                                    NULL)
298                                         username = NULL;
299                                 else
300                                         username = pwd_ret->pw_name;
301                                 (void) sprintf (errorMessage, 
302                                                 errorRegisterUsername,
303                                                 hostname,
304                                                 username);
305                                 break;
306                         case SPC_Register_Netrc:
307                                 (void) sprintf (errorMessage, 
308                                                 errorRegisterNetrc,
309                                                 hostname);
310                                 break;
311                         case SPC_Env_Too_Big:
312                                 (void) sprintf (errorMessage, 
313                                                 errorEnvTooBig,
314                                                 hostname,
315                                                 SPC_BUFSIZ);
316                                 break;
317                         case SPC_Connection_EOF:
318 #ifdef __hpux
319                                 (void) sprintf (errorMessage, 
320                                                 errorInetSecurity,
321                                                 hostname,
322                                                 _cmdClientHost,
323                                                 SPC_SERVICE,
324                                                 _cmdClientHost,
325                                                 SPC_SERVICE,
326                                                 INETD_SECURITY_FILE,
327                                                 hostname);
328
329 #else /* __hpux */
330                                 (void) sprintf (errorMessage, 
331                                                 errorBadConnect,
332                                                 hostname,
333                                                 SPC_SERVICE,
334                                                 _cmdClientHost);
335 #endif /* __hpux */
336                                 break;
337                         default:
338                                 /*
339                                  * SPC_Register_Open:
340                                  */
341                                 (void) sprintf (errorMessage, 
342                                                 errorRegisterOpen,
343                                                 hostname);
344                 }
345         }
346         
347         /*
348          * Restore some env var paths.
349          */
350         (void) _DtEnvRestoreLocal();
351
352         /*
353          * Restore the DT environment
354          */
355         (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
356         
357         return chan;
358 }
359
360
361 /******************************************************************************
362  *
363  * QueueRequest - takes the "state" from a request and puts it on the
364  *   "requestQueue".
365  *
366  * PARAMETERS:
367  *
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.
381  *
382  * MODIFIED:
383  *
384  *   Cmd_RequestQueue *requestQueue;            - This request to added.
385  *
386  *****************************************************************************/
387
388 static void
389 QueueRequest (
390         SPC_Channel_Ptr channel,
391         char *context,
392         char *execHost,
393         char *execString,
394         char **argv,
395         int  winType,
396         unsigned long requestNum,
397         DtSvcMsgContext replyContext,
398         DtCmdInvExecuteProc success_proc,
399         void *success_data,
400         DtCmdInvExecuteProc failure_proc,
401         void *failure_data)
402
403 {
404    Cmd_RequestQueue *pNode;
405    Cmd_RequestQueue *pNewNode;
406
407    pNewNode = (Cmd_RequestQueue *) XtMalloc (sizeof (Cmd_RequestQueue));
408
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;
419    else
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;
425
426    if (requestQueue == NULL) 
427    {
428       requestQueue = pNewNode;
429       return;
430    }
431
432    /*
433     * Find the End Of the Queue and link in the NewNode.
434     */
435    for (pNode = requestQueue; pNode->next != NULL; pNode = pNode->next);
436
437    pNode->next = pNewNode;
438
439 }
440
441 /******************************************************************************
442  *
443  * ExecuteQueuedRequest - given a key into the requestQueue (requestNum)
444  *   find the appropriate request and execute it.
445  *
446  * PARAMETERS:
447  *
448  *   unsigned long      requestNum;             - Key into the requestQueue.
449  *
450  * MODIFIED:
451  *
452  *   Cmd_RequestQueue   *requestQueue;          - The executed request gets
453  *                                                freed.
454  *
455  *****************************************************************************/
456
457 static void
458 ExecuteQueuedRequest (
459         unsigned long requestNum)
460 {
461    char                 *errorMessage;
462    Boolean              success = True;
463    Cmd_RequestQueue     *prev  = NULL;
464    Cmd_RequestQueue     *pNode = requestQueue;
465    unsigned long        iomode;
466
467    for (; pNode != NULL; pNode = pNode->next)
468    {
469        if ( pNode->request_num == requestNum )
470        {
471            /*
472             * Pluck pNode out of the queue
473             */
474            if (prev)
475                prev->next = pNode->next;
476            else
477                requestQueue = pNode->next;
478
479            pNode->next = NULL;
480            break;
481        }
482        /*
483         * Move alone to the next node
484         */
485        prev = pNode;
486    }
487
488    if (pNode == NULL)
489       return;
490
491    errorMessage = XtMalloc (MAX_BUF_SIZE * sizeof (char));
492
493    /*
494     *  Reopen SPC Channel
495     */
496
497
498    iomode = ( SPCIO_NOIO 
499             | SPCIO_SYNC_TERMINATOR 
500             | SPCIO_FORCE_CONTEXT );
501
502    
503    if ((pNode->channel = (_DtSPCOpen(pNode->exec_host, 
504           iomode,
505           errorMessage))) == SPC_ERROR) 
506       {
507          success = False;
508       }
509
510    if ( success )
511        if ((_DtSPCSpawn(pNode->argv[0], pNode->context, pNode->argv, NULL, 
512                     pNode->channel, pNode->exec_host, NULL, NULL,
513                     errorMessage)) == SPC_ERROR) 
514        {
515           success = False;
516           if (DtSPCErrorNumber != SPC_Arg_Too_Long)
517              DtSPCClose(pNode->channel);
518        }
519
520    if (success && pNode->success_proc != NULL)
521    {
522       if (cmd_Resources.executionHostLogging && pNode->success_data != NULL)
523       {
524          CallbackData *data;
525          data = (CallbackData *) pNode->success_data;
526          (void) sprintf (errorMessage, successHost, 
527                          data->actionLabel, pNode->exec_host);
528          _DtCmdLogErrorMessage (errorMessage);
529       }
530
531       (*pNode->success_proc) (NULL, pNode->success_data);
532    }
533    else if (!success)
534    {
535       if (cmd_Resources.executionHostLogging)
536       {
537          if (DtSPCErrorNumber == SPC_Arg_Too_Long)
538          {
539             int cmdlen,i;
540             char *cmdp; /* pointer to complete command string */
541             char *tmp_message;
542
543             /*
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.
549              */
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 */
553             }
554          
555             tmp_message = (char *) XtMalloc (strlen (errorSpawn) + 
556                                              strlen (pNode->exec_host) +
557                                              cmdlen + 4);
558             cmdp = (char *) XtMalloc(cmdlen + 1);
559             *cmdp = NULL;
560             for (i = 0; pNode->argv[i]; i++) {
561                strcat(cmdp,pNode->argv[i]);
562                strcat(cmdp, " ");
563             }
564             (void) sprintf (tmp_message, errorSpawn, pNode->exec_host, cmdp);
565             _DtCmdLogErrorMessage (tmp_message);
566             XtFree(cmdp);
567             XtFree(tmp_message);
568          }
569       }
570       if (pNode->failure_proc != NULL)
571          (*pNode->failure_proc) (errorMessage, pNode->failure_data);
572    }
573
574    XtFree ((char *)errorMessage);
575    FreeRequest (pNode);
576 }
577
578 Cmd_RequestQueue *
579 _DtCmdGetQueueHead(void)
580 {
581         return requestQueue;
582 }
583
584 /******************************************************************************
585  *
586  * FreeRequest - Frees the malloced data associated with the node.
587  *               and frees the node.
588  *
589  * PARAMETERS:
590  *
591  *  Cmd_RequestQueue *pNode
592  *
593  *
594  *****************************************************************************/
595
596 static void
597 FreeRequest (Cmd_RequestQueue *pNode)
598 {
599
600    if (pNode == NULL)
601       return;
602
603    XtFree (pNode->context);
604    XtFree (pNode->exec_host);
605    XtFree (pNode->exec_string);
606    Cmd_FreeAllocatedStringVector (pNode->argv);
607
608    XtFree ((char *) pNode);
609 }
610
611 /******************************************************************************
612  *
613  * _DtCmdCommandInvokerExecute - executes a request on the specified host.
614  *
615  * RETURNS:  int
616  *
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
621  *
622  *
623  *****************************************************************************/
624
625 int
626 _DtCmdCommandInvokerExecute (
627         char *errorMessage,             /* MODIFIED */
628         DtSvcMsgContext replyContext,   /* OBSOLETE -- always NULL */
629         int  winMask,
630         char *contextHost,
631         char *contextDir,
632         char *contextFile,              /* OBSOLETE -- always NULL */
633         char *execParms,
634         char *execHost,
635         char *execString,
636         char *procId,
637         char *tmpFiles,
638         DtCmdInvExecuteProc success_proc,
639         void *success_data,
640         DtCmdInvExecuteProc failure_proc,
641         void *failure_data)
642
643 {
644    int ioMode, i, index1;
645    int windowType;
646    pid_t commandPid;
647    char context[MAXPATHLEN];
648    char tmpDir [MAXPATHLEN];
649    char **commandArray;
650    SPC_Channel_Ptr cmdChannel;
651    char *theCommand = NULL;
652    Boolean terminalRequest = False;
653    char *commandArray2[MAX_EXEC_ARGS];
654    Boolean localExecution = True;
655    Boolean xhostError;
656    static unsigned long requestNum = 0;
657    char *toolRequest = NULL;    /* backward compatibility kludge */
658
659
660    myassert( !(contextFile && replyContext) );
661
662    /*
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.
666     */
667    if ((windowType=
668         DtCmdGetWindowType(winMask))== -1) 
669    {
670       (void) sprintf (errorMessage, errorRequest, toolRequest, 
671                       DtTERMINAL, DtPERM_TERMINAL, DtOUTPUT_ONLY, 
672                       DtSHARED_OUTPUT, "" /* Obsolete shell window */,
673                       DtNO_STDIO);
674       return (_CMD_EXECUTE_FATAL);
675    }
676
677    /* 
678     * Create the command to be exec'ed.
679     */
680    if (windowType == PERM_TERMINAL || windowType == TERMINAL) 
681    {
682       _DtCmdCreateTerminalCommand (&theCommand, windowType, execString, 
683          execParms, execHost, procId, tmpFiles);
684       terminalRequest = True;
685    }
686    else 
687    {
688       /* 
689        * NO-STDIO || START-SESSION request.
690        */
691       
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 */);
699
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), 
705           execString);
706
707    }
708
709    /*
710     * See if the request requires Remote Execution.
711     */
712    localExecution = _DtIsSameHost(execHost,NULL);
713
714    /*
715     * If this is a terminalRequest and the Command Invoker subprocess
716     * is not executable, return now.
717     */
718    if (localExecution && terminalRequest && !cmd_Globals.subprocess_ok) 
719    {
720       if (!(_DtCmdCheckForExecutable (cmd_Resources.dtexecPath))) 
721       {
722          (void) sprintf (errorMessage, cmd_Globals.error_subprocess,
723                          cmd_Resources.dtexecPath);
724          XtFree ((char *) theCommand);
725          return (_CMD_EXECUTE_FAILURE);
726       }
727       else
728          cmd_Globals.subprocess_ok = True;
729    }
730
731    /*
732     * If this is a terminalRequest and the terminal emulator
733     * is not executable, return now.
734     */
735    if (localExecution && terminalRequest && !cmd_Globals.terminal_ok) 
736    {
737       if (!(_DtCmdCheckForExecutable (cmd_Resources.localTerminal))) 
738       {
739          (void) sprintf (errorMessage, cmd_Globals.error_terminal, 
740                          cmd_Resources.localTerminal);
741          XtFree ((char *) theCommand);
742          return (_CMD_EXECUTE_FAILURE);
743       }
744       else
745          cmd_Globals.terminal_ok = True;
746    }
747
748    /* 
749     * Break the command into something execvp or SPCSpawn can handle
750     * and then free "theCommand" if this is a termianl-based request.
751     */
752    commandArray = (char **) XtMalloc (MAX_EXEC_ARGS * sizeof (char *));
753    _DtCmdStringToArrayOfStrings (theCommand, commandArray);
754
755    XtFree (theCommand);
756
757    if (!localExecution) 
758    {
759       char *netfile;
760       char *argv[4];
761       char *tmp;
762
763       /* REMOTE Execution */
764
765       ioMode = SPCIO_NOIO | SPCIO_SYNC_TERMINATOR | SPCIO_FORCE_CONTEXT;
766
767       if ((cmdChannel = (_DtSPCOpen(execHost, 
768                          ioMode, 
769                          errorMessage))) == SPC_ERROR) 
770       {
771          Cmd_FreeAllocatedStringVector (commandArray);
772          return (_CMD_EXECUTE_FAILURE);
773       }
774
775       /* Old syntax should no longer appear in contextHost/Dir */
776       myassert( (contextHost?*contextHost != '*':1) && 
777                 (contextDir?*contextDir != '*':1) );
778       /* 
779        * Create a "netfile" for the cwd to be used.
780        */
781       netfile = (char *) tt_host_file_netfile (
782          ((contextHost == NULL) ? execHost : contextHost),
783          ((contextDir  == NULL) ? (char *) getenv ("HOME") : contextDir));
784
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);
792       }
793       (void) strcpy (context, netfile);
794       tt_free (netfile);
795
796      /*
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.
800       *
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.
804       */
805
806      argv[0] = cmd_Resources.dtexecPath;
807      argv[1] = (char *) NULL;
808
809      if ((_DtSPCSpawn(argv[0], context, argv, NULL, cmdChannel,
810                       execHost, contextHost, contextDir, errorMessage)) 
811           == SPC_ERROR) 
812      {
813         if (DtSPCErrorNumber != SPC_cannot_Chdir &&
814             DtSPCErrorNumber != SPC_Cannot_Fork  &&
815             DtSPCErrorNumber != SPC_Env_Too_Big  &&
816             DtSPCErrorNumber != SPC_Arg_Too_Long)
817            /*
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.
822             */
823            (void) sprintf (errorMessage, errorRemoteSubprocess, execHost, 
824                            cmd_Resources.dtexecPath);
825         DtSPCClose(cmdChannel);
826         Cmd_FreeAllocatedStringVector (commandArray);
827         return (_CMD_EXECUTE_FAILURE);
828      }
829
830      /* The dtexec process is now known to exist on the remote host */
831
832      /*
833       *  Now run a test to see if the command is executable
834       *  on this exec host.
835       */
836      _DtCmdStringToArrayOfStrings (execString, commandArray2);
837
838      tmp = (char *) XtMalloc (strlen (commandArray2[0]) +
839                              strlen ("whence ") + 2);
840      (void) sprintf (tmp, "whence %s", commandArray2[0]);
841
842      _DtCmdFreeStringVector (commandArray2);
843
844      argv[0] = "ksh";
845      argv[1] = "-c";
846      argv[2] = tmp;
847      argv[3] = (char *) NULL;
848
849      /*
850       * Reopen the channel
851       */
852      if ((cmdChannel = (_DtSPCOpen(execHost, 
853                          ioMode, 
854                          errorMessage))) == SPC_ERROR) 
855       {
856          Cmd_FreeAllocatedStringVector (commandArray);
857          return (_CMD_EXECUTE_FAILURE);
858       }
859
860       /* 
861        * Set up a callback to be invoked when the test command 
862        * terminates.
863        */
864       _DtSvcProcessLock();
865       if ((DtSPCRegisterTerminator(cmdChannel,
866                     (SPC_TerminateHandlerType) CheckCommandTerminator,
867                     (void *) ++requestNum)) == SPC_ERROR) 
868       {
869         DtSPCClose(cmdChannel);
870         Cmd_FreeAllocatedStringVector (commandArray);
871         (void) strcpy (errorMessage, errorSpcTerminator);
872         XtFree ((char *) tmp);
873         _DtSvcProcessUnlock();
874         return (_CMD_EXECUTE_FAILURE);
875       }
876       
877       if ((_DtSPCSpawn(argv[0], context, argv, NULL, cmdChannel,
878                       execHost, contextHost, contextDir, errorMessage)) 
879           == SPC_ERROR) 
880       {
881         DtSPCClose(cmdChannel);
882         (void) sprintf (errorMessage, errorRemoteSubprocess, execHost,
883                 argv[0]);
884         Cmd_FreeAllocatedStringVector (commandArray);
885         XtFree ((char *) tmp);
886         _DtSvcProcessUnlock();
887         return (_CMD_EXECUTE_FAILURE);
888       }
889       /* 
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
894        * terminates.
895        */
896       QueueRequest (cmdChannel, context, execHost, execString, 
897               commandArray, windowType, requestNum, replyContext,
898               success_proc, success_data, failure_proc, failure_data);
899       _DtSvcProcessUnlock();
900       XtFree(tmp);
901       return (_CMD_EXECUTE_QUEUED);
902    }
903    else 
904    {     
905       /* LOCAL Execution */
906
907       /* 
908        * Must first check to see if the execvp will potentially fail.
909        *
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.
914        */
915      /* Break the command into something execvp can handle */
916        _DtCmdStringToArrayOfStrings (execString, commandArray2);
917
918       if (!_DtCmdCheckForExecutable (commandArray2[0])) 
919       {
920          (void) sprintf (errorMessage, errorExec, commandArray2[0]);
921          Cmd_FreeAllocatedStringVector (commandArray);
922          _DtCmdFreeStringVector (commandArray2);
923          return (_CMD_EXECUTE_FAILURE);
924       }
925       _DtCmdFreeStringVector (commandArray2);
926
927       /*
928        * Save the current directory and then "chdir" to the directory
929        * to do the execution.  If the chdir fails, return.
930        */
931       (void) getcwd (tmpDir, MAXPATHLEN);
932
933       if (!_DtCmdValidDir (_cmdClientHost, contextDir, contextHost)) 
934       {
935          Cmd_FreeAllocatedStringVector (commandArray);
936          (void) sprintf (errorMessage, errorChdir, contextDir, execHost);
937          (void) chdir (tmpDir);
938          return (_CMD_EXECUTE_FAILURE);
939       }
940
941       /*
942        * Restore the original environment and remove any DT
943        * specific environment variables that were added.
944        */
945       (void) _DtEnvControl (DT_ENV_RESTORE_PRE_DT);
946
947       /* Fork and then execvp the execution string */
948       for (index1 = 0; (index1 < 10) && 
949                ((commandPid = fork ()) < 0); index1++) 
950       {
951          /* Out of resources ? */
952          if (errno != EAGAIN) 
953             break;
954          /* If not out of resources, sleep and try again */
955          (void) sleep ((unsigned long) 2);
956       }
957
958       if (commandPid < 0) 
959       {
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);
965       }
966
967       if (commandPid == 0) 
968       {
969
970 #if defined(__hp_osf) || defined(__osf__)
971          setsid() ;
972 #else
973          (void) setpgrp ();
974 #endif
975         
976          if (!terminalRequest ) 
977          {
978             int fd;
979
980             /*
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.
985              */
986             if ((fd = open ("/dev/null", O_RDWR)) > 0)
987                (void) dup2 (fd, fileno (stdout));
988          }
989
990          /* 
991           * Mark file descriptiors >=3 as "Close on Exec".
992           */
993          {
994            long open_max;
995
996            open_max = sysconf(_SC_OPEN_MAX);
997            if (open_max == -1)
998            {
999 #ifdef _SUN_OS
1000              open_max = NOFILE;
1001 #else
1002 #if defined(USL) || defined(__uxp__) || defined(_AIX)
1003              open_max = FOPEN_MAX;
1004 #else
1005              open_max = FD_SETSIZE;
1006 #endif
1007 #endif /* _SUN_OS */
1008            }
1009
1010            for (i=3; i < open_max; i++)
1011                (void) fcntl (i, F_SETFD, 1);
1012          }
1013
1014
1015          (void) execvp (commandArray[0], commandArray);
1016          
1017          /* Should never get here, but if you do, must exit */
1018
1019          /*
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
1023           * terminal.
1024           */
1025          (void) sprintf (errorMessage, errorExec, commandArray[0]);
1026          (void) printf ("%s\n", errorMessage);
1027          (void) _exit (1);
1028       }
1029
1030       /*
1031        * Restore the pre-fork environment.
1032        */
1033       (void) chdir (tmpDir);
1034       (void) _DtEnvControl (DT_ENV_RESTORE_POST_DT);
1035    }
1036
1037    Cmd_FreeAllocatedStringVector (commandArray);
1038
1039    return (_CMD_EXECUTE_SUCCESS);
1040 }
1041
1042 /******************************************************************************
1043  *
1044  * CheckCommandTerminator - this is the SPC termination callback 
1045  *   that is invoked when the command line checking process terminates.  
1046  *
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,
1050  *   return.
1051  *
1052  * PARAMETERS:  This parameters for this callback are those defined by
1053  *   the type "SPC_TerminateHandlerType".  Most are not used.
1054  *
1055  *****************************************************************************/
1056
1057 static void 
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. */
1064 {
1065    Boolean xhostError;
1066    char errorMessage[MAX_BUF_SIZE];
1067    Cmd_RequestQueue *prev  = NULL;
1068    Cmd_RequestQueue *pNode = requestQueue;
1069
1070    DtSPCClose(cmdChannel);
1071
1072    /*
1073     * Must find the node in the queue.
1074     */
1075    for (; pNode != NULL; pNode = pNode->next)
1076    {
1077        if ( pNode->request_num == requestNum )
1078        {
1079            /*
1080             * Pluck pNode out of the queue
1081             */
1082            if (prev)
1083                prev->next = pNode->next;
1084            else
1085                requestQueue = pNode->next;
1086
1087            pNode->next = NULL;
1088            break;
1089        }
1090        /*
1091         * Move alone to the next node
1092         */
1093        prev = pNode;
1094    }
1095
1096    if (pNode == NULL)
1097       return;
1098
1099    /*
1100     * Check the exit status of the remote process.
1101     */
1102    if (cause == COMMAND_CHECK_FAILURE)
1103    {
1104       if (pNode->failure_proc != NULL)
1105       {
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);
1111       }
1112
1113       FreeRequest (pNode);
1114
1115       return;
1116    }
1117
1118     /*
1119      * Re-queue this node -- we will execute the command
1120      */
1121     pNode->next = requestQueue;
1122     requestQueue = pNode;
1123
1124     ExecuteQueuedRequest (requestNum);
1125 }
1126
1127 /******************************************************************************
1128  * 
1129  * DtCmdGetWindowType - given a window-type mask, determine its'
1130  *   internal window type number.
1131  *
1132  * It should not be possible for this to be called with a bogus mask, 
1133  *
1134  * PARAMETERS:
1135  *
1136  *   unsigned long mask;        - The request window type mask
1137  *
1138  * RETURNS: The window type if one if found, otherwise "-1".
1139  *
1140  *****************************************************************************/
1141
1142 static int 
1143 DtCmdGetWindowType(
1144         unsigned long windowTypeMask) 
1145 {
1146         int winTypeNum = -1;
1147
1148         /*
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.
1153          */
1154
1155         switch ( windowTypeMask )
1156         {
1157         case _DtAct_NO_STDIO_BIT:
1158                 winTypeNum = NULL;
1159                 break;
1160         case _DtAct_TERMINAL_BIT:
1161                 winTypeNum = TERMINAL;
1162                 break;
1163         case _DtAct_PERM_TERM_BIT:
1164                 winTypeNum = PERM_TERMINAL;
1165                 break;
1166         default:
1167                 myassert(0);    /* should never get here */
1168                 winTypeNum = PERM_TERMINAL;
1169                 break;
1170         } 
1171
1172         
1173         return winTypeNum;
1174 }
1175
1176 /******************************************************************************
1177  *
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 
1183  *      commands.
1184  *
1185  *      If logging is turned on, the success or failure message is logged.
1186  ******************************************************************************/
1187 int
1188 _DtActionCommandInvoke(
1189         long wintype,
1190         char * cwdHost,
1191         char * cwdDir,
1192         char * execString,
1193         char * termOpts,
1194         char * execHost,
1195         char * procId,
1196         char * tmpFiles,
1197         void (*success_proc)(),
1198         void *success_data,
1199         void (*failure_proc)(),
1200         void *failure_data)
1201 {
1202         int status;
1203         char errorMessage[MAX_BUF_SIZE * 2];
1204
1205         status = _DtCmdCommandInvokerExecute (errorMessage, NULL, 
1206                                wintype, 
1207                                cwdHost, cwdDir, NULL,
1208                                termOpts, execHost, execString,
1209                                procId, tmpFiles,
1210                                success_proc, success_data,
1211                                failure_proc, failure_data);
1212         switch (status)
1213         {
1214         case _CMD_EXECUTE_SUCCESS :
1215                 if (cmd_Resources.executionHostLogging && success_data != NULL)
1216                 {
1217                         CallbackData *data;
1218                         data = (CallbackData *) success_data;
1219                         (void) sprintf (errorMessage, successHost, 
1220                                 data->actionLabel, execHost);
1221                         _DtCmdLogErrorMessage (errorMessage);
1222                 }
1223                 if (success_proc != NULL)
1224                         (*success_proc) (NULL, success_data);
1225                 break;
1226         case _CMD_EXECUTE_QUEUED :
1227                  /*
1228                   * Return for now and when the termination handler
1229                   * gets hit, the queued request will be executed.
1230                   */
1231                  break;
1232         default :
1233                  /*
1234                   * _CMD_EXECUTE_FAILURE or _CMD_EXECUTE_FATAL
1235                   */
1236                 if (cmd_Resources.executionHostLogging)
1237                         _DtCmdLogErrorMessage (errorMessage);
1238                 if (failure_proc != NULL)
1239                         (*failure_proc) (errorMessage, failure_data);
1240                 break;
1241         }
1242
1243         return (status == _CMD_EXECUTE_QUEUED) ? 1 : 0;
1244 }
1245
1246 /******************************************************************************
1247  *
1248  * _DtCommandInvokerExecute -
1249  *
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.
1253  *
1254  *   For local execution, the "fork" and "execvp" system calls are
1255  *   used.  For remote execution, the "SPCD" is used.
1256  *
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.
1260  *
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).  
1264  *
1265  *****************************************************************************/
1266
1267 void
1268 _DtCommandInvokerExecute(
1269         char *request_name,
1270         char *context_host,
1271         char *context_dir,
1272         char *context_file,
1273         char *exec_parameters,
1274         char *exec_host,
1275         char *exec_string,
1276         DtCmdInvExecuteProc success_proc,
1277         void *success_data,
1278         DtCmdInvExecuteProc failure_proc,
1279         void *failure_data)
1280
1281 {
1282    _DtSvcAppLock(cmd_Globals.app_context);
1283
1284    _DtActionCommandInvoke(_DtAct_NO_STDIO_BIT,context_host,
1285                 context_dir, exec_string, exec_parameters, exec_host,
1286                 NULL, NULL,
1287                 success_proc,success_data, failure_proc,failure_data);
1288    _DtSvcAppUnlock(cmd_Globals.app_context);
1289                 
1290 }
1291
1292 /******************************************************************************
1293  *
1294  * _DtInitializeCommandInvoker - initialize some global variables and
1295  *   and call the appropriate initialization routines.
1296  *
1297  * PARAMETERS:
1298  *
1299  *   Display *display;          - The X server connection.
1300  *
1301  *   char *toolClass;           - The client's tool class.
1302  *
1303  *   char *appClass;            - The client's application class.
1304  *
1305  *   DtSvcMessageProc reloadDBHandler; - The callback function for handling
1306  *                                       a "RELOAD-TYPES-DB" request. (OBSOLETE)
1307  *
1308  *   XtAppContext appContext;   - The client's application context.
1309  *
1310  * MODIFIED:
1311  *
1312  *   SbInputId (*SbAddInput_hookfn);            - Set to _DtCmdSPCAddInputHandler
1313  *
1314  *   SbInputId (*SbRemoveInput_hookfn);         - Set to XtRemoveInput
1315
1316  *   SbInputId (*SbAddException_hookfn);        - Set to _DtCmdSPCAddExceptionHandler
1317  *   SbInputId (*SbRemoveException_hookfn);     - Set to XtRemoveInput
1318  *
1319  *****************************************************************************/
1320
1321 void 
1322 _DtInitializeCommandInvoker(
1323         Display *display,
1324         char *toolClass,        /* ignored */
1325         char *appClass,         /* ignored */
1326         DtSvcMessageProc reloadDBHandler,       /* OBSOLETE -- ignored */
1327         XtAppContext appContext)
1328 {
1329    static       int beenCalled = 0;
1330
1331    _DtSvcAppLock(appContext);
1332
1333    /*
1334     * Prevent repeat calls
1335     */
1336    _DtSvcProcessLock();
1337    if ( beenCalled ) {
1338         _DtSvcProcessUnlock();
1339         return;
1340       }
1341
1342    beenCalled++;
1343
1344    cmd_Globals.app_context = appContext;
1345
1346    SbAddInput_hookfn = _DtCmdSPCAddInputHandler;
1347
1348    SbRemoveInput_hookfn = XtRemoveInput;
1349
1350    SbAddException_hookfn = _DtCmdSPCAddExceptionHandler;
1351
1352    SbRemoveException_hookfn = XtRemoveInput;
1353
1354    _DtCmdBuildPathList ();
1355
1356    _DtCmdInitializeErrorMessages ();
1357
1358    /*
1359     * Must get the name of the invoking host, so that requests
1360     * can be checked for remote execution.
1361     */
1362    if ((DtGetShortHostname(_cmdClientHost, MAXHOSTNAMELEN)) == -1) {
1363       _DtCmdLogErrorMessage ("Cannot determine the local host name.\n");
1364    }
1365
1366    _DtCmdGetResources (display);
1367
1368    _DtSvcProcessUnlock();
1369    _DtSvcAppUnlock(appContext);
1370 }
1371
1372 /*****************************************************************************
1373  *
1374  * _DtCmdInitializeErrorMessages - initializes all of the command invoker's
1375  *   error messages.
1376  *
1377  * PARAMETERS: None.
1378  *
1379  * MODIFIED:  all of the Command Invoker's error messages are initialized.
1380  *
1381  *****************************************************************************/
1382
1383 static void 
1384 _DtCmdInitializeErrorMessages( void )
1385 {
1386
1387    /* 
1388     * Non-Fatal -> Abort the request
1389     */
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.")));
1391
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.")));
1393
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.")));
1395
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\".")));
1397
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.")));
1399
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.")));
1401
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")));
1403
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.")));
1405
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")));
1407
1408         /*
1409          * The following errors may occur when a SPC
1410          * channel is opened.
1411          */
1412    errorUnknownHost = XtNewString (((char *)Dt11GETMESSAGE(3, 24, "This action cannot be executed because\nhost \"%s\" cannot be reached.")));
1413
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.")));
1415
1416    errorBadService = XtNewString (((char *)Dt11GETMESSAGE(3, 26, "This action cannot be executed because the \"%s\"\nservice is not configured on host \"%s\".")));
1417
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\".")));
1419
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.")));
1421
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.")));
1423
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.")));
1425
1426    errorEnvTooBig = XtNewString (((char *)Dt11GETMESSAGE(3, 31, "This action cannot be executed on host \"%s\" because\nthe environment exceeds \"%d\" bytes.")));
1427
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\".")));
1429
1430    /* 
1431     * Do not post a dialog, write to the error log file only.
1432     */
1433
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.")));
1435
1436    successHost = strdup (((char *)Dt11GETMESSAGE(3, 21, "The action \"%s\" was successfully executed on host \"%s\".")));
1437
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)")));
1439
1440 }