Use C to exit ssh session to linux - c

I"m running a program that runs over ssh session. Meaning I connect to a linux using putty, the program starts, using the /etc/bash.bashrc file. At some point the program suppose to end and with it the ssh session via putty should disconnect.
What I"ve done untill now with a code below, and it doesn't work: the program exits, and stays in linux shell, meaning the putty is connected. What I expected is the command "exit" to end the putty ssh session.
char file_name[20];
pid_t pid = fork();
if (pid == 0)
{
printf("Starting vi\r\n");
char external_cmd[200] = "vi ";
strcat(external_cmd, file_name);
system(external_cmd);
} else
{
waitpid(pid,0,0);
printf("Exit..\r\n");
system("exit");
}
thanks for the help.

The easiest solution is to start your C program with exec so that it replaces the shell. The SSH session will naturally end when the program exits.
$ exec your_program

This code doesn't accomplish anything:
system("exit");
system() runs a child process under sh:
The system() function shall behave as if a child process were
created using fork(), and the child process invoked the sh utility
using execl() as follows:
execl(<shell path>, "sh", "-c", command, (char *)0);
So, your call to system() starts a sh process, which then executes the exit command you passed to it - and the child process exits, doing nothing to the parent processes.
You can kill the parent shell, though, by obtaining the PID of the parent process with getppid() and then calling kill() to kill it:
#include <unistd.h>
#include <signal.h>
...
pid_t parent = getppid();
kill( parent, SIGKILL );
SIGKILL is probably a bit extreme - it kills a process immediately, with no chance for the process to clean up after itself, but it will work (unless you're running a non-root setuid child process in this case - if you don't know what that is, don't worry about it.). SIGTERM is a less-extreme signal, but since it can be caught or blocked it isn't guaranteed to end a process. SIGINT is the equivalent of CTRL-C and may also work, but again the process can catch or ignore the signal. SIGQUIT can also be used, but it's purpose is to cause the process to quit and dump a core file, which you probably don't want.

Related

Execlp execute in another terminal

I am creating an application in C which I have to execute the firefox with the command execlp but every time I execute it I "lost" my current terminal, but after the execlp i still need to use the terminal which I was before, so my question is: Is there a way where I can be in one terminal call execlp and it executes in another one without block the one I am on?
here is a snippet of my code:
pid_t child = fork();
if (child == -1) {
perror("fork error");
} else if (child == 0) {
exec_pid = getpid();
execlp("firefox", "firefox", URL, NULL);
perror("exec error");
}
// keep with program logic
If I'm understanding you correctly, you're saying that your program launches Firefox and then keeps control of your shell until Firefox terminates. If this is the case, there are a couple of ways around this.
The easiest solution is to run your program in the background. Execute it like ./my_program & and it be launched in a separate process and control of your terminal will be returned to you immediately.
If you want to solve this from your C code, the first step would be to print out the process ID of the child process after the fork. In a separate shell, use ps to monitor both your program and the forked PID. Ensure that your program is actually terminating and that it's not just stuck waiting on something.

In a basic Shell Program in C, how to exit all processes associated with a parent?

I am writing a basic shell program for a university assignment, and i need to test for when the user enters the string "exit". When this happens the program should quit.
I can test for this successfully, but if i have forked new processes that have dealt with an strerror in my program, i have to keep entering exit for however many active processes are running at that current time.
Is there a way of exiting all associated processes with a program under this condition?
Cheers.
As said in comments, you should not spawn interactive processes in the background (at least how your shell and your command will handle the only stdin?).
Also as a shell you should keep track of all spawned processes (in background) so that you are able to catch their return code, as done in sh/bash (at least). For exemple in bash:
> sleep 1 &
[1] 8215
>
(1 sec later)
[1]+ Terminated sleep 1
So if you have the list of existing children you can send SIGINT/SIGKILL to all of them.
Whatever if you really want to be sure to kill everyone you should use process group (PG) killing. Using kill() function with PID=0 sends the kill signal to all processes in the same process group than you.
So you can start your shell by setting a new process group (to be sure to not kill something else), and this PG will be inherited by your children (appart if a child set a new PG of course).
This would looks like:
// at the begining of your main code
// try to get a new process group for me
x = setpgid(0,0);
if (x == -1) {
perror("setpgid");
exit(1);
}
(…)
// here you're about to exit from main, just kill
// all members of your group
kill(0, SIGINT); // send an INT signal
kill(0, SIGKILL); // paranoid: if a child catch INT it will get a KILL
// now you can exit, but you're probably dead 'cause you
// also receive the SIGINT. If you want to survive you have to
// catch SIGINT, but you will not catch KILL whatever
If it is needed for you to survive the kill you may catch the signal using signal() or better sigaction() so that you will not be killed and so able to perform other before-exit actions.

Gracefully Terminating a process when its controlling shells gets killed

I have a command line application. The issue I am facing is that sometimes the users of that application close directly the terminal in which our application is running that also using the below command:
kill -9 pid_of_parent_console
I the above case our application should close gracefully by doing all the necessary cleanup. For that I wrote a signal handler for handling SIGHUP signal as when controlling terminal of process exits it sends SIGHUP to processes running under it, which we have handled to exit our process gracefully.But the thing is if user open a terminal suppose that is by default bash and then he again types bash command in it then run our application and if suppose kills that applications parent process that is bash executed manually after opening terminal then our application doesn't gets SIGHUP and does not exit gracefully.For simplicity I have written the below code which reproduces the issue:
#include <stdio.h>
#include <signal.h>
FILE *fp = NULL;
int flag = 1;
void handler(int signum)
{
flag = 0;
}
int main()
{
signal(SIGHUP, handler);
// just for testing
fp = fopen("file", "w");
// loop terminates only when HUP is generated
while (flag);
// if SIGHUP is generated then code should reach here
// and write the below in file.
fprintf(fp, "SIGHUP Generated");
fclose(fp);
return 0;
}
For simplicity I am not using sigaction for handling signals.
What I have observed is that when I open a terminal and press tty command and note the name of stdin file associated with it, and then when in the same terminal if I enter bash command and again if I note down the stdin file associated with it using tty command, what I found out is that both the bash shells, one that opens by default when I launch terminal and one I manually opened by typing bash command in bash console share the same stdin file name.
So, due to which when I kill that second bash which is parent of my process the stdin file associated with it doesn't gets closed and I think thats why I am not receiving SIGHUP signal.
Is there any other way I can use to kill my process too gracefully when its controlling console gets killed.
Terminal emulator used: GNOME Terminal 2.31.3
Default shell: bash
Regardless of the OS, SIGKILL (i.e. signal -9) is directly handled by the kernel and the process is killed before any userland handler had a chance to process anything. This is true for the Linux kernel just like the Solaris one.
There is then no way for the target process to protect itself against that signal (outside intercepting it on the sender side or in the kernel).
On the other hand, closing a terminal emulator window send an XEvent to it. Before exiting, the terminal emulator should probably send a SIGHUP signal to your process.
I would suggest to use dtrace on the Solaris 10 machine to investigate this process. Start with this script which show all signals sent: http://www.brendangregg.com/DTrace/kill.d

killing a child process if execvp fails

I have a C program similar in structure to: http://www.csl.mtu.edu/cs4411/www/NOTES/process/fork/exec.html (that is, it's a shell that runs one command with execvp when entered and loops indefinitely until "exit" is entered).
What is the best way to kill a child process immediately if an unrecognized command is passed to execvp? For example, if I typed "ehco" instead of "echo" how could I quickly kill this child process? I've noticed if I enter a command not in my PATH and then immediately type exit it doesn't exit until I type exit again later.
The linked example already does the right thing: the child should unconditionally call _exit() after execvp(). The execvp() will only return if it fails.
(In other words, you don't kill the child process from the parent; you wait for the child process to exit, and write the child process so that it kills itself if the exec fails).

Non-blocking version of system()

I want to launch a process from within my c program, but I don't want to wait for that program to finish. I can launch that process OK using system() but that always waits. Does anyone know of a 'non-blocking' version that will return as soon as the process has been started?
[Edit - Additional Requirement] When the original process has finished executing, the child process needs to keep on running.
One option is in your system call, do this:
system("ls -l &");
the & at the end of the command line arguments forks the task you've launched.
Why not use fork() and exec(), and simply don't call waitpid()?
For example, you could do the following:
// ... your app code goes here ...
pid = fork();
if( pid < 0 )
// error out here!
if( !pid && execvp( /* process name, args, etc. */ )
// error in the child proc here!
// ...parent execution continues here...
The normal way to do it, and in fact you shouldn't really use system() anymore is popen.
This also allows you to read or write from the spawned process's stdin/out
edit: See popen2() if you need to read and write - thansk quinmars
You could use posix_spawnp() function. It's much similar to system() than the fork and exec* combination, but non-blocking.
In the end, this code appears to work. Bit of a mis-mash of the above answers:
pid = fork();
if (!pid)
{
system("command here &");
}
exit(0);
Not quite sure why it works, but it does what I'm after, thanks to everyone for your help
How about using "timeout" command if you are looking for your command to exit after a specific time:
Ex: system("timeout 5 your command here"); // Kills the command in 5 seconds if process is not completed

Resources