Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/geom/journal/geom_journal.c
35068 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2005-2006 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 <sys/types.h>
30
#include <errno.h>
31
#include <paths.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <stdint.h>
35
#include <string.h>
36
#include <strings.h>
37
#include <assert.h>
38
#include <libgeom.h>
39
#include <geom/journal/g_journal.h>
40
#include <core/geom.h>
41
#include <misc/subr.h>
42
43
#include "geom_journal.h"
44
45
46
uint32_t lib_version = G_LIB_VERSION;
47
uint32_t version = G_JOURNAL_VERSION;
48
49
static void journal_main(struct gctl_req *req, unsigned flags);
50
static void journal_clear(struct gctl_req *req);
51
static void journal_dump(struct gctl_req *req);
52
static void journal_label(struct gctl_req *req);
53
54
struct g_command class_commands[] = {
55
{ "clear", G_FLAG_VERBOSE, journal_main, G_NULL_OPTS,
56
"[-v] prov ..."
57
},
58
{ "dump", 0, journal_main, G_NULL_OPTS,
59
"prov ..."
60
},
61
{ "label", G_FLAG_VERBOSE, journal_main,
62
{
63
{ 'c', "checksum", NULL, G_TYPE_BOOL },
64
{ 'f', "force", NULL, G_TYPE_BOOL },
65
{ 'h', "hardcode", NULL, G_TYPE_BOOL },
66
{ 's', "jsize", "-1", G_TYPE_NUMBER },
67
G_OPT_SENTINEL
68
},
69
"[-cfhv] [-s jsize] dataprov [jprov]"
70
},
71
{ "stop", G_FLAG_VERBOSE, NULL,
72
{
73
{ 'f', "force", NULL, G_TYPE_BOOL },
74
G_OPT_SENTINEL
75
},
76
"[-fv] name ..."
77
},
78
{ "sync", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
79
"[-v]"
80
},
81
G_CMD_SENTINEL
82
};
83
84
static int verbose = 0;
85
86
static void
87
journal_main(struct gctl_req *req, unsigned flags)
88
{
89
const char *name;
90
91
if ((flags & G_FLAG_VERBOSE) != 0)
92
verbose = 1;
93
94
name = gctl_get_ascii(req, "verb");
95
if (name == NULL) {
96
gctl_error(req, "No '%s' argument.", "verb");
97
return;
98
}
99
if (strcmp(name, "label") == 0)
100
journal_label(req);
101
else if (strcmp(name, "clear") == 0)
102
journal_clear(req);
103
else if (strcmp(name, "dump") == 0)
104
journal_dump(req);
105
else
106
gctl_error(req, "Unknown command: %s.", name);
107
}
108
109
static int
110
g_journal_fs_exists(const char *prov)
111
{
112
113
if (g_journal_ufs_exists(prov))
114
return (1);
115
#if 0
116
if (g_journal_otherfs_exists(prov))
117
return (1);
118
#endif
119
return (0);
120
}
121
122
static int
123
g_journal_fs_using_last_sector(const char *prov)
124
{
125
126
if (g_journal_ufs_using_last_sector(prov))
127
return (1);
128
#if 0
129
if (g_journal_otherfs_using_last_sector(prov))
130
return (1);
131
#endif
132
return (0);
133
}
134
135
static void
136
journal_label(struct gctl_req *req)
137
{
138
struct g_journal_metadata md;
139
const char *data, *journal, *str;
140
u_char sector[512];
141
intmax_t jsize, msize, ssize;
142
int error, force, i, nargs, checksum, hardcode;
143
144
bzero(sector, sizeof(sector));
145
nargs = gctl_get_int(req, "nargs");
146
str = NULL; /* gcc */
147
148
strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic));
149
md.md_version = G_JOURNAL_VERSION;
150
md.md_id = arc4random();
151
md.md_joffset = 0;
152
md.md_jid = 0;
153
md.md_flags = GJ_FLAG_CLEAN;
154
checksum = gctl_get_int(req, "checksum");
155
if (checksum)
156
md.md_flags |= GJ_FLAG_CHECKSUM;
157
force = gctl_get_int(req, "force");
158
hardcode = gctl_get_int(req, "hardcode");
159
160
if (nargs != 1 && nargs != 2) {
161
gctl_error(req, "Invalid number of arguments.");
162
return;
163
}
164
165
/* Verify the given providers. */
166
for (i = 0; i < nargs; i++) {
167
str = gctl_get_ascii(req, "arg%d", i);
168
if (g_get_mediasize(str) == 0) {
169
gctl_error(req, "Invalid provider %s.", str);
170
return;
171
}
172
}
173
174
data = gctl_get_ascii(req, "arg0");
175
jsize = gctl_get_intmax(req, "jsize");
176
journal = NULL;
177
switch (nargs) {
178
case 1:
179
if (!force && g_journal_fs_exists(data)) {
180
gctl_error(req, "File system exists on %s and this "
181
"operation would destroy it.\nUse -f if you "
182
"really want to do it.", data);
183
return;
184
}
185
journal = data;
186
msize = g_get_mediasize(data);
187
ssize = g_get_sectorsize(data);
188
if (jsize == -1) {
189
/*
190
* No journal size specified. 1GB should be safe
191
* default.
192
*/
193
jsize = 1073741824ULL;
194
} else {
195
if (jsize < 104857600) {
196
gctl_error(req, "Journal too small.");
197
return;
198
}
199
if ((jsize % ssize) != 0) {
200
gctl_error(req, "Invalid journal size.");
201
return;
202
}
203
}
204
if (jsize + ssize >= msize) {
205
gctl_error(req, "Provider too small for journalling. "
206
"You can try smaller jsize (default is %jd).",
207
jsize);
208
return;
209
}
210
md.md_jstart = msize - ssize - jsize;
211
md.md_jend = msize - ssize;
212
break;
213
case 2:
214
if (!force && g_journal_fs_using_last_sector(data)) {
215
gctl_error(req, "File system on %s is using the last "
216
"sector and this operation is going to overwrite "
217
"it. Use -f if you really want to do it.", data);
218
return;
219
}
220
journal = gctl_get_ascii(req, "arg1");
221
if (jsize != -1) {
222
gctl_error(req, "jsize argument is valid only for "
223
"all-in-one configuration.");
224
return;
225
}
226
msize = g_get_mediasize(journal);
227
ssize = g_get_sectorsize(journal);
228
md.md_jstart = 0;
229
md.md_jend = msize - ssize;
230
break;
231
}
232
233
if (g_get_sectorsize(data) != g_get_sectorsize(journal)) {
234
gctl_error(req, "Not equal sector sizes.");
235
return;
236
}
237
238
/*
239
* Clear last sector first, to spoil all components if device exists.
240
*/
241
for (i = 0; i < nargs; i++) {
242
str = gctl_get_ascii(req, "arg%d", i);
243
error = g_metadata_clear(str, NULL);
244
if (error != 0) {
245
gctl_error(req, "Cannot clear metadata on %s: %s.", str,
246
strerror(error));
247
return;
248
}
249
}
250
251
/*
252
* Ok, store metadata.
253
*/
254
for (i = 0; i < nargs; i++) {
255
switch (i) {
256
case 0:
257
str = data;
258
md.md_type = GJ_TYPE_DATA;
259
if (nargs == 1)
260
md.md_type |= GJ_TYPE_JOURNAL;
261
break;
262
case 1:
263
str = journal;
264
md.md_type = GJ_TYPE_JOURNAL;
265
break;
266
}
267
md.md_provsize = g_get_mediasize(str);
268
assert(md.md_provsize != 0);
269
if (!hardcode)
270
bzero(md.md_provider, sizeof(md.md_provider));
271
else {
272
if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
273
str += sizeof(_PATH_DEV) - 1;
274
strlcpy(md.md_provider, str, sizeof(md.md_provider));
275
}
276
journal_metadata_encode(&md, sector);
277
error = g_metadata_store(str, sector, sizeof(sector));
278
if (error != 0) {
279
fprintf(stderr, "Cannot store metadata on %s: %s.\n",
280
str, strerror(error));
281
gctl_error(req, "Not fully done.");
282
continue;
283
}
284
if (verbose)
285
printf("Metadata value stored on %s.\n", str);
286
}
287
}
288
289
static void
290
journal_clear(struct gctl_req *req)
291
{
292
const char *name;
293
int error, i, nargs;
294
295
nargs = gctl_get_int(req, "nargs");
296
if (nargs < 1) {
297
gctl_error(req, "Too few arguments.");
298
return;
299
}
300
301
for (i = 0; i < nargs; i++) {
302
name = gctl_get_ascii(req, "arg%d", i);
303
error = g_metadata_clear(name, G_JOURNAL_MAGIC);
304
if (error != 0) {
305
fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
306
name, strerror(error));
307
gctl_error(req, "Not fully done.");
308
continue;
309
}
310
if (verbose)
311
printf("Metadata cleared on %s.\n", name);
312
}
313
}
314
315
static void
316
journal_dump(struct gctl_req *req)
317
{
318
struct g_journal_metadata md, tmpmd;
319
const char *name;
320
int error, i, nargs;
321
322
nargs = gctl_get_int(req, "nargs");
323
if (nargs < 1) {
324
gctl_error(req, "Too few arguments.");
325
return;
326
}
327
328
for (i = 0; i < nargs; i++) {
329
name = gctl_get_ascii(req, "arg%d", i);
330
error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
331
G_JOURNAL_MAGIC);
332
if (error != 0) {
333
fprintf(stderr, "Cannot read metadata from %s: %s.\n",
334
name, strerror(error));
335
gctl_error(req, "Not fully done.");
336
continue;
337
}
338
if (journal_metadata_decode((u_char *)&tmpmd, &md) != 0) {
339
fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
340
name);
341
gctl_error(req, "Not fully done.");
342
continue;
343
}
344
printf("Metadata on %s:\n", name);
345
journal_metadata_dump(&md);
346
printf("\n");
347
}
348
}
349
350