简体   繁体   中英

System Calls in C signals and fork

Hi I've this problem to solve with a functional program in C.

"Write a C program where a process F create a childprocess C. The childprocess C waits the user to type the password, if is correct sends a signal SIGUSR1 to the father, if after 3 attempts the password is still incorrect it will send a SIGUSR2 signal to the father and terminate; if it receives from the father SIGUSR1 signal must stop viewing the "timeout" message.

His father after 30 seconds (if it has not received any signal from the child) must send the signal SIGUSR1 to the child and end with exit(1); if it receives the SIGUSR1 signal must end with exit(0); if it receives the signal SIGUSR2 must end with exit (2)."

I'm trying to solve it but I'm stuck . This is what I've done:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

void fatherprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        exit(2);
    }

}


void childprocess(int mysignal){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        exit(1);
    }
}


int main(int argc, char *argcv[]){
    int fatherpid, childpid;
    char enteredpassword[], password[] = "test";
    int i =0;
    unsigned int time_to_sleep = 30;

   fatherpid = getpid();
   childpid = fork();

   if (childpid == 0) {
       printf("Child Process waiting for a password\n");
       while (1){
           if (i < 3) {
               printf("Enter Password: ");
               scanf("%s", enteredpassword);
               if (enteredpassword == password)
                   signal(SIGUSR1, fatherprocess);
           } else {
               signal(SIGUSR2, fatherprocess);
               exit(1);
           }
          i++;
      }
    } else {
        printf("Father Process\n");
        while(time_to_sleep){
            time_to_sleep = sleep(time_to_sleep);
            signal(SIGUSR1, childprocess);
        }
    }
    return 0;
    }

I've edited my program in this way:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

void fatherprocess(int mysignal, int fatherpid){
    if (mysignal == SIGUSR1) {
        printf("ACCESS GRANTED!\n");
        kill(fatherpid, SIGUSR1);
        exit(0);
    }

    if (mysignal == SIGUSR2){
        printf("ACCESS DISCARDED! More than 3 tentatives!\n");
        kill(fatherpid, SIGUSR2);
        exit(2);
    }

}


void childprocess(int mysignal, int childpid){
    if (mysignal == SIGUSR1) {
        printf("TIMEOUT\n");
        kill(childpid, SIGUSR1);
        exit(1);
    }
}


int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[] = "test", password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;

fatherpid = getpid();
childpid = fork();

if (childpid == 0) {
    printf("Child Process waiting for a password\n");
    while (1){
        if (i < 3) {
            printf("Enter Password: ");
            scanf("%s", enteredpassword);
            if (strcmp(enteredpassword, password) == 0)
                fatherprocess(SIGUSR1, fatherpid);
        } else {
            fatherprocess(SIGUSR2, fatherpid);
            exit(1);
        }
        i++;
    }
} else {
    printf("Father Process\n");
    while(time_to_sleep){
        time_to_sleep = sleep(time_to_sleep);
        childprocess(SIGUSR1, childpid);
    }
}
return 0;
}

Now it works perfectly but I don't know if I've respected the exercise text.

As was mentioned in the comments (by Jonathan Leffler), you need to use the kill() system call (to send the signals) and register a signal handler using a call like sigaction() . I have linked these two calls to online manual pages that provide additional information about them.

Here's some code that demonstrates how these can be used towards achieving your stated goal. You will still need to add/modify the code for things like the prompts you want and the acceptable input string. Please note that I'm not claiming this to be the best way to do it, only that it's an example of how it could be done (it compiled and worked for me):

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static void get_password(char* buf, int maxbuf)
{
    fgets(buf, maxbuf, stdin);
}

static int is_password_correct(char* buf)
{
    return buf[0] == 'a';
}

volatile int got_signal = 0;
volatile int child_signal = 0;

static void parent_sig_handler(int signum)
{
    if (!got_signal)
    {
        got_signal = signum;
        printf("parent_sig_handler: got sig %d\n", signum);
    }
}

static void child_sig_handler(int signum)
{
    if (!child_signal)
    {
        child_signal = signum;
        printf("child_sig_handler: got sig %d\n", signum);
    }
}

int main()
{
    struct sigaction act;
    sigfillset(&act.sa_mask);
    act.sa_handler = parent_sig_handler;
    sigaction(SIGALRM, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);

    pid_t child_pid = fork();
    if (child_pid == -1)
    {
        perror("error forking");
        exit(3);
    }
    if (child_pid == 0)
    {
        printf("child running\n");
        act.sa_handler = child_sig_handler;
        sigaction(SIGUSR1, &act, NULL);
        pid_t parent_pid = getppid();
        for (int i = 0; i < 3; ++i)
        {   
            char passwd[64];
            passwd[0] = '\0';
            get_password(passwd, sizeof(passwd));
            if (is_password_correct(passwd))
            {       
                kill(parent_pid, SIGUSR1);
                exit(0);    
            }       
        }   
        kill(parent_pid, SIGUSR2);
        exit(2);
    }

    printf("parent running\n");
    alarm(30); /* sets parent up to receive a SIGALRM signal in 30 seconds */
    sigset_t sigmask;
    sigemptyset(&sigmask);
    while (!got_signal)
    {
        sigsuspend(&sigmask);
    }

    switch (got_signal)
    {
        case SIGALRM:
            kill(child_pid, SIGUSR1);
            exit(1);
        case SIGUSR1:
            exit(0);
        case SIGUSR2:
            exit(2);
        default:
            exit(3);
    }
    exit(3);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM