2 /*----------------------------------------------------------------------------------------------------------------------------------
3 Module : vms.c for Fvwm on Open VMS
4 Author : Fabien Villard (Villard_F@Decus.Fr)
6 Action : special functions for running Fvwm with OpenVms. They can be helpfull for other VMS ports.
8 internal functions : AttentionAST() and TimerAST()
9 exported functions : VMS_msg(), VMS_SplitCommand() and VMS_select_pipes()
10 Copyright : Fabien Villard, 1999. No guarantees or warantees are provided or implied in any way whatsoever. Use this program
11 at your own risk. Permission to use, modify, and redistribute this program is hereby given, provided that this
12 copyright is kept intact.
13 ----------------------------------------------------------------------------------------------------------------------------------*/
27 #include <lib$routines.h>
32 /* --- Define to debug VMS_select_pipes() routine --- */
35 /* --- Define to debug VMS_SplitCommand() routine --- */
38 /* --- Define this to post a read attention AST on a write pipe in VMS_select_pipes(). --- */
39 #undef POST_READATTN_AST
41 /* --- Define to debug VMS_ExecL() routine --- */
44 /* --- Define to close or sync output file after each line in VMS_msg() --- */
45 #undef DEBUG_CLOSE_OUTPUT
46 #undef DEBUG_SYNC_OUTPUT
66 #define SELECT_ERROR -1
67 #define SELECT_TIMEOUT 0
68 #define MAX_DEVICE 32 /* - Maximum FD to check - */
69 #define MAX_DEVICENAME 256
72 #define DEV_READPIPE 1
73 #define DEV_WRITEPIPE 2
76 /* --- File descriptors information. We allocate statically for it's a very oten used function. --- */
78 int eventFlag
; /* - Event flag pour les attentes passives - */
79 unsigned short vmsChannel
; /* - Canal VMS sur la mailbox - */
80 char deviceName
[MAX_DEVICENAME
]; /* - Nom du device (la mailbox ou les X events) - */
81 char devType
; /* - Type de device : DEV_xxx - */
82 char qioPending
; /* - Une QIO est en attente (1) ou non (0) - */
91 /* --- Global variables. I do not like them, but, because of the AST it's the easiest way :-) They have to be volatile because
92 they are modified by AST and main function. --- */
93 volatile unsigned int SpecialEfn
; /* - One ef for all. This to avoid multi ef clusters problem - */
94 volatile char SpecialEfnToClear
; /* - Special ef is set by us - */
96 /*----------------------------------------------------------------------------------------------------------------------------------
97 Fonctions : AttentionAST et TimedAST
98 Actions : attention AST : activated by the attention QIO (ReadAttention or WriteAttention) on the pipe's mailbox. It gets
99 the ef to set in the AstPrm.
100 Timed AST : activated when time has come.
101 This two functions set also the special ef on which we then waitfr. This is to avoid multi ef clusters problem.
102 ----------------------------------------------------------------------------------------------------------------------------------*/
103 void AttentionAST(int efn
) {
104 unsigned int sysStat
, efnState
;
105 sysStat
= sys$
setef(efn
);
106 if (! (sysStat
& 1)) fvwm_msg(ERR
, "AttentionAST", "<Asynchrone> Error setting efn %d (%d)", efn
, sysStat
);
107 else if (DBG_SEL
) fvwm_msg(DBG
, "AttentionAST", "<Asynchrone> Efn %d set.", efn
);
108 if (0 < SpecialEfn
) {
109 sysStat
= sys$
setef(SpecialEfn
);
110 if (! (sysStat
& 1)) fvwm_msg(ERR
, "AttentionAST", "<Asynchrone> Error setting special efn %d (%d)", SpecialEfn
, sysStat
);
111 else if (DBG_SEL
) fvwm_msg(DBG
, "AttentionAST", "<Asynchrone> Special efn %d set. We'll have to clear it.", SpecialEfn
);
112 SpecialEfnToClear
= 1;
115 void TimedAST(int filler
) {
116 unsigned int sysStat
;
117 if (0 < SpecialEfn
) {
118 sysStat
= sys$
setef(SpecialEfn
);
119 if (! (sysStat
& 1)) fvwm_msg(ERR
, "TimedAST", "<Asynchrone> Error setting special efn %d (%d)", SpecialEfn
, sysStat
);
120 else if (DBG_SEL
) fvwm_msg(DBG
, "TimedAST", "<Asynchrone> Special efn %d set. We'll have to clear it.", SpecialEfn
);
121 SpecialEfnToClear
= 1;
125 #define VMS_TestStatus(stat, message, degage) {\
127 if (DBG_SEL) fvwm_msg(ERR, "VMS_select_pipes", message, stat);\
129 result = SELECT_ERROR;\
130 goto End_VMS_select_pipes;\
135 /*----------------------------------------------------------------------------------------------------------------------------------
136 Fonction : VMS_select_pipes
137 Action : replacement for select() for pipes and other devices (such as X communications) with an ef already assigned.
138 Prototype is identical to select().
139 ----------------------------------------------------------------------------------------------------------------------------------*/
140 int VMS_select_pipes(int nbPipes
, fd_set
*readFds
, fd_set
*writeFds
, fd_set
*filler
, struct timeval
*timeoutVal
) {
141 int iFd
, result
, nbPipesReady
, sysStat
, libStat
, timeoutEf
;
143 unsigned short vmsChannel
;
144 unsigned int efnState
, qioFuncCode
;
145 struct dsc$descriptor_s deviceNameDesc
;
146 Pipe_Infos_Type infosPipes
[MAX_DEVICE
];
148 struct { unsigned int l0
, l1
; } timeoutBin
;
149 char specialEfnToFree
;
151 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "********************************************************************************");
154 specialEfnToFree
= SpecialEfnToClear
= 0;
155 nbPipesReady
= result
= 0;
156 deviceNameDesc
.dsc$b_dtype
= DSC$K_DTYPE_T
;
157 deviceNameDesc
.dsc$b_class
= DSC$K_CLASS_S
;
159 /* --- Too much pipes : trace and truncat. --- */
160 if (MAX_DEVICE
< nbPipes
) {
161 if (DBG_SEL
) fvwm_msg(ERR
, "VMS_select_pipes", "Too much pipes (%d instead of %d max), reduced.", nbPipes
, MAX_DEVICE
);
162 nbPipes
= MAX_DEVICE
;
165 /* --- Pre-work of selected fd to get their types and search special ef. --- */
166 if (NULL
!= readFds
|| NULL
!= writeFds
) {
167 for (iFd
= 0; iFd
< nbPipes
; iFd
++) {
168 infosPipes
[iFd
].devType
= DEV_UNUSED
;
169 infosPipes
[iFd
].qioPending
= 0;
170 infosPipes
[iFd
].vmsChannel
= 0;
171 if ( (NULL
!= readFds
&& FD_ISSET(iFd
, readFds
)) || (NULL
!= writeFds
&& FD_ISSET(iFd
, writeFds
)) ) {
172 if (FD_ISSET(iFd
, readFds
)) infosPipes
[iFd
].devType
= DEV_READPIPE
;
173 else if (FD_ISSET(iFd
, writeFds
)) infosPipes
[iFd
].devType
= DEV_WRITEPIPE
;
174 /* --- Get VMS mailbox name. This function is VMS specific. --- */
175 retPtr
= getname(iFd
, infosPipes
[iFd
].deviceName
);
176 /* --- If we fail, it's probably because the FD is an EF. --- */
177 if (NULL
== retPtr
) {
178 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Special efn trouve : %d", iFd
);
179 infosPipes
[iFd
].devType
= DEV_EFN
;
183 /* --- Trying to connect to the mailbox --- */
184 deviceNameDesc
.dsc$w_length
= strlen(infosPipes
[iFd
].deviceName
);
185 deviceNameDesc
.dsc$a_pointer
= infosPipes
[iFd
].deviceName
;
186 sysStat
= sys$
assign(&deviceNameDesc
, &(infosPipes
[iFd
].vmsChannel
), 0, NULL
, 0);
187 VMS_TestStatus(sysStat
, "Error : sys$assign returns %d", 1);
192 /* --- No special ef found. Create one. Then in both cases, clear it. --- */
193 if (-1 == SpecialEfn
) {
194 specialEfnToFree
= 1;
195 libStat
= lib$
get_ef(&SpecialEfn
);
196 VMS_TestStatus(libStat
, "No event flags left (Error %d)", 1);
197 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Special efn created : %d", SpecialEfn
);
199 sysStat
= sys$
clref(SpecialEfn
);
200 VMS_TestStatus(sysStat
, "Can't clear special event flag (Error %d)", 1);
202 /* --- DO the real work on fd --- */
203 for (iFd
= 0; iFd
< nbPipes
; iFd
++) {
204 if (DEV_READPIPE
== infosPipes
[iFd
].devType
|| DEV_WRITEPIPE
== infosPipes
[iFd
].devType
) {
205 /* --- Allocate and initialize an ef --- */
206 libStat
= lib$
get_ef(&(infosPipes
[iFd
].eventFlag
));
207 VMS_TestStatus(libStat
, "No more event flags (Error %d)", 1);
208 sysStat
= sys$
clref(infosPipes
[iFd
].eventFlag
);
209 VMS_TestStatus(sysStat
, "Can't clear ef (err %d)", 1);
211 fvwm_msg(DBG
, "VMS_select_pipes", "FD %2d %s Nom <%s> Canal %d Efn %d cleared", iFd
,
212 (DEV_READPIPE
== infosPipes
[iFd
].devType
)?"READ":(DEV_WRITEPIPE
== infosPipes
[iFd
].devType
)?"WRIT":"UNKN",
213 infosPipes
[iFd
].deviceName
, infosPipes
[iFd
].vmsChannel
, infosPipes
[iFd
].eventFlag
);
216 /* --- Read pipe, we wait for a writer to... write. --- */
217 if (FD_ISSET(iFd
, readFds
)) {
218 qioFuncCode
= IO$_SETMODE
| IO$M_WRTATTN
;
219 sysStat
= sys$
qio(0, infosPipes
[iFd
].vmsChannel
, qioFuncCode
, &qioIosb
,
220 NULL
, 0, AttentionAST
, infosPipes
[iFd
].eventFlag
, 0, 0, 0, 0);
221 VMS_TestStatus(qioIosb
.condVal
, "Attention QIO failed (Secondary error %d)", 0);
222 VMS_TestStatus(sysStat
, "Attention QIO failed (Error %d)", 1);
223 infosPipes
[iFd
].qioPending
= 1;
224 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Attention QIO ok. qioIosb.condVal = %d (%x)", qioIosb
.condVal
, qioIosb
.condVal
);
227 /* --- Write pipe. Sometimes we can wait for a reader to post a read request. But when the process is not symetrical
228 we may stay blocked here. So, better consider pipe is always ready. --- */
229 else if (FD_ISSET(iFd
, writeFds
)) {
230 #ifdef POST_READATTN_AST
231 qioFuncCode
= IO$_SETMODE
| IO$M_READATTN
;
232 sysStat
= sys$
qio(0, infosPipes
[iFd
].vmsChannel
, qioFuncCode
, &qioIosb
,
233 NULL
, 0, AttentionAST
, infosPipes
[iFd
].eventFlag
, 0, 0, 0, 0);
234 VMS_TestStatus(qioIosb
.condVal
, "Read attention QIO failed (Secondary error %d)", 0);
235 VMS_TestStatus(sysStat
, "Read attention QIO failed (Error %d)", 1);
236 infosPipes
[iFd
].qioPending
= 1;
237 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Read attention QIO ok. qioIosb.condVal = %d (%x)", qioIosb
.condVal
, qioIosb
.condVal
);
239 AttentionAST(infosPipes
[iFd
].eventFlag
);
240 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Attention automatique");
245 /* --- Not a pipe. It's probably an ef already allocated elsewhere, by us for example. --- */
246 else if (DEV_EFN
== infosPipes
[iFd
].devType
) {
247 infosPipes
[iFd
].qioPending
= 0;
248 strcpy(infosPipes
[iFd
].deviceName
, "Device_non_pipe");
249 infosPipes
[iFd
].vmsChannel
= 0;
250 infosPipes
[iFd
].eventFlag
= iFd
;
251 /* --- We clear this special ef only if we own it. In the other case, the owner had coped with that. --- */
252 if (iFd
!= SpecialEfn
) {
253 sysStat
= sys$
clref(infosPipes
[iFd
].eventFlag
);
254 VMS_TestStatus(sysStat
, "Can't clear ef (Error %d)", 1);
256 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "FD %2d EFN Nom <%s> Canal %d Efn %d", iFd
, infosPipes
[iFd
].deviceName
,
257 infosPipes
[iFd
].vmsChannel
, infosPipes
[iFd
].eventFlag
);
262 /* --- Time out event --- */
263 if (NULL
!= timeoutVal
) {
265 unsigned int libCvtFunc
= LIB$K_DELTA_SECONDS_F
;
266 libStat
= lib$
get_ef(&timeoutEf
);
267 VMS_TestStatus(libStat
, "No event flags left (Error %d)", 1);
268 if (0 != timeoutVal
->tv_sec
|| 0 != timeoutVal
->tv_usec
) {
269 sysStat
= sys$
clref(timeoutEf
);
270 VMS_TestStatus(sysStat
, "Can't clear timer ef (Error %d)", 1);
271 timeoutFloat
= (float)timeoutVal
->tv_sec
+ (float)timeoutVal
->tv_usec
/ 1000000.0;
272 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Timer %f, %d sec %d usec", timeoutFloat
, timeoutVal
->tv_sec
, timeoutVal
->tv_usec
);
273 libStat
= lib$
cvtf_to_internal_time(&libCvtFunc
, &timeoutFloat
, &timeoutBin
);
274 VMS_TestStatus(libStat
, "Can't convert time in float (Error %d)", 1);
275 sysStat
= sys$
setimr(timeoutEf
, &timeoutBin
, TimedAST
, 0, 0);
276 VMS_TestStatus(sysStat
, "Can't post the timed AST (Error %d)", 1);
277 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Timed AST with ef %d in %f s", timeoutEf
, timeoutFloat
);
279 /* --- Null time out --- */
281 sysStat
= sys$
clref(timeoutEf
);
282 VMS_TestStatus(sysStat
, "Can't clear (timeout = 0) timer ef (Error %d)", 1);
286 /* --- Wait for one of all those events :-) --- */
287 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Waiting events...");
288 sysStat
= sys$
waitfr(SpecialEfn
);
289 VMS_TestStatus(sysStat
, "Wait events request failed (Error %d)", 1);
290 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "One event happened.", time(NULL
));
292 /* --- Some events did come --- */
293 if (NULL
!= readFds
) FD_ZERO(readFds
);
294 if (NULL
!= writeFds
) FD_ZERO(writeFds
);
296 /* --- Time out --- */
297 if (NULL
!= timeoutVal
) {
298 sysStat
= sys$
readef(timeoutEf
, &efnState
);
299 VMS_TestStatus(sysStat
, "Can't read timeout ef state (Error %d)", 1);
300 if (SS$_WASSET
== sysStat
) {
301 timeoutVal
->tv_sec
= 0;
302 timeoutVal
->tv_usec
= 0;
303 result
= SELECT_TIMEOUT
;
304 goto End_VMS_select_pipes
;
306 /* --- Cancel timeout --- */
308 sysStat
= sys$
cantim(0, 0);
309 VMS_TestStatus(sysStat
, "Can't cancel timer request (Error %d)", 0);
313 /* --- Checking other events --- */
314 for (iFd
= 0; iFd
< nbPipes
; iFd
++) {
315 if (DEV_UNUSED
!= infosPipes
[iFd
].devType
) {
316 sysStat
= sys$
readef(infosPipes
[iFd
].eventFlag
, &efnState
);
317 VMS_TestStatus(sysStat
, "Can't read ef state (Error %d)", 1);
318 if (SS$_WASSET
== sysStat
) {
320 infosPipes
[iFd
].qioPending
= 0;
321 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Event flag %d set !", infosPipes
[iFd
].eventFlag
);
322 if (DEV_READPIPE
== infosPipes
[iFd
].devType
) FD_SET(iFd
, readFds
);
323 else if (DEV_WRITEPIPE
== infosPipes
[iFd
].devType
) FD_SET(iFd
, writeFds
);
324 else FD_SET(iFd
, readFds
);
329 /* --- Don't give false informations : if we set the special event and we don't own it, don't say it. --- */
331 if (! specialEfnToFree && SpecialEfnToClear) {
333 if (FD_ISSET(SpecialEfn, readFds)) FD_CLR(SpecialEfn, readFds);
334 else if (FD_ISSET(SpecialEfn, writeFds)) FD_CLR(SpecialEfn, writeFds);
338 result
= nbPipesReady
;
339 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "Nombre de pipes prets : %d", nbPipesReady
);
341 End_VMS_select_pipes
:;
342 /* --- Clear resources --- */
343 for (iFd
= 0; iFd
< nbPipes
; iFd
++) {
344 if (DEV_UNUSED
!= infosPipes
[iFd
].devType
) {
345 if (1 == infosPipes
[iFd
].qioPending
) {
346 sysStat
= sys$
cancel(infosPipes
[iFd
].vmsChannel
);
347 VMS_TestStatus(sysStat
, "Can't cancel QIO (Error %d)", 0);
349 if (0 != infosPipes
[iFd
].vmsChannel
) {
350 sysStat
= sys$
dassgn(infosPipes
[iFd
].vmsChannel
);
351 VMS_TestStatus(sysStat
, "Can't deallocate channel (Error %d)", 0);
353 if (DEV_EFN
!= infosPipes
[iFd
].devType
) {
354 libStat
= lib$
free_ef(&(infosPipes
[iFd
].eventFlag
));
355 VMS_TestStatus(libStat
, "Can't free ef (Error %d)", 0);
359 if (specialEfnToFree
) {
360 libStat
= lib$
free_ef(&SpecialEfn
);
361 VMS_TestStatus(libStat
, "Can't free special ef (Error %d)", 0);
363 if (NULL
!= timeoutVal
) {
364 libStat
= lib$
free_ef(&timeoutEf
);
365 VMS_TestStatus(libStat
, "Can't free timer ef (Error %d)", 0);
368 if (DBG_SEL
) fvwm_msg(DBG
, "VMS_select_pipes", "********************************************************************************");
372 /*----------------------------------------------------------------------------------------------------------------------------------
374 Action : replacement for fvwm_msg
375 ----------------------------------------------------------------------------------------------------------------------------------*/
376 char FabName
[] = "Sys$Login:Fvwm.log";
378 void VMS_msg(int type
,char *id
,char *msg
,...) {
381 char buffer1
[1024], buffer2
[1024];
382 static FILE *fabFD
= NULL
;
383 static int fabNew
= 1;
386 case DBG
: typestr
="Dbg"; break;
387 case ERR
: typestr
="Err"; break;
388 case WARN
: typestr
="Wrn"; break;
395 sprintf(buffer1
,"[fvwm-%d/%d-%s-%s] ", time(NULL
), clock(), typestr
, id
);
398 vsprintf(buffer2
, msg
, args
);
401 strcat(buffer1
, buffer2
);
405 fabFD
= fopen(FabName
, "w");
408 else fabFD
= fopen(FabName
, "a");
412 fprintf(fabFD
, "%s\n", buffer1
);
413 #ifdef DEBUG_SYNC_OUTPUT
414 fsync(fileno(fabFD
));
416 #ifdef DEBUG_CLOSE_OUTPUT
421 else fprintf(stderr
, "FAB-ERROR : file %s not opened <%s>", FabName
, strerror(errno
));
424 /*----------------------------------------------------------------------------------------------------------------------------------
425 Function : VMS_SplitCommand
426 Action : split command string in an array of string pointers to words of command. Array is passed. Each pointer is
427 freed if necessary. The pointer after the last used argument pointer is set to NULL.
428 ----------------------------------------------------------------------------------------------------------------------------------*/
429 void VMS_SplitCommand(
430 char *cmd
, /* - Command to split - */
431 char **argums
, /* - Array of arguments - */
432 int maxArgums
, /* - Size of the array of argumets - */
433 int *nbArgums
) { /* - Number of arguments created - */
434 int iArgum
, argumLen
;
435 char *tmpChar
, *tmpArgum
;
437 if (DBG_SPL
) fvwm_msg(DBG
,"VMS_SplitCommand","Splitting <%s>", cmd
);
438 tmpChar
= tmpArgum
= cmd
;
439 iArgum
= 0; argumLen
= 0;
441 /* --- Split command in arguments --- */
442 while (0 != *tmpChar
) {
443 if (' ' == *tmpChar
) {
444 if (DBG_SPL
) fvwm_msg(DBG
,"VMS_SplitCommand","End word...");
446 if (NULL
!= argums
[iArgum
]) free(argums
[iArgum
]);
447 argums
[iArgum
] = (char *)malloc(argumLen
+ 1);
448 if (NULL
== argums
[iArgum
]) {
449 VMS_msg(ERR
, "VMS_SplitCommand", "Can't allocate memory");
452 strncpy(argums
[iArgum
], tmpArgum
, argumLen
);
453 argums
[iArgum
][argumLen
] = 0;
454 if (DBG_SPL
) fvwm_msg(DBG
,"VMS_SplitCommand","New word <%s>, Len: %d", argums
[iArgum
], strlen(argums
[iArgum
]));
456 tmpArgum
= tmpChar
+ 1;
464 /* --- Get last argument --- */
466 argums
[iArgum
] = (char *)malloc(argumLen
+ 1);
467 if (NULL
== argums
[iArgum
]) {
468 VMS_msg(ERR
, "VMS_SplitCommand", "Can't allocate memory");
471 strncpy(argums
[iArgum
], tmpArgum
, argumLen
);
472 argums
[iArgum
][argumLen
] = 0;
473 if (DBG_SPL
) fvwm_msg(DBG
,"VMS_SplitCommand","Last word <%s>, Len: %d", argums
[iArgum
], strlen(argums
[iArgum
]));
477 argums
[iArgum
] = NULL
;
480 /* --- Remove quotes in each argument --- */
481 for (iArgum
= 0; iArgum
< *nbArgums
; iArgum
++) {
482 if ('"' == argums
[iArgum
][0]) {
483 tmpChar
= (char *)malloc(strlen(argums
[iArgum
]));
484 if (NULL
== tmpChar
) {
485 VMS_msg(ERR
, "VMS_SplitCommand", "Can't allocate memory");
488 strncpy(tmpChar
, argums
[iArgum
] + 1, strlen(argums
[iArgum
]) - 1);
489 tmpChar
[strlen(argums
[iArgum
]) - 1] = 0;
490 free(argums
[iArgum
]);
491 argums
[iArgum
] = tmpChar
;
493 if ('"' == argums
[iArgum
][strlen(argums
[iArgum
]) - 1]) argums
[iArgum
][strlen(argums
[iArgum
]) - 1] = 0;
494 if (DBG_SPL
) fvwm_msg(DBG
,"VMS_SplitCommand","Argument %d <%s>", iArgum
, argums
[iArgum
]);
498 /*----------------------------------------------------------------------------------------------------------------------------------
500 Action : replacemant for execl. It splits command and calls execv() from the Dec RTL. This function assumes its
501 params are passed a special way. It can't be considered working in all cases. In fact it works only in one :-)
502 The array containing splitted command is statically allocated, so we never free it and allocate it just once.
503 ----------------------------------------------------------------------------------------------------------------------------------*/
505 const char *fileSpec
, /* - Conventionnaly, image to run. With Unix, often a shell - */
506 const char *arg0
, /* - The same as fileSpec, by convention - */
507 ...) { /* - Real unix command, eventually splitted - */
509 int execStat
, nbArgums
;
510 static char **argums
= NULL
;
514 if (DBG_EXL
) fvwm_msg(DBG
,"VMS_ExecL","Entering function...");
516 /* --- Allocates the arguments array, once --- */
517 if (NULL
== argums
) {
518 argums
= (char **)malloc(sizeof(char *) * VMS_MAX_ARGUMENT_IN_CMD
);
519 if (NULL
== argums
) {
520 fvwm_msg(ERR
,"VMS_ExecL","Error allocating argums <%s>", strerror(errno
));
523 memset(argums
, 0, sizeof(char *) * VMS_MAX_ARGUMENT_IN_CMD
);
526 /* --- Initialize the varying argument list --- */
527 va_start(vaCmd
, arg0
);
529 /* --- Assumes the shell command is in the fourth argument, third would be "-c" or something indicating the image to
530 be run by the shell. Well of course, it can be something very different. --- */
531 cmdPtr
= va_arg(vaCmd
, char*);
532 cmdPtr
= va_arg(vaCmd
, char*);
536 if (DBG_EXL
) fvwm_msg(DBG
,"VMS_ExecL","cmd <%s>", cmdPtr
);
538 /* --- Splits command in the argument array --- */
539 VMS_SplitCommand(cmdPtr
, argums
, VMS_MAX_ARGUMENT_IN_CMD
, &nbArgums
);
540 if (DBG_EXL
) fvwm_msg(DBG
,"VMS_ExecL","cmd now broken in %d arguments", nbArgums
);
542 /* --- Calling exec : if it fails, don't return the fact. Thus, the unix code won't remark the problem and continue
543 the parent process. --- */
544 execStat
= execv(argums
[0], argums
);
545 if (-1 == execStat
) fvwm_msg(ERR
,"VMS_ExecL","execl failed (%s)", strerror(errno
));