-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathmain.c
242 lines (170 loc) · 7.02 KB
/
main.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*
vdev: a virtual device manager for *nix
Copyright (C) 2015 Jude Nelson
This program is dual-licensed: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 or later as
published by the Free Software Foundation. For the terms of this
license, see LICENSE.GPLv3+ or <http://www.gnu.org/licenses/>.
You are free to use this program under the terms of the GNU General
Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Alternatively, you are free to use this program under the terms of the
Internet Software Consortium License, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For the terms of this license, see LICENSE.ISC or
<http://www.isc.org/downloads/software-support-policy/isc-license/>.
*/
#include "main.h"
// global vdev state
static struct vdev_state vdev;
// reload handler
void vdev_reload_sighup( int ignored ) {
vdev_reload( &vdev );
}
// run!
int main( int argc, char** argv ) {
int rc = 0;
int coldplug_quiesce_pipe[2];
bool is_child = false;
bool is_parent = false;
ssize_t nr = 0;
int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests
memset( &vdev, 0, sizeof(struct vdev_state) );
// ignore SIGPIPE from daemonlets
signal( SIGPIPE, SIG_IGN );
// set up global vdev state
rc = vdev_init( &vdev, argc, argv );
if( rc != 0 ) {
vdev_error("vdev_init rc = %d\n", rc );
vdev_shutdown( &vdev, false );
exit(1);
}
// run the preseed command
rc = vdev_preseed_run( &vdev );
if( rc != 0 ) {
vdev_error("vdev_preseed_run rc = %d\n", rc );
vdev_shutdown( &vdev, false );
exit(1);
}
// if we're going to daemonize, then redirect logging to the logfile
if( !vdev.config->foreground ) {
// sanity check
if( vdev.config->logfile_path == NULL ) {
fprintf(stderr, "No logfile specified\n");
vdev_shutdown( &vdev, false );
exit(2);
}
// do we need to connect to syslog?
if( strcmp( vdev.config->logfile_path, "syslog" ) == 0 ) {
vdev_debug("%s", "Switching to syslog for messages\n");
vdev_enable_syslog();
}
else {
// send to a specific logfile
rc = vdev_log_redirect( vdev.config->logfile_path );
if( rc != 0 ) {
vdev_error("vdev_log_redirect('%s') rc = %d\n", vdev.config->logfile_path, rc );
vdev_shutdown( &vdev, false );
exit(2);
}
}
if( !vdev.config->coldplug_only ) {
// will become a daemon after handling coldplug.
// set up a pipe between parent and child, so the child can
// signal the parent when it's device queue has been emptied
// (meaning the parent can safely exit).
rc = pipe( coldplug_quiesce_pipe );
if( rc != 0 ) {
vdev_error("pipe rc = %d\n", rc );
vdev_shutdown( &vdev, false );
exit(3);
}
// become a daemon
rc = vdev_daemonize();
if( rc < 0 ) {
vdev_error("vdev_daemonize rc = %d\n", rc );
vdev_shutdown( &vdev, false );
exit(3);
}
if( rc == 0 ) {
// child
close( coldplug_quiesce_pipe[0] );
coldplug_finished_fd = coldplug_quiesce_pipe[1];
// write a pidfile
if( vdev.config->pidfile_path != NULL ) {
rc = vdev_pidfile_write( vdev.config->pidfile_path );
if( rc != 0 ) {
vdev_error("vdev_pidfile_write('%s') rc = %d\n", vdev.config->pidfile_path, rc );
vdev_shutdown( &vdev, false );
exit(4);
}
}
// set reload handler
signal( SIGHUP, vdev_reload_sighup );
is_child = true;
}
else {
// parent
is_parent = true;
close( coldplug_quiesce_pipe[1] );
}
}
}
if( !is_parent || vdev.config->foreground || vdev.config->coldplug_only ) {
// child, or foreground, or coldplug only. start handling (coldplug) device events
rc = vdev_start( &vdev );
if( rc != 0 ) {
vdev_error("vdev_backend_init rc = %d\n", rc );
vdev_stop( &vdev );
vdev_shutdown( &vdev, false );
// if child, and we're connected to the parent, then tell the parent to exit failure
if( is_child && !vdev.config->foreground && !vdev.config->coldplug_only ) {
write( coldplug_quiesce_pipe[1], &rc, sizeof(rc) );
close( coldplug_quiesce_pipe[1] );
}
exit(5);
}
// main loop: get events from the OS and process them.
// wake up the parent once we finish the coldplugged devices
rc = vdev_main( &vdev, coldplug_finished_fd );
if( rc != 0 ) {
vdev_error("vdev_main rc = %d\n", rc );
}
// if only doing coldplug, find and remove all stale coldplug devices.
// use the metadata directory to figure this out
if( vdev.config->coldplug_only ) {
rc = vdev_remove_unplugged_devices( &vdev );
if( rc != 0 ) {
vdev_error("vdev_remove_unplugged_devices() rc = %d\n", rc );
}
}
// quiesce requests
vdev_stop( &vdev );
// print benchmarks...
vdev_debug("%s", "Action benchmarks:\n");
for( unsigned int i = 0; i < vdev.num_acts; i++ ) {
vdev_action_log_benchmarks( &vdev.acts[i] );
}
// clean up
// keep the pidfile unless we're doing coldplug only (in which case don't touch it)
vdev_shutdown( &vdev, !vdev.config->coldplug_only );
return rc;
}
else {
// parent process--wait for the child to finish processing the coldplugged devices, and exit.
nr = read( coldplug_quiesce_pipe[0], &rc, sizeof(rc) );
if( nr < 0 || rc != 0 ) {
if( nr < 0 ) {
vdev_error("read(%d) rc = %zd\n", coldplug_quiesce_pipe[0], nr );
}
vdev_error("device quiesce failure, child rc = %d\n", rc );
exit(6);
}
printf("parent: all initial devices processed\n");
// clean up, but keep the pidfile
vdev_shutdown( &vdev, false );
close( coldplug_quiesce_pipe[0] );
return 0;
}
}