Getting unwanted signals/input from terminal in c program - c

I written c program in the below concepts.
main_process.c
/* check the give process id is alive or not. if not alive then start that process.*/
void * thread1()
{
while(1) {
if (kill(pid, 0)!=0) {
system(process1);
}
}
}
/* Get the process id for the started process */
void *thread2() {
while (1) {
FILE *fp = popen("ps -af | grep "process1");
get_pid(pid, fp);
pclose(pid);
}
}
get_pid(pid, fp) {
/* Get the pid for the new process using getline() and string parsing using string token function, its long code so not pasted here.*/
}
main(int arg, char *args[]) {
pthread_t tid1, tid2;
pthread_create(tid1,NULL, &thread1, NULL);
pthread_create(tid2, NULL, &thread2, NULL);
//Checks thread created success or not.
pthread_join(tid1);
pthread_join(tid2);
}
process:
main() {
char input[100];
while (1) {
fgets(input, 100, stdin);
printf("\n Input is %s \n", input);
}
I started the process program first, and get the pid and starting the main_process.
After some time I killed the process program using kill -9 pid. So the if condition of thread1 in main_process passed and starts the process program.
Getting inputs from the terminal. After some time I again killed the process program using kill -9 pid. So thread1 again starts the process program.
Issue is the following: When the process program starts for the second time, getting unwanted inputs from terminal. I have no idea about who's sending, issue in keyboard or in my program concepts.
Please inform where I made mistakes.

Related

Background execvp : how to do it properly?

Like many others, I'm trying to simulate a shell. I've gotten to use the execvp properly on a string coming from the user. The string is parsed and an array of strings is generated (each word has its array, split on the space character), including a NULL at the very end.
When I find that the last word entered by the user is &, I set a flag up to notify my shell that the command is to be executed in the background while letting the user input another command right away. The "background-executed" command sees its & replaced by a NULL character within the array of strings passed to execvp.
As it is, I've been trying to use a pthread to run the process in the background, but it's acting somewhat weird: the command passed to execvp through the thread's function requires me to press two times ENTER after sending the command.
Here is my simplified main function that is to simulate a shell:
int main (void) {
fprintf (stdout, "%% ");
bool running = true;
while(running) {
/* Ask for an instruction and parses it. */
char** args = query_and_split_input();
/* Executing the commands. */
if (args == NULL) { // error while reading input
running = false;
} else {
printf("shell processing new command\n");
int count = count_words(args);
split_line* line = form_split_line(args, count);
Expression* ast = parse_line(line, 0, line->size - 1);
if(line->thread_flag) {
pthread_t cmd_thr;
/* Setting up the content of the thread. */
thread_data_t thr_data;
thr_data.ast = *ast;
thr_data.line = *line;
/* Executing the thread. */
int thr_err;
if ((thr_err = pthread_create(&cmd_thr, NULL, thr_func, &thr_data))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", thr_err);
return EXIT_FAILURE;
}
printf("thread has been created.\n");
} else {
run_shell(args);
}
free(line);
printf("done running shell on one command\n");
}
}
/* We're all done here. See you! */
printf("Bye!\n");
exit (0);
}
Here is my thread's function:
void *thr_func(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
data->line.content[data->line.size-1] = NULL; // to replace the trailing '&' from the command
run_shell(data->line.content);
printf("thread should have ran the command\n");
pthread_exit(NULL);
}
And the actual line that runs a command:
void run_shell(char** args) {
/* Forking. */
int status;
pid_t pid; /* Right here, the created THREAD somehow awaits a second 'ENTER' before going on and executing the next instruction that forks the process. This is the subject of my first question. */
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed");
} else if (pid == 0) { // child
printf("Child executing the command.\n");
/* Executing the commands. */
execvp(args[0], args);
/* Child process failed. */
printf("execvp didn't finish properly: running exit on child process\n");
exit(-1);
} else { // back in parent
waitpid(-1, &status, 0); // wait for child to finish
if (WIFEXITED(status)) { printf("OK: Child exited with exit status %d.\n", WEXITSTATUS(status)); }
else { printf("ERROR: Child has not terminated correctly. Status is: %d\n", status); }
free(args);
printf("Terminating parent of the child.\n");
}
}
So basically, as an example, what run_shell(args) receives is either ["echo","bob","is","great",NULL] (in the case of a sequential execution) or ["echo","bob","is","great",NULL,NULL] (in the case of a command to be executed in the background).
I've left the printf traces since it might help you understand the execution flow.
If I input echo bob is great, the output (printf traces) is:
shell processing new command
Child executing the command.
bob is great
OK: Child exited with exit status 0.
Terminating parent of the child.
done running shell on one command
However, if I input echo bob is great &, the output is:
shell processing new command
thread has been created.
done running shell on one command
And then I actually need to press ENTER again to obtain the following output:
Child executing the command.
bob is great
OK: Child exited with exit status 0.
Terminating parent of the child.
thread should have ran the command
(On that last execution, I also get traces of my function that queries and parses the input of the user, but that seemed irrelevant so I abstracted this whole part.)
So my questions are:
How comes the created thread awaits a second ENTER before running the execvp ? (thr_func stops executing run_shell and awaits the second ENTER right before the pid = fork(); instruction)
Do I have the right approach to solve the problem at hand? (Trying to execute a shell command in the background.)
You cannot use a thread to simulate a process. Well, strictly you can, but there's no use on doing that. The problem is that all the threads belonging to a process share the same virtual address space. There's no reason to create a thread, as you finally need to fork() to create a new process (you'll need this for reasons explained below), so why to create two threads of execution if one of them will be stopped all the time just waiting for the subprocess to finish. There's no use on this schema.
The need of a fork() system call comes historically to make a simple call to create a new process (with different virtual memory map) to allow for a new program to be able to be executed. You need to create a new, complete process before calling exec(2) system call, because the process address space will be overwritten by the text and data segments of the new program. If you do this in a thread, you'll be overwriting the whole process address space (this is the shell) and killing all the threads you can have running on behalf of that process. The schema to follow is (pseudocode):
/* create pipes for redirection here, before fork()ing, so they are available
* in the parent process and the child process */
int fds[2];
if (pipe(fds) < 0) { /* error */
... /* do error treatment */
}
pid_t child_pid = fork();
switch(child_pid) {
case -1: /* fork failed for some reason, no subprocess created */
...
break;
case 0: /* this code is executed in the childd process, do redirections
* here on pipes acquired ***before*** the fork() call */
if (dup2(0 /* or 1, or 2... */, fds[0 /* or 1, or 2... */]) < 0) { /* error */
... /* do error management, considering you are in a different process now */
}
execvpe(argc, argv, envp);
... /* do error management, as execvpe failed (exec* is non-returning if ok) */
break; /* or exit(2) or whatever */
default: /* we are the parent, use the return value to track the child */
save_child_pid(child_pid);
... /* close the unused file descriptors */
close(fds[1 /* or 0, or 2, ... */]);
... /* more bookkeeping */
/* next depends on if you have to wait for the child or not */
wait*(...); /* wait has several flavours */
} /* switch */
Exec and fork system calls are separated by two reasons:
you need to be able to do housekeeping between both calls to execute the actual redirections in the child before exec().
there was a time when unix was not multitasking or protected, and the exec call just replaced all the memory in the system with the new program to execute (including kernel code, to cope with the fact that an unprotected system could be corrupted by the executing program) This was common in old operating systems and I've seen it on systems like CP/M or TRS-DOS. The implementation in unix conserved almost all the semantics of exec() call and added with fork() the unavailable functionality only. This was good, as it allowed both, parent and child processes to do the necessary bookkeeping when the time for pipes came.
Only if you need a different thread to communicate with each child is when you probably can use a different thread to do the task. But think that a thread shares all the virtual space with the parent (case we can talk about a parent/child relationship between threads) and if you do an exec call you'll get that virtual space overwritten for the whole process (all threads there)

Handling signals SIGSTP, SIGCONT, SIGINT with child process

I'm currently writing a simple shell in C and i'm facing issues with signals.
For example when I launch my program, I type ping command then CTRL-Z I want that the child process (the ping command) to be paused and then to come back when I use fg.
I think that I need to store as a global variable the child pid of the one that execute the ping command.
I already checked other posts to resolve the problem by my own but I can't get it working.
This is the code to execute a command (multiple commands with |) and where I store the child pid.
int exec_proc(int input, int output, char** command) {
pid_t runner;
runner = fork();
f_pid = runner;
if (runner == 0) {
// Use input for stdin
if (input != 0) {
dup2(input, 0);
close(input);
}
// Use output for stdout
if (output != 1) {
dup2(output, 1);
close(output);
}
// Return command code
execvp(command[0], command);
}
// An error occured
return -1;
This is my handler c file.
pid_t f_pid;
/**
* Handles every handler !
*/
void handlerManager()
{
signal(SIGINT,INTHandler);
signal(SIGTSTP,TSTPHandler);
signal(SIGCONT,CONTHandler);
}
/**
* Handler for CTRL-C
* #param sig
*/
void INTHandler(int sig)
{
printf("\nDo you really want to quit ? [y/n] \n");
int answer = getchar();
if(toupper(answer) == 'Y')
kill(f_pid,SIGINT);
}
/**
* Handler for CTRL-Z (processus sleep)
* #param sig
*/
void TSTPHandler(int sig)
{
printf("\nGoing to sleep! \n");
printf("%d", f_pid);
kill(f_pid,SIGTSTP);
}
/**
* Handler to reset a processus
* #param sig
*/
void CONTHandler(int sig)
{
printf("\nHey i'm awake\n");
kill(f_pid,SIGCONT);
}`
When I print the pid I am getting the right PID.
Finally this where I call my handler Manager.
int main() {
char* line;
char** args[MAX_ARG_SIZE] = {NULL};
int status;
handlerManager();
do {
fflush(stdin);
prompt();
line = readline();
char linecpy[strlen(line)];
strcpy(linecpy, line);
splitBy(line, " ", args);
status = exec(args, linecpy);
switch (status) {
case EMPTY_LINE:
break;
}
} while (status);
return 0;
Thank you in advance and sorry for my english.
Doing proper job-control signal handling lifts your project a bit beyond what I would characterize as a "simple" shell. The GLIBC manual has a whole multi-part section on implementing a job-control shell, and it sounds like much of it would apply to your project.
A key aspect that you seem to be disregarding is managing process groups and which of those has control of the terminal. The way you're doing things now, your shell's child processes will belong to the same process group as the shell itself, and that will present a problem when a signal, such as SIGSTP, is sent to the child's whole process group.
To avoid such problems, your shell should make new child processes be process-group leaders of their own process groups (via setpgid()). When such process groups are meant to initially be in the foreground, your shell should make them terminal's controlling process group (tcsetpgrp()).
There's more to it than that, of course, but that should get you going in the right direction.
The exec_proc file should have
pid_t f_pid;
as a global variable (reverse the two lines)
pid_t runner;
int exec_proc(int input, int output, char** command) {
The handler C file needs to access the global variable declared in the other file via extern
extern pid_t f_pid;
This way, both object files share the same variable f_pid.
edit -----
Try to change the handler TSTP, and add the following ALRM
void TSTPHandler(int sig)
{
signal(SIGTSTP,SIG_DFL); // <+++++
printf("\nGoing to sleep! \n");
printf("%d", f_pid);
kill(f_pid,SIGTSTP);
kill(getpid(),SIGTSTP); // <+++++
alarm(1); // <+++++
}
void ALRMHandler(int sig) // <+++++
{
signal(SIGTSTP,TSTPHandler);
}
Add Alarm signal
void handlerManager()
{
signal(SIGINT,INTHandler);
signal(SIGTSTP,TSTPHandler);
signal(SIGCONT,CONTHandler);
signal(SIGALRM,ALRMHandler); // <+++++
}
Works on my Linux box. When a stop occurs
disable TSTP handling
do the current stuff
kill the main process!
start an alarm to set the TSTP handling back (adding that to the handler seems to create some trouble...)
Note that alarm() takes seconds, setitimer() goes down to the microsecond (in theory).

Minishell problems with cd (C)

I made a simple minishell in C and it works, except for the cd command. When I try to run it nothing happens except it creates a child process that never actually ends. For example, after running cd in my minishell I need to type exit twice to exit the minishell, not the standard once.
Code:
int debug=0;
void safeQuit(){
if (debug==1)
printf("INFO: Parent process, pid=%d exiting.\n", getpid());
exit(0);
}
int main(int argc,char** argv)
{
int pid, stat;
char * Array_arg[50];
char command_line[200];//user input
if (argc>1)
if (strcmp(argv[1],"-debug")==0)
debug=1;
while (1){
printf("[minishell]> "+debug);
gets(command_line);
if (strcmp(command_line,"exit")==0)
safeQuit();
char * subcommand=strtok(command_line," "); //divides the string according to the spaces
int i=0;
while (subcommand!= NULL)//insert to array
{
Array_arg[i]=subcommand;
subcommand=strtok(NULL," ");
i++;
}
Array_arg[i]='\0';
if (fork()==0){
if (debug==1)
printf("INFO: child process, pid = %d, executing command %s\n", getpid(), command_line);
execvp(Array_arg[0],Array_arg); //execution of cmd
}
else{
pid=wait(&stat);
}
}
}
cd is necessarily a shell built-in, not an external utility. You want to change the current working directory of the current process (the shell itself), not of a child process. Call chdir instead of forking a child process.
Separately, check execvp for errors and defensively terminate the child after a failed exec. You'd have seen an informative error if you had done so:
... (child) ...
execvp(Array_arg[0], Array_arg);
perror("Error - exec failed"); // If we are here, we did *not* replace the process image
exit(0);

Why SIGINT is send to a child process and does nothing?

I am building a simple debugger for my university class and I have a problem in handling SIGINT.
What I want to do is when the debugger process (from now on PDB) takes a SIGINT signal passes that to the child process (the one that is being actually debugged by PDB).
I am doing this:
pid_t childid;
void catch_sigint(int sig)
{
signal(SIGINT,SIG_DFL);
kill(childid,sig);
}
int debuger (char *address, parm *vars)
{
int ignore=1;
int status;
childid = fork();
signal(SIGINT,catch_sigint);
if(childid==0)
{
ptrace(PTRACE_TRACEME,0, NULL,NULL);
if(execve(address,NULL,NULL)==-1)
{
perror("ERROR occured when trying to create program to trace\n");
exit(1);
}
}
else
{
int f_time=1;
while(1)
{
long system_call;
wait(&status);
if(WIFEXITED(status))break;
if(WIFSIGNALED(status))break;
system_call = ptrace(PTRACE_PEEKUSER,childid, 4 * ORIG_EAX, NULL);
if(!strcmp(vars->category,"process-control") || !strcmp(vars->category,"all"))
ignore = pr_calls(system_call,ignore,limit,childid,vars->mode); //function that takes the system call that is made and prints info about it
if(!strcmp(vars->category,"file-management") || !strcmp(vars->category,"all"))
ignore = fl_calls(system_call,ignore,limit,childid,vars->mode);
if(f_time){ignore=1;f_time=0;}
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
}
}
signal(SIGINT,SIG_DFL);
return 0;
}
This program runs and forks a child process and execs a program to trace its system calls. That works fine when it doesn't get any signal.
But when in the middle of some tracing I press ctrl+c I expect the child process to stop and PDB to continue and stop (because of this line if(WIFSIGNALED(status))break;. That never happens. The program it traces continues its system calls and prints.
The tracing program is that:
#include <stdio.h>
int main(void)
{
for(;;) printf("HELLO WORLD\n");
return 0;
}
That program continues printing HELLO WORLD even after I hit ctrl+c.
I also observed that the system calls that ptrace gives after ctrl+c are -38 and that the status in wait changes only once after the signal from 1407 (I think is the normal value) to 639 and then back again to 1407 on the next wait.
So what I am doing wrong in that?
The problem it's on this line:
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
It has to be like that:
ptrace(PTRACE_SYSCALL,childid, NULL, signal_variable);
Where signal_variable is an int declared in global scope so the handler and the debugger can see it. It has a starting value of 0.
The signal handler now takes the signal and passes it in this variable and at the next loop when the ptrace orders the tracee program to continue it sends it the signal too.
That happens because when you trace a program the tracee stops execution when it receives a signal and waits further instruction for what to do with the signal from the tracer through ptrace.

c: catch a segfault in exec() which was run in a child process

EDIT:
I am trying to write a simple smoketest, where all options and reasonable parameters are tested.
I used popen() to execute the program that should be tested.
Using this approach does not work, because if the process dies with a signal (SIGINT, SIGSEGV...) the pipe from popen() does not tell me what happend.
Writing a signal handler did not help since popen creates a new process that receives the signals but not my smoketest.
Thanks to the answers i used pipe(), fork() and execv() to create my own popen()-version.
When the program now segfaults there is the problem that the pipe is useless (a read caused weird behavior -> blocked the process until i send a sigkill to the parent!)
To avoid this i tried different things and my solution is the following (it is simple but it took me a while to figure it out). so here is my example-code:
static int child_dead = 0;
void sigaction_sigchld(int signal) { /* Child died */
child_dead = 1;
}
int main(int argc, char *argv[], char *env[])
{
char *crashing_program = "/program_path/and_name";
int ret;
int byte;
pid = fork();
if(pid == 0) /* Child */
{
execve(crashing_program, argv, env);
/* if execve returns that it mus have failed! */
fprintf(stderr, "Exec failed\n");
_exit(-1);
} else /* Parent */
{
if(!child_dead)
{
byte = read(pipe_out[1], line, BUFFSIZE);
if(!byte){
perror("Smoketest:Line:xxx");
} else
{
fprintf(stdout, line);
}
}
wait(&child_status);
/*
check if the child died with SIGSEGV etc
*/
}
This seems to work fine as long as i only have one child at a time which is sufficient for me though. I anyone has a better idea or any tipps for me i would be glad to update this entry.
Last but not least: Of course using this method it is probably impossible to do any cleanup.
Cheers.
See the documentation for waitpid(2). There are a bunch of macros you can use to test how the child process was terminated. In particular, you can use WIFSIGNALED() and WTERMSIG() to test if the child process was terminated by a signal, and if so, which signal:
int status = pclose(...);
if (WIFSIGNALED(status))
{
// It was terminated by a signal
if (WTERMSIG(status) == SIGSEGV)
{
// It was terminated by a segfault
}
}
Edit: As stated in the comments, you'd rather make use of fork and exec, then use waitpid(2) to correctly update status.

Resources