Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ggate/ggatel/ggatel.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2004 Pawel Jakub Dawidek <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <stdint.h>
32
#include <fcntl.h>
33
#include <unistd.h>
34
#include <string.h>
35
#include <err.h>
36
#include <errno.h>
37
#include <assert.h>
38
#include <sys/param.h>
39
#include <sys/time.h>
40
#include <sys/bio.h>
41
#include <sys/disk.h>
42
#include <sys/ioctl.h>
43
#include <sys/stat.h>
44
#include <sys/syslog.h>
45
46
#include "ggate.h"
47
48
49
static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
50
51
static const char *path = NULL;
52
static int unit = G_GATE_UNIT_AUTO;
53
static unsigned flags = 0;
54
static int direct_flag = 0;
55
static int force = 0;
56
static unsigned sectorsize = 0;
57
static unsigned timeout = G_GATE_TIMEOUT;
58
59
static void
60
usage(void)
61
{
62
63
fprintf(stderr, "usage: %s create [-v] [-o option] ... "
64
"[-s sectorsize] [-t timeout] [-u unit] <path>\n", getprogname());
65
fprintf(stderr, " %s rescue [-v] [-o option] ... <-u unit> "
66
"<path>\n", getprogname());
67
fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname());
68
fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname());
69
fprintf(stderr, " option = {ro, wo, rw, direct}\n");
70
exit(EXIT_FAILURE);
71
}
72
73
static int
74
g_gate_openflags(unsigned ggflags)
75
{
76
int openflags = O_RDWR;
77
78
if ((ggflags & G_GATE_FLAG_READONLY) != 0)
79
openflags = O_RDONLY;
80
else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0)
81
openflags = O_WRONLY;
82
83
if (direct_flag)
84
openflags |= O_DIRECT;
85
86
return (openflags);
87
}
88
89
static void
90
g_gatel_serve(int fd)
91
{
92
struct g_gate_ctl_io ggio;
93
size_t bsize;
94
95
if (g_gate_verbose == 0) {
96
if (daemon(0, 0) == -1) {
97
g_gate_destroy(unit, 1);
98
err(EXIT_FAILURE, "Cannot daemonize");
99
}
100
}
101
g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid());
102
ggio.gctl_version = G_GATE_VERSION;
103
ggio.gctl_unit = unit;
104
bsize = sectorsize;
105
ggio.gctl_data = malloc(bsize);
106
for (;;) {
107
int error;
108
once_again:
109
ggio.gctl_length = bsize;
110
ggio.gctl_error = 0;
111
g_gate_ioctl(G_GATE_CMD_START, &ggio);
112
error = ggio.gctl_error;
113
switch (error) {
114
case 0:
115
break;
116
case ECANCELED:
117
/* Exit gracefully. */
118
free(ggio.gctl_data);
119
g_gate_close_device();
120
close(fd);
121
exit(EXIT_SUCCESS);
122
case ENOMEM:
123
/* Buffer too small. */
124
assert(ggio.gctl_cmd == BIO_DELETE ||
125
ggio.gctl_cmd == BIO_WRITE);
126
ggio.gctl_data = realloc(ggio.gctl_data,
127
ggio.gctl_length);
128
if (ggio.gctl_data != NULL) {
129
bsize = ggio.gctl_length;
130
goto once_again;
131
}
132
/* FALLTHROUGH */
133
case ENXIO:
134
default:
135
g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
136
strerror(error));
137
}
138
139
error = 0;
140
switch (ggio.gctl_cmd) {
141
case BIO_READ:
142
if ((size_t)ggio.gctl_length > bsize) {
143
ggio.gctl_data = realloc(ggio.gctl_data,
144
ggio.gctl_length);
145
if (ggio.gctl_data != NULL)
146
bsize = ggio.gctl_length;
147
else
148
error = ENOMEM;
149
}
150
if (error == 0) {
151
if (pread(fd, ggio.gctl_data, ggio.gctl_length,
152
ggio.gctl_offset) == -1) {
153
error = errno;
154
}
155
}
156
break;
157
case BIO_DELETE:
158
case BIO_WRITE:
159
if (pwrite(fd, ggio.gctl_data, ggio.gctl_length,
160
ggio.gctl_offset) == -1) {
161
error = errno;
162
}
163
break;
164
default:
165
error = EOPNOTSUPP;
166
}
167
168
ggio.gctl_error = error;
169
g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
170
}
171
}
172
173
static void
174
g_gatel_create(void)
175
{
176
struct g_gate_ctl_create ggioc;
177
int fd;
178
179
fd = open(path, g_gate_openflags(flags) | O_DIRECT | O_FSYNC);
180
if (fd == -1)
181
err(EXIT_FAILURE, "Cannot open %s", path);
182
memset(&ggioc, 0, sizeof(ggioc));
183
ggioc.gctl_version = G_GATE_VERSION;
184
ggioc.gctl_unit = unit;
185
ggioc.gctl_mediasize = g_gate_mediasize(fd);
186
if (sectorsize == 0)
187
sectorsize = g_gate_sectorsize(fd);
188
ggioc.gctl_sectorsize = sectorsize;
189
ggioc.gctl_timeout = timeout;
190
ggioc.gctl_flags = flags;
191
ggioc.gctl_maxcount = 0;
192
strlcpy(ggioc.gctl_info, path, sizeof(ggioc.gctl_info));
193
g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
194
if (unit == -1)
195
printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
196
unit = ggioc.gctl_unit;
197
g_gatel_serve(fd);
198
}
199
200
static void
201
g_gatel_rescue(void)
202
{
203
struct g_gate_ctl_cancel ggioc;
204
int fd;
205
206
fd = open(path, g_gate_openflags(flags));
207
if (fd == -1)
208
err(EXIT_FAILURE, "Cannot open %s", path);
209
210
ggioc.gctl_version = G_GATE_VERSION;
211
ggioc.gctl_unit = unit;
212
ggioc.gctl_seq = 0;
213
g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
214
215
g_gatel_serve(fd);
216
}
217
218
int
219
main(int argc, char *argv[])
220
{
221
222
if (argc < 2)
223
usage();
224
if (strcasecmp(argv[1], "create") == 0)
225
action = CREATE;
226
else if (strcasecmp(argv[1], "rescue") == 0)
227
action = RESCUE;
228
else if (strcasecmp(argv[1], "destroy") == 0)
229
action = DESTROY;
230
else if (strcasecmp(argv[1], "list") == 0)
231
action = LIST;
232
else
233
usage();
234
argc -= 1;
235
argv += 1;
236
for (;;) {
237
int ch;
238
239
ch = getopt(argc, argv, "fo:s:t:u:v");
240
if (ch == -1)
241
break;
242
switch (ch) {
243
case 'f':
244
if (action != DESTROY)
245
usage();
246
force = 1;
247
break;
248
case 'o':
249
if (action != CREATE && action != RESCUE)
250
usage();
251
if (strcasecmp("ro", optarg) == 0)
252
flags = G_GATE_FLAG_READONLY;
253
else if (strcasecmp("wo", optarg) == 0)
254
flags = G_GATE_FLAG_WRITEONLY;
255
else if (strcasecmp("rw", optarg) == 0)
256
flags = 0;
257
else if (strcasecmp("direct", optarg) == 0)
258
direct_flag = 1;
259
else {
260
errx(EXIT_FAILURE,
261
"Invalid argument for '-o' option.");
262
}
263
break;
264
case 's':
265
if (action != CREATE)
266
usage();
267
errno = 0;
268
sectorsize = strtoul(optarg, NULL, 10);
269
if (sectorsize == 0 && errno != 0)
270
errx(EXIT_FAILURE, "Invalid sectorsize.");
271
break;
272
case 't':
273
if (action != CREATE)
274
usage();
275
errno = 0;
276
timeout = strtoul(optarg, NULL, 10);
277
if (timeout == 0 && errno != 0)
278
errx(EXIT_FAILURE, "Invalid timeout.");
279
break;
280
case 'u':
281
errno = 0;
282
unit = strtol(optarg, NULL, 10);
283
if (unit == 0 && errno != 0)
284
errx(EXIT_FAILURE, "Invalid unit number.");
285
break;
286
case 'v':
287
if (action == DESTROY)
288
usage();
289
g_gate_verbose++;
290
break;
291
default:
292
usage();
293
}
294
}
295
argc -= optind;
296
argv += optind;
297
298
switch (action) {
299
case CREATE:
300
if (argc != 1)
301
usage();
302
g_gate_load_module();
303
g_gate_open_device();
304
path = argv[0];
305
g_gatel_create();
306
break;
307
case RESCUE:
308
if (argc != 1)
309
usage();
310
if (unit == -1) {
311
fprintf(stderr, "Required unit number.\n");
312
usage();
313
}
314
g_gate_open_device();
315
path = argv[0];
316
g_gatel_rescue();
317
break;
318
case DESTROY:
319
if (unit == -1) {
320
fprintf(stderr, "Required unit number.\n");
321
usage();
322
}
323
g_gate_verbose = 1;
324
g_gate_open_device();
325
g_gate_destroy(unit, force);
326
break;
327
case LIST:
328
g_gate_list(unit, g_gate_verbose);
329
break;
330
case UNSET:
331
default:
332
usage();
333
}
334
g_gate_close_device();
335
exit(EXIT_SUCCESS);
336
}
337
338