/** * Try to handle special commands like "cd" or "export" internally. This will * work if we have a simple commend with no redirection, piping, or such. * * @param context The Exit oontext. * @param cmd The command string. * @param rc The operating system return code. * * @return True if command was handled, false otherwise. */ logical_t handleCommandInternally(RexxExitContext *context, char *cmd, RexxObjectPtr rc) { /* check for redirection symbols, ignore them when enclosed in double quotes. escaped quotes are ignored. */ bool noDirectInvoc = false; bool inQuotes = false; bool escape = false; size_t i; for (i = 0; i<strlen(cmd); i++) { if (escape) { escape = false; } else if (cmd[i] == '\\') { escape = true; } else if (cmd[i] == '"') { inQuotes = !inQuotes; } else { /* if we're in the unquoted part and the current character is one of */ /* the redirection characters or the & for multiple commands then we */ /* will no longer try to invoke the command directly */ if (!inQuotes && (strchr("<>|&;", cmd[i]) != NULL)) { noDirectInvoc = true; break; } } } if (!noDirectInvoc) { // execute special commands in the same process // we currently don't handle formats like " cd" or "'cd'" internally if (strcmp("cd", cmd) == 0 || strncmp("cd ", cmd, 3) == 0) { return sys_process_cd(context, cmd, rc); } if (strncmp("set ", cmd, 4) == 0) { return sys_process_export(context, cmd, rc, SET_FLAG); } if (strncmp("unset ", cmd, 6) == 0) { return sys_process_export(context, cmd, rc, UNSET_FLAG); } if (strncmp("export ", cmd, 7) == 0) { return sys_process_export(context, cmd, rc, EXPORT_FLAG); } } return false; }
RexxObjectPtr RexxEntry systemCommandHandler(RexxExitContext *context, RexxStringObject address, RexxStringObject command) { const char *cmd = context->StringData(command); const char *envName = context->StringData(address); RexxObjectPtr rc = NULLOBJECT; /* check for redirection symbols, ignore them when enclosed in double quotes. escaped quotes are ignored. */ bool noDirectInvoc = false; bool inQuotes = false; bool escape = false; size_t i; for (i = 0; i<strlen(cmd); i++) { if (escape) { escape = false; } else if (cmd[i] == '\\') { escape = true; } else if (cmd[i] == '"') { inQuotes = !inQuotes; } else { /* if we're in the unquoted part and the current character is one of */ /* the redirection characters or the & for multiple commands then we */ /* will no longer try to invoke the command directly */ if (!inQuotes && (strchr("<>|&", cmd[i]) != NULL)) { noDirectInvoc = true; break; } } } if (!noDirectInvoc) { /* execute 'cd' in the same process */ size_t commandLen = strlen(cmd); if (strcmp(cmd, "cd") == 0) { if (sys_process_cd(context, cmd, rc)) { return rc; } } else if (commandLen >= 3) { char tmp[16]; strncpy(tmp, cmd, 3); tmp[3] = '\0'; if (strcmp("cd ",tmp) == 0) { if (sys_process_cd(context, cmd, rc)) { return rc; } } strncpy(tmp, cmd, 4); tmp[4] = '\0'; if (strcmp("set ",tmp) == 0) { if (sys_process_export(context, cmd, rc, SET_FLAG)) /*unset works fine for me*/ { return rc; } } strncpy(tmp, cmd, 6); tmp[6] = '\0'; if (Utilities::strCaselessCompare("unset ", tmp) == 0) { if (sys_process_export(context, cmd, rc, UNSET_FLAG)) { return rc; } } strncpy(tmp, cmd, 7); tmp[7] = '\0'; if (Utilities::strCaselessCompare("export ", tmp) == 0) { if (sys_process_export(context, cmd, rc, EXPORT_FLAG)) { return rc; } } } } /****************************************************************************/ /* Invoke the system command handler to execute the command */ /****************************************************************************/ // if this is the null string, then use the default address environment // for the platform if (strlen(envName) == 0) { envName = SYSINITIALADDRESS; } int errCode = 0; #ifdef LINUX if (Utilities::strCaselessCompare("bash", envName) == 0) { errCode = system( cmd ); if ( errCode >= 256 ) { errCode = errCode / 256; } } else #endif { int pid = fork(); int status; if (pid != 0) /* spawn a child process to run the */ { waitpid ( pid, &status, 0); /* command and wait for it to finish */ if (WIFEXITED(status)) /* If cmd process ended normal */ { /* Give 'em the exit code */ errCode = WEXITSTATUS(status); } else /* Else process died ugly, so */ { errCode = -(WTERMSIG(status)); if (errCode == 1) /* If process was stopped */ { errCode = -1; /* Give 'em a -1. */ } } } else { /* run the command in the child */ if (Utilities::strCaselessCompare("sh", envName) == 0) { #ifdef ANDROID execl("/system/bin/sh", "sh", "-c", cmd, NULL); #else execl("/bin/sh", "sh", "-c", cmd, NULL); #endif } else if (Utilities::strCaselessCompare("ksh", envName) == 0) { execl("/bin/ksh", "ksh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("bsh", envName) == 0) { execl("/bin/bsh", "bsh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("csh", envName) == 0) { execl("/bin/csh", "csh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("bash", envName) == 0) { execl("/bin/bash", "bash", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("cmd", envName) == 0) { char * args[MAX_COMMAND_ARGS+1]; /* Array for argument parsing */ if (!scan_cmd(cmd, args)) /* Parse cmd into arguments */ { exit(1); } execvp(args[0], args); /* Invoke command directly */ exit(1); /* we couldn't run the */ } else { execl("/bin/sh", "sh", "-c", cmd, NULL); } } } // unknown command code? if (errCode == UNKNOWN_COMMAND) { // failure condition context->RaiseCondition("FAILURE", context->String(cmd), NULL, context->WholeNumberToObject(errCode)); } else if (errCode != 0) { // non-zero is an error condition context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode)); } return context->False(); // zero return code }