unix/SystemCommands.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX UNIX Support aixcmd.c */
40 /* */
41 /* AIX specific command processing routines */
42 /* */
43 /******************************************************************************/
44 /******************************************************************************/
45 /* aixcmd.c - C methods for handling calls to system exits and subcommand */
46 /* handlers. */
47 /* */
48 /* C methods: */
49 /* SysCommand - Method to invoke a subcommand handler */
50 /* */
51 /* Internal routines: */
52 /* sys_command - Run a command through system command processor. */
53 /******************************************************************************/
54 
55 #include <string.h> /* Get strcpy, strcat, etc. */
56 #include <sys/wait.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 
60 #include "RexxCore.h" /* global REXX declarations */
61 #include "StringClass.hpp"
62 #include "RexxActivity.hpp"
63 #include "ActivityManager.hpp"
64 #include "SystemInterpreter.hpp"
65 #include "InterpreterInstance.hpp"
67 
68 #include "RexxInternalApis.h"
69 #include <sys/types.h>
70 #include <pwd.h>
71 #include <limits.h>
72 
73 #define CMDBUFSIZE 1024 /* Max size of executable cmd */
74 #define MAX_COMMAND_ARGS 400
75 
76 #if defined(AIX)
77 #define CMDDEFNAME "/bin/ksh" /* Korn shell is default for AIX */
78 #elif defined(OPSYS_SUN) /* path for AIX */
79 #define CMDDEFNAME "/bin/sh" /* Bourne Again Shell is default */
80 #else /* shell for Linux */
81 #define CMDDEFNAME "/bin/bash" /* Bourne Again Shell is default */
82 #endif
83 
84 #define UNKNOWN_COMMAND 127 /* unknown command return code */
85 
86 #define SYSENV "command" /* Default cmd environment */
87 #define SHELL "SHELL" /* UNIX cmd handler env. var. name*/
88 #define EXPORT_FLAG 1
89 #define SET_FLAG 2
90 #define UNSET_FLAG 3
91 #define MAX_VALUE 1280
92 
93 extern int putflag;
94 
95 
96 /**
97  * Retrieve the globally default initial address.
98  *
99  * @return The string name of the default address.
100  */
102 {
103  return OREF_INITIALADDRESS;
104 }
105 
106 /* Handle "export" command in same process */
107 bool sys_process_export(RexxExitContext *context, const char * cmd, RexxObjectPtr &rc, int flag)
108 {
109  char *Env_Var_String = NULL; /* Environment variable string for */
110  size_t size, allocsize; /* size of the string */
111  char **Environment; /* environment pointer */
112  char *np;
113  size_t i,j,k,l,iLength, copyval;
114  char namebufcurr[1281]; /* buf for extracted name */
115  char cmd_name[1281]; /* name of the envvariable setting */
116  char *array, *runarray, *runptr, *endptr, *maxptr;
117  char temparray[1281];
118  const char *st;
119  char *tmpptr;
120  char name[1281]; /* is the name + value + = */
121  char value[1281]; /* is the part behind = */
122  char *del = NULL; /* ptr to old unused memory */
123  char *hit = NULL;
124  bool HitFlag = false;
125  l = 0;
126  j = 0;
127  allocsize = 1281 * 2;
128 
129  memset(temparray, '\0', sizeof(temparray));
130 
131  Environment = getEnvironment(); /* get the environment */
132  if (flag == EXPORT_FLAG)
133  {
134  st = &cmd[6];
135  }
136  else if (flag == UNSET_FLAG)
137  {
138  st = &cmd[5];
139  }
140  else
141  {
142  st = &cmd[3];
143  }
144  while ((*st) && (*st == ' '))
145  {
146  st++;
147  }
148  strcpy(name, st);
149  iLength = strlen(st) + 1;
150 
151 /* if string == EXPORT_FLAG or string == SET and only blanks are delivered */
152 
153  if ( ((flag == EXPORT_FLAG) || (flag == SET_FLAG)) && (iLength == 1) )
154  {
155  return false;
156  }
157 
158  if (!putflag)
159  { /* first change in the environment ? */
160  /* copy all entries to dynamic memory */
161  for (;*Environment != NULL; Environment++)
162  { /*for all entries in the env */
163  size = strlen(*Environment)+1; /* get the size of the string */
164  Env_Var_String = (char *)malloc(size); /* and alloc space for it */
165  memcpy(Env_Var_String,*Environment,size);/* copy the string */
166  putenv(Env_Var_String); /* and chain it in */
167  }
168  }
169  putflag = 1; /* prevent do it again */
170  Environment = getEnvironment(); /* reset the environment pointer */
171 
172 /* do we have a assignment operator? If not return true */
173 /* The operating system treads this like no command, and so do we */
174 
175  if ( !(strchr(name, '=')) && (flag != UNSET_FLAG) ) /*only set and export */
176  {
177 /* we do not have a assignment operator, but maybe a '|' for a */
178 /* controlled output */
179  if ( (strchr(name, '|')) || (strchr(name, '>')) || (strstr(name, ">>")) )
180  {
181  return false;
182  }
183  else
184  {
185  // this worked ok (well, sort of)
186  rc = context->False();
187  return true;
188  }
189  }
190 
191 /* no '=' for unset, so force a shell error message */
192 
193  if ( (strchr(name, '=')) && (flag == UNSET_FLAG) )
194  {
195  return false;
196  }
197 
198  for (i=0;(name[i]!='=')&&(i<iLength);i++)
199  {
200  cmd_name[i] = name[i];
201  }
202 
203 /* lets try handling variables in the assignment string */
204 
205  cmd_name[i] = '\0'; /* copy the terminator */
206 
207  i++; /* the place after'=' */
208 
209 /* lets search the value for variable part(s) */
210 
211  strcpy(value, &(name[i])); /* value contains the part behind '=' */
212  array = (char *) malloc(1281);
213  strcpy(array, cmd_name);
214  array[strlen(cmd_name)] = '=';
215  array[i] = '\0'; /* copy the terminator */
216  runarray = array + strlen(array);
217  runptr = value;
218  endptr = runptr + strlen(value); /*this is the end of the input*/
219  maxptr = array + MAX_VALUE -1; /* this is the end of our new string */
220 
221  while ((tmpptr = (strchr(runptr, '$'))) != 0)
222  {
223  Environment = getEnvironment(); /* get the beginning of the environment*/
224  HitFlag = true; /* if not true inputvalue= outputvalue*/
225  copyval = tmpptr - runptr;
226  if (copyval) /* runarray should keep the 'real' environment */
227  {
228  while ((runarray + copyval) > maxptr)
229  {
230  array = (char *) realloc(array, allocsize);
231  runarray = array + strlen(array);
232  maxptr = array + allocsize - 1;
233  allocsize = allocsize * 2;
234  }
235  memcpy(runarray,runptr, copyval);
236  runarray= runarray + copyval; /* a new place to copy */
237  *runarray = '\0';
238  runptr = tmpptr; /* now runptr is at the place of $ */
239  }
240  runptr++;
241  for (j = 0;(*runptr != '/') && (*runptr != ':') && (*runptr != '$') &&
242  (*runptr); j++)
243  {
244  memcpy(&(temparray[j]), runptr,1); /*temparray is the env var to search*/
245  runptr++;
246  }
247 
248  temparray[j] = '\0'; /* lets see what we can do */
249  np = NULL;
250 
251  for (;(*Environment != NULL) && (hit == NULL) ;Environment++)
252  {
253  np = *Environment;
254 
255  for (k=0;(*np!='=')&&(k<255);np++,k++)
256  {
257  memcpy(&(namebufcurr[k]),np,1); /* copy the character */
258  }
259 
260  namebufcurr[k] = '\0'; /* copy the terminator */
261 
262  if (!strcmp(temparray,namebufcurr)) /* have a match ? */
263  {
264  hit = *Environment;
265  /* copy value to new string*/
266  }
267  }
268  if (hit) /* if we have found an entry of the env var in the env list */
269  {
270  np ++; /* don't copy equal */
271  while ((runarray + strlen(np)) > maxptr)
272  {
273  array = (char *) realloc(array, allocsize);
274  runarray = array + strlen(array);
275  maxptr = array + allocsize - 1;
276  allocsize = allocsize * 2;
277  }
278  strcpy(runarray, np);
279  runarray = runarray + strlen(np);
280  *runarray = '\0';
281  hit = NULL;
282  }
283  }
284 
285  if (HitFlag == true)
286  {
287  if (runptr < endptr)
288  {
289  while ((runarray + strlen(runptr)) > maxptr)
290  {
291  array = (char *) realloc(array, allocsize);
292  runarray = array + strlen(array);
293  maxptr = array + allocsize - 1;
294  allocsize = allocsize * 2;
295  }
296  strcpy(runarray, runptr); /* if there is a part after a var */
297  runarray = runarray + strlen(runptr);
298  *runarray = '\0';
299  }
300  }
301  else /* no hit so lets copy the value as it is */
302  {
303  while ((runarray + strlen(value)) > maxptr)
304  {
305  array = (char *) realloc(array, allocsize);
306  runarray = array + strlen(array);
307  maxptr = array + allocsize - 1;
308  allocsize = allocsize * 2;
309  }
310  strcpy(runarray,value);
311  runarray = runarray + strlen(runptr);
312  *runarray = '\0';
313  }
314 
315  Environment = getEnvironment(); /* get the beginning of the environment*/
316 
317  for (;*Environment != NULL;Environment++)
318  {
319  np = *Environment;
320 
321  for (i=0;(*np!='=')&&(i<255);np++,i++)
322  {
323  memcpy(&(namebufcurr[i]),np,1); /* copy the character */
324  }
325 
326  namebufcurr[i] = '\0'; /* copy the terminator */
327 
328  if (!strcmp(cmd_name,namebufcurr))/* have a match ? */
329  {
330  del = *Environment; /* remember it for deletion */
331  }
332  }
333  /* find the entry in the environ */
334  if (flag != UNSET_FLAG)
335  {
336  size = strlen(array)+1;
337  Env_Var_String = (char *)malloc(size);/* get the memory */
338  memcpy(Env_Var_String, array, size);
339  int errCode = putenv(Env_Var_String);
340  if (errCode != 0)
341  {
342  // non-zero is an error condition
343  context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
344  }
345  else
346  {
347  rc = context->False();
348  }
349  }
350 
351  if (del) /* if there was a old one */
352  {
353  free(del); /* free it */
354  }
355  rc = context->False();
356  return true;
357 }
358 
359 
360 /* Returns a copy of s without quotes. Escaped characters are kept unchanged */
361 char *unquote(const char *s)
362 {
363  if ( s == NULL )
364  {
365  return NULL;
366  }
367  size_t size = strlen(s) + 1;
368  char *unquoted = (char*)malloc(sizeof(char)*size);
369  if ( unquoted == NULL )
370  {
371  return NULL;
372  }
373  char *u = unquoted;
374  char c;
375  bool escape = false;
376  do
377  {
378  c = *s;
379  if ( escape )
380  {
381  *u++ = *s;
382  escape = false;
383  }
384  else if ( c == '\\' )
385  {
386  escape = true;
387  }
388  else if ( c != '"' )
389  {
390  *u++ = *s;
391  }
392  s++;
393  }
394  while ( c != '\0' );
395  return unquoted;
396 }
397 
398 
399 /* Handle "cd XXX" command in same process */
400 bool sys_process_cd(RexxExitContext *context, const char * cmd, RexxObjectPtr rc)
401 {
402  const char * st;
403  const char *home_dir = NULL; /* home directory path */
404  char *dir_buf = NULL; /* full directory path */
405  const char *slash; /* ptr to '/' */
406  struct passwd *ppwd;
407 
408  st = &cmd[2];
409  while ((*st) && (*st == ' '))
410  {
411  st++;
412  }
413  if ((!*st) || (strlen(cmd) == 2))
414  {
415  home_dir = getenv("HOME");
416  if (!home_dir)
417  {
418  return false;
419  }
420  dir_buf = (char *)malloc(strlen(home_dir)+1);
421  strcpy(dir_buf, home_dir);
422  } /* if no user name */
423  else if (*(st) == '~' && (*(st+1) == '\0' || *(st+1) == '/'|| *(st+1) == ' ' ))
424  {
425  if (*(st+1) == '/') /* if there is a path */
426  {
427  st +=2; /* jump over '~/' */
428  /* get home directory path */
429  home_dir = getenv("HOME"); /* from the environment */
430  if (!home_dir) /* if no home dir info */
431  {
432  return false;
433  }
434  /* get space for the buf */
435  dir_buf = (char *)malloc(strlen(home_dir)+strlen(st)+2);
436  if (!dir_buf)
437  {
438  return false;
439  }
440  /* merge the strings */
441  sprintf(dir_buf, "%s/%s", home_dir, st);
442  }
443  else
444  {
445  /* get home directory path */
446  home_dir = getenv("HOME"); /* from the environment */
447  /* get space for the buf */
448  dir_buf = (char *)malloc(strlen(home_dir)+2);
449  if (!dir_buf)
450  {
451  return false;
452  }
453  sprintf(dir_buf, "%s/", home_dir);
454  }
455  }
456  else if (*(st) == '~') /* cmd is '~username...' */
457  {
458  st++; /* jump over '~' */
459  slash = strchr(st,'/'); /* search for '/' */
460  if (!slash) /* if no '/' */
461  {
462  /* rest of string is username */
463  ppwd = getpwnam(st); /* get info about the user */
464  if (ppwd == NULL || ppwd->pw_dir == NULL)
465  {
466  return false;
467  }
468  /* get space for the buf */
469  dir_buf = (char *)malloc(strlen(ppwd->pw_dir)+2);
470  if (!dir_buf)
471  {
472  return false;
473  }
474  /* merge the strings */
475  sprintf(dir_buf, "%s/", ppwd->pw_dir);
476  }
477  else /* there is a slash */
478  {
479  char username[256]; // need to copy the user name
480  memcpy(username, st, slash - st);
481  username[slash - st] = '\0';
482 
483  ppwd = getpwnam(username); /* get info about the user */
484  if (ppwd == NULL || ppwd->pw_dir == NULL)
485  {
486  return false;
487  }
488  slash++; /* step over the slash */
489  /* get space for the buf */
490  dir_buf = (char *)malloc(strlen(ppwd->pw_dir)+strlen(slash)+2);
491  if (!dir_buf)
492  {
493  return false;
494  }
495  /* merge the strings */
496  sprintf(dir_buf, "%s/%s", ppwd->pw_dir, slash);
497  }
498  }
499  else
500  {
501  dir_buf = strdup(st);
502  }
503 
504  char *unquoted = unquote(dir_buf);
505  if (unquoted == NULL)
506  {
507  return false;
508  }
509  int errCode = chdir(unquoted);
510  free(unquoted);
511 
512  free(dir_buf);
513  if (errCode != 0)
514  {
515  // non-zero is an error condition
516  context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
517  }
518  else
519  {
520  rc = context->False();
521  }
522  return true;
523 }
524 
525 
526 /*********************************************************************/
527 /* This function breaks a command up into whitespace-delimited pieces*/
528 /* to create the pointer array for the execvp call. It is only used */
529 /* to support the "COMMAND" command environment, which does not use */
530 /* a shell to invoke its commands. */
531 /*********************************************************************/
532 
533 bool scan_cmd(const char *parm_cmd, char **argPtr)
534 {
535  char *cmd = strdup(parm_cmd); /* Allocate for copy */
536 
537  char *end = cmd + strlen(cmd); /* Find the end of the command*/
538 
539  /* This loop scans our copy of the command, setting pointers in */
540  /* the args[] array to point to each of the arguments, and null- */
541  /* terminating each one of them. */
542 
543  /* LOOP INVARIANT: */
544  /* pos points to the next character of the command to be examined. */
545  /* i indicates the next element of the args[] array to be loaded. */
546  size_t i = 0; /* Start with args[0] */
547  for (char *pos = cmd; pos < end; pos++)
548  {
549  while (*pos==' ' || *pos=='\t')
550  {
551  pos++; /* Skip to first non-white */
552  }
553 
554  if (*pos == '\0') /* If we're at the end, */
555  {
556  break; /* get out. */
557  }
558 
559  /* If at this point, we've used up all but one of the available */
560  /* elements of our args[] array, let the user know, and we must */
561  /* terminate. */
562  if (i == MAX_COMMAND_ARGS)
563  {
564  return false;
565  }
566 
567  argPtr[i++] = pos; /* Point to current argument */
568  /* and advance i to next */
569  /* element of args[] */
570  while (*pos!=' ' && *pos!='\t' && *pos!='\0')
571  {
572  pos++; /* Look for next whitespace */
573  } /* or end of command */
574  *pos = '\0'; /* Null-terminate this arg */
575 
576  }
577 
578  /* Finally, put a null pointer in args[] to indicate the end. */
579  argPtr[i] = NULL;
580  return true;
581 }
582 
583 /******************************************************************************/
584 /* Name: sys_command */
585 /* */
586 /* Arguments: cmd - Command to be executed */
587 /* local_env_type - integer indicating which shell */
588 /* */
589 /* Returned: rc - Return Code */
590 /* */
591 /* Notes: Handles processing of a system command. */
592 /* Uses the 'fork' and 'exec' system calls to create a new process*/
593 /* and invoke the shell indicated by the local_env_type argument. */
594 /* This is modeled after command handling done in Classic REXX. */
595 /******************************************************************************/
597 {
598  const char *cmd = context->StringData(command);
599  const char *envName = context->StringData(address);
600 
602 
603  /* check for redirection symbols, ignore them when enclosed in double quotes.
604  escaped quotes are ignored. */
605  bool noDirectInvoc = false;
606  bool inQuotes = false;
607  bool escape = false;
608  size_t i;
609  for (i = 0; i<strlen(cmd); i++)
610  {
611  if (escape)
612  {
613  escape = false;
614  }
615  else if (cmd[i] == '\\')
616  {
617  escape = true;
618  }
619  else if (cmd[i] == '"')
620  {
621  inQuotes = !inQuotes;
622  }
623  else
624  {
625  /* if we're in the unquoted part and the current character is one of */
626  /* the redirection characters or the & for multiple commands then we */
627  /* will no longer try to invoke the command directly */
628  if (!inQuotes && (strchr("<>|&", cmd[i]) != NULL))
629  {
630  noDirectInvoc = true;
631  break;
632  }
633  }
634  }
635 
636  if (!noDirectInvoc)
637  {
638  /* execute 'cd' in the same process */
639  size_t commandLen = strlen(cmd);
640 
641  if (strcmp(cmd, "cd") == 0)
642  {
643  if (sys_process_cd(context, cmd, rc))
644  {
645  return rc;
646  }
647  }
648  else if (commandLen >= 3)
649  {
650  char tmp[16];
651  strncpy(tmp, cmd, 3);
652  tmp[3] = '\0';
653  if (strcmp("cd ",tmp) == 0)
654  {
655  if (sys_process_cd(context, cmd, rc))
656  {
657  return rc;
658  }
659  }
660  strncpy(tmp, cmd, 4);
661  tmp[4] = '\0';
662  if (strcmp("set ",tmp) == 0)
663  {
664  if (sys_process_export(context, cmd, rc, SET_FLAG)) /*unset works fine for me*/
665  {
666  return rc;
667  }
668  }
669  strncpy(tmp, cmd, 6);
670  tmp[6] = '\0';
671  if (Utilities::strCaselessCompare("unset ", tmp) == 0)
672  {
673  if (sys_process_export(context, cmd, rc, UNSET_FLAG))
674  {
675  return rc;
676  }
677  }
678  strncpy(tmp, cmd, 7);
679  tmp[7] = '\0';
680  if (Utilities::strCaselessCompare("export ", tmp) == 0)
681  {
682  if (sys_process_export(context, cmd, rc, EXPORT_FLAG))
683  {
684  return rc;
685  }
686  }
687  }
688  }
689 
690 
691  /****************************************************************************/
692  /* Invoke the system command handler to execute the command */
693  /****************************************************************************/
694  // if this is the null string, then use the default address environment
695  // for the platform
696  if (strlen(envName) == 0)
697  {
698  envName = SYSINITIALADDRESS;
699  }
700 
701  int errCode = 0;
702 #ifdef LINUX
703 
704  // JLF : I don't know why a special case is made to call system()
705  // But something sure : it's wrong to call system() when the passed address is "bash".
706  // Since system() delegates always to /bin/sh, the only acceptable address is "sh".
707  if (Utilities::strCaselessCompare("sh", envName) == 0)
708  {
709  errCode = system( cmd );
710  if ( errCode >= 256 )
711  {
712  errCode = errCode / 256;
713  }
714  }
715  else
716 #endif
717  {
718  int pid = fork();
719  int status;
720 
721  if (pid != 0) /* spawn a child process to run the */
722  {
723  waitpid ( pid, &status, 0); /* command and wait for it to finish */
724  if (WIFEXITED(status)) /* If cmd process ended normal */
725  {
726  /* Give 'em the exit code */
727  errCode = WEXITSTATUS(status);
728  }
729  else /* Else process died ugly, so */
730  {
731  errCode = -(WTERMSIG(status));
732  if (errCode == 1) /* If process was stopped */
733  {
734  errCode = -1; /* Give 'em a -1. */
735  }
736  }
737  }
738  else
739  { /* run the command in the child */
740  if (Utilities::strCaselessCompare("sh", envName) == 0)
741  {
742  execl("/bin/sh", "sh", "-c", cmd, NULL);
743  }
744  else if (Utilities::strCaselessCompare("ksh", envName) == 0)
745  {
746  execl("/bin/ksh", "ksh", "-c", cmd, NULL);
747  }
748  else if (Utilities::strCaselessCompare("bsh", envName) == 0)
749  {
750  execl("/bin/bsh", "bsh", "-c", cmd, NULL);
751  }
752  else if (Utilities::strCaselessCompare("csh", envName) == 0)
753  {
754  execl("/bin/csh", "csh", "-c", cmd, NULL);
755  }
756  else if (Utilities::strCaselessCompare("bash", envName) == 0)
757  {
758  execl("/bin/bash", "bash", "-c", cmd, NULL);
759  }
760  else if (Utilities::strCaselessCompare("cmd", envName) == 0)
761  {
762  char * args[MAX_COMMAND_ARGS+1]; /* Array for argument parsing */
763  if (!scan_cmd(cmd, args)) /* Parse cmd into arguments */
764  {
765  exit(1);
766  }
767  execvp(args[0], args); /* Invoke command directly */
768  perror(" *E* Address COMMAND"); /* If we get to this point, */
769  exit(1); /* we couldn't run the */
770  }
771  else
772  {
773  execl("/bin/sh", "sh", "-c", cmd, NULL);
774  }
775  }
776  }
777  // unknown command code?
778  if (errCode == UNKNOWN_COMMAND)
779  {
780  // failure condition
781  context->RaiseCondition("FAILURE", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
782  }
783  else if (errCode != 0)
784  {
785  // non-zero is an error condition
786  context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
787  }
788  return context->False(); // zero return code
789 }
790 
791 
792 /**
793  * Register the standard system command handlers.
794  *
795  * @param instance The created instance.
796  */
798 {
799  // Unix has a whole collection of similar environments, services by a single handler
800  _instance->addCommandHandler("COMMAND", (REXXPFN)systemCommandHandler);
803  _instance->addCommandHandler("KSH", (REXXPFN)systemCommandHandler);
804  _instance->addCommandHandler("CSH", (REXXPFN)systemCommandHandler);
805  _instance->addCommandHandler("BSH", (REXXPFN)systemCommandHandler);
806  _instance->addCommandHandler("BASH", (REXXPFN)systemCommandHandler);
807 }
808 
809 
810 
811 
812 
void addCommandHandler(const char *name, const char *registeredName)
void registerCommandHandlers(InterpreterInstance *i)
static RexxString * getDefaultAddressName()
static int strCaselessCompare(const char *opt1, const char *opt2)
Definition: Utilities.cpp:82
struct _RexxStringObject * RexxStringObject
Definition: rexx.h:128
struct _RexxObjectPtr * RexxObjectPtr
Definition: rexx.h:127
#define NULLOBJECT
Definition: rexx.h:147
#define RexxEntry
Definition: rexx.h:412
char ** getEnvironment()
#define SYSINITIALADDRESS
#define MAX_COMMAND_ARGS
#define MAX_VALUE
bool scan_cmd(const char *parm_cmd, char **argPtr)
char * unquote(const char *s)
#define SET_FLAG
#define EXPORT_FLAG
#define UNKNOWN_COMMAND
bool sys_process_cd(RexxExitContext *context, const char *cmd, RexxObjectPtr rc)
RexxObjectPtr RexxEntry systemCommandHandler(RexxExitContext *context, RexxStringObject address, RexxStringObject command)
bool sys_process_export(RexxExitContext *context, const char *cmd, RexxObjectPtr &rc, int flag)
#define UNSET_FLAG
void * REXXPFN