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  size_t size = strlen(home_dir)+strlen(st)+2;
436  dir_buf = (char *)malloc(size);
437  if (!dir_buf)
438  {
439  return false;
440  }
441  /* merge the strings */
442  snprintf(dir_buf, size, "%s/%s", home_dir, st);
443  }
444  else
445  {
446  /* get home directory path */
447  home_dir = getenv("HOME"); /* from the environment */
448  /* get space for the buf */
449  size_t size = strlen(home_dir)+2;
450  dir_buf = (char *)malloc(size);
451  if (!dir_buf)
452  {
453  return false;
454  }
455  snprintf(dir_buf, size, "%s/", home_dir);
456  }
457  }
458  else if (*(st) == '~') /* cmd is '~username...' */
459  {
460  st++; /* jump over '~' */
461  slash = strchr(st,'/'); /* search for '/' */
462  if (!slash) /* if no '/' */
463  {
464  /* rest of string is username */
465  ppwd = getpwnam(st); /* get info about the user */
466  if (ppwd == NULL || ppwd->pw_dir == NULL)
467  {
468  return false;
469  }
470  /* get space for the buf */
471  size_t size = strlen(ppwd->pw_dir)+2;
472  dir_buf = (char *)malloc(size);
473  if (!dir_buf)
474  {
475  return false;
476  }
477  /* merge the strings */
478  snprintf(dir_buf, size, "%s/", ppwd->pw_dir);
479  }
480  else /* there is a slash */
481  {
482  char username[256]; // need to copy the user name
483  memcpy(username, st, slash - st);
484  username[slash - st] = '\0';
485 
486  ppwd = getpwnam(username); /* get info about the user */
487  if (ppwd == NULL || ppwd->pw_dir == NULL)
488  {
489  return false;
490  }
491  slash++; /* step over the slash */
492  /* get space for the buf */
493  size_t size = strlen(ppwd->pw_dir)+strlen(slash)+2;
494  dir_buf = (char *)malloc(size);
495  if (!dir_buf)
496  {
497  return false;
498  }
499  /* merge the strings */
500  snprintf(dir_buf, size, "%s/%s", ppwd->pw_dir, slash);
501  }
502  }
503  else
504  {
505  dir_buf = strdup(st);
506  }
507 
508  char *unquoted = unquote(dir_buf);
509  if (unquoted == NULL)
510  {
511  return false;
512  }
513  int errCode = chdir(unquoted);
514  free(unquoted);
515 
516  free(dir_buf);
517  if (errCode != 0)
518  {
519  // non-zero is an error condition
520  context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
521  }
522  else
523  {
524  rc = context->False();
525  }
526  return true;
527 }
528 
529 
530 /*********************************************************************/
531 /* This function breaks a command up into whitespace-delimited pieces*/
532 /* to create the pointer array for the execvp call. It is only used */
533 /* to support the "COMMAND" command environment, which does not use */
534 /* a shell to invoke its commands. */
535 /*********************************************************************/
536 
537 bool scan_cmd(const char *parm_cmd, char **argPtr)
538 {
539  char *cmd = strdup(parm_cmd); /* Allocate for copy */
540 
541  char *end = cmd + strlen(cmd); /* Find the end of the command*/
542 
543  /* This loop scans our copy of the command, setting pointers in */
544  /* the args[] array to point to each of the arguments, and null- */
545  /* terminating each one of them. */
546 
547  /* LOOP INVARIANT: */
548  /* pos points to the next character of the command to be examined. */
549  /* i indicates the next element of the args[] array to be loaded. */
550  size_t i = 0; /* Start with args[0] */
551  for (char *pos = cmd; pos < end; pos++)
552  {
553  while (*pos==' ' || *pos=='\t')
554  {
555  pos++; /* Skip to first non-white */
556  }
557 
558  if (*pos == '\0') /* If we're at the end, */
559  {
560  break; /* get out. */
561  }
562 
563  /* If at this point, we've used up all but one of the available */
564  /* elements of our args[] array, let the user know, and we must */
565  /* terminate. */
566  if (i == MAX_COMMAND_ARGS)
567  {
568  return false;
569  }
570 
571  argPtr[i++] = pos; /* Point to current argument */
572  /* and advance i to next */
573  /* element of args[] */
574  while (*pos!=' ' && *pos!='\t' && *pos!='\0')
575  {
576  pos++; /* Look for next whitespace */
577  } /* or end of command */
578  *pos = '\0'; /* Null-terminate this arg */
579 
580  }
581 
582  /* Finally, put a null pointer in args[] to indicate the end. */
583  argPtr[i] = NULL;
584  return true;
585 }
586 
587 /******************************************************************************/
588 /* Name: sys_command */
589 /* */
590 /* Arguments: cmd - Command to be executed */
591 /* local_env_type - integer indicating which shell */
592 /* */
593 /* Returned: rc - Return Code */
594 /* */
595 /* Notes: Handles processing of a system command. */
596 /* Uses the 'fork' and 'exec' system calls to create a new process*/
597 /* and invoke the shell indicated by the local_env_type argument. */
598 /* This is modeled after command handling done in Classic REXX. */
599 /******************************************************************************/
601 {
602  const char *cmd = context->StringData(command);
603  const char *envName = context->StringData(address);
604 
606 
607  /* check for redirection symbols, ignore them when enclosed in double quotes.
608  escaped quotes are ignored. */
609  bool noDirectInvoc = false;
610  bool inQuotes = false;
611  bool escape = false;
612  size_t i;
613  for (i = 0; i<strlen(cmd); i++)
614  {
615  if (escape)
616  {
617  escape = false;
618  }
619  else if (cmd[i] == '\\')
620  {
621  escape = true;
622  }
623  else if (cmd[i] == '"')
624  {
625  inQuotes = !inQuotes;
626  }
627  else
628  {
629  /* if we're in the unquoted part and the current character is one of */
630  /* the redirection characters or the & for multiple commands then we */
631  /* will no longer try to invoke the command directly */
632  if (!inQuotes && (strchr("<>|&", cmd[i]) != NULL))
633  {
634  noDirectInvoc = true;
635  break;
636  }
637  }
638  }
639 
640  if (!noDirectInvoc)
641  {
642  /* execute 'cd' in the same process */
643  size_t commandLen = strlen(cmd);
644 
645  if (strcmp(cmd, "cd") == 0)
646  {
647  if (sys_process_cd(context, cmd, rc))
648  {
649  return rc;
650  }
651  }
652  else if (commandLen >= 3)
653  {
654  char tmp[16];
655  strncpy(tmp, cmd, 3);
656  tmp[3] = '\0';
657  if (strcmp("cd ",tmp) == 0)
658  {
659  if (sys_process_cd(context, cmd, rc))
660  {
661  return rc;
662  }
663  }
664  strncpy(tmp, cmd, 4);
665  tmp[4] = '\0';
666  if (strcmp("set ",tmp) == 0)
667  {
668  if (sys_process_export(context, cmd, rc, SET_FLAG)) /*unset works fine for me*/
669  {
670  return rc;
671  }
672  }
673  strncpy(tmp, cmd, 6);
674  tmp[6] = '\0';
675  if (Utilities::strCaselessCompare("unset ", tmp) == 0)
676  {
677  if (sys_process_export(context, cmd, rc, UNSET_FLAG))
678  {
679  return rc;
680  }
681  }
682  strncpy(tmp, cmd, 7);
683  tmp[7] = '\0';
684  if (Utilities::strCaselessCompare("export ", tmp) == 0)
685  {
686  if (sys_process_export(context, cmd, rc, EXPORT_FLAG))
687  {
688  return rc;
689  }
690  }
691  }
692  }
693 
694 
695  /****************************************************************************/
696  /* Invoke the system command handler to execute the command */
697  /****************************************************************************/
698  // if this is the null string, then use the default address environment
699  // for the platform
700  if (strlen(envName) == 0)
701  {
702  envName = SYSINITIALADDRESS;
703  }
704 
705  int errCode = 0;
706 #ifdef LINUX
707 
708  // JLF : I don't know why a special case is made to call system()
709  // But something sure : it's wrong to call system() when the passed address is "bash".
710  // Since system() delegates always to /bin/sh, the only acceptable address is "sh".
711  if (Utilities::strCaselessCompare("sh", envName) == 0)
712  {
713  errCode = system( cmd );
714  if ( errCode >= 256 )
715  {
716  errCode = errCode / 256;
717  }
718  }
719  else
720 #endif
721  {
722  int pid = fork();
723  int status;
724 
725  if (pid != 0) /* spawn a child process to run the */
726  {
727  waitpid ( pid, &status, 0); /* command and wait for it to finish */
728  if (WIFEXITED(status)) /* If cmd process ended normal */
729  {
730  /* Give 'em the exit code */
731  errCode = WEXITSTATUS(status);
732  }
733  else /* Else process died ugly, so */
734  {
735  errCode = -(WTERMSIG(status));
736  if (errCode == 1) /* If process was stopped */
737  {
738  errCode = -1; /* Give 'em a -1. */
739  }
740  }
741  }
742  else
743  { /* run the command in the child */
744  if (Utilities::strCaselessCompare("sh", envName) == 0)
745  {
746  execl("/bin/sh", "sh", "-c", cmd, NULL);
747  }
748  else if (Utilities::strCaselessCompare("ksh", envName) == 0)
749  {
750  execl("/bin/ksh", "ksh", "-c", cmd, NULL);
751  }
752  else if (Utilities::strCaselessCompare("bsh", envName) == 0)
753  {
754  execl("/bin/bsh", "bsh", "-c", cmd, NULL);
755  }
756  else if (Utilities::strCaselessCompare("csh", envName) == 0)
757  {
758  execl("/bin/csh", "csh", "-c", cmd, NULL);
759  }
760  else if (Utilities::strCaselessCompare("bash", envName) == 0)
761  {
762  execl("/bin/bash", "bash", "-c", cmd, NULL);
763  }
764  else if (Utilities::strCaselessCompare("cmd", envName) == 0)
765  {
766  char * args[MAX_COMMAND_ARGS+1]; /* Array for argument parsing */
767  if (!scan_cmd(cmd, args)) /* Parse cmd into arguments */
768  {
769  exit(1);
770  }
771  execvp(args[0], args); /* Invoke command directly */
772  perror(" *E* Address COMMAND"); /* If we get to this point, */
773  exit(1); /* we couldn't run the */
774  }
775  else
776  {
777  execl("/bin/sh", "sh", "-c", cmd, NULL);
778  }
779  }
780  }
781  // unknown command code?
782  if (errCode == UNKNOWN_COMMAND)
783  {
784  // failure condition
785  context->RaiseCondition("FAILURE", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
786  }
787  else if (errCode != 0)
788  {
789  // non-zero is an error condition
790  context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode));
791  }
792  return context->False(); // zero return code
793 }
794 
795 
796 /**
797  * Register the standard system command handlers.
798  *
799  * @param instance The created instance.
800  */
802 {
803  // Unix has a whole collection of similar environments, services by a single handler
804  _instance->addCommandHandler("COMMAND", (REXXPFN)systemCommandHandler);
807  _instance->addCommandHandler("KSH", (REXXPFN)systemCommandHandler);
808  _instance->addCommandHandler("CSH", (REXXPFN)systemCommandHandler);
809  _instance->addCommandHandler("BSH", (REXXPFN)systemCommandHandler);
810  _instance->addCommandHandler("BASH", (REXXPFN)systemCommandHandler);
811 }
812 
813 
814 
815 
816 
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:102
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:235
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