zdb: fix printf() length for uint64_t devid
[zfs.git] / cmd / zstream / zstream_recompress.c
blob8392ef3de72fd76011bf1fb655eaa0dd419765aa
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2022 Axcient. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2022 by Delphix. All rights reserved.
31 #include <err.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/zfs_ioctl.h>
36 #include <sys/zio_checksum.h>
37 #include <sys/zstd/zstd.h>
38 #include "zfs_fletcher.h"
39 #include "zstream.h"
41 static int
42 dump_record(dmu_replay_record_t *drr, void *payload, int payload_len,
43 zio_cksum_t *zc, int outfd)
45 assert(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum)
46 == sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
47 fletcher_4_incremental_native(drr,
48 offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc);
49 if (drr->drr_type != DRR_BEGIN) {
50 assert(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.
51 drr_checksum.drr_checksum));
52 drr->drr_u.drr_checksum.drr_checksum = *zc;
54 fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum,
55 sizeof (zio_cksum_t), zc);
56 if (write(outfd, drr, sizeof (*drr)) == -1)
57 return (errno);
58 if (payload_len != 0) {
59 fletcher_4_incremental_native(payload, payload_len, zc);
60 if (write(outfd, payload, payload_len) == -1)
61 return (errno);
63 return (0);
66 int
67 zstream_do_recompress(int argc, char *argv[])
69 int bufsz = SPA_MAXBLOCKSIZE;
70 char *buf = safe_malloc(bufsz);
71 dmu_replay_record_t thedrr;
72 dmu_replay_record_t *drr = &thedrr;
73 zio_cksum_t stream_cksum;
74 int c;
75 int level = -1;
77 while ((c = getopt(argc, argv, "l:")) != -1) {
78 switch (c) {
79 case 'l':
80 if (sscanf(optarg, "%d", &level) != 0) {
81 fprintf(stderr,
82 "failed to parse level '%s'\n",
83 optarg);
84 zstream_usage();
86 break;
87 case '?':
88 (void) fprintf(stderr, "invalid option '%c'\n",
89 optopt);
90 zstream_usage();
91 break;
95 argc -= optind;
96 argv += optind;
98 if (argc != 1)
99 zstream_usage();
100 int type = 0;
101 zio_compress_info_t *cinfo = NULL;
102 if (0 == strcmp(argv[0], "off")) {
103 type = ZIO_COMPRESS_OFF;
104 cinfo = &zio_compress_table[type];
105 } else if (0 == strcmp(argv[0], "inherit") ||
106 0 == strcmp(argv[0], "empty") ||
107 0 == strcmp(argv[0], "on")) {
108 // Fall through to invalid compression type case
109 } else {
110 for (int i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) {
111 if (0 == strcmp(zio_compress_table[i].ci_name,
112 argv[0])) {
113 cinfo = &zio_compress_table[i];
114 type = i;
115 break;
119 if (cinfo == NULL) {
120 fprintf(stderr, "Invalid compression type %s.\n",
121 argv[0]);
122 exit(2);
125 if (cinfo->ci_compress == NULL) {
126 type = 0;
127 cinfo = &zio_compress_table[0];
130 if (isatty(STDIN_FILENO)) {
131 (void) fprintf(stderr,
132 "Error: The send stream is a binary format "
133 "and can not be read from a\n"
134 "terminal. Standard input must be redirected.\n");
135 exit(1);
138 fletcher_4_init();
139 zio_init();
140 zstd_init();
141 int begin = 0;
142 boolean_t seen = B_FALSE;
143 while (sfread(drr, sizeof (*drr), stdin) != 0) {
144 struct drr_write *drrw;
145 uint64_t payload_size = 0;
148 * We need to regenerate the checksum.
150 if (drr->drr_type != DRR_BEGIN) {
151 memset(&drr->drr_u.drr_checksum.drr_checksum, 0,
152 sizeof (drr->drr_u.drr_checksum.drr_checksum));
156 switch (drr->drr_type) {
157 case DRR_BEGIN:
159 ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
160 VERIFY0(begin++);
161 seen = B_TRUE;
163 uint32_t sz = drr->drr_payloadlen;
165 VERIFY3U(sz, <=, 1U << 28);
167 if (sz != 0) {
168 if (sz > bufsz) {
169 buf = realloc(buf, sz);
170 if (buf == NULL)
171 err(1, "realloc");
172 bufsz = sz;
174 (void) sfread(buf, sz, stdin);
176 payload_size = sz;
177 break;
179 case DRR_END:
181 struct drr_end *drre = &drr->drr_u.drr_end;
183 * We would prefer to just check --begin == 0, but
184 * replication streams have an end of stream END
185 * record, so we must avoid tripping it.
187 VERIFY3B(seen, ==, B_TRUE);
188 begin--;
190 * Use the recalculated checksum, unless this is
191 * the END record of a stream package, which has
192 * no checksum.
194 if (!ZIO_CHECKSUM_IS_ZERO(&drre->drr_checksum))
195 drre->drr_checksum = stream_cksum;
196 break;
199 case DRR_OBJECT:
201 struct drr_object *drro = &drr->drr_u.drr_object;
202 VERIFY3S(begin, ==, 1);
204 if (drro->drr_bonuslen > 0) {
205 payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro);
206 (void) sfread(buf, payload_size, stdin);
208 break;
211 case DRR_SPILL:
213 struct drr_spill *drrs = &drr->drr_u.drr_spill;
214 VERIFY3S(begin, ==, 1);
215 payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs);
216 (void) sfread(buf, payload_size, stdin);
217 break;
220 case DRR_WRITE_BYREF:
221 VERIFY3S(begin, ==, 1);
222 fprintf(stderr,
223 "Deduplicated streams are not supported\n");
224 exit(1);
225 break;
227 case DRR_WRITE:
229 VERIFY3S(begin, ==, 1);
230 drrw = &thedrr.drr_u.drr_write;
231 payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
233 * In order to recompress an encrypted block, you have
234 * to decrypt, decompress, recompress, and
235 * re-encrypt. That can be a future enhancement (along
236 * with decryption or re-encryption), but for now we
237 * skip encrypted blocks.
239 boolean_t encrypted = B_FALSE;
240 for (int i = 0; i < ZIO_DATA_SALT_LEN; i++) {
241 if (drrw->drr_salt[i] != 0) {
242 encrypted = B_TRUE;
243 break;
246 if (encrypted) {
247 (void) sfread(buf, payload_size, stdin);
248 break;
250 if (drrw->drr_compressiontype >=
251 ZIO_COMPRESS_FUNCTIONS) {
252 fprintf(stderr, "Invalid compression type in "
253 "stream: %d\n", drrw->drr_compressiontype);
254 exit(3);
256 zio_compress_info_t *dinfo =
257 &zio_compress_table[drrw->drr_compressiontype];
259 /* Set up buffers to minimize memcpys */
260 char *cbuf, *dbuf;
261 if (cinfo->ci_compress == NULL)
262 dbuf = buf;
263 else
264 dbuf = safe_calloc(bufsz);
266 if (dinfo->ci_decompress == NULL)
267 cbuf = dbuf;
268 else
269 cbuf = safe_calloc(payload_size);
271 /* Read and decompress the payload */
272 (void) sfread(cbuf, payload_size, stdin);
273 if (dinfo->ci_decompress != NULL) {
274 if (0 != dinfo->ci_decompress(cbuf, dbuf,
275 payload_size, MIN(bufsz,
276 drrw->drr_logical_size), dinfo->ci_level)) {
277 warnx("decompression type %d failed "
278 "for ino %llu offset %llu",
279 type,
280 (u_longlong_t)drrw->drr_object,
281 (u_longlong_t)drrw->drr_offset);
282 exit(4);
284 payload_size = drrw->drr_logical_size;
285 free(cbuf);
288 /* Recompress the payload */
289 if (cinfo->ci_compress != NULL) {
290 payload_size = P2ROUNDUP(cinfo->ci_compress(
291 dbuf, buf, drrw->drr_logical_size,
292 MIN(payload_size, bufsz), (level == -1 ?
293 cinfo->ci_level : level)),
294 SPA_MINBLOCKSIZE);
295 if (payload_size != drrw->drr_logical_size) {
296 drrw->drr_compressiontype = type;
297 drrw->drr_compressed_size =
298 payload_size;
299 } else {
300 memcpy(buf, dbuf, payload_size);
301 drrw->drr_compressiontype = 0;
302 drrw->drr_compressed_size = 0;
304 free(dbuf);
305 } else {
306 drrw->drr_compressiontype = type;
307 drrw->drr_compressed_size = 0;
309 break;
312 case DRR_WRITE_EMBEDDED:
314 struct drr_write_embedded *drrwe =
315 &drr->drr_u.drr_write_embedded;
316 VERIFY3S(begin, ==, 1);
317 payload_size =
318 P2ROUNDUP((uint64_t)drrwe->drr_psize, 8);
319 (void) sfread(buf, payload_size, stdin);
320 break;
323 case DRR_FREEOBJECTS:
324 case DRR_FREE:
325 case DRR_OBJECT_RANGE:
326 VERIFY3S(begin, ==, 1);
327 break;
329 default:
330 (void) fprintf(stderr, "INVALID record type 0x%x\n",
331 drr->drr_type);
332 /* should never happen, so assert */
333 assert(B_FALSE);
336 if (feof(stdout)) {
337 fprintf(stderr, "Error: unexpected end-of-file\n");
338 exit(1);
340 if (ferror(stdout)) {
341 fprintf(stderr, "Error while reading file: %s\n",
342 strerror(errno));
343 exit(1);
347 * We need to recalculate the checksum, and it needs to be
348 * initially zero to do that. BEGIN records don't have
349 * a checksum.
351 if (drr->drr_type != DRR_BEGIN) {
352 memset(&drr->drr_u.drr_checksum.drr_checksum, 0,
353 sizeof (drr->drr_u.drr_checksum.drr_checksum));
355 if (dump_record(drr, buf, payload_size,
356 &stream_cksum, STDOUT_FILENO) != 0)
357 break;
358 if (drr->drr_type == DRR_END) {
360 * Typically the END record is either the last
361 * thing in the stream, or it is followed
362 * by a BEGIN record (which also zeros the checksum).
363 * However, a stream package ends with two END
364 * records. The last END record's checksum starts
365 * from zero.
367 ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
370 free(buf);
371 fletcher_4_fini();
372 zio_fini();
373 zstd_fini();
375 return (0);