-
Notifications
You must be signed in to change notification settings - Fork 0
/
signalcp.c
executable file
·182 lines (158 loc) · 4.5 KB
/
signalcp.c
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
void usage()
{
printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
"\tCOPY PROGRAM ON SIGNAL.\n"
"It allows you to copy files using signals\n"
"SYNOPSIS\n"
"\tsignalcp [FILE_FROM] [FILE_TO] \n\n"
"DESCRIPTION\n"
"\tFILE_FROM - is a file which should be copied to FILE_TO\n\n"
"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
);
}
pid_t pid;
int output_char = 0;
int counter = 128;
// SIGCHLD
void childexit(int sign)
{
exit(EXIT_SUCCESS);
}
// SIGALRM
void parentexit(int sign)
{
exit(EXIT_FAILURE);
}
// Nothing
void nothing(int sign) {
}
// SIGUSR2
void zero_handler(int sign)
{
counter /= 2;
kill(pid, SIGUSR1);
}
// SIGUSR1
void one_handler(int sign)
{
output_char += counter;
counter /= 2;
kill(pid, SIGUSR1);
}
int copy(char** argv)
{
pid_t parent_pid = getpid();
sigset_t set;
// при SIGCHLD - выходим
struct sigaction child_exit_action;
memset(&child_exit_action, 0, sizeof(child_exit_action));
child_exit_action.sa_handler = childexit;
sigfillset(&child_exit_action.sa_mask);
sigaction(SIGCHLD, &child_exit_action, NULL);
// SIGUSR1 - one_handler()
struct sigaction one_signal;
memset(&one_signal, 0, sizeof(one_signal));
one_signal.sa_handler = one_handler;
sigfillset(&one_signal.sa_mask);
sigaction(SIGUSR1, &one_signal, NULL);
// SIGUSR2 - zero_handler()
struct sigaction zero_signal;
memset(&zero_signal, 0, sizeof(zero_signal));
zero_signal.sa_handler = zero_handler;
sigfillset(&zero_signal.sa_mask);
sigaction(SIGUSR2, &zero_signal, NULL);
// блокировки
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, NULL );
sigemptyset(&set);
int fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Can't open file %s\n", argv[1]);
fprintf(stderr, "%s\n", strerror(errno));
return -1;
}
pid = fork();
if (pid == 0)
{
sigemptyset(&set); // очищаем набор сигналов
// SIGUSR1 - nothing()
struct sigaction nothing_action;
memset(¬hing_action, 0, sizeof(nothing_action));
nothing_action.sa_handler = nothing;
sigfillset(¬hing_action.sa_mask);
sigaction(SIGUSR1, ¬hing_action, NULL);
// SIGALRM - parentexit()
struct sigaction alarm_action;
memset(&alarm_action, 0, sizeof(alarm_action));
alarm_action.sa_handler = parentexit;
sigfillset(&alarm_action.sa_mask);
sigaction(SIGALRM, &alarm_action, NULL);
int i;
char c;
while (read(fd, &c, 1) > 0)
{
// SIGALRM Будет получен если родитель не успеет ответить за секунду
alarm(1);
// Побитовые операции
for ( i = 128; i >= 1; i /= 2)
{
if ( i & c )
// 1
kill(parent_pid, SIGUSR1);
else
// 0
kill(parent_pid, SIGUSR2);
// Ждём подтверждения от родителя
// приостанавливает процесс до получения сигнала
sigsuspend(&set);
}
}
exit(EXIT_SUCCESS);
}
// Получаем пока ребёнок не умрёт
int out = open(argv[2], O_CREAT | O_WRONLY | O_EXCL, 0666);
if (out == -1)
{
fprintf(stderr, "Can't copy in file %s\n", argv[2]);
fprintf(stderr, "%s\n", strerror(errno));
return -1;
}
do
{
if(counter == 0)
{ // считали весь байт
write(out, &output_char, 1);
counter=128;
output_char = 0;
}
sigsuspend(&set); // Ждём сигнал от ребёнка
} while (1);
return 0;
}
int main(int argc, char ** argv)
{
if (argc != 3)
{
usage();
exit(EXIT_FAILURE);
}
int cp = copy(argv);
if (cp == -1)
{
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}