Why doensn't Ctrl+C doesn't work in my terminal? - c

I've the following problem:
I'm creating two threads in main. These threads never stop (they're always listening for messages).
So, in main, after creating this two threads, I've this snippet code to keep the program running:
for (;;)
{
sleep(10);
}
return 0;
It works, but the problem is that when I execute the program, in the terminal, Ctrl+C doesn't allow me to exit from the program. I've to exit with Ctrl+\. I've this function (not made by me). Where is the problem?
void app_signal_handler(int sig_num)
{
if (sig_num == SIGINT) {
printf("SIGINT signal!\n");
}
if (sig_num == SIGTERM) {
printf("SIGTERM signal!\n");
}
app_running = false;
}
char app_sigaltstack[SIGSTKSZ];
int app_setup_signals(void)
{
stack_t sigstack;
struct sigaction sa;
int ret = -1;
sigstack.ss_sp = app_sigaltstack;
sigstack.ss_size = SIGSTKSZ;
sigstack.ss_flags = 0;
if (sigaltstack(&sigstack, NULL) == -1) {
perror("signalstack()");
goto END;
}
sa.sa_handler = app_signal_handler;
sa.sa_flags = SA_ONSTACK;
if (sigaction(SIGINT, &sa, 0) != 0) {
perror("sigaction()");
goto END;
}
if (sigaction(SIGTERM, &sa, 0) != 0) {
perror("sigaction()");
goto END;
}
ret = 0;
END:
return ret;
}

You never use app_running. Replace
for (;;)
{
sleep(10);
}
with
while (app_running)
{
sleep(10);
}

Related

Changing directories in a shell. Writing my own shell in C

I am writing a simple shell in C. Right now when I run the command cd only work in the current environment that I am. So for example if I am in the Desktop folder I can only cd for a folder inside Desktop, I can't go to other folders in my computer.
How do I control this change of directories?
Thant's my cd function right now. Please let me know if you need more information.
int cmd_cd(char **args)
{
if (args[1] == NULL) {
fprintf(stderr, "expected argument to \"cd\"\n");
} else {
if (chdir(args[1]) != 0) {
fprintf(stderr, args[1],strerror(errno));;
}
}
return 1;
}
Here is my exec function that calls cd
char* builtCommandList[] = {"cd", "exit"};
int builtinSize = sizeof(builtCommandList) / sizeof(char *);
int (*builtin_func[]) (char **) = {
&cmd_cd,
&cmd_exit
};
int execute(char **args){
if(args[0] == NULL)
return 1;
for(int i =0; i<builtinSize;i++){
if (strcmp(args[0], builtCommandList[i]) == 0) {
printf("function is here");
return (*builtin_func[i])(args);
}
}
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) {
// Child process
if (execvp(args[0], args) == -1) {
fprintf(stderr, "error in child process");
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
// Error forking
fprintf(stderr, "error forking");
} else {
// Parent process
do {
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}

Timer disarms when interval is too small

Timers seem to disarm after process is resumed (SIGCONT) ONLY when interval is too small.
I use timer_create with CLOCK_REALTIME.
My linux distribution is ubuntu 20.04.1
This is the code that shows the problem
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
volatile siginfo_t sigInfo;
void childFunction();
void parentFunction(pid_t pid);
void ignoreChild();
void signalFunction(int signo, siginfo_t* SI, void* data);
int main(int argc, char* argv[])
{
ignoreChild();
pid_t pid;
pid = fork();
switch(pid)
{
case -1:
{
perror("Error in fork!\n");
exit(EXIT_FAILURE);
}
case 0:
{
childFunction();
exit(EXIT_SUCCESS);
}
default:
{
parentFunction(pid);
break;
}
}
return 0;
}
void signalFunction(int signo, siginfo_t* SI, void* data)
{
sigInfo = *SI;
}
void parentFunction(pid_t pid)
{
struct sigaction sa;
struct timespec sleepTime = { .tv_sec = 1, .tv_nsec = 0};
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signalFunction;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
//---- for blocking
sigset_t set = {0};
if (sigaddset(&set, SIGCHLD) == -1)
{
perror("Error in sigaddset!\n");
exit(EXIT_FAILURE);
}
while (1)
{
if (pause() == -1)
{
if (errno == EINTR)
{
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask!\n");
exit(EXIT_FAILURE);
}
if (sigInfo.si_status == SIGSTOP)
{
printf("Child received SIG_STOP signal\n");
nanosleep(&sleepTime, NULL);
kill(pid, SIGCONT);
}
if (sigInfo.si_status == SIGCONT)
{
printf("Child received SIGCONT signal!\n");
}
if (sigInfo.si_code == CLD_EXITED)
{
printf("Child is dead!\n");
break;
}
if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask2!\n");
exit(EXIT_FAILURE);
}
}
}
}
}
void ignoreChild()
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
}
void childFunction()
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if (timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working!\n");
nanosleep(&timeToWaitInLoop,NULL);
}
}
When I set timeForTimer to 3 seconds the program works correctly, for 2 seconds it still works but for 1 second it doesn't.
To compile:
gcc -Wall main.c -lrt
This is shorter example
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if( timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working! (PID) %d\n", getpid());
nanosleep(&timeToWaitInLoop,NULL);
}
}
In above example only one SIGSTOP signal occured. After sending SIGCONT with command kill -18 <pid> there was no more SIGSTOP signals.It looks like my timer disarmed.

How to print stdout and stderr of a command with different colors in C langage

I am writing a program in C language that acts like a shell terminal, the user enters a command and I parse the line then use "execv()" to execute the command.
Now I'm trying to print the standard output and the error output with different colors (making sure that the order doesn't change. But I'm having troubles both outputs.
Thanks you for your help
void dumsh_execute(char **command_args, char **redirection_args) {
if ( redirection_args[0] ) {
printf("%s\n", "Redirecting");
if ( !redirection_args[1] ) {
printf("%s\n", "redirection requiers a file path");
return;
}
} else {
if ( strcmp( command_args[0], "cd" ) == 0 ) {
execute_cd( command_args );
} else if ( strcmp( command_args[0], "clear" ) == 0 ) {
execute_clear( command_args );
} else if ( strcmp( command_args[0], "exit" ) == 0 ) {
execute_exit( command_args );
} else {
int first_pipe[2];
int second_pipe[2];
if( pipe(first_pipe) == -1 || pipe(second_pipe) ) {
fprintf(stderr, "Error creating pipe\n");
}
pid_t pid = fork();
if (pid == -1) {
printf("Failed forking child..\n");
return;
} else if (pid == 0) {
close(first_pipe[0]);
close(second_pipe[0]);
dup2(first_pipe[1], 1);
dup2(second_pipe[1], 2);
if (execvp(command_args[0], command_args) < 0) {
printf("Could not execute command..\n");
exit(0);
}
close(first_pipe[1]);
close(second_pipe[1]);
} else {
close(first_pipe[1]);
close(second_pipe[1]);
fd_set rfds;
int retval;
/* Watch stdin (fd 0), stdout (fd 1) and stderr (fd 2) to see when it has I/O. */
FD_ZERO(&rfds);
FD_SET(first_pipe[0], &rfds);
FD_SET(second_pipe[0], &rfds);
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 100000;
retval = select(7, &rfds, 0, 0, &timeout);
if (retval == -1) {
perror("select()");
} else if (retval) {
if ( FD_ISSET(first_pipe[0], &rfds) ) {
char msg[4024];
while (read(first_pipe[0], msg, sizeof(msg)) > 0) {
printf("\033[%sm%s", GREEN , msg);
}
}
if ( FD_ISSET(second_pipe[0], &rfds) ) {
char msg[4024];
while (read(second_pipe[0], msg, sizeof(msg)) > 0) {
printf("\033[%sm%s", RED , msg);
}
}
}
wait(NULL);
close(first_pipe[0]);
close(second_pipe[0]);
return;
}
}
}
}
This is the function that executes the command, but as you can see the close and dupe are a mess !

Why the child process will not exit normally?

Why is the following program will not work properly?
int cnt = 0;
void deal(int sig) {
++cnt;
}
int main() {
signal(SIGUSR1, deal);
pid_t child = fork();
if (child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
raise(SIGSTOP);
freopen("ab.out", "w", stdout);
printf("child : %d\n", cnt);
} else {
int app_status, app_sig, fd;
struct user_regs_struct app_reg;
struct rusage app_ruse;
waitpid(child, &app_status, 0);
printf("father: waitpid: %d\n", app_status);
while (1) {
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
wait4(child, &app_status, 0, &app_ruse);
if (WIFEXITED(app_status)) {
printf("father: child exit normally, pid - %d\n", child);
break;
}
if (WIFSIGNALED(app_status) || (WIFSTOPPED(app_status)
&& WSTOPSIG(app_status) != SIGTRAP)) {
....
break;
}
ptrace(PTRACE_GETREGS, child, NULL, &app_reg);
if (app_reg.orig_rax == SYS_open && (fd = app_reg.rax) >= 0) {
kill(child, SIGUSR1);
}
}
}
return 0;
}
When run the program, got follow result
Why did the child process exit directly after receiving the signal?
The full code can got here.
https://pastebin.ubuntu.com/p/FddVZpfGH7/

Redirect output in shell?

I have written a function for the purposes of redirecting output from some command to a file. Something like this
ls > ls.txt
Here is the function that does output redirection:
int redirect_output(char* cmdline, char **output_filename) {
int i;
char* args[MAX_ARGS];
// int nargs = get_args(cmdline, args);
for(i = 0; args[i] != NULL; i++) {
// Look for the >
if(!strcmp(args[i], ">")) {
// Get the filename
if(args[i+1] != NULL) {
*output_filename = args[i+1];
} else {
return -1; //syntax error
}
return 1; //there is an >
}
}
return 0; //no redirect
}
The function successfully redirects output from some command to a file, but for some reason it causes other commands to stop working. So for example, my program with redirect_output works for something like ls but it does not work for something like cat ls.txt, if I do not call the function it works for any command. And, by not work it mean it gets stuck. Here are the other important functions.
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL) {
if(i >= MAX_ARGS) {
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
void execute(int output, char *outputefile, char* cmdline)
{
int pid, async;
char* args[MAX_ARGS];
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) {
exit(0);
}
/* check if async call */
if(!strcmp(args[nargs-1], "&")) {
async = 1;
args[--nargs] = 0;
}
else async = 0;
pid = fork();
if(pid == 0) { /* child process */
//if(output)
// freopen(outputefile, "w+", stdout);
execvp(args[0], args);
/* return only when exec fails */
perror("exec failed");
exit(-1);
} else if(pid > 0) { /* parent process */
if(!async) waitpid(pid, NULL, 0);
else printf("this is an async call\n");
} else { /* error occurred */
perror("fork failed");
exit(1);
}
}
And here is my main:
int main (int argc, char* argv [])
{
char cmdline[BUFSIZ];
char *output_filename;
char **args;
int output;
for(;;) {
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZ, stdin) == NULL) {
perror("fgets failed");
exit(1);
}
output = redirect_output(cmdline, &output_filename);
switch(0) {
case -1:
printf("Syntax error!\n");
break;
case 0:
break;
case 1:
printf("Redirecting output to: %s\n", output_filename);
break;
}
execute (output, output_filename, cmdline);
}
return 0;
}
Any help will be much appreciated! Thanks!

Resources