Search code examples
cbackground-processsigchldsigaction

Signal handling for background processes


I'm trying to implement a simple Unix shell in C. However, I could not implement background process feature by using sigaction. My code structure is like the following:

int main() {
struct sigaction act;
act.sa_handler = handler;

sigaction(SIGCHLD, &act, 0);

while(1) {
    parseCommand();
    execCommand();
}
}

Also, in my execCommand function, the structure is like:

if (fork()) {
    if (!isBackground) {
        wait(&child_status);
    }
    else
    printf("Background process\n");
}
else
    ... // Command execution...

My handler is like the following:

void handler(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0) {
}
printf("OK.\n");
}

But this structure harms my whole implementation. Even the foreground processes are not working. When I execute a foreground command, it gives:

Segmentation fault (core dumped) 

When I execute a background command, it gives:

Bus error (core dumped)

So, how can I solve this problem?

Thanks in advance...

EDIT : When I debug my code with valgrind, it gives the following:

==6768== Memcheck, a memory error detector
==6768== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6768== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6768== Command: ./shell
==6768== 
==6768== Syscall param rt_sigaction(act->sa_mask) points to uninitialised byte(s)
==6768==    at 0x4E6F5AE: __libc_sigaction (sigaction.c:62)
==6768==    by 0x400E90: main (in /home/enes/Desktop/Shell/shell)
==6768==  Address 0xffefff908 is on thread 1's stack
==6768== 
==6768== Syscall param rt_sigaction(act->sa_flags) points to uninitialised byte(s)
==6768==    at 0x4E6F5AE: __libc_sigaction (sigaction.c:62)
==6768==    by 0x400E90: main (in /home/enes/Desktop/Shell/shell)
==6768==  Address 0xffefff8f8 is on thread 1's stack
==6768== 
> ls
==6768== Use of uninitialised value of size 8
==6768==    at 0x4EA8C80: _IO_getline_info (iogetline.c:77)
==6768==    by 0x4EA7B7C: fgets (iofgets.c:53)
==6768==    by 0x400EC9: main (in /home/enes/Desktop/Shell/shell)
==6768== 
==6768== Invalid write of size 1
==6768==    at 0x4EA8C80: _IO_getline_info (iogetline.c:77)
==6768==    by 0x4EA7B7C: fgets (iofgets.c:53)
==6768==    by 0x400EC9: main (in /home/enes/Desktop/Shell/shell)
==6768==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6768== 
==6768== 
==6768== Process terminating with default action of signal 11 (SIGSEGV)
==6768==  Access not within mapped region at address 0x0
==6768==    at 0x4EA8C80: _IO_getline_info (iogetline.c:77)
==6768==    by 0x4EA7B7C: fgets (iofgets.c:53)
==6768==    by 0x400EC9: main (in /home/enes/Desktop/Shell/shell)
==6768==  If you believe this happened as a result of a stack
==6768==  overflow in your program's main thread (unlikely but
==6768==  possible), you can try to increase the size of the
==6768==  main thread stack using the --main-stacksize= flag.
==6768==  The main thread stack size used in this run was 8388608.
==6768== 
==6768== HEAP SUMMARY:
==6768==     in use at exit: 0 bytes in 0 blocks
==6768==   total heap usage: 2 allocs, 2 frees, 2,048 bytes allocated
==6768== 
==6768== All heap blocks were freed -- no leaks are possible
==6768== 
==6768== For counts of detected and suppressed errors, rerun with: -v
==6768== Use --track-origins=yes to see where uninitialised values come from
==6768== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Solution

  • Syscall param rt_sigaction(act->sa_mask) points to uninitialised byte(s)
    

    You need to completely initialise the sigaction structure, else it contains indeterminate values. Reading those (probably by the sigaction() function call) might very well cause Undefined Behaviour, from which on anything can happen.

    To fix this change

    struct sigaction act;
    

    to be

    struct sigaction act = {0};
    

    Probably not the issue you are facing, but still:

    It is not save to call any member of the printf()-family of functions from a signal handler.

    Even more: the set of functions which can safely be called from a signal handler is (very) limited. For a complete list see chapter 2.4.3 on this page.

    To fix this change

    printf("OK.\n");
    

    to be

    write(STDERR_FILENO, "OK.\n", sizeof "OK.\n" -1);
    

    or alike. As per the list linked above write() is save to call from a signal handler.


    ==6768== Use of uninitialised value of size 8
    ==6768==    at 0x4EA8C80: _IO_getline_info (iogetline.c:77)
    ==6768==    by 0x4EA7B7C: fgets (iofgets.c:53)
    

    What's actually wrong with the call to fgets() we cannot tell, as you do not show us the relevant code.