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