C program is interrupted during the execution of “system” function - c

I have a problem with my C code, basically I need to send email via mutt program. It must be send when an interrupt comes up from GPIO pin. My sendMail function is listed below. I realized this by using system function. Main contains loop with logAlarm func which contains sendMail. The thing is when system(cmd) function finishes, the whole C program stops. For instance when i put sendMail function at the begining of the main it works and is sending email to my mailbox without stopping whole program, in the loop it manages to send it but it terminates program. I tried to using & sign to run it in background but it didnt help.
P.S i dont know if it matters but im also using system call from setitimer with 2 sec intervals to check few things but i guess it has no impact for this case.
Any ideas?
Thanks in advance :)
sendMail function:
void sendMail(char * msg, char * recipientMail){
char cmd[100];
char subject[30];
char body[60];
sprintf(body, "Intruder detected!!!\n%s", msg);
strcpy(subject, "\"ALARM - SECURITY BREACH\"");
sprintf(cmd,"echo \"%s\" | mutt -s %s %s &", body, subject, recipientMail);
printf("%s\n\n", cmd);
system(cmd);
}
Here is a piece of my main function:
while(1){
sleep(1);
if(prev_state == triggered && !emailDetach){
if(!logAlarm()){
printf("Error writing to log file!!!\n");
}
emailDetach = true;
}
//printf("Czas od poprzedniego alarmu: %d", millis() - alarmTriggeredTime);
if((prev_state == triggered) && (millis() - alarmTriggeredTime >= ALARM_TIME)){
digitalWrite(ALARM_ON_DIODE, LOW);
digitalWrite(ALARM_OFF_DIODE, HIGH);
//warunek czasowy osobno na syrene TODO
if(!silentMode && (millis() - alarmTriggeredTime >= siren_alarm_time)){
digitalWrite(SIREN, LOW);
}
prev_state = nottriggered;
}
}

Good question. As per description, I consider that sendMail function works properly. I've not worked with mutt. But i've worked with system().
What system does is, it forks a child process of your current process and executes the command using execve(). So the problem should be in the returning of the system.
So, first you should check the return status of system function. If you are able to make printf() below the system(), then you're not having problem with system(). If you are not able get printf below the system(), then system() is killing your process. (by sending sigkill or similer signals, but not sigint or sigquit, since it is ignored by system()). You are creating a child process in the cmd itself (echo output piping to mutt). May be this should be root cause.
If you find problem here, then the problem is critical, and you will find directions from the "NOTES" section of "man system", since you have implemented the same logic mentioned there. First just try to wait for conditions mentioned there. If you're still unable to do this, try to fork two new child process, run execl or any other exec family function ("man 3 exec") from that child process to run echo and mutt.
If system() is ok, then check logAlarm(). is it giving the right arguments to the sendMail? if you are getting "Error writing to log file!!!", then entire sequence is ok.

Related

return readline to its original state when recieving SIGINT

In bash when a user hits ctrl-c (sending SIGINT) it takes back readline to its original state canceling search/vi-mode/... state.
I tried UNSETSTATE macro but it has no effect, actually even SETSTATE has no effect on the state of readline, however the rl_readline_state variable is changed.
In signal handler I tried:
RL_UNSETSTATE(RL_STATE_ISEARCH|RL_STATE_NSEARCH|RL_STATE_SEARCH|RL_STATE_VIMOTION|RL_STATE_NUMERICARG|RL_STATE_MULTIKEY);
I tried rl_redisplay() but nothing works.
Keep in mind that I have:
rl_catch_signals = 0;
I have a handler for rl_getc_function.
Here is my code:
https://gitlab.com/abellaismail/minishell/-/blob/dev/src/sig_handler.c
I knew it had to do with 42 in some way.
Here's my repo for the project, if you want to look further into how exactly the solution I found works.
Assuming your question applies when the prompt is waiting for a command and you press ctrl + C (when on heredoc or executing childs processes the behaviour is a bit different), I called the following function:
void ft_signal_ctrl_c(int sig)
{
(void)sig;
write(2, "\n", 1);
rl_replace_line("", 0);
rl_on_new_line();
rl_redisplay();
}
This succesfully goes back to the shell while (running) loop, showing a new prompt. errno should be updated separately too (ctrl+ C gives $? = 1).

use SIGQUIT and SIGINT

I'm trying to solve a problem because I'm learning to use system calls in C. I used a Ubuntu 12.04 64bit.
The statement of the problem says that I need to implement a code that allows to execute a command (cmd2) after the correct end of other command (cmd1). Also says that user can specify both commands and all of the arguments that user wants.
At this point I create this little program:
#include <syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int cmd1 = system("sleep 5");
if((cmd1 = (-1)))
{
write(1,"error in command 1",18);
}
if(cmd1=(0))
{
write(1, "hello world", 11);
}
return EXIT_SUCCESS;
}
Next, statement says that if the first command doesn't finish correctly the second will not execute, also, user can abort the execution of the cmd1 using Ctrl+\ or Ctrl+4 (SIGQUIT) and the second command (cmd2) using Ctrl+C (SIGINT). If second command is canceled the first must be completed normaly.
I have problems in this second part of the statement because I never used this kind of things in C and also I'm really noob in linux. I tried to read something about SIGQUIT and SIGINT but I don't understand all that I've read probably because there are a lot of things of linux that I've not learned yet.
Can anyone help me please?
Thanks!
I edit the code for this version using if functions. It doesn't work correctly, I'm finding how to check if the first command finishes correctly.
Just to get you started. Let me explain the question because I feel you haven't understood it.
The statement of the problem says that I need to implement a code that allows to execute a command (cmd2) after the correct end of other command (cmd1).
You will will be given two commands by the user cmd1 and cmd2. cmd1 should be executed first.
Next, statement says that if the first command doesn't finish correctly the second will not execute,
ONLY IF cmd1 finished executing normally should cmd2 be executed.
If second command is canceled the first must be completed normaly.
Execution of cmd1 is not dependent on cmd2.
user can abort the execution of the cmd1 using Ctrl+\ or Ctrl+4 (SIGQUIT)
You seem confused here. Here, they mean to say, cmd1 can be abnormally terminated by passing SIGQUIT to it(Ctrl+\ or Ctrl+4), in which case cmd2 should not be executed. You do NOT have to code the signals part. What you have to do is, check how cmd1 was terminated and then execute cmd2 if it was a normal termination else don't execute cmd2.
Note The code in the question was extremely different when the above part was posted.
This was your code on 5:02 AM Wednesday, 20 May 2015 GMT.(Had to include this because you are changing the code too often and too much)
int main(void)
{
int cmd1 = system("sleep 5");
if((cmd1 = (-1)))
{
write(1,"error in command 1",18);
}
if(cmd1=(0))
{
write(1, "hello world", 11);
}
return EXIT_SUCCESS;
}
Here you are using = for comparing. = is used for assignment and not equality compassion. == is used for equality compassion. So, if((cmd1 = (-1))) and if(cmd1=(0)) should have been if((cmd1 == (-1))) and if(cmd1 == (0))
You are checking if the returned value is -1 for failure. This is incorrect. Exit code for success is 0 for failure is any value other than 0. So, if((cmd1 = (-1))) should have been if(cmd1 != 0).

C - SIGALRM blocks getchar()

I'm working on a C terminal multiprocess application. The application is menu based, so the user have to choose from the possibilities to do the action. The menu is blocked with a getchar(). Let me show the codepart:
do
{
do
{
printf("\n\n---------------\nMenu\n\n");
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("3. Option 3\n");
printf("4. Exit");
printf("\n\n---------------\n");
scanf("%d", &end);
int c = getchar();
if(end < 1 || end > 4)
{
printf("Try it again!!!\n\n");
}
}
while(end < 1 || end > 4);
}
while(end != 4);
So the user need to choose one of the options. But the problem is that the 2nd option needs to kick off a function in every 5 seconds in the background. One of the children will be handled by the function. So I've created an alarm() handler firstly with the simple signal() method. After that I'm realized that the getchar() I/O process is blocked by received signals. I've tried to create a new child which should handle the stdin processes, and send back the result in a pipe for the parent, but this was not worked too.
Let me share the current signal handling part for better understanding:
// Alarm handling
void CatchAlarm(int sig)
{
if(someCounts > 0)
{
DoSomething();
alarm(5);
}
}
Also the alarm binding:
struct sigaction alarmAction;
alarmAction.sa_handler = CatchAlarm;
sigemptyset(&alarmAction.sa_mask);
alarmAction.sa_flags = SA_RESTART;
sigaction(SIGALRM, &alarmAction, NULL);
My problem is that, I can't send the parent process to sleep, because the user have to be able to do other activities during the alarm is pending. When I get the SIGALRM, the full stdin reading process is going to crazy. Please help me what can I use to block the reading and waiting for user interaction instead of the getchar(), because I've already tried everything. Or if someone can help me how can I solve the issue I can appreciate that.
Of course, if you have further questions or concerns please let me know, and I'm going to update my question as soon as possible.
Thanks in advance
Just put an alarm(5); call before the getchar(); so the kernel is advised to send a SIGALRM signal to interrupt getchar(3). Then, you don't have to put any code inside the signal handler (but you do need the signal handler or the program will be killed, see alarm(2) and kill(2) for an explanation) You'll have to uninstall it after the getchar call either case or the signal handler will be called anyway after 5 seconds, but that's left as an exercise for the reader.
Note on notation
As standard in unix for a long time a reference like getchar(3) means the man page for getchar routine that is located in section 3 of the online unix reference manual. Section 2 is dedicated to system calls and section 3 to library calls historically.

I am trying to create a interactive shell

I am trying to create a interactive shell program that prompts the user for a command, parses the command, and then executes it with a child process. Here is the code that I have but im not sure where to go after this PLEAE HELP !!!!
Int shell(char *cmd_str ){
int commandLength=0;
cmd_t command;
commandLength=make_cmd(cmd_str, command);
cout<< commandLength<<endl;
cout << command.argv[0]<< endl;
if( execvp( command.argv[0], command.argv)==-1)
//if the command it executed nothing runs after this line
{
commandLength=-1;
}else
{
cout<<"work"<<endl;
}
cout<< commandLength<<endl;
return commandLength;
}
Assuming shell() is being run within a child process called with fork(), you'll need to ensure that the parent process properly waits for the child process to terminate. See the wait(2) family of functions.
Additionally, you'll want to retrieve the exit status of said child process (again, see wait(2)).
You can also try to implement stream redirection. Assuming this is an exercise, I'll leave the additional research on how to implement these things up to the user :) -- look into dup(2).

How to cancel an alarm() signal via a child process?

For an assignment, I am working on creating a time aware shell. The shell forks and executes commands and kills them if they run for more than a set amount of time. For example.
input# /bin/ls
a.out code.c
input# /bin/cat
Error - Expired After 10 Seconds.
input#
Now, my question is: is there a way to prevent the alarm from starting if an error is incurred in the processing of the program, that is, when exevce returns -1?
Since the child-process runs separately and after hours of experimenting and research I have yet to find anything that discusses or even hints at this type of task, I have a feeling it may be impossible. If it is indeed impossible, how can I prevent something like the following from happening...
input# /bin/fgdsfgs
Error executing program
input# Error - Expired After 10 Seconds.
For context, here is the code I am currently working with, with my attempt at doing this myself removed. Thanks for the help in advance!
while(1){
write(1, prompt, sizeof(prompt)); //Prompt user
byteCount = read(0, cmd, 1024); //Retrieve command from user, and count bytes
cmd[byteCount-1] = '\0'; //Prepare command for execution
//Create Thread
child = fork();
if(child == -1){
write(2, error_fork, sizeof(error_fork));
}
if(child == 0){ //Working in child
if(-1 == execve(cmd,arg,env)){ //Execute program or error
write(2, error_exe, sizeof(error_exe));
}
}else if(child != 0){ //Working in the parent
signal(SIGALRM, handler); //Handle the alarm when it goes off
alarm(time);
wait();
alarm(0);
}
}
According to the man page:
Description
The alarm() function shall cause the system to generate a SIGALRM signal for the process after the number of realtime seconds specified by seconds have elapsed. Processor scheduling delays may prevent the process from handling the signal as soon as it is generated.
If seconds is 0, a pending alarm request, if any, is canceled.
Alarm requests are not stacked; only one SIGALRM generation can be scheduled in this manner. If the SIGALRM signal has not yet been generated, the call shall result in rescheduling the time at which the SIGALRM signal is generated.
Interactions between alarm() and any of setitimer(), ualarm(), or usleep() are unspecified.
So, to cancel an alarm: alarm(0). It is even present in your sample code.
The main problem
By the way, you're missing an important piece here:
if(child == 0){ //Working in child
if(-1 == execve(cmd,arg,env)){ //Execute program or error
write(2, error_exe, sizeof(error_exe));
_exit(EXIT_FAILURE); // EXIT OR A FORKED SHELL WILL KEEP GOING
}
}else if(child != 0){ //Working in the parent
The wait() system call takes an argument; why aren't you compiling with the right headers in the source file and with compiler warnings (preferably errors) for undeclared functions? Or, if you are getting such warnings, pay heed to them before submitting code for review on places like StackOverflow.
You don't need to test the return status from execve() (or any of the exec*() functions); if it returns, it failed.
It is good to write an error on failure. It would be better if the child process exited as well, so that it doesn't go back into the while (1) loop, competing with your main shell for input data.
if (child == 0)
{
execve(cmd, arg, env);
write(2, error_exe, sizeof(error_exe));
exit((errno == ENOEXEC) ? 126 : 127);
}
In fact, the non-exiting of your child is the primary cause of your problem; the wait doesn't return until the alarm goes off because the child hasn't exited. The exit statuses shown are intended to match the POSIX shell specification.

Resources