I have tried to write a program that run in ubuntu terminal .Program will open a new gnome terminal and run command in that new terminal to open new abcd.txt using vim.And then when i Ctrl+C in the first terminal which run the program ,new gnome terminal will shut vim down and have an announcement in the first terminal
I have tried system("`gnome-terminal`<< vim abcd.txt");
and this system("vim abcd.txt>>`gnome-terminal`");
but the new one terminal cannot recieve command
My full code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop=1;
void DEF()
{
system("kill -9 pidof vim");
loop=0;
}
void *subthreads(void *threadid)
{
loop=1;
long tid;
tid=(long)threadid;
system("`gnome-terminal`<< vim abcd.txt");
signal(SIGINT,DEF);
while(loop){}
pthread_exit(NULL);
}
void main()
{
int loop=1;
pthread_t threads;
int check;
long tID;
check= pthread_create(&threads,NULL,&subthreads,(void*)tID);
while(loop){}
printf("Ctrl+C is pressed!\n");
}
Not sure what you are trying to achieve in the end. But here are a few ideas, starting from your code:
The terminal command (in system()) should be something like Mark Setchell pointed out, like for example system("gnome-terminal -e vim file.txt");
The system() command is blocking further execution of your code, so the call to signal() is not happening until you terminate the system() call.
pidof is not working on my Linux system. I would use pkill <program>. Still, that would kill all running instances of , for example vim or your terminal.
You are declaring the variable loop in the global scope first and then redeclaring it in main(). If you really want to use it as a global variable, it should just be loop=1 in main().
You are not using the variable tid for anything.
Here is an improved version of your program, with additional printf calls to explain to the user what is happening. I also used xterm and nano because I don't have gnome-terminal, and I didn't want to interfere with my running instance of vim. But it still is maybe not exactly what you are trying to do. The main problem is that system("xterm -e sh &") is blocking and when you press Ctrl-C, that system call will terminate xterm so that the def() function will do nothing when it is called later.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop = 1;
void def()
{
printf("In def\n");
system("pkill xterm");
loop=0;
}
void *subthreads(void *threadid)
{
printf("Starting subthread\n");
loop = 1;
long tid;
tid = (long)threadid;
signal(SIGINT, def);
system("xterm -e sh -c nano &"); // Note: xterm will still exit when you press Ctrl-C
printf("Terminal exited in subthread\n");
while (loop);
printf("Exited loop in subthread\n");
pthread_exit(NULL);
}
void main()
{
pthread_t threads;
int check;
long tID;
check = pthread_create(&threads, NULL, &subthreads, (void*)tID);
printf("In main after thread creation\n");
while (loop);
printf("Ctrl+C is pressed!\n");
}
Another option is to use fork() instead of pthread to split into a separate process. (Note that processes are like separate applications while threads are processor threads in the same application.)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void def()
{
system("pkill nano");
printf("def(): Killed nano\n");
}
int subprocess()
{
signal(SIGINT, def);
pid_t parent_id = getpid(); // Get process ID of main process
fork(); // Fork into two identical copies of the running app.
if (getpid() != parent_id) { // The part in the if block is only done in the second process!
system("xterm -e sh -c nano &");
printf("subprocess(): system call ended in forked process\n");
exit(0);
}
}
int main()
{
subprocess();
printf("Entering while loop in main process\n");
while (1);
printf("Exited main thread\n");
}
The one flaw with this version is the same as the previous one: when Ctrl-C is pressed, xterm/nano is killed and def() will subsequently do nothing except catch any Ctrl-C done afterwards.
If you explain further what your final goal is, maybe I can give some suggestions.
Like, why do you want to start vim in a terminal from a C application and then kill vim? Do you want to kill the whole terminal or only vim?
Related
If I have a C++ code with an infinite loop inside i want a command that will kill the execution after certain time.
so i came up with something like this-
g++ -std=c++20 -DLOCAL_PROJECT solution.cpp -o solution.exe & solution.exe & timeout /t 0 & taskkill /im solution.exe /f
But the problem with this was that it would first execute the program so due to the infinite loop it won't even come to timeout and taskkill part.
Does anybody have any solution to it or other alternatives instead of timeout?
I am using windows 10 and my compiler is gnu 11.2.0
Also in case there is No TLE i don't want taskkill to show this error
ERROR: The process "solution.exe" not found.
Your main loop could exit after a certain time limit, if you're confident it is called regularly enough.
#include <chrono>
using namespace std::chrono_literals;
using Clock = std::chrono::system_clock;
int main()
{
auto timeLimit = Clock::now() + 1s;
while (Clock::now() < timeLimit) {
//...
}
}
Alternatively you could launch a thread in your main throwing an exception after a certain delay:
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
struct TimeOutException {};
int main()
{
std::thread([]{
std::this_thread::sleep_for(1s);
std::cerr << "TLE" << std::endl;
throw TimeOutException{};
}).detach();
//...
}
terminate called after throwing an instance of 'TimeOutException'
I use chdir() to switch the directory, and then use execvp() to execute "java Main". I'm sure there is Main.class, but something went wrong. I want to know why.
#include <cstdio>
#include <unistd.h>
using namespace std;
int main(){
char buf[80];
getcwd(buf,sizeof(buf));
printf("current working directory: %s\n", buf);
chdir("/home/keane/Judge/temp");
getcwd(buf,sizeof(buf));
printf("current working directory: %s\n", buf);
char *array[3];
array[0] = "java";
array[1] = "Main";
array[2] = NULL;
execvp("java", array);
return 0;
}
the error is could not find the main class , and I can run java Main in that directory.
What drives me crazy is that I can't use system("java Main"), and the error is that Error: Could not find or load main class Main, and it's just like this on my computer
update:
#include <unistd.h>
#include <cstdlib>
int main(){
chdir("/home/keane/Judge/temp");
system("pwd");
system("ls");
system("java Main");
return 0;
}
the output on console is:
/home/keane/Judge/temp
1.out 3.out 5.out Main.class stdout_spj.txt
2.out 4.out ce.txt Main.java
Error: Could not find or load the main class Main
my final solution is to reboot the computer and add -cp . to the java command.
althought I don't why is necessary.
thanks everyone!
This works as intended on my system, maybe you need to add -cp . to your java call.
EDIT: to elaborate: -cp (for classpath) tells java where to look for user provided .class files. This does not necessarily include the current working directory by default.
The execution of execvp() is non-blocking and takes ownership of the caller, that means that when it starts if the program ends too quickly you will never be able to see the result, to solve this I use fork(). The wait is just to avoid using sleep as I used at the begining. Its all in c.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char** argv){
char buf[80];
getcwd(buf,sizeof(buf));
printf("current working directory: %s\n", buf);
chdir("/home/");
getcwd(buf,sizeof(buf));
printf("current working directory: %s\n", buf);
char *array[3] = {"java", "Main", NULL};
if(fork() == 0) {
if(execvp("java", array) < 0) {
fprintf(stderr, "Error spawning command: %s\n", strerror(errno));
}
} else {
printf("Command spawned\n");
wait(NULL); // Wait to the forked process to end (avoid using sleep)
}
return 0;
}
I am running a C++ console application in an embedded linux environment. I want to run a std::system command just like this. I have taken tar for an example.
int main(int argc, char *argv[]) {
std::system("tar xvzf /path/to/some/file.tar.gz");
exit 0;
}
Question:
If I exit the application right after the tar command like above, will the tar command continue to execute?
I understand that it depends a bit on how tar is implemented itself. But lets say tar doesn't work after parent process exits (considering worst case scenario), is there a way I can run the command std::system command safely in background and exit my app trusting that it will complete its job after my app or parent process has exited?
The commands executed by system() will usually not continue after system() returns. system() starts a new process (using fork() + exec*() or CreateProcess() etc.) and then waits until that process is finished before it returns. If the command however spawns orphaned children, then they may live on.
This may have that effect depending on the SHELL used by system():
std::system("nohup tar xvzf /path/to/some/file.tar.gz &");
Since system() starts the command using a shell (probably /bin/sh) and that it in turn uses the process's current environment (most notably PATH and variables that may be used to affect which shared libraries that are used by the command) - and that you can also send command strings with redirects, putting commands in the background (as shown above) etc. - it's often considered a security risk. One way to minimize the risk is to create your own system function that does not use a shell or the environment. Example:
#include <iostream>
#include <array>
#include <type_traits> // std::common_type_t
#include <cstdlib> // std::exit
#include <utility> // std::forward
// fork, exec, waitpid
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
template<typename... Ts>
int mysystem(Ts&&... ts) {
int wstatus=-1;
pid_t pid = fork();
if(pid==0) { // in child process
std::array<std::common_type_t<Ts...>, sizeof...(ts) + 1> cmd{ std::forward<Ts>(ts)... };
execv(cmd[0], const_cast<char* const*>( cmd.data() ));
std::exit(1); // we'll only get here if execv failed starting the command
} else if(pid!=-1) { // in parent process
// wait for the child to terminate
// the exit status from the child will be returned in wstatus
waitpid(pid, &wstatus, 0); // 0 = wait forever
} // else { /* fork() failed */ }
return wstatus;
}
int main() {
//int ws = mysystem("/usr/bin/find", ".");
//int ws = mysystem("/usr/bin/bash", "-i");
int ws = mysystem("/usr/bin/tar", "xvzf", "/path/to/some/file.tar.gz");
std::cout << "--------------------\n"
"Exit status: " << WEXITSTATUS(ws) << "\n"
"Termination signal: " << WTERMSIG(ws) << "\n"
"Core dumped: " << std::boolalpha << WCOREDUMP(ws) << "\n";
}
std::system is a blocking call...
That means you don't reach the exit before the tar command itself is finished.
All, the first part of my homework assignment is simply a demo program that I need to compile, and then modify. It was provided by the teacher, however I simply cannot get it to compile using g++. I will be creating a make file at the end of the assignment, but for the moment I am simply trying to test it out, and am having no luck. I've tried the most basic g++ command: g++ -o main TwoPipesTwoChildren.cpp . Can someone please help? I can't even get started on this until I can get this working.
// description: This program will execute "ls -ltr | grep 3376"
// by using a parent and child process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv){
printf("TEST");
int status;
int childpid;
char *cat_args[] = {"ls", "-ltr", NULL};
char *grep_args[] = {"grep", "3376", NULL};
// create one pipe to send the output of "ls" process to "grep" process
int pipes[2];
pipe(pipes);
// fork the first child (to execute cat)
if((childpid = fork()) == -1)
{
perror("Error creating a child process");
exit(1);
}
// replace cat's stdout with write part of 1st pipe
if (childpid == 0)
{
dup2(pipes[1], 1);
printf("AFTER FORK CHILD");
//close all pipes (very important!); end we're using was safely copied
close(pipes[0]);
close(pipes[1]);
execvp(*cat_args, cat_args);
exit(0);
}
else
{
// replace grep's stdin with read end of 1st pipe
dup2(pipes[0], 0);
close(pipes[0]);
close(pipes[1]);
execvp(*grep_args, grep_args);
}
return (0);
}
Sorry for my grammar\spelling. I'm Romanian.
I am using Code::Blocks to edit in C++ and Notepad to edit in Batch.
I can't find a better title for this.
I'm trying to use this program:
#include <iostream>
#include <fstream>
#include "windows.h"
#include <string>
#include "G:\other.h"
using namespace std;
char message[500],from[20];
int interm;
int main()
{
ofstream wait1("errorlevel.f"); wait1<<0; wait1.close();
fstream wait2("errorlevel.f",ios::in); wait2>>interm;
cout<<"Another window is waiting for you...";
system("start options_load-new.bat");
while (interm==0) { wait2>>interm; Sleep(10); }
st();
//and program continues...
}
where st(); function is declared in other.h as
void st()
{
system("cls");
}
and the options_load-new.bat file is this:
#echo off
echo What do you want to do?
echo [L] Load a pre-made message
echo [N] Make a new one
choice /c ln
echo %errorlevel% > errorlevel.f
exit
but -
When I run the program, is opens, starts the .bat file, that file sets errorlevel.f to 1 or 2, and closes. After that, the main program remains to Another windws is waiting for you... without any action.
What should I do to make the main program continue his operations?