summaryrefslogtreecommitdiff
path: root/Year_2/OS/hw/hw7.c
blob: ca5199841655f5c68f008adabc83595f4b003e20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
    Homework n.7

    Modificare l'homework precedente (n.6) facendo in modo che il figlio che
    riceve il comando da eseguire tramite la coda, catturi lo standard output
    e lo standard error del figlio nipote usando la redirezione su pipe tra
    processi. L'output catturato dovrà essere mandato indietro al padre
    tramite un messaggio (per semplicita', assumiamo sufficiente grande).
    Tale contenuto sara' poi visualizzato sul terminale dal padre.

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define MTYPE 1
#define MTYPE_EXE 2

struct msgbuf {
    long mtype;
    char mtext[1024];
};

void
execute(int qid)
{
    pid_t pid;
    struct msgbuf msg;
    char command[1024];
    int n;
    char* p;
    int pipefd[2];

    while (1) {
        if (msgrcv(qid, (void*)&msg, 1024, MTYPE, 0) == -1) {
            perror("msgrcv");
            exit(1);
        }

        /* The variable `command` will be the substring of the passed string
         * until the first space, ignoring all parameters */
        n = 0;
        p = msg.mtext;
        while (*p != '\0') {
            if (*p == ' ')
                break;
            n++;
            p++;
        }

        strncpy(command, msg.mtext, n);
        command[n] = '\0';

        if (strcmp(command, "exit") == 0)
            break;

        if (pipe(pipefd) == -1) {
            perror("pipe");
            exit(1);
        }

        pid = fork();
        if (pid == -1) {
            perror("fork");
            exit(1);
        }

        if (pid == 0) {
            dup2(pipefd[1], 1);
            dup2(pipefd[1], 2);
            close(pipefd[0]);
            execlp(command, "", NULL);
            fprintf(stderr, "Error executing '%s'\n", command);
            exit(1);
        } else {
            wait(NULL);

            close(pipefd[1]);
            n = read(pipefd[0], msg.mtext, 1024);
            msg.mtext[n] = '\0';
            msg.mtype = MTYPE_EXE;
            close(pipefd[0]);

            if (msgsnd(qid, (void*)&msg, strlen(msg.mtext) + 1, 0) == -1) {
                perror("msgsnd");
                exit(1);
            }
        }
    }

    msgctl(qid, IPC_RMID, NULL);
}

int
main()
{
    pid_t pid;
    int qid;
    int n;

    if ((qid = msgget(IPC_PRIVATE, IPC_CREAT | 0644)) == -1) {
        perror("msgget");
        exit(1);
    }

    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    }

    if (pid != 0) {
        struct msgbuf msg;
        while (1) {
            printf("Insert a command: ");
            fgets(msg.mtext, 1024, stdin);
            n = strlen(msg.mtext);
            msg.mtext[n - 1] = '\0';
            msg.mtype = MTYPE;

            /* Ignore empty string */
            if (strcmp(msg.mtext, "") == 0)
                continue;

            if (msgsnd(qid, (void*)&msg, sizeof(msg.mtext), IPC_NOWAIT) == -1) {
                perror("msgsnd");
                exit(1);
            }

            /* Check first if the message is exit, because executing this when
             * message is "exit" raises 
             * msgrcv: Identifier removed
             */
            if (strcmp(msg.mtext, "exit") == 0) {
                break;
            }

            if (msgrcv(qid, (void*)&msg, 1024, MTYPE_EXE, 0) == -1) {
                perror("msgrcv");
                exit(1);
            }

            printf("%s\n", msg.mtext);
            sleep(1);
        }
    } else {
        execute(qid);
    }

    return 0;
}