xref: /freebsd/tests/sys/fs/tarfs/tarsum.c (revision 38b3683592d4c20a74f52a6e8e29368e6fa61858)
1*38b36835SDag-Erling Smørgrav /*-
2*38b36835SDag-Erling Smørgrav  * Copyright (c) 2024 Klara, Inc.
3*38b36835SDag-Erling Smørgrav  *
4*38b36835SDag-Erling Smørgrav  * SPDX-License-Identifier: BSD-2-Clause
5*38b36835SDag-Erling Smørgrav  *
6*38b36835SDag-Erling Smørgrav  * This program reads a tarball from stdin, recalculates the checksums of
7*38b36835SDag-Erling Smørgrav  * all ustar records within it, and writes the result to stdout.
8*38b36835SDag-Erling Smørgrav  */
9*38b36835SDag-Erling Smørgrav 
10*38b36835SDag-Erling Smørgrav #include <err.h>
11*38b36835SDag-Erling Smørgrav #include <stdarg.h>
12*38b36835SDag-Erling Smørgrav #include <stdbool.h>
13*38b36835SDag-Erling Smørgrav #include <stdint.h>
14*38b36835SDag-Erling Smørgrav #include <stdio.h>
15*38b36835SDag-Erling Smørgrav #include <stdlib.h>
16*38b36835SDag-Erling Smørgrav #include <string.h>
17*38b36835SDag-Erling Smørgrav #include <unistd.h>
18*38b36835SDag-Erling Smørgrav 
19*38b36835SDag-Erling Smørgrav static bool opt_v;
20*38b36835SDag-Erling Smørgrav 
21*38b36835SDag-Erling Smørgrav static int
verbose(const char * fmt,...)22*38b36835SDag-Erling Smørgrav verbose(const char *fmt, ...)
23*38b36835SDag-Erling Smørgrav {
24*38b36835SDag-Erling Smørgrav 	va_list ap;
25*38b36835SDag-Erling Smørgrav 	int ret;
26*38b36835SDag-Erling Smørgrav 
27*38b36835SDag-Erling Smørgrav 	if (!opt_v)
28*38b36835SDag-Erling Smørgrav 		return (0);
29*38b36835SDag-Erling Smørgrav 	va_start(ap, fmt);
30*38b36835SDag-Erling Smørgrav 	ret = vfprintf(stderr, fmt, ap);
31*38b36835SDag-Erling Smørgrav 	va_end(ap);
32*38b36835SDag-Erling Smørgrav 	return (ret);
33*38b36835SDag-Erling Smørgrav }
34*38b36835SDag-Erling Smørgrav 
35*38b36835SDag-Erling Smørgrav static void
tarsum(FILE * in,const char * ifn,FILE * out,const char * ofn)36*38b36835SDag-Erling Smørgrav tarsum(FILE *in, const char *ifn, FILE *out, const char *ofn)
37*38b36835SDag-Erling Smørgrav {
38*38b36835SDag-Erling Smørgrav 	union {
39*38b36835SDag-Erling Smørgrav 		uint8_t bytes[512];
40*38b36835SDag-Erling Smørgrav 		struct {
41*38b36835SDag-Erling Smørgrav 			uint8_t	prelude[148];
42*38b36835SDag-Erling Smørgrav 			char	checksum[8];
43*38b36835SDag-Erling Smørgrav 			uint8_t	interlude[101];
44*38b36835SDag-Erling Smørgrav 			char	magic[6];
45*38b36835SDag-Erling Smørgrav 			char	version[2];
46*38b36835SDag-Erling Smørgrav 			char	postlude[];
47*38b36835SDag-Erling Smørgrav 		};
48*38b36835SDag-Erling Smørgrav 	} ustar;
49*38b36835SDag-Erling Smørgrav 	unsigned long sum;
50*38b36835SDag-Erling Smørgrav 	off_t offset = 0;
51*38b36835SDag-Erling Smørgrav 	ssize_t ret;
52*38b36835SDag-Erling Smørgrav 	size_t i;
53*38b36835SDag-Erling Smørgrav 
54*38b36835SDag-Erling Smørgrav 	for (;;) {
55*38b36835SDag-Erling Smørgrav 		if ((ret = fread(&ustar, 1, sizeof(ustar), in)) < 0)
56*38b36835SDag-Erling Smørgrav 			err(1, "%s", ifn);
57*38b36835SDag-Erling Smørgrav 		else if (ret == 0)
58*38b36835SDag-Erling Smørgrav 			break;
59*38b36835SDag-Erling Smørgrav 		else if ((size_t)ret < sizeof(ustar))
60*38b36835SDag-Erling Smørgrav 			errx(1, "%s: Short read", ifn);
61*38b36835SDag-Erling Smørgrav 		if (strcmp(ustar.magic, "ustar") == 0 &&
62*38b36835SDag-Erling Smørgrav 		    ustar.version[0] == '0' && ustar.version[1] == '0') {
63*38b36835SDag-Erling Smørgrav 			verbose("header found at offset %#lx\n", offset);
64*38b36835SDag-Erling Smørgrav 			verbose("current checksum %.*s\n",
65*38b36835SDag-Erling Smørgrav 			    (int)sizeof(ustar.checksum), ustar.checksum);
66*38b36835SDag-Erling Smørgrav 			memset(ustar.checksum, ' ', sizeof(ustar.checksum));
67*38b36835SDag-Erling Smørgrav 			for (sum = i = 0; i < sizeof(ustar); i++)
68*38b36835SDag-Erling Smørgrav 				sum += ustar.bytes[i];
69*38b36835SDag-Erling Smørgrav 			verbose("calculated checksum %#lo\n", sum);
70*38b36835SDag-Erling Smørgrav 			sprintf(ustar.checksum, "%#lo", sum);
71*38b36835SDag-Erling Smørgrav 		}
72*38b36835SDag-Erling Smørgrav 		if ((ret = fwrite(&ustar, 1, sizeof(ustar), out)) < 0)
73*38b36835SDag-Erling Smørgrav 			err(1, "%s", ofn);
74*38b36835SDag-Erling Smørgrav 		else if ((size_t)ret < sizeof(ustar))
75*38b36835SDag-Erling Smørgrav 			errx(1, "%s: Short write", ofn);
76*38b36835SDag-Erling Smørgrav 		offset += sizeof(ustar);
77*38b36835SDag-Erling Smørgrav 	}
78*38b36835SDag-Erling Smørgrav 	verbose("%lu bytes processed\n", offset);
79*38b36835SDag-Erling Smørgrav }
80*38b36835SDag-Erling Smørgrav 
81*38b36835SDag-Erling Smørgrav static void
usage(void)82*38b36835SDag-Erling Smørgrav usage(void)
83*38b36835SDag-Erling Smørgrav {
84*38b36835SDag-Erling Smørgrav 	fprintf(stderr, "usage: tarsum [-v] [-o output] [input]\n");
85*38b36835SDag-Erling Smørgrav 	exit(1);
86*38b36835SDag-Erling Smørgrav }
87*38b36835SDag-Erling Smørgrav 
88*38b36835SDag-Erling Smørgrav int
main(int argc,char * argv[])89*38b36835SDag-Erling Smørgrav main(int argc, char *argv[])
90*38b36835SDag-Erling Smørgrav {
91*38b36835SDag-Erling Smørgrav 	const char *ifn, *ofn = NULL;
92*38b36835SDag-Erling Smørgrav 	FILE *in, *out;
93*38b36835SDag-Erling Smørgrav 	int opt;
94*38b36835SDag-Erling Smørgrav 
95*38b36835SDag-Erling Smørgrav 	while ((opt = getopt(argc, argv, "o:v")) != -1) {
96*38b36835SDag-Erling Smørgrav 		switch (opt) {
97*38b36835SDag-Erling Smørgrav 		case 'o':
98*38b36835SDag-Erling Smørgrav 			ofn = optarg;
99*38b36835SDag-Erling Smørgrav 			break;
100*38b36835SDag-Erling Smørgrav 		case 'v':
101*38b36835SDag-Erling Smørgrav 			opt_v = true;
102*38b36835SDag-Erling Smørgrav 			break;
103*38b36835SDag-Erling Smørgrav 		default:
104*38b36835SDag-Erling Smørgrav 			usage();
105*38b36835SDag-Erling Smørgrav 		}
106*38b36835SDag-Erling Smørgrav 	}
107*38b36835SDag-Erling Smørgrav 	argc -= optind;
108*38b36835SDag-Erling Smørgrav 	argv += optind;
109*38b36835SDag-Erling Smørgrav 	if (argc == 0 || strcmp(*argv, "-") == 0) {
110*38b36835SDag-Erling Smørgrav 		ifn = "stdin";
111*38b36835SDag-Erling Smørgrav 		in = stdin;
112*38b36835SDag-Erling Smørgrav 	} else if (argc == 1) {
113*38b36835SDag-Erling Smørgrav 		ifn = *argv;
114*38b36835SDag-Erling Smørgrav 		if ((in = fopen(ifn, "rb")) == NULL)
115*38b36835SDag-Erling Smørgrav 			err(1, "%s", ifn);
116*38b36835SDag-Erling Smørgrav 	} else {
117*38b36835SDag-Erling Smørgrav 		usage();
118*38b36835SDag-Erling Smørgrav 	}
119*38b36835SDag-Erling Smørgrav 	if (ofn == NULL || strcmp(ofn, "-") == 0) {
120*38b36835SDag-Erling Smørgrav 		ofn = "stdout";
121*38b36835SDag-Erling Smørgrav 		out = stdout;
122*38b36835SDag-Erling Smørgrav 	} else {
123*38b36835SDag-Erling Smørgrav 		if ((out = fopen(ofn, "wb")) == NULL)
124*38b36835SDag-Erling Smørgrav 			err(1, "%s", ofn);
125*38b36835SDag-Erling Smørgrav 	}
126*38b36835SDag-Erling Smørgrav 	tarsum(in, ifn, out, ofn);
127*38b36835SDag-Erling Smørgrav 	return (0);
128*38b36835SDag-Erling Smørgrav }
129