2021-12-29 13:16:03 +08:00
|
|
|
/*
|
2021-12-30 19:25:47 +08:00
|
|
|
* This file is part of Red Panda C++
|
2021-12-29 13:16:03 +08:00
|
|
|
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
2021-12-29 19:15:50 +08:00
|
|
|
#include <vector>
|
2021-12-29 13:16:03 +08:00
|
|
|
using std::string;
|
2021-12-29 19:15:50 +08:00
|
|
|
using std::vector;
|
2021-12-29 13:16:03 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2023-09-05 19:14:08 +08:00
|
|
|
#include <errno.h>
|
2021-12-29 13:16:03 +08:00
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h> /* For mode constants */
|
|
|
|
#include <fcntl.h> /* For O_* constants */
|
|
|
|
#include <chrono>
|
2022-12-13 09:46:16 +08:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
2021-12-29 13:16:03 +08:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#define MAX_COMMAND_LENGTH 32768
|
|
|
|
#define MAX_ERROR_LENGTH 2048
|
|
|
|
|
|
|
|
enum RunProgramFlag {
|
|
|
|
RPF_PAUSE_CONSOLE = 0x0001,
|
|
|
|
RPF_REDIRECT_INPUT = 0x0002
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void PauseExit(int exitcode, bool reInp) {
|
|
|
|
if (reInp) {
|
|
|
|
freopen("/dev/tty","r",stdin);
|
|
|
|
}
|
|
|
|
fflush(stdin);
|
|
|
|
printf("\n");
|
|
|
|
printf("Press ANY key to exit...");
|
|
|
|
getchar();
|
|
|
|
exit(exitcode);
|
|
|
|
}
|
|
|
|
|
2021-12-29 19:15:50 +08:00
|
|
|
vector<string> GetCommand(int argc,char** argv,bool &reInp,bool &pauseAfterExit) {
|
|
|
|
vector<string> result;
|
2021-12-29 13:16:03 +08:00
|
|
|
int flags = atoi(argv[1]);
|
|
|
|
reInp = flags & RPF_REDIRECT_INPUT;
|
|
|
|
pauseAfterExit = flags & RPF_PAUSE_CONSOLE;
|
2022-03-16 20:39:11 +08:00
|
|
|
for(int i = 3;i < argc;i++) {
|
2021-12-29 13:16:03 +08:00
|
|
|
//result += string("\"") + string(argv[i]) + string("\"");
|
|
|
|
std::string s(argv[i]);
|
2021-12-29 19:15:50 +08:00
|
|
|
|
2022-03-16 20:39:11 +08:00
|
|
|
if (i==3 || (reInp && i==4 ))
|
2021-12-29 13:16:03 +08:00
|
|
|
if (s.length()>2 && s[0]=='\"' && s[s.length()-1]=='\"') {
|
|
|
|
s = s.substr(1,s.length()-2);
|
|
|
|
}
|
2021-12-29 19:15:50 +08:00
|
|
|
result.push_back(s);
|
2021-12-29 13:16:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-10-29 17:21:38 +08:00
|
|
|
string unescapeSpaces(const string& s) {
|
|
|
|
string result;
|
2022-12-13 09:46:16 +08:00
|
|
|
size_t i=0;
|
2022-10-29 17:21:38 +08:00
|
|
|
while(i<s.length()) {
|
|
|
|
if (s[i]=='%' && (i+2)<s.length() && s[i+1]=='2' && s[i+2]=='0') {
|
|
|
|
result.push_back(' ');
|
|
|
|
i+=3;
|
|
|
|
} else {
|
|
|
|
result.push_back(s[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-12-13 09:46:16 +08:00
|
|
|
int ExecuteCommand(vector<string>& command,bool reInp, long int &peakMemory) {
|
|
|
|
peakMemory = 0;
|
2021-12-29 13:16:03 +08:00
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
2021-12-29 19:15:50 +08:00
|
|
|
string path_to_command;
|
|
|
|
char * * argv;
|
|
|
|
int command_begin;
|
|
|
|
int command_size;
|
|
|
|
if (reInp) {
|
|
|
|
if (command.size()<2) {
|
|
|
|
printf("not enough arguments1!\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
2022-10-29 17:21:38 +08:00
|
|
|
freopen(unescapeSpaces(command[0]).c_str(),"r",stdin);
|
|
|
|
path_to_command = unescapeSpaces(command[1]);
|
2021-12-29 19:15:50 +08:00
|
|
|
command_size = command.size()+1;
|
|
|
|
command_begin = 1;
|
|
|
|
} else {
|
|
|
|
if (command.size()<1) {
|
|
|
|
printf("not enough arguments2!\n");
|
|
|
|
exit(-1);
|
|
|
|
}
|
2022-10-29 17:21:38 +08:00
|
|
|
path_to_command = unescapeSpaces(command[0]);
|
2021-12-29 19:15:50 +08:00
|
|
|
command_size = command.size()+1;
|
|
|
|
command_begin = 0;
|
|
|
|
}
|
|
|
|
argv = (char * *)malloc(sizeof(char *)*command_size);
|
2022-10-19 09:49:09 +08:00
|
|
|
for (size_t i=command_begin;i<command.size();i++) {
|
2021-12-29 19:15:50 +08:00
|
|
|
argv[i-command_begin] = (char *)command[i].c_str();
|
|
|
|
}
|
|
|
|
argv[command.size()-command_begin]=NULL;
|
2021-12-29 13:16:03 +08:00
|
|
|
//child process
|
2021-12-29 19:15:50 +08:00
|
|
|
int pos = path_to_command.find_last_of('/');
|
|
|
|
std::string file = path_to_command;
|
2021-12-29 13:16:03 +08:00
|
|
|
if (pos>=0) {
|
2021-12-29 19:15:50 +08:00
|
|
|
file = path_to_command.substr(pos+1);
|
2021-12-29 13:16:03 +08:00
|
|
|
}
|
2021-12-29 19:15:50 +08:00
|
|
|
argv[0]=(char *)file.c_str();
|
|
|
|
int result=execv(path_to_command.c_str(),argv);
|
2021-12-29 13:16:03 +08:00
|
|
|
if (result) {
|
2021-12-29 19:15:50 +08:00
|
|
|
printf("Failed to start command %s %s!\n",path_to_command.c_str(), file.c_str());
|
2021-12-29 13:16:03 +08:00
|
|
|
printf("errno %d: %s\n",errno,strerror(errno));
|
2022-05-23 01:34:38 +08:00
|
|
|
char* current_dir = getcwd(nullptr, 0);
|
|
|
|
printf("current dir: %s",current_dir);
|
|
|
|
free(current_dir);
|
2021-12-29 13:16:03 +08:00
|
|
|
exit(-1);
|
|
|
|
}
|
2022-10-19 09:49:09 +08:00
|
|
|
free(argv);
|
2021-12-29 13:16:03 +08:00
|
|
|
} else {
|
|
|
|
int status;
|
|
|
|
pid_t w;
|
2022-12-13 09:46:16 +08:00
|
|
|
struct rusage usage;
|
|
|
|
w = wait4(pid, &status, WUNTRACED | WCONTINUED, &usage);
|
2021-12-29 13:16:03 +08:00
|
|
|
if (w==-1) {
|
2022-12-13 09:46:16 +08:00
|
|
|
perror("wait4 failed!");
|
2021-12-29 13:16:03 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2022-12-13 09:46:16 +08:00
|
|
|
peakMemory = usage.ru_maxrss;
|
2021-12-29 13:16:03 +08:00
|
|
|
if (WIFEXITED(status)) {
|
|
|
|
return WEXITSTATUS(status);
|
|
|
|
} else {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
2022-03-16 20:39:11 +08:00
|
|
|
char* sharedMemoryId;
|
2021-12-29 13:16:03 +08:00
|
|
|
// First make sure we aren't going to read nonexistent arrays
|
2022-03-16 20:39:11 +08:00
|
|
|
if(argc < 4) {
|
2021-12-29 13:16:03 +08:00
|
|
|
printf("\n--------------------------------");
|
2022-12-30 09:06:39 +08:00
|
|
|
printf("\nUsage: consolepauser <0|1> <shared_memory_id> <filename> <parameters>\n");
|
2021-12-30 19:25:47 +08:00
|
|
|
printf("\n 1 means the STDIN is redirected by Red Panda C++; 0 means not\n");
|
2021-12-29 13:16:03 +08:00
|
|
|
PauseExit(EXIT_SUCCESS,false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make us look like the paused program
|
2022-03-16 20:39:11 +08:00
|
|
|
//SetConsoleTitleA(argv[3]);
|
|
|
|
sharedMemoryId = argv[2];
|
2021-12-29 13:16:03 +08:00
|
|
|
|
|
|
|
bool reInp;
|
|
|
|
bool pauseAfterExit;
|
|
|
|
// Then build the to-run application command
|
2021-12-29 19:15:50 +08:00
|
|
|
vector<string> command = GetCommand(argc,argv,reInp, pauseAfterExit);
|
2021-12-29 13:16:03 +08:00
|
|
|
if (reInp) {
|
|
|
|
freopen("/dev/tty","w+",stdout);
|
|
|
|
freopen("/dev/tty","w+",stderr);
|
|
|
|
} else {
|
|
|
|
fflush(stdin);
|
|
|
|
}
|
|
|
|
|
|
|
|
int BUF_SIZE=1024;
|
|
|
|
char* pBuf=nullptr;
|
2022-03-16 20:39:11 +08:00
|
|
|
int fd_shm = shm_open(sharedMemoryId,O_RDWR,S_IRWXU);
|
2021-12-29 13:16:03 +08:00
|
|
|
if (fd_shm==-1) {
|
|
|
|
//todo: handle error
|
2022-03-16 20:39:11 +08:00
|
|
|
printf("shm open failed %d:%s\n",errno,strerror(errno));
|
2021-12-29 13:16:03 +08:00
|
|
|
} else {
|
2023-09-05 19:14:08 +08:00
|
|
|
// `ftruncate` has already done in RedPandaIDE
|
|
|
|
pBuf = (char*)mmap(NULL,BUF_SIZE,PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm,0);
|
|
|
|
if (pBuf == MAP_FAILED) {
|
|
|
|
printf("mmap failed %d:%s\n",errno,strerror(errno));
|
|
|
|
pBuf = nullptr;
|
2021-12-29 13:16:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save starting timestamp
|
|
|
|
auto starttime = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
|
|
// Execute the command
|
2022-12-13 09:46:16 +08:00
|
|
|
long int peakMemory;
|
|
|
|
int returnvalue = ExecuteCommand(command,reInp, peakMemory);
|
2021-12-29 13:16:03 +08:00
|
|
|
|
|
|
|
// Get ending timestamp
|
|
|
|
auto endtime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto difftime = endtime - starttime;
|
|
|
|
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(difftime);
|
2022-12-20 17:08:09 +08:00
|
|
|
double seconds = milliseconds.count()/1000.0;
|
2021-12-29 13:16:03 +08:00
|
|
|
|
|
|
|
if (pBuf) {
|
|
|
|
strcpy(pBuf,"FINISHED");
|
|
|
|
munmap(pBuf,BUF_SIZE);
|
|
|
|
}
|
|
|
|
if (fd_shm!=-1) {
|
2022-03-16 20:39:11 +08:00
|
|
|
shm_unlink(sharedMemoryId);
|
2021-12-29 13:16:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Done? Print return value of executed program
|
|
|
|
printf("\n--------------------------------");
|
2022-12-20 17:08:09 +08:00
|
|
|
printf("\nProcess exited after %.4g seconds with return value %d, %ld KB mem used.\n",seconds,returnvalue,peakMemory);
|
2021-12-29 13:16:03 +08:00
|
|
|
if (pauseAfterExit)
|
|
|
|
PauseExit(returnvalue,reInp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|