diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:24:29 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:24:29 +0300 |
| commit | 8140f2d060d59da3126354897937676c2a6b5217 (patch) | |
| tree | 5d90317ac7c74833d2fbfce278f7f50dac355cdf /corebinutils/dd | |
| parent | c800ffec456be2f8f346a3a3f50e1e5fa6ee2f0e (diff) | |
| parent | 54a575952b5661c61d14538277d3548ca939b342 (diff) | |
| download | Project-Tick-8140f2d060d59da3126354897937676c2a6b5217.tar.gz Project-Tick-8140f2d060d59da3126354897937676c2a6b5217.zip | |
Add 'corebinutils/dd/' from commit '54a575952b5661c61d14538277d3548ca939b342'
git-subtree-dir: corebinutils/dd
git-subtree-mainline: c800ffec456be2f8f346a3a3f50e1e5fa6ee2f0e
git-subtree-split: 54a575952b5661c61d14538277d3548ca939b342
Diffstat (limited to 'corebinutils/dd')
31 files changed, 3615 insertions, 0 deletions
diff --git a/corebinutils/dd/.gitignore b/corebinutils/dd/.gitignore new file mode 100644 index 0000000000..a74d30b48c --- /dev/null +++ b/corebinutils/dd/.gitignore @@ -0,0 +1,25 @@ +*.a +*.core +*.lo +*.nossppico +*.o +*.orig +*.pico +*.pieo +*.po +*.rej +*.so +*.so.[0-9]* +*.sw[nop] +*~ +.*DS_Store +.cache +.clangd +.ccls-cache +.depend* +compile_commands.json +compile_commands.events.json +tags +build/ +out/ +.linux-obj/ diff --git a/corebinutils/dd/GNUmakefile b/corebinutils/dd/GNUmakefile new file mode 100644 index 0000000000..9f20554575 --- /dev/null +++ b/corebinutils/dd/GNUmakefile @@ -0,0 +1,63 @@ +.DEFAULT_GOAL := all + +CC ?= cc +CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -I$(CURDIR) +CFLAGS ?= -O2 +CFLAGS += -std=c17 -g -Wall -Wextra -Wno-unused-parameter +LDFLAGS ?= +LDLIBS ?= + +OBJDIR := $(CURDIR)/build +OUTDIR := $(CURDIR)/out +TARGET := $(OUTDIR)/dd +GEN := $(OUTDIR)/dd-gen +OBJS := \ + $(OBJDIR)/args.o \ + $(OBJDIR)/conv.o \ + $(OBJDIR)/conv_tab.o \ + $(OBJDIR)/dd.o \ + $(OBJDIR)/misc.o \ + $(OBJDIR)/position.o + +.PHONY: all clean dirs status test + +all: $(TARGET) + +dirs: + @mkdir -p "$(OBJDIR)" "$(OUTDIR)" + +$(TARGET): $(OBJS) | dirs + $(CC) $(LDFLAGS) -o "$@" $(OBJS) $(LDLIBS) + +$(GEN): $(OBJDIR)/gen.o | dirs + $(CC) $(LDFLAGS) -o "$@" "$(OBJDIR)/gen.o" $(LDLIBS) + +$(OBJDIR)/args.o: $(CURDIR)/args.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/args.c" -o "$@" + +$(OBJDIR)/conv.o: $(CURDIR)/conv.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/conv.c" -o "$@" + +$(OBJDIR)/conv_tab.o: $(CURDIR)/conv_tab.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/conv_tab.c" -o "$@" + +$(OBJDIR)/dd.o: $(CURDIR)/dd.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/dd.c" -o "$@" + +$(OBJDIR)/misc.o: $(CURDIR)/misc.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/misc.c" -o "$@" + +$(OBJDIR)/position.o: $(CURDIR)/position.c $(CURDIR)/dd.h $(CURDIR)/extern.h | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/position.c" -o "$@" + +$(OBJDIR)/gen.o: $(CURDIR)/gen.c | dirs + $(CC) $(CPPFLAGS) $(CFLAGS) -c "$(CURDIR)/gen.c" -o "$@" + +test: $(TARGET) $(GEN) + DD_BIN="$(TARGET)" DD_GEN="$(GEN)" sh "$(CURDIR)/tests/test.sh" + +status: + @printf '%s\n' "$(TARGET)" + +clean: + @rm -rf "$(OBJDIR)" "$(OUTDIR)" diff --git a/corebinutils/dd/LICENSE b/corebinutils/dd/LICENSE new file mode 100644 index 0000000000..7417e15064 --- /dev/null +++ b/corebinutils/dd/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 1991, 1993, 1994 + The Regents of the University of California. All rights reserved. + +Copyright (c) 2026 + Project Tick. All rights reserved. + +This code is derived from software contributed to Berkeley by +Kevin Fall. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE.
\ No newline at end of file diff --git a/corebinutils/dd/LICENSES/BSD-2-Clause.txt b/corebinutils/dd/LICENSES/BSD-2-Clause.txt new file mode 100644 index 0000000000..5f662b354c --- /dev/null +++ b/corebinutils/dd/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) <year> <owner> + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/corebinutils/dd/LICENSES/BSD-3-Clause.txt b/corebinutils/dd/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000000..ea890afbc7 --- /dev/null +++ b/corebinutils/dd/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) <year> <owner>. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/corebinutils/dd/README.md b/corebinutils/dd/README.md new file mode 100644 index 0000000000..ffbd3403f5 --- /dev/null +++ b/corebinutils/dd/README.md @@ -0,0 +1,28 @@ +# dd + +Standalone musl-libc-based Linux port of FreeBSD `dd` for Project Tick BSD/Linux Distribution. + +## Build + +```sh +gmake -f GNUmakefile +gmake -f GNUmakefile CC=musl-gcc +``` + +## Test + +```sh +gmake -f GNUmakefile test +gmake -f GNUmakefile test CC=musl-gcc +``` + +## Notes + +- Port structure follows the existing standalone sibling ports: local `GNUmakefile`, short technical `README.md`, and shell tests under `tests/`. +- Port strategy is Linux-native API mapping, not a BSD compatibility shim. The mature FreeBSD copy/conversion core is kept, but FreeBSD-only process isolation and device typing paths are removed or replaced. +- Input/output typing uses Linux `fstat(2)`, `lseek(2)`, and `MTIOCGET`/`MTIOCTOP` from `sys/mtio.h`. `files=` remains available only for real tape devices; on non-tape inputs it fails explicitly. +- FreeBSD `SIGINFO` status requests map to Linux `SIGUSR1`. Periodic `status=progress` updates continue to use `setitimer(2)`/`SIGALRM`. +- `iflag=direct` and `oflag=direct` use Linux `O_DIRECT`; buffers are allocated with page-aligned `posix_memalign(3)`. Linux still enforces filesystem/device-specific alignment for block size and offsets, so invalid direct-I/O combinations fail with the kernel error instead of being silently emulated. +- `oflag=sync`/`oflag=fsync` use Linux `O_SYNC` for named outputs and an explicit `fsync(2)` after each completed write so inherited descriptors such as stdout are not silently downgraded. +- `conv=fdatasync` and `conv=fsync` map to `fdatasync(2)` and `fsync(2)` at close, matching Linux-native durability APIs. +- Unsupported semantics are explicit rather than stubbed: FreeBSD Capsicum/Casper integration is removed, non-tape `files=` is rejected, and `seek=` on a non-seekable non-tape output returns a clear error instead of taking a fake compatibility path. diff --git a/corebinutils/dd/args.c b/corebinutils/dd/args.c new file mode 100644 index 0000000000..9f92edd9ff --- /dev/null +++ b/corebinutils/dd/args.c @@ -0,0 +1,604 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> + +#include "dd.h" +#include "extern.h" + +static int c_arg(const void *, const void *); +static int c_conv(const void *, const void *); +static int c_iflag(const void *, const void *); +static int c_oflag(const void *, const void *); +static void f_bs(char *); +static void f_cbs(char *); +static void f_conv(char *); +static void f_count(char *); +static void f_files(char *); +static void f_fillchar(char *); +static void f_ibs(char *); +static void f_if(char *); +static void f_iflag(char *); +static void f_obs(char *); +static void f_of(char *); +static void f_oflag(char *); +static void f_seek(char *); +static void f_skip(char *); +static void f_speed(char *); +static void f_status(char *); +static uintmax_t get_num(const char *); +static off_t get_off_t(const char *); +static char *next_list_token(char **); + +static const struct arg { + const char *name; + void (*f)(char *); + uint64_t set, noset; +} args[] = { + { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, + { "cbs", f_cbs, C_CBS, C_CBS }, + { "conv", f_conv, 0, 0 }, + { "count", f_count, C_COUNT, C_COUNT }, + { "files", f_files, C_FILES, C_FILES }, + { "fillchar", f_fillchar, C_FILL, C_FILL }, + { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, + { "if", f_if, C_IF, C_IF }, + { "iflag", f_iflag, 0, 0 }, + { "iseek", f_skip, C_SKIP, C_SKIP }, + { "obs", f_obs, C_OBS, C_BS|C_OBS }, + { "of", f_of, C_OF, C_OF }, + { "oflag", f_oflag, 0, 0 }, + { "oseek", f_seek, C_SEEK, C_SEEK }, + { "seek", f_seek, C_SEEK, C_SEEK }, + { "skip", f_skip, C_SKIP, C_SKIP }, + { "speed", f_speed, 0, 0 }, + { "status", f_status, C_STATUS,C_STATUS }, +}; + +static char *oper; + +static char * +next_list_token(char **listp) +{ + char *token, *next; + + token = *listp; + if (token == NULL) + return (NULL); + next = strchr(token, ','); + if (next != NULL) { + *next = '\0'; + *listp = next + 1; + } else { + *listp = NULL; + } + return (token); +} + +/* + * args -- parse JCL syntax of dd. + */ +void +jcl(char **argv) +{ + struct arg *ap, tmp; + char *arg; + + in.dbsz = out.dbsz = 512; + + while ((oper = *++argv) != NULL) { + if ((oper = strdup(oper)) == NULL) + errx(1, "unable to allocate space for the argument \"%s\"", *argv); + if ((arg = strchr(oper, '=')) == NULL) + errx(1, "unknown operand %s", oper); + *arg++ = '\0'; + if (!*arg) + errx(1, "no value specified for %s", oper); + tmp.name = oper; + if (!(ap = (struct arg *)bsearch(&tmp, args, + sizeof(args)/sizeof(struct arg), sizeof(struct arg), + c_arg))) + errx(1, "unknown operand %s", tmp.name); + if (ddflags & ap->noset) + errx(1, "%s: illegal argument combination or already set", + tmp.name); + ddflags |= ap->set; + ap->f(arg); + } + + /* Final sanity checks. */ + + if (ddflags & C_BS) { + /* + * Bs is turned off by any conversion -- we assume the user + * just wanted to set both the input and output block sizes + * and didn't want the bs semantics, so we don't warn. + */ + if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | + C_UNBLOCK)) + ddflags &= ~C_BS; + + /* Bs supersedes ibs and obs. */ + if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) + warnx("bs supersedes ibs and obs"); + } + + /* + * Ascii/ebcdic and cbs implies block/unblock. + * Block/unblock requires cbs and vice-versa. + */ + if (ddflags & (C_BLOCK | C_UNBLOCK)) { + if (!(ddflags & C_CBS)) + errx(1, "record operations require cbs"); + if (cbsz == 0) + errx(1, "cbs cannot be zero"); + cfunc = ddflags & C_BLOCK ? block : unblock; + } else if (ddflags & C_CBS) { + if (ddflags & (C_ASCII | C_EBCDIC)) { + if (ddflags & C_ASCII) { + ddflags |= C_UNBLOCK; + cfunc = unblock; + } else { + ddflags |= C_BLOCK; + cfunc = block; + } + } else + errx(1, "cbs meaningless if not doing record operations"); + } else + cfunc = def; +} + +static int +c_arg(const void *a, const void *b) +{ + + return (strcmp(((const struct arg *)a)->name, + ((const struct arg *)b)->name)); +} + +static void +f_bs(char *arg) +{ + uintmax_t res; + + res = get_num(arg); + if (res < 1 || res > SSIZE_MAX) + errx(1, "bs must be between 1 and %zd", (ssize_t)SSIZE_MAX); + in.dbsz = out.dbsz = (size_t)res; +} + +static void +f_cbs(char *arg) +{ + uintmax_t res; + + res = get_num(arg); + if (res < 1 || res > SSIZE_MAX) + errx(1, "cbs must be between 1 and %zd", (ssize_t)SSIZE_MAX); + cbsz = (size_t)res; +} + +static void +f_count(char *arg) +{ + uintmax_t res; + + res = get_num(arg); + if (res == UINTMAX_MAX) + errx(1, "%s: %s", oper, strerror(ERANGE)); + if (res == 0) + cpy_cnt = UINTMAX_MAX; + else + cpy_cnt = res; +} + +static void +f_files(char *arg) +{ + + files_cnt = get_num(arg); + if (files_cnt < 1) + errx(1, "files must be between 1 and %zu", SIZE_MAX); +} + +static void +f_fillchar(char *arg) +{ + + if (strlen(arg) != 1) + errx(1, "need exactly one fill char"); + + fill_char = arg[0]; +} + +static void +f_ibs(char *arg) +{ + uintmax_t res; + + if (!(ddflags & C_BS)) { + res = get_num(arg); + if (res < 1 || res > SSIZE_MAX) + errx(1, "ibs must be between 1 and %zd", + (ssize_t)SSIZE_MAX); + in.dbsz = (size_t)res; + } +} + +static void +f_if(char *arg) +{ + + in.name = arg; +} + +static const struct iflag { + const char *name; + uint64_t set, noset; +} ilist[] = { + { "direct", C_IDIRECT, 0 }, + { "fullblock", C_IFULLBLOCK, C_SYNC }, +}; + +static void +f_iflag(char *arg) +{ + struct iflag *ip, tmp; + + while (arg != NULL) { + tmp.name = next_list_token(&arg); + if (tmp.name[0] == '\0') + errx(1, "empty iflag value"); + ip = bsearch(&tmp, ilist, nitems(ilist), sizeof(struct iflag), + c_iflag); + if (ip == NULL) + errx(1, "unknown iflag %s", tmp.name); + if (ddflags & ip->noset) + errx(1, "%s: illegal conversion combination", tmp.name); + ddflags |= ip->set; + } +} + +static int +c_iflag(const void *a, const void *b) +{ + + return (strcmp(((const struct iflag *)a)->name, + ((const struct iflag *)b)->name)); +} + +static void +f_obs(char *arg) +{ + uintmax_t res; + + if (!(ddflags & C_BS)) { + res = get_num(arg); + if (res < 1 || res > SSIZE_MAX) + errx(1, "obs must be between 1 and %zd", + (ssize_t)SSIZE_MAX); + out.dbsz = (size_t)res; + } +} + +static void +f_of(char *arg) +{ + + out.name = arg; +} + +static void +f_seek(char *arg) +{ + + out.offset = get_off_t(arg); +} + +static void +f_skip(char *arg) +{ + + in.offset = get_off_t(arg); +} + +static void +f_speed(char *arg) +{ + + speed = get_num(arg); +} + +static void +f_status(char *arg) +{ + + if (strcmp(arg, "none") == 0) + ddflags |= C_NOINFO; + else if (strcmp(arg, "noxfer") == 0) + ddflags |= C_NOXFER; + else if (strcmp(arg, "progress") == 0) + ddflags |= C_PROGRESS; + else + errx(1, "unknown status %s", arg); +} + +static const struct conv { + const char *name; + uint64_t set, noset; + const u_char *ctab; +} clist[] = { + { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, + { "block", C_BLOCK, C_UNBLOCK, NULL }, + { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, + { "fdatasync", C_FDATASYNC, 0, NULL }, + { "fsync", C_FSYNC, 0, NULL }, + { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, + { "lcase", C_LCASE, C_UCASE, NULL }, + { "noerror", C_NOERROR, 0, NULL }, + { "notrunc", C_NOTRUNC, 0, NULL }, + { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, + { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, + { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, + { "osync", C_OSYNC, C_BS, NULL }, + { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL}, + { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL}, + { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL}, + { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, + { "sparse", C_SPARSE, 0, NULL }, + { "swab", C_SWAB, 0, NULL }, + { "sync", C_SYNC, C_IFULLBLOCK, NULL }, + { "ucase", C_UCASE, C_LCASE, NULL }, + { "unblock", C_UNBLOCK, C_BLOCK, NULL }, +}; + +static void +f_conv(char *arg) +{ + struct conv *cp, tmp; + + while (arg != NULL) { + tmp.name = next_list_token(&arg); + if (tmp.name[0] == '\0') + errx(1, "empty conv value"); + cp = bsearch(&tmp, clist, nitems(clist), sizeof(struct conv), + c_conv); + if (cp == NULL) + errx(1, "unknown conversion %s", tmp.name); + if (ddflags & cp->noset) + errx(1, "%s: illegal conversion combination", tmp.name); + ddflags |= cp->set; + if (cp->ctab) + ctab = cp->ctab; + } +} + +static int +c_conv(const void *a, const void *b) +{ + + return (strcmp(((const struct conv *)a)->name, + ((const struct conv *)b)->name)); +} + +static const struct oflag { + const char *name; + uint64_t set; +} olist[] = { + { "direct", C_ODIRECT }, + { "fsync", C_OFSYNC }, + { "sync", C_OFSYNC }, +}; + +static void +f_oflag(char *arg) +{ + struct oflag *op, tmp; + + while (arg != NULL) { + tmp.name = next_list_token(&arg); + if (tmp.name[0] == '\0') + errx(1, "empty oflag value"); + op = bsearch(&tmp, olist, nitems(olist), sizeof(struct oflag), + c_oflag); + if (op == NULL) + errx(1, "unknown open flag %s", tmp.name); + ddflags |= op->set; + } +} + +static int +c_oflag(const void *a, const void *b) +{ + + return (strcmp(((const struct oflag *)a)->name, + ((const struct oflag *)b)->name)); +} + +static intmax_t +postfix_to_mult(const char expr) +{ + intmax_t mult; + + mult = 0; + switch (expr) { + case 'B': + case 'b': + mult = 512; + break; + case 'K': + case 'k': + mult = 1 << 10; + break; + case 'M': + case 'm': + mult = 1 << 20; + break; + case 'G': + case 'g': + mult = 1 << 30; + break; + case 'T': + case 't': + mult = (uintmax_t)1 << 40; + break; + case 'P': + case 'p': + mult = (uintmax_t)1 << 50; + break; + case 'W': + case 'w': + mult = sizeof(int); + break; + } + + return (mult); +} + +/* + * Convert an expression of the following forms to a uintmax_t. + * 1) A positive decimal number. + * 2) A positive decimal number followed by a 'b' or 'B' (mult by 512). + * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). + * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). + * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). + * 6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40). + * 7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50). + * 8) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int). + * 9) Two or more positive decimal numbers (with/without [BbKkMmGgWw]) + * separated by 'x' or 'X' (also '*' for backwards compatibility), + * specifying the product of the indicated values. + */ +static uintmax_t +get_num(const char *val) +{ + uintmax_t num, mult, prevnum; + char *expr; + + errno = 0; + num = strtoumax(val, &expr, 0); + if (expr == val) /* No valid digits. */ + errx(1, "%s: invalid numeric value", oper); + if (errno != 0) + err(1, "%s", oper); + + mult = postfix_to_mult(*expr); + + if (mult != 0) { + prevnum = num; + num *= mult; + /* Check for overflow. */ + if (num / mult != prevnum) + goto erange; + expr++; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible. */ + case 'X': + case 'x': + mult = get_num(expr + 1); + prevnum = num; + num *= mult; + if (num / mult == prevnum) + break; +erange: + errx(1, "%s: %s", oper, strerror(ERANGE)); + default: + errx(1, "%s: illegal numeric value", oper); + } + return (num); +} + +/* + * Convert an expression of the following forms to an off_t. This is the + * same as get_num(), but it uses signed numbers. + * + * The major problem here is that an off_t may not necessarily be a intmax_t. + */ +static off_t +get_off_t(const char *val) +{ + intmax_t num, mult, prevnum; + char *expr; + + errno = 0; + num = strtoimax(val, &expr, 0); + if (expr == val) /* No valid digits. */ + errx(1, "%s: invalid numeric value", oper); + if (errno != 0) + err(1, "%s", oper); + + mult = postfix_to_mult(*expr); + + if (mult != 0) { + prevnum = num; + num *= mult; + /* Check for overflow. */ + if ((prevnum > 0) != (num > 0) || num / mult != prevnum) + goto erange; + expr++; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible. */ + case 'X': + case 'x': + mult = (intmax_t)get_off_t(expr + 1); + prevnum = num; + num *= mult; + if ((prevnum > 0) == (num > 0) && num / mult == prevnum) + break; +erange: + errx(1, "%s: %s", oper, strerror(ERANGE)); + default: + errx(1, "%s: illegal numeric value", oper); + } + return (num); +} diff --git a/corebinutils/dd/conv.c b/corebinutils/dd/conv.c new file mode 100644 index 0000000000..f24985b28e --- /dev/null +++ b/corebinutils/dd/conv.c @@ -0,0 +1,263 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <err.h> +#include <inttypes.h> +#include <string.h> + +#include "dd.h" +#include "extern.h" + +/* + * def -- + * Copy input to output. Input is buffered until reaches obs, and then + * output until less than obs remains. Only a single buffer is used. + * Worst case buffer calculation is (ibs + obs - 1). + */ +void +def(void) +{ + u_char *inp; + const u_char *t; + size_t cnt; + + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + + /* Make the output buffer look right. */ + out.dbp = in.dbp; + out.dbcnt = in.dbcnt; + + if (in.dbcnt >= out.dbsz) { + /* If the output buffer is full, write it. */ + dd_out(0); + + /* + * dd_out copies the leftover output to the beginning of + * the buffer and resets the output buffer. Reset the + * input buffer to match it. + */ + in.dbp = out.dbp; + in.dbcnt = out.dbcnt; + } +} + +void +def_close(void) +{ + /* Just update the count, everything is already in the buffer. */ + if (in.dbcnt) + out.dbcnt = in.dbcnt; +} + +/* + * Copy variable length newline terminated records with a max size cbsz + * bytes to output. Records less than cbs are padded with spaces. + * + * max in buffer: MAX(ibs, cbsz) + * max out buffer: obs + cbsz + */ +void +block(void) +{ + u_char *inp, *outp; + const u_char *t; + size_t cnt, maxlen; + static int intrunc; + int ch; + + /* + * Record truncation can cross block boundaries. If currently in a + * truncation state, keep tossing characters until reach a newline. + * Start at the beginning of the buffer, as the input buffer is always + * left empty. + */ + if (intrunc) { + for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt) + ; + if (!cnt) { + in.dbcnt = 0; + in.dbp = in.db; + return; + } + intrunc = 0; + /* Adjust the input buffer numbers. */ + in.dbcnt = cnt - 1; + in.dbp = inp + cnt - 1; + } + + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation is done as we copy into the output buffer. + */ + ch = 0; + for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { + maxlen = MIN(cbsz, (size_t)in.dbcnt); + if ((t = ctab) != NULL) + for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; + ++cnt) + *outp++ = t[ch]; + else + for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; + ++cnt) + *outp++ = ch; + /* + * Check for short record without a newline. Reassemble the + * input block. + */ + if (ch != '\n' && (size_t)in.dbcnt < cbsz) { + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + break; + } + + /* Adjust the input buffer numbers. */ + in.dbcnt -= cnt; + if (ch == '\n') + --in.dbcnt; + + /* Pad short records with spaces. */ + if (cnt < cbsz) + (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); + else { + /* + * If the next character wouldn't have ended the + * block, it's a truncation. + */ + if (!in.dbcnt || *inp != '\n') + ++st.trunc; + + /* Toss characters to a newline. */ + for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt) + ; + if (!in.dbcnt) + intrunc = 1; + else + --in.dbcnt; + } + + /* Adjust output buffer numbers. */ + out.dbp += cbsz; + if ((out.dbcnt += cbsz) >= out.dbsz) + dd_out(0); + outp = out.dbp; + } + in.dbp = in.db + in.dbcnt; +} + +void +block_close(void) +{ + /* + * Copy any remaining data into the output buffer and pad to a record. + * Don't worry about truncation or translation, the input buffer is + * always empty when truncating, and no characters have been added for + * translation. The bottom line is that anything left in the input + * buffer is a truncated record. Anything left in the output buffer + * just wasn't big enough. + */ + if (in.dbcnt) { + ++st.trunc; + (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); + (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ', + cbsz - in.dbcnt); + out.dbcnt += cbsz; + } +} + +/* + * Convert fixed length (cbsz) records to variable length. Deletes any + * trailing blanks and appends a newline. + * + * max in buffer: MAX(ibs, cbsz) + cbsz + * max out buffer: obs + cbsz + */ +void +unblock(void) +{ + u_char *inp; + const u_char *t; + size_t cnt; + + /* Translation and case conversion. */ + if ((t = ctab) != NULL) + for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) + *inp = t[*inp]; + /* + * Copy records (max cbsz size chunks) into the output buffer. The + * translation has to already be done or we might not recognize the + * spaces. + */ + for (inp = in.db; (size_t)in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { + for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t) + ; + if (t >= inp) { + cnt = t - inp + 1; + (void)memmove(out.dbp, inp, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + *out.dbp++ = '\n'; + if (++out.dbcnt >= out.dbsz) + dd_out(0); + } + if (in.dbcnt) + (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); + in.dbp = in.db + in.dbcnt; +} + +void +unblock_close(void) +{ + u_char *t; + size_t cnt; + + if (in.dbcnt) { + warnx("%s: short input record", in.name); + for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t) + ; + if (t >= in.db) { + cnt = t - in.db + 1; + (void)memmove(out.dbp, in.db, cnt); + out.dbp += cnt; + out.dbcnt += cnt; + } + ++out.dbcnt; + *out.dbp++ = '\n'; + } +} diff --git a/corebinutils/dd/conv_tab.c b/corebinutils/dd/conv_tab.c new file mode 100644 index 0000000000..45a399b76d --- /dev/null +++ b/corebinutils/dd/conv_tab.c @@ -0,0 +1,287 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <signal.h> +#include <stdint.h> + +#include "dd.h" +#include "extern.h" + +/* + * There are currently six tables: + * + * ebcdic -> ascii 32V conv=oldascii + * ascii -> ebcdic 32V conv=oldebcdic + * ascii -> ibm ebcdic 32V conv=oldibm + * + * ebcdic -> ascii POSIX/S5 conv=ascii + * ascii -> ebcdic POSIX/S5 conv=ebcdic + * ascii -> ibm ebcdic POSIX/S5 conv=ibm + * + * Other tables are built from these if multiple conversions are being + * done. + * + * Tables used for conversions to/from IBM and EBCDIC to support an extension + * to POSIX P1003.2/D11. The tables referencing POSIX contain data extracted + * from tables 4-3 and 4-4 in P1003.2/Draft 11. The historic tables were + * constructed by running against a file with all possible byte values. + * + * More information can be obtained in "Correspondences of 8-Bit and Hollerith + * Codes for Computer Environments-A USASI Tutorial", Communications of the + * ACM, Volume 11, Number 11, November 1968, pp. 783-789. + */ + +u_char casetab[256]; + +/* EBCDIC to ASCII -- 32V compatible. */ +const u_char e2a_32V[] = { + 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */ + 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */ + 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */ + 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */ + 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */ + 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */ + 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */ + 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */ + 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041, /* 0110 */ + 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */ + 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136, /* 0130 */ + 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */ + 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077, /* 0150 */ + 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */ + 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */ + 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */ + 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */ + 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */ + 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, /* 0230 */ + 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */ + 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, /* 0250 */ + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */ + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, /* 0270 */ + 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */ + 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */ + 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */ + 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */ + 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */ + 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */ + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */ + 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to EBCDIC -- 32V compatible. */ +const u_char a2e_32V[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to IBM EBCDIC -- 32V compatible. */ +const u_char a2ibm_32V[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* EBCDIC to ASCII -- POSIX and System V compatible. */ +const u_char e2a_POSIX[] = { + 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */ + 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */ + 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */ + 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */ + 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */ + 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */ + 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */ + 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */ + 0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174, /* 0110 */ + 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */ + 0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176, /* 0130 */ + 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */ + 0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077, /* 0150 */ + 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */ + 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */ + 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */ + 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */ + 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */ + 0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320, /* 0230 */ + 0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */ + 0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327, /* 0250 */ + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */ + 0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347, /* 0270 */ + 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */ + 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */ + 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */ + 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */ + 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */ + 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */ + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */ + 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to EBCDIC -- POSIX and System V compatible. */ +const u_char a2e_POSIX[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; + +/* ASCII to IBM EBCDIC -- POSIX and System V compatible. */ +const u_char a2ibm_POSIX[] = { + 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */ + 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */ + 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */ + 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */ + 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */ + 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */ + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */ + 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */ + 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */ + 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */ + 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */ + 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */ + 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */ + 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */ + 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */ + 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */ + 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */ + 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */ + 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */ + 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */ + 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */ + 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */ + 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */ + 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */ + 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */ + 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */ + 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */ + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */ + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */ + 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */ + 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */ + 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */ +}; diff --git a/corebinutils/dd/dd.1 b/corebinutils/dd/dd.1 new file mode 100644 index 0000000000..e8b8eef39d --- /dev/null +++ b/corebinutils/dd/dd.1 @@ -0,0 +1,506 @@ +.\"- +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Copyright (c) 2026 +.\" Project Tick. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Keith Muller of the University of California, San Diego. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 2020 +.Dt DD 1 +.Os +.Sh NAME +.Nm dd +.Nd convert and copy a file +.Sh SYNOPSIS +.Nm +.Op Ar operands ... +.Sh DESCRIPTION +The +.Nm +utility copies the standard input to the standard output. +Input data is read and written in 512-byte blocks. +If input reads are short, input from multiple reads are aggregated +to form the output block. +When finished, +.Nm +displays the number of complete and partial input and output blocks +and truncated input records to the standard error output. +.Pp +The following operands are available: +.Bl -tag -width "of=file" +.It Cm bs Ns = Ns Ar n +Set both input and output block size to +.Ar n +bytes, superseding the +.Cm ibs +and +.Cm obs +operands. +If no conversion values other than +.Cm noerror , +.Cm notrunc +or +.Cm sync +are specified, then each input block is copied to the output as a +single block without any aggregation of short blocks. +.It Cm cbs Ns = Ns Ar n +Set the conversion record size to +.Ar n +bytes. +The conversion record size is required by the record oriented conversion +values. +.It Cm count Ns = Ns Ar n +Copy only +.Ar n +input blocks. +.It Cm files Ns = Ns Ar n +Copy +.Ar n +input files before terminating. +This operand is only applicable when the input device is a tape. +.It Cm fillchar Ns = Ns Ar c +When padding a block in conversion mode or due to use of +.Cm noerror +and +.Cm sync +modes, fill with the specified +.Tn ASCII +character, rather than using a space or +.Dv NUL . +.It Cm ibs Ns = Ns Ar n +Set the input block size to +.Ar n +bytes instead of the default 512. +.It Cm if Ns = Ns Ar file +Read input from +.Ar file +instead of the standard input. +.It Cm iflag Ns = Ns Ar value Ns Op , Ns Ar value ... +Where +.Cm value +is one of the symbols from the following list. +.Bl -tag -width "fullblock" +.It Cm fullblock +Reading from the input file may not obtain a full block. +When a read returns short, continue reading to fill the block. +Without this flag, +.Cm count +limits the number of times +.Xr read 2 +is called on the input rather than the number of blocks copied in full. +May not be combined with +.Cm conv=sync . +.It Cm direct +Set the O_DIRECT flag on the input file to make reads bypass any local caching. +.El +.It Cm iseek Ns = Ns Ar n +Seek on the input file +.Ar n +blocks. +This is synonymous with +.Cm skip Ns = Ns Ar n . +.It Cm obs Ns = Ns Ar n +Set the output block size to +.Ar n +bytes instead of the default 512. +.It Cm of Ns = Ns Ar file +Write output to +.Ar file +instead of the standard output. +Any regular output file is truncated unless the +.Cm notrunc +conversion value is specified. +If an initial portion of the output file is seeked past (see the +.Cm oseek +operand), +the output file is truncated at that point. +.It Cm oflag Ns = Ns Ar value Ns Op , Ns Ar value ... +Where +.Cm value +is one of the symbols from the following list. +.Bl -tag -width "direct" +.It Cm fsync +Set the O_FSYNC flag on the output file to make writes synchronous. +.It Cm sync +Set the O_SYNC flag on the output file to make writes synchronous. +This is synonymous with the +.Cm fsync +value. +.It Cm direct +Set the O_DIRECT flag on the output file to make writes bypass any local caching. +.El +.It Cm oseek Ns = Ns Ar n +Seek on the output file +.Ar n +blocks. +This is synonymous with +.Cm seek Ns = Ns Ar n . +.It Cm seek Ns = Ns Ar n +Seek +.Ar n +blocks from the beginning of the output before copying. +On non-tape devices, an +.Xr lseek 2 +operation is used. +Otherwise, existing blocks are read and the data discarded. +If the user does not have read permission for the tape, it is positioned +using the tape +.Xr ioctl 2 +function calls. +If the seek operation is past the end of file, space from the current +end of file to the specified offset is filled with blocks of +.Dv NUL +bytes. +.It Cm skip Ns = Ns Ar n +Skip +.Ar n +blocks from the beginning of the input before copying. +On input which supports seeks, an +.Xr lseek 2 +operation is used. +Otherwise, input data is read and discarded. +For pipes, the correct number of bytes is read. +For all other devices, the correct number of blocks is read without +distinguishing between a partial or complete block being read. +.It Cm speed Ns = Ns Ar n +Limit the copying speed to +.Ar n +bytes per second. +.It Cm status Ns = Ns Ar value +Where +.Cm value +is one of the symbols from the following list. +.Bl -tag -width "progress" +.It Cm noxfer +Do not print the transfer statistics as the last line of status output. +.It Cm none +Do not print the status output. +Error messages are shown; informational messages are not. +.It Cm progress +Print basic transfer statistics once per second. +.El +.It Cm conv Ns = Ns Ar value Ns Op , Ns Ar value ... +Where +.Cm value +is one of the symbols from the following list. +.Bl -tag -width "unblock" +.It Cm ascii , oldascii +The same as the +.Cm unblock +value except that characters are translated from +.Tn EBCDIC +to +.Tn ASCII +before the +records are converted. +(These values imply +.Cm unblock +if the operand +.Cm cbs +is also specified.) +There are two conversion maps for +.Tn ASCII . +The value +.Cm ascii +specifies the recommended one which is compatible with +.At V . +The value +.Cm oldascii +specifies the one used in historic +.At +and +.No pre- Ns Bx 4.3 reno +systems. +.It Cm block +Treats the input as a sequence of newline or end-of-file terminated variable +length records independent of input and output block boundaries. +Any trailing newline character is discarded. +Each input record is converted to a fixed length output record where the +length is specified by the +.Cm cbs +operand. +Input records shorter than the conversion record size are padded with spaces. +Input records longer than the conversion record size are truncated. +The number of truncated input records, if any, are reported to the standard +error output at the completion of the copy. +.It Cm ebcdic , ibm , oldebcdic , oldibm +The same as the +.Cm block +value except that characters are translated from +.Tn ASCII +to +.Tn EBCDIC +after the +records are converted. +(These values imply +.Cm block +if the operand +.Cm cbs +is also specified.) +There are four conversion maps for +.Tn EBCDIC . +The value +.Cm ebcdic +specifies the recommended one which is compatible with +.At V . +The value +.Cm ibm +is a slightly different mapping, which is compatible with the +.At V +.Cm ibm +value. +The values +.Cm oldebcdic +and +.Cm oldibm +are maps used in historic +.At +and +.No pre- Ns Bx 4.3 reno +systems. +.It Cm fdatasync +Perform an +.Xr fdatasync 2 +on the output file before closing it. +.It Cm fsync +Perform an +.Xr fsync 2 +on the output file before closing it. +.It Cm lcase +Transform uppercase characters into lowercase characters. +.It Cm pareven , parnone , parodd , parset +Output data with the specified parity. +The parity bit on input is stripped unless +.Tn EBCDIC +to +.Tn ASCII +conversions is also specified. +.It Cm noerror +Do not stop processing on an input error. +When an input error occurs, a diagnostic message followed by the current +input and output block counts will be written to the standard error output +in the same format as the standard completion message. +If the +.Cm sync +conversion is also specified, any missing input data will be replaced +with +.Dv NUL +bytes (or with spaces if a block oriented conversion value was +specified) and processed as a normal input buffer. +If the +.Cm fillchar +option is specified, the fill character provided on the command line +will override +the automatic selection of the fill character. +If the +.Cm sync +conversion is not specified, the input block is omitted from the output. +On input files which are not tapes or pipes, the file offset +will be positioned past the block in which the error occurred using +.Xr lseek 2 . +.It Cm notrunc +Do not truncate the output file. +This will preserve any blocks in the output file not explicitly written +by +.Nm . +The +.Cm notrunc +value is not supported for tapes. +.It Cm osync +Pad the final output block to the full output block size. +If the input file is not a multiple of the output block size +after conversion, this conversion forces the final output block +to be the same size as preceding blocks for use on devices that require +regularly sized blocks to be written. +This option is incompatible with use of the +.Cm bs Ns = Ns Ar n +block size specification. +.It Cm sparse +If one or more output blocks would consist solely of +.Dv NUL +bytes, try to seek the output file by the required space instead of +filling them with +.Dv NUL Ns s , +resulting in a sparse file. +.It Cm swab +Swap every pair of input bytes. +If an input buffer has an odd number of bytes, the last byte will be +ignored during swapping. +.It Cm sync +Pad every input block to the input buffer size. +Spaces are used for pad bytes if a block oriented conversion value is +specified, otherwise +.Dv NUL +bytes are used. +.It Cm ucase +Transform lowercase characters into uppercase characters. +.It Cm unblock +Treats the input as a sequence of fixed length records independent of input +and output block boundaries. +The length of the input records is specified by the +.Cm cbs +operand. +Any trailing space characters are discarded and a newline character is +appended. +.El +.El +.Pp +Where sizes or speed are specified, a decimal, octal, or hexadecimal number of +bytes is expected. +If the number ends with a +.Dq Li b , +.Dq Li k , +.Dq Li m , +.Dq Li g , +.Dq Li t , +.Dq Li p , +or +.Dq Li w , +the +number is multiplied by 512, 1024 (1K), 1048576 (1M), 1073741824 (1G), +1099511627776 (1T), 1125899906842624 (1P) +or the number of bytes in an integer, respectively. +Two or more numbers may be separated by an +.Dq Li x +to indicate a product. +.Pp +When finished, +.Nm +displays the number of complete and partial input and output blocks, +truncated input records and odd-length byte-swapping blocks to the +standard error output. +A partial input block is one where less than the input block size +was read. +A partial output block is one where less than the output block size +was written. +Partial output blocks to tape devices are considered fatal errors. +Otherwise, the rest of the block will be written. +Partial output blocks to character devices will produce a warning message. +A truncated input block is one where a variable length record oriented +conversion value was specified and the input line was too long to +fit in the conversion record or was not newline terminated. +.Pp +Normally, data resulting from input or conversion or both are aggregated +into output blocks of the specified size. +After the end of input is reached, any remaining output is written as +a block. +This means that the final output block may be shorter than the output +block size. +.Pp +If +.Nm +receives a +.Dv SIGINFO +(see the +.Cm status +argument for +.Xr stty 1 ) +signal, the current input and output block counts will +be written to the standard error output +in the same format as the standard completion message. +If +.Nm +receives a +.Dv SIGINT +signal, the current input and output block counts will +be written to the standard error output +in the same format as the standard completion message and +.Nm +will exit. +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Check that a disk drive contains no bad blocks: +.Pp +.Dl "dd if=/dev/ada0 of=/dev/null bs=1m" +.Pp +Do a refresh of a disk drive, in order to prevent presently +recoverable read errors from progressing into unrecoverable read errors: +.Pp +.Dl "dd if=/dev/ada0 of=/dev/ada0 bs=1m" +.Pp +Remove parity bit from a file: +.Pp +.Dl "dd if=file conv=parnone of=file.txt" +.Pp +Check for (even) parity errors on a file: +.Pp +.Dl "dd if=file conv=pareven | cmp -x - file" +.Pp +To create an image of a Mode-1 CD-ROM, which is a commonly used format +for data CD-ROM disks, use a block size of 2048 bytes: +.Pp +.Dl "dd if=/dev/cd0 of=filename.iso bs=2048" +.Pp +Write a filesystem image to a memory stick, padding the end with zeros, +if necessary, to a 1MiB boundary: +.Pp +.Dl "dd if=memstick.img of=/dev/da0 bs=1m conv=noerror,sync" +.Sh SEE ALSO +.Xr cp 1 , +.Xr mt 1 , +.Xr recoverdisk 1 , +.Xr tr 1 , +.Xr geom 4 , +.Xr trim 8 +.Sh STANDARDS +The +.Nm +utility is expected to be a superset of the +.St -p1003.2 +standard. +The +.Cm files +and +.Cm status +operands and the +.Cm ascii , +.Cm ebcdic , +.Cm ibm , +.Cm oldascii , +.Cm oldebcdic +and +.Cm oldibm +values are extensions to the +.Tn POSIX +standard. +.Sh HISTORY +A +.Nm +command appeared in +.At v5 . +.Sh BUGS +Protection mechanisms in the +.Xr geom 4 +subsystem might prevent the super-user from writing blocks to a disk. +Instructions for temporarily disabling these protection mechanisms can be +found in the +.Xr geom 4 +man page. diff --git a/corebinutils/dd/dd.c b/corebinutils/dd/dd.c new file mode 100644 index 0000000000..5f733f1829 --- /dev/null +++ b/corebinutils/dd/dd.c @@ -0,0 +1,656 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mtio.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "dd.h" +#include "extern.h" + +static void *alloc_io_buffer(size_t); +static void dd_close(void); +static void dd_in(void); +static void getfdtype(IO *); +static void install_handler(int, void (*)(int)); +static void setup(void); +static int is_tape_device(int); + +IO in, out; /* input/output state */ +STAT st; /* statistics */ +void (*cfunc)(void); /* conversion function */ +uintmax_t cpy_cnt; /* # of blocks to copy */ +static off_t pending = 0; /* pending seek if sparse */ +uint64_t ddflags = 0; /* conversion options */ +size_t cbsz; /* conversion block size */ +uintmax_t files_cnt = 1; /* # of files to copy */ +const u_char *ctab; /* conversion table */ +char fill_char; /* Character to fill with if defined */ +size_t speed = 0; /* maximum speed, in bytes per second */ +volatile sig_atomic_t need_summary; +volatile sig_atomic_t need_progress; +volatile sig_atomic_t kill_signal; + +int +main(int argc __unused, char *argv[]) +{ + struct itimerval itv = { { 1, 0 }, { 1, 0 } }; /* SIGALARM every second, if needed */ + + prepare_io(); + + (void)setlocale(LC_CTYPE, ""); + jcl(argv); + setup(); + + install_handler(summary_signal_number(), siginfo_handler); + if (ddflags & C_PROGRESS) { + install_handler(SIGALRM, sigalarm_handler); + setitimer(ITIMER_REAL, &itv, NULL); + } + + atexit(summary); + + while (files_cnt--) + dd_in(); + + dd_close(); + /* + * Some devices such as cfi(4) may perform significant amounts + * of work when a write descriptor is closed. Close the out + * descriptor explicitly so that the summary handler (called + * from an atexit() hook) includes this work. + */ + if (close(out.fd) == -1 && errno != EINTR) + err(1, "close"); + exit(0); +} + +static void * +alloc_io_buffer(size_t size) +{ + size_t alignment; + void *buf; + int error; + + if ((ddflags & (C_IDIRECT | C_ODIRECT)) == 0) { + buf = malloc(size); + if (buf == NULL) + err(1, "malloc"); + return (buf); + } + + alignment = (size_t)sysconf(_SC_PAGESIZE); + if (alignment == 0 || alignment == (size_t)-1) + alignment = 4096; + error = posix_memalign(&buf, alignment, size); + if (error != 0) { + errno = error; + err(1, "posix_memalign"); + } + return (buf); +} + +static void +install_handler(int signo, void (*handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + if (sigemptyset(&sa.sa_mask) == -1) + err(1, "sigemptyset"); + if (sigaction(signo, &sa, NULL) == -1) + err(1, "sigaction"); +} + +static int +parity(u_char c) +{ + int i; + + i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ + (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); + return (i & 1); +} + +static void +setup(void) +{ + u_int cnt; + int iflags, oflags; + + if (in.name == NULL) { + in.name = "stdin"; + in.fd = STDIN_FILENO; + } else { + iflags = 0; + if (ddflags & C_IDIRECT) + iflags |= O_DIRECT; + before_io(); + in.fd = open(in.name, O_RDONLY | iflags, 0); + after_io(); + if (in.fd == -1) + err(1, "%s", in.name); + } + + getfdtype(&in); + + if (files_cnt > 1 && !(in.flags & ISTAPE)) + errx(1, "files is not supported for non-tape devices"); + + if (out.name == NULL) { + out.fd = STDOUT_FILENO; + out.name = "stdout"; + } else { + oflags = O_CREAT; + if (!(ddflags & (C_SEEK | C_NOTRUNC))) + oflags |= O_TRUNC; + if (ddflags & C_OFSYNC) + oflags |= O_SYNC; + if (ddflags & C_ODIRECT) + oflags |= O_DIRECT; + before_io(); + out.fd = open(out.name, O_RDWR | oflags, DEFFILEMODE); + after_io(); + /* + * May not have read access, so try again with write only. + * Without read we may have a problem if output also does + * not support seeks. + */ + if (out.fd == -1) { + before_io(); + out.fd = open(out.name, O_WRONLY | oflags, DEFFILEMODE); + after_io(); + out.flags |= NOREAD; + } + if (out.fd == -1) + err(1, "%s", out.name); + } + + getfdtype(&out); + + /* + * Allocate space for the input and output buffers. If not doing + * record oriented I/O, only need a single buffer. + */ + if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { + in.db = alloc_io_buffer((size_t)out.dbsz + in.dbsz - 1); + out.db = in.db; + } else { + in.db = alloc_io_buffer(MAX((size_t)in.dbsz, cbsz) + cbsz); + out.db = alloc_io_buffer(out.dbsz + cbsz); + } + + /* dbp is the first free position in each buffer. */ + in.dbp = in.db; + out.dbp = out.db; + + /* Position the input/output streams. */ + if (in.offset) + pos_in(); + if (out.offset) + pos_out(); + + /* + * Truncate the output file. If it fails on a type of output file + * that it should _not_ fail on, error out. + */ + if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && + out.flags & ISTRUNC) + if (ftruncate(out.fd, out.offset * out.dbsz) == -1) + err(1, "truncating %s", out.name); + + if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { + if (ctab != NULL) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = ctab[cnt]; + } else { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = cnt; + } + if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { + /* + * If the input is not EBCDIC, and we do parity + * processing, strip input parity. + */ + for (cnt = 200; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt & 0x7f]; + } + if (ddflags & C_LCASE) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = tolower(casetab[cnt]); + } else if (ddflags & C_UCASE) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = toupper(casetab[cnt]); + } + if ((ddflags & C_PARITY)) { + /* + * This should strictly speaking be a no-op, but I + * wonder what funny LANG settings could get us. + */ + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt] & 0x7f; + } + if ((ddflags & C_PARSET)) { + for (cnt = 0; cnt <= 0377; ++cnt) + casetab[cnt] = casetab[cnt] | 0x80; + } + if ((ddflags & C_PAREVEN)) { + for (cnt = 0; cnt <= 0377; ++cnt) + if (parity(casetab[cnt])) + casetab[cnt] = casetab[cnt] | 0x80; + } + if ((ddflags & C_PARODD)) { + for (cnt = 0; cnt <= 0377; ++cnt) + if (!parity(casetab[cnt])) + casetab[cnt] = casetab[cnt] | 0x80; + } + + ctab = casetab; + } + + if (clock_gettime(CLOCK_MONOTONIC, &st.start)) + err(1, "clock_gettime"); +} + +static int +is_tape_device(int fd) +{ + struct mtget status; + + return (ioctl(fd, MTIOCGET, &status) == 0); +} + +static void +getfdtype(IO *io) +{ + struct stat sb; + off_t cur; + + if (fstat(io->fd, &sb) == -1) + err(1, "%s", io->name); + if (S_ISREG(sb.st_mode)) + io->flags |= ISTRUNC | ISSEEK; + if (S_ISBLK(sb.st_mode)) + io->flags |= ISSEEK; + if (S_ISCHR(sb.st_mode)) { + io->flags |= ISCHR; + if (is_tape_device(io->fd)) { + io->flags |= ISTAPE; + return; + } + } + errno = 0; + cur = lseek(io->fd, (off_t)0, SEEK_CUR); + if (cur == -1 && errno == ESPIPE) + io->flags |= ISPIPE; + else if (cur != -1) + io->flags |= ISSEEK; +} + +/* + * Limit the speed by adding a delay before every block read. + * The delay (t_usleep) is equal to the time computed from block + * size and the specified speed limit (t_target) minus the time + * spent on actual read and write operations (t_io). + */ +static void +speed_limit(void) +{ + static double t_prev, t_usleep; + double t_now, t_io, t_target; + + t_now = secs_elapsed(); + t_io = t_now - t_prev - t_usleep; + t_target = (double)in.dbsz / (double)speed; + t_usleep = t_target - t_io; + if (t_usleep > 0) + usleep(t_usleep * 1000000); + else + t_usleep = 0; + t_prev = t_now; +} + +static void +swapbytes(void *v, size_t len) +{ + unsigned char *p = v; + unsigned char t; + + while (len > 1) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + len -= 2; + } +} + +static void +dd_in(void) +{ + ssize_t n; + + for (;;) { + switch (cpy_cnt) { + case -1: /* count=0 was specified */ + return; + case 0: + break; + default: + if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) + return; + break; + } + + if (speed > 0) + speed_limit(); + + /* + * Zero the buffer first if sync; if doing block operations, + * use spaces. + */ + if (ddflags & C_SYNC) { + if (ddflags & C_FILL) + memset(in.dbp, fill_char, in.dbsz); + else if (ddflags & (C_BLOCK | C_UNBLOCK)) + memset(in.dbp, ' ', in.dbsz); + else + memset(in.dbp, 0, in.dbsz); + } + + in.dbrcnt = 0; +fill: + before_io(); + n = read(in.fd, in.dbp + in.dbrcnt, in.dbsz - in.dbrcnt); + after_io(); + + /* EOF */ + if (n == 0 && in.dbrcnt == 0) + return; + + /* Read error */ + if (n == -1) { + if (errno == EINTR) { + service_pending_signals(); + goto fill; + } + /* + * If noerror not specified, die. POSIX requires that + * the warning message be followed by an I/O display. + */ + if (!(ddflags & C_NOERROR)) + err(1, "%s", in.name); + warn("%s", in.name); + summary(); + + /* + * If it's a seekable file descriptor, seek past the + * error. If your OS doesn't do the right thing for + * raw disks this section should be modified to re-read + * in sector size chunks. + */ + if (in.flags & ISSEEK && + lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) + warn("%s", in.name); + + /* If sync not specified, omit block and continue. */ + if (!(ddflags & C_SYNC)) + continue; + } + + /* If conv=sync, use the entire block. */ + if (ddflags & C_SYNC) + n = in.dbsz; + + /* Count the bytes read for this block. */ + in.dbrcnt += n; + + /* Count the number of full and partial blocks. */ + if (in.dbrcnt == in.dbsz) + ++st.in_full; + else if (ddflags & C_IFULLBLOCK && n != 0) + goto fill; /* these don't count */ + else + ++st.in_part; + + /* Count the total bytes read for this file. */ + in.dbcnt += in.dbrcnt; + + /* + * POSIX states that if bs is set and no other conversions + * than noerror, notrunc or sync are specified, the block + * is output without buffering as it is read. + */ + if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) { + out.dbcnt = in.dbcnt; + dd_out(1); + in.dbcnt = 0; + continue; + } + + if (ddflags & C_SWAB) { + if ((n = in.dbrcnt) & 1) { + ++st.swab; + --n; + } + swapbytes(in.dbp, (size_t)n); + } + + /* Advance to the next block. */ + in.dbp += in.dbrcnt; + (*cfunc)(); + if (need_summary) + summary(); + if (need_progress) + progress(); + } +} + +/* + * Clean up any remaining I/O and flush output. If necessary, the output file + * is truncated. + */ +static void +dd_close(void) +{ + if (cfunc == def) + def_close(); + else if (cfunc == block) + block_close(); + else if (cfunc == unblock) + unblock_close(); + if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { + if (ddflags & C_FILL) + memset(out.dbp, fill_char, out.dbsz - out.dbcnt); + else if (ddflags & (C_BLOCK | C_UNBLOCK)) + memset(out.dbp, ' ', out.dbsz - out.dbcnt); + else + memset(out.dbp, 0, out.dbsz - out.dbcnt); + out.dbcnt = out.dbsz; + } + if (out.dbcnt || pending) + dd_out(1); + + /* + * If the file ends with a hole, ftruncate it to extend its size + * up to the end of the hole (without having to write any data). + */ + if (out.seek_offset > 0 && (out.flags & ISTRUNC)) { + if (ftruncate(out.fd, out.seek_offset) == -1) + err(1, "truncating %s", out.name); + } + + if (ddflags & C_FSYNC) { + if (fsync(out.fd) == -1) + err(1, "fsyncing %s", out.name); + } else if (ddflags & C_FDATASYNC) { + if (fdatasync(out.fd) == -1) + err(1, "fdatasyncing %s", out.name); + } +} + +void +dd_out(int force) +{ + u_char *outp; + size_t cnt, n; + ssize_t nw; + static int warned; + int sparse; + + /* + * Write one or more blocks out. The common case is writing a full + * output block in a single write; increment the full block stats. + * Otherwise, we're into partial block writes. If a partial write, + * and it's a character device, just warn. If a tape device, quit. + * + * The partial writes represent two cases. 1: Where the input block + * was less than expected so the output block was less than expected. + * 2: Where the input block was the right size but we were forced to + * write the block in multiple chunks. The original versions of dd(1) + * never wrote a block in more than a single write, so the latter case + * never happened. + * + * One special case is if we're forced to do the write -- in that case + * we play games with the buffer size, and it's usually a partial write. + */ + outp = out.db; + + /* + * If force, first try to write all pending data, else try to write + * just one block. Subsequently always write data one full block at + * a time at most. + */ + for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { + cnt = n; + do { + sparse = 0; + if (ddflags & C_SPARSE) { + /* Is buffer sparse? */ + sparse = BISZERO(outp, cnt); + } + if (sparse && !force) { + pending += cnt; + nw = cnt; + } else { + if (pending != 0) { + /* + * Seek past hole. Note that we need to record the + * reached offset, because we might have no more data + * to write, in which case we'll need to call + * ftruncate to extend the file size. + */ + out.seek_offset = lseek(out.fd, pending, SEEK_CUR); + if (out.seek_offset == -1) + err(2, "%s: seek error creating sparse file", + out.name); + pending = 0; + } + if (cnt) { + before_io(); + nw = write(out.fd, outp, cnt); + after_io(); + out.seek_offset = 0; + } else { + return; + } + } + + if (nw <= 0) { + if (nw == 0) + errx(1, "%s: end of device", out.name); + if (errno == EINTR) { + service_pending_signals(); + nw = 0; + continue; + } + if (errno != EINTR) + err(1, "%s", out.name); + nw = 0; + } + if ((ddflags & C_OFSYNC) != 0 && nw > 0) { + if (fsync(out.fd) == -1) + err(1, "fsyncing %s", out.name); + } + + outp += nw; + st.bytes += nw; + + if ((size_t)nw == n && n == (size_t)out.dbsz) + ++st.out_full; + else + ++st.out_part; + + if ((size_t) nw != cnt) { + if (out.flags & ISTAPE) + errx(1, "%s: short write on tape device", + out.name); + if (out.flags & ISCHR && !warned) { + warned = 1; + warnx("%s: short write on character device", + out.name); + } + } + + cnt -= nw; + } while (cnt != 0); + + if ((out.dbcnt -= n) < out.dbsz) + break; + } + + /* Reassemble the output block. */ + if (out.dbcnt) + (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); + out.dbp = out.db + out.dbcnt; +} diff --git a/corebinutils/dd/dd.h b/corebinutils/dd/dd.h new file mode 100644 index 0000000000..cc63e9fa73 --- /dev/null +++ b/corebinutils/dd/dd.h @@ -0,0 +1,158 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Linux/musl build glue for the standalone port. + * Keep the main dd data path close to FreeBSD, but avoid relying on + * FreeBSD-only typedefs and helper macros. + */ + +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <sys/types.h> +#include <time.h> + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + +#ifndef __dead2 +#define __dead2 __attribute__((__noreturn__)) +#endif + +#ifndef nitems +#define nitems(array) (sizeof(array) / sizeof((array)[0])) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef OFF_MAX +#define OFF_MAX ((off_t)INT64_MAX) +#endif + +#ifndef DEFFILEMODE +#define DEFFILEMODE 0666 +#endif + +typedef unsigned char u_char; +typedef unsigned int u_int; + +/* Input/output stream state. */ +typedef struct { + u_char *db; /* buffer address */ + u_char *dbp; /* current buffer I/O address */ + ssize_t dbcnt; /* current buffer byte count */ + ssize_t dbrcnt; /* last read byte count */ + ssize_t dbsz; /* block size */ + +#define ISCHR 0x01 /* character device (warn on short) */ +#define ISPIPE 0x02 /* pipe-like (see position.c) */ +#define ISTAPE 0x04 /* tape */ +#define ISSEEK 0x08 /* valid to seek on */ +#define NOREAD 0x10 /* not readable */ +#define ISTRUNC 0x20 /* valid to ftruncate() */ + u_int flags; + + const char *name; /* name */ + int fd; /* file descriptor */ + off_t offset; /* # of blocks to skip */ + off_t seek_offset; /* offset of last seek past output hole */ +} IO; + +typedef struct { + uintmax_t in_full; /* # of full input blocks */ + uintmax_t in_part; /* # of partial input blocks */ + uintmax_t out_full; /* # of full output blocks */ + uintmax_t out_part; /* # of partial output blocks */ + uintmax_t trunc; /* # of truncated records */ + uintmax_t swab; /* # of odd-length swab blocks */ + uintmax_t bytes; /* # of bytes written */ + struct timespec start; /* start time of dd */ +} STAT; + +/* Flags (in ddflags). */ +#define C_ASCII 0x0000000000000001ULL +#define C_BLOCK 0x0000000000000002ULL +#define C_BS 0x0000000000000004ULL +#define C_CBS 0x0000000000000008ULL +#define C_COUNT 0x0000000000000010ULL +#define C_EBCDIC 0x0000000000000020ULL +#define C_FILES 0x0000000000000040ULL +#define C_IBS 0x0000000000000080ULL +#define C_IF 0x0000000000000100ULL +#define C_LCASE 0x0000000000000200ULL +#define C_NOERROR 0x0000000000000400ULL +#define C_NOTRUNC 0x0000000000000800ULL +#define C_OBS 0x0000000000001000ULL +#define C_OF 0x0000000000002000ULL +#define C_OSYNC 0x0000000000004000ULL +#define C_PAREVEN 0x0000000000008000ULL +#define C_PARNONE 0x0000000000010000ULL +#define C_PARODD 0x0000000000020000ULL +#define C_PARSET 0x0000000000040000ULL +#define C_SEEK 0x0000000000080000ULL +#define C_SKIP 0x0000000000100000ULL +#define C_SPARSE 0x0000000000200000ULL +#define C_SWAB 0x0000000000400000ULL +#define C_SYNC 0x0000000000800000ULL +#define C_UCASE 0x0000000001000000ULL +#define C_UNBLOCK 0x0000000002000000ULL +#define C_FILL 0x0000000004000000ULL +#define C_STATUS 0x0000000008000000ULL +#define C_NOXFER 0x0000000010000000ULL +#define C_NOINFO 0x0000000020000000ULL +#define C_PROGRESS 0x0000000040000000ULL +#define C_FSYNC 0x0000000080000000ULL +#define C_FDATASYNC 0x0000000100000000ULL +#define C_OFSYNC 0x0000000200000000ULL +#define C_IFULLBLOCK 0x0000000400000000ULL +#define C_IDIRECT 0x0000000800000000ULL +#define C_ODIRECT 0x0000001000000000ULL + +#define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET) + +#define BISZERO(p, s) ((s) > 0 && *((const char *)p) == 0 && !memcmp( \ + (const void *)(p), (const void *) \ + ((const char *)p + 1), (s) - 1)) diff --git a/corebinutils/dd/extern.h b/corebinutils/dd/extern.h new file mode 100644 index 0000000000..0a91146194 --- /dev/null +++ b/corebinutils/dd/extern.h @@ -0,0 +1,77 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void block(void); +void block_close(void); +void dd_out(int); +void def(void); +void def_close(void); +void jcl(char **); +void pos_in(void); +void pos_out(void); +double secs_elapsed(void); +void progress(void); +void summary(void); +void sigalarm_handler(int); +void siginfo_handler(int); +void prepare_io(void); +void before_io(void); +void after_io(void); +void service_pending_signals(void); +int summary_signal_number(void); +const char *summary_signal_name(void); +void unblock(void); +void unblock_close(void); + +extern IO in, out; +extern STAT st; +extern void (*cfunc)(void); +extern uintmax_t cpy_cnt; +extern size_t cbsz; +extern uint64_t ddflags; +extern size_t speed; +extern uintmax_t files_cnt; +extern const u_char *ctab; +extern const u_char a2e_32V[], a2e_POSIX[]; +extern const u_char e2a_32V[], e2a_POSIX[]; +extern const u_char a2ibm_32V[], a2ibm_POSIX[]; +extern u_char casetab[]; +extern char fill_char; +extern volatile sig_atomic_t need_summary; +extern volatile sig_atomic_t need_progress; +extern volatile sig_atomic_t kill_signal; diff --git a/corebinutils/dd/gen.c b/corebinutils/dd/gen.c new file mode 100644 index 0000000000..01e0f61b27 --- /dev/null +++ b/corebinutils/dd/gen.c @@ -0,0 +1,22 @@ +/*- + * This program is in the public domain + */ + +#include <stdio.h> +#include <string.h> + +int +main(int argc, char **argv) +{ + int i; + + if (argc > 1 && !strcmp(argv[1], "189284")) { + fputs("ABCDEFGH", stdout); + for (i = 0; i < 8; i++) + putchar(0); + } else { + for (i = 0; i < 256; i++) + putchar(i); + } + return (0); +} diff --git a/corebinutils/dd/misc.c b/corebinutils/dd/misc.c new file mode 100644 index 0000000000..000c37c18e --- /dev/null +++ b/corebinutils/dd/misc.c @@ -0,0 +1,255 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <signal.h> +#include <stdatomic.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "dd.h" +#include "extern.h" + +static void format_scaled(char *, size_t, double, unsigned int, + const char *const *); + +static void +format_scaled(char *buf, size_t bufsz, double value, unsigned int base, + const char *const *units) +{ + size_t unit; + double scaled; + + scaled = value; + unit = 0; + while (scaled >= base && units[unit + 1] != NULL) { + scaled /= base; + unit++; + } + if (unit == 0) + (void)snprintf(buf, bufsz, "%.0f %s", scaled, units[unit]); + else if (scaled >= 10.0) + (void)snprintf(buf, bufsz, "%.0f %s", scaled, units[unit]); + else + (void)snprintf(buf, bufsz, "%.1f %s", scaled, units[unit]); +} + +double +secs_elapsed(void) +{ + struct timespec end, ts_res; + double secs, res; + + if (clock_gettime(CLOCK_MONOTONIC, &end)) + err(1, "clock_gettime"); + if (clock_getres(CLOCK_MONOTONIC, &ts_res)) + err(1, "clock_getres"); + secs = (end.tv_sec - st.start.tv_sec) + \ + (end.tv_nsec - st.start.tv_nsec) * 1e-9; + res = ts_res.tv_sec + ts_res.tv_nsec * 1e-9; + if (secs < res) + secs = res; + + return (secs); +} + +int +summary_signal_number(void) +{ +#ifdef SIGINFO + return (SIGINFO); +#else + return (SIGUSR1); +#endif +} + +const char * +summary_signal_name(void) +{ +#ifdef SIGINFO + return ("SIGINFO"); +#else + return ("SIGUSR1"); +#endif +} + +void +summary(void) +{ + double secs; + + if (ddflags & C_NOINFO) + return; + + if (ddflags & C_PROGRESS) + fprintf(stderr, "\n"); + + secs = secs_elapsed(); + + (void)fprintf(stderr, + "%ju+%ju records in\n%ju+%ju records out\n", + st.in_full, st.in_part, st.out_full, st.out_part); + if (st.swab) + (void)fprintf(stderr, "%ju odd length swab %s\n", + st.swab, (st.swab == 1) ? "block" : "blocks"); + if (st.trunc) + (void)fprintf(stderr, "%ju truncated %s\n", + st.trunc, (st.trunc == 1) ? "block" : "blocks"); + if (!(ddflags & C_NOXFER)) { + (void)fprintf(stderr, + "%ju bytes transferred in %.6f secs (%.0f bytes/sec)\n", + st.bytes, secs, st.bytes / secs); + } + need_summary = 0; +} + +void +progress(void) +{ + static int outlen; + static const char *const si_units[] = { + "B", "kB", "MB", "GB", "TB", "PB", "EB", NULL + }; + static const char *const iec_units[] = { + "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", NULL + }; + char buf[160]; + char iec[16]; + double secs; + char persec[16]; + char si[16]; + + secs = secs_elapsed(); + format_scaled(si, sizeof(si), (double)st.bytes, 1000, si_units); + format_scaled(iec, sizeof(iec), (double)st.bytes, 1024, iec_units); + format_scaled(persec, sizeof(persec), st.bytes / secs, 1000, si_units); + (void)snprintf(buf, sizeof(buf), + " %ju bytes (%s, %s) transferred %.3fs, %s/s", + (uintmax_t)st.bytes, si, iec, secs, persec); + outlen = fprintf(stderr, "%-*s\r", outlen, buf) - 1; + fflush(stderr); + need_progress = 0; +} + +/* ARGSUSED */ +void +siginfo_handler(int signo __unused) +{ + + need_summary = 1; +} + +/* ARGSUSED */ +void +sigalarm_handler(int signo __unused) +{ + + need_progress = 1; +} + +void +service_pending_signals(void) +{ + if (need_summary) + summary(); + if (need_progress) + progress(); +} + +static void terminate(int signo) __dead2; +static void +terminate(int signo) +{ + kill_signal = signo; + summary(); + (void)fflush(stderr); + raise(kill_signal); + /* NOT REACHED */ + _exit(1); +} + +static sig_atomic_t in_io = 0; +static sig_atomic_t sigint_seen = 0; + +static void +sigint_handler(int signo __unused) +{ + atomic_signal_fence(memory_order_acquire); + if (in_io) + terminate(SIGINT); + sigint_seen = 1; +} + +void +prepare_io(void) +{ + struct sigaction sa; + int error; + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NODEFER | SA_RESETHAND; + sa.sa_handler = sigint_handler; + error = sigaction(SIGINT, &sa, 0); + if (error != 0) + err(1, "sigaction"); +} + +void +before_io(void) +{ + in_io = 1; + atomic_signal_fence(memory_order_seq_cst); + if (sigint_seen) + terminate(SIGINT); +} + +void +after_io(void) +{ + in_io = 0; + atomic_signal_fence(memory_order_seq_cst); + if (sigint_seen) + terminate(SIGINT); +} diff --git a/corebinutils/dd/position.c b/corebinutils/dd/position.c new file mode 100644 index 0000000000..4de72c0c96 --- /dev/null +++ b/corebinutils/dd/position.c @@ -0,0 +1,234 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2026 + * Project Tick. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/mtio.h> + +#include <err.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <signal.h> +#include <unistd.h> + +#include "dd.h" +#include "extern.h" + +static off_t +seek_offset(IO *io) +{ + off_t n; + size_t sz; + + n = io->offset; + sz = io->dbsz; + + _Static_assert(sizeof(io->offset) == sizeof(int64_t), "64-bit off_t"); + + /* + * If the lseek offset will be negative, verify that this is a special + * device file. Some such files (e.g. /dev/kmem) permit "negative" + * offsets. + * + * Bail out if the calculation of a file offset would overflow. + */ + if ((io->flags & ISCHR) == 0 && (n < 0 || n > OFF_MAX / (ssize_t)sz)) + errx(1, "seek offsets cannot be larger than %jd", + (intmax_t)OFF_MAX); + else if ((io->flags & ISCHR) != 0 && (uint64_t)n > UINT64_MAX / sz) + errx(1, "seek offsets cannot be larger than %ju", + (uintmax_t)UINT64_MAX); + + return ((off_t)( (uint64_t)n * sz )); +} + +/* + * Position input/output data streams before starting the copy. Device type + * dependent. Seekable devices use lseek, and the rest position by reading. + * Seeking past the end of file can cause null blocks to be written to the + * output. + */ +void +pos_in(void) +{ + off_t cnt; + int warned; + ssize_t nr; + size_t bcnt; + + /* If known to be seekable, try to seek on it. */ + if (in.flags & ISSEEK) { + errno = 0; + if (lseek(in.fd, seek_offset(&in), SEEK_CUR) == -1 && + errno != 0) + err(1, "%s", in.name); + return; + } + + /* Don't try to read a really weird amount (like negative). */ + if (in.offset < 0) + errx(1, "%s: illegal offset", "iseek/skip"); + + /* + * Read the data. If a pipe, read until satisfy the number of bytes + * being skipped. No differentiation for reading complete and partial + * blocks for other devices. + */ + for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) { + if ((nr = read(in.fd, in.db, bcnt)) > 0) { + if (in.flags & ISPIPE) { + if (!(bcnt -= nr)) { + bcnt = in.dbsz; + --cnt; + } + } else + --cnt; + if (need_summary) + summary(); + if (need_progress) + progress(); + continue; + } + if (nr == -1 && errno == EINTR) { + service_pending_signals(); + continue; + } + + if (nr == 0) { + if (files_cnt > 1) { + --files_cnt; + continue; + } + errx(1, "skip reached end of input"); + } + + /* + * Input error -- either EOF with no more files, or I/O error. + * If noerror not set die. POSIX requires that the warning + * message be followed by an I/O display. + */ + if (ddflags & C_NOERROR) { + if (!warned) { + warn("%s", in.name); + warned = 1; + summary(); + } + continue; + } + err(1, "%s", in.name); + } +} + +void +pos_out(void) +{ + struct mtop t_op; + off_t cnt; + ssize_t n; + + /* + * If not a tape, try seeking on the file. Seeking on a pipe is + * going to fail, but don't protect the user -- they shouldn't + * have specified the seek operand. + */ + if (out.flags & (ISSEEK | ISPIPE)) { + errno = 0; + if (lseek(out.fd, seek_offset(&out), SEEK_CUR) == -1 && + errno != 0) + err(1, "%s", out.name); + return; + } + if ((out.flags & ISTAPE) == 0) + errx(1, "%s: seek not supported on this output type", out.name); + + /* Don't try to read a really weird amount (like negative). */ + if (out.offset < 0) + errx(1, "%s: illegal offset", "oseek/seek"); + + /* If no read access, try using mtio. */ + if (out.flags & NOREAD) { + t_op.mt_op = MTFSR; + t_op.mt_count = out.offset; + + if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) + err(1, "%s", out.name); + return; + } + + /* Read it. */ + for (cnt = 0; cnt < out.offset; ++cnt) { + before_io(); + n = read(out.fd, out.db, out.dbsz); + after_io(); + if (n == -1 && errno == EINTR) { + service_pending_signals(); + --cnt; + continue; + } + if (n > 0) + continue; + if (n == -1) + err(1, "%s", out.name); + + /* + * If reach EOF, fill with NUL characters; first, back up over + * the EOF mark. Note, cnt has not yet been incremented, so + * the EOF read does not count as a seek'd block. + */ + t_op.mt_op = MTBSR; + t_op.mt_count = 1; + if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) + err(1, "%s", out.name); + + while (cnt++ < out.offset) { + before_io(); + n = write(out.fd, out.db, out.dbsz); + after_io(); + if (n == -1 && errno == EINTR) { + service_pending_signals(); + --cnt; + continue; + } + if (n == -1) + err(1, "%s", out.name); + if (n != out.dbsz) + errx(1, "%s: write failure", out.name); + } + break; + } +} diff --git a/corebinutils/dd/ref.ascii b/corebinutils/dd/ref.ascii new file mode 100644 index 0000000000..a8299b6cb0 --- /dev/null +++ b/corebinutils/dd/ref.ascii @@ -0,0 +1,17 @@ +00000000 00 01 02 03 9c 09 86 7f 97 8d 8e 0b 0c 0d 0e 0f |................| +00000010 10 11 12 13 9d 85 08 87 18 19 92 8f 1c 1d 1e 1f |................| +00000020 80 81 82 83 84 0a 17 1b 88 89 8a 8b 8c 05 06 07 |................| +00000030 90 91 16 93 94 95 96 04 98 99 9a 9b 14 15 9e 1a |................| +00000040 20 a0 a1 a2 a3 a4 a5 a6 a7 a8 d5 2e 3c 28 2b 7c | ...........<(+|| +00000050 26 a9 aa ab ac ad ae af b0 b1 21 24 2a 29 3b 7e |&.........!$*);~| +00000060 2d 2f b2 b3 b4 b5 b6 b7 b8 b9 cb 2c 25 5f 3e 3f |-/.........,%_>?| +00000070 ba bb bc bd be bf c0 c1 c2 60 3a 23 40 27 3d 22 |.........`:#@'="| +00000080 c3 61 62 63 64 65 66 67 68 69 c4 c5 c6 c7 c8 c9 |.abcdefghi......| +00000090 ca 6a 6b 6c 6d 6e 6f 70 71 72 5e cc cd ce cf d0 |.jklmnopqr^.....| +000000a0 d1 e5 73 74 75 76 77 78 79 7a d2 d3 d4 5b d6 d7 |..stuvwxyz...[..| +000000b0 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 5d e6 e7 |.............]..| +000000c0 7b 41 42 43 44 45 46 47 48 49 e8 e9 ea eb ec ed |{ABCDEFGHI......| +000000d0 7d 4a 4b 4c 4d 4e 4f 50 51 52 ee ef f0 f1 f2 f3 |}JKLMNOPQR......| +000000e0 5c 9f 53 54 55 56 57 58 59 5a f4 f5 f6 f7 f8 f9 |\.STUVWXYZ......| +000000f0 30 31 32 33 34 35 36 37 38 39 fa fb fc fd fe ff |0123456789......| +00000100 diff --git a/corebinutils/dd/ref.ebcdic b/corebinutils/dd/ref.ebcdic new file mode 100644 index 0000000000..b2428c8517 --- /dev/null +++ b/corebinutils/dd/ref.ebcdic @@ -0,0 +1,17 @@ +00000000 00 01 02 03 37 2d 2e 2f 16 05 25 0b 0c 0d 0e 0f |....7-./..%.....| +00000010 10 11 12 13 3c 3d 32 26 18 19 3f 27 1c 1d 1e 1f |....<=2&..?'....| +00000020 40 5a 7f 7b 5b 6c 50 7d 4d 5d 5c 4e 6b 60 4b 61 |@Z.{[lP}M]\Nk`Ka| +00000030 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 7a 5e 4c 7e 6e 6f |..........z^L~no| +00000040 7c c1 c2 c3 c4 c5 c6 c7 c8 c9 d1 d2 d3 d4 d5 d6 ||...............| +00000050 d7 d8 d9 e2 e3 e4 e5 e6 e7 e8 e9 ad e0 bd 9a 6d |...............m| +00000060 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 |y...............| +00000070 97 98 99 a2 a3 a4 a5 a6 a7 a8 a9 c0 4f d0 5f 07 |............O._.| +00000080 20 21 22 23 24 15 06 17 28 29 2a 2b 2c 09 0a 1b | !"#$...()*+,...| +00000090 30 31 1a 33 34 35 36 08 38 39 3a 3b 04 14 3e e1 |01.3456.89:;..>.| +000000a0 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 |ABCDEFGHIQRSTUVW| +000000b0 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |XYbcdefghipqrstu| +000000c0 76 77 78 80 8a 8b 8c 8d 8e 8f 90 6a 9b 9c 9d 9e |vwx........j....| +000000d0 9f a0 aa ab ac 4a ae af b0 b1 b2 b3 b4 b5 b6 b7 |.....J..........| +000000e0 b8 b9 ba bb bc a1 be bf ca cb cc cd ce cf da db |................| +000000f0 dc dd de df ea eb ec ed ee ef fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.ibm b/corebinutils/dd/ref.ibm new file mode 100644 index 0000000000..3d05cf9a9e --- /dev/null +++ b/corebinutils/dd/ref.ibm @@ -0,0 +1,17 @@ +00000000 00 01 02 03 37 2d 2e 2f 16 05 25 0b 0c 0d 0e 0f |....7-./..%.....| +00000010 10 11 12 13 3c 3d 32 26 18 19 3f 27 1c 1d 1e 1f |....<=2&..?'....| +00000020 40 5a 7f 7b 5b 6c 50 7d 4d 5d 5c 4e 6b 60 4b 61 |@Z.{[lP}M]\Nk`Ka| +00000030 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 7a 5e 4c 7e 6e 6f |..........z^L~no| +00000040 7c c1 c2 c3 c4 c5 c6 c7 c8 c9 d1 d2 d3 d4 d5 d6 ||...............| +00000050 d7 d8 d9 e2 e3 e4 e5 e6 e7 e8 e9 ad e0 bd 5f 6d |.............._m| +00000060 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 |y...............| +00000070 97 98 99 a2 a3 a4 a5 a6 a7 a8 a9 c0 4f d0 a1 07 |............O...| +00000080 20 21 22 23 24 15 06 17 28 29 2a 2b 2c 09 0a 1b | !"#$...()*+,...| +00000090 30 31 1a 33 34 35 36 08 38 39 3a 3b 04 14 3e e1 |01.3456.89:;..>.| +000000a0 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 |ABCDEFGHIQRSTUVW| +000000b0 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |XYbcdefghipqrstu| +000000c0 76 77 78 80 8a 8b 8c 8d 8e 8f 90 9a 9b 9c 9d 9e |vwx.............| +000000d0 9f a0 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 |................| +000000e0 b8 b9 ba bb bc bd be bf ca cb cc cd ce cf da db |................| +000000f0 dc dd de df ea eb ec ed ee ef fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.lcase b/corebinutils/dd/ref.lcase new file mode 100644 index 0000000000..a653527f8c --- /dev/null +++ b/corebinutils/dd/ref.lcase @@ -0,0 +1,17 @@ +00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| +00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................| +00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./| +00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?| +00000040 40 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |@abcdefghijklmno| +00000050 70 71 72 73 74 75 76 77 78 79 7a 5b 5c 5d 5e 5f |pqrstuvwxyz[\]^_| +00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno| +00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.| +00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| +00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................| +000000a0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |................| +000000b0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |................| +000000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |................| +000000d0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |................| +000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................| +000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.obs_zeroes b/corebinutils/dd/ref.obs_zeroes new file mode 100644 index 0000000000..e26380a1e7 --- /dev/null +++ b/corebinutils/dd/ref.obs_zeroes @@ -0,0 +1,2 @@ +00000000 41 42 43 44 45 46 47 48 00 00 00 00 00 00 00 00 |ABCDEFGH........| +00000010 diff --git a/corebinutils/dd/ref.oldascii b/corebinutils/dd/ref.oldascii new file mode 100644 index 0000000000..a748a9d636 --- /dev/null +++ b/corebinutils/dd/ref.oldascii @@ -0,0 +1,17 @@ +00000000 00 01 02 03 9c 09 86 7f 97 8d 8e 0b 0c 0d 0e 0f |................| +00000010 10 11 12 13 9d 85 08 87 18 19 92 8f 1c 1d 1e 1f |................| +00000020 80 81 82 83 84 0a 17 1b 88 89 8a 8b 8c 05 06 07 |................| +00000030 90 91 16 93 94 95 96 04 98 99 9a 9b 14 15 9e 1a |................| +00000040 20 a0 a1 a2 a3 a4 a5 a6 a7 a8 5b 2e 3c 28 2b 21 | .........[.<(+!| +00000050 26 a9 aa ab ac ad ae af b0 b1 5d 24 2a 29 3b 5e |&.........]$*);^| +00000060 2d 2f b2 b3 b4 b5 b6 b7 b8 b9 7c 2c 25 5f 3e 3f |-/........|,%_>?| +00000070 ba bb bc bd be bf c0 c1 c2 60 3a 23 40 27 3d 22 |.........`:#@'="| +00000080 c3 61 62 63 64 65 66 67 68 69 c4 c5 c6 c7 c8 c9 |.abcdefghi......| +00000090 ca 6a 6b 6c 6d 6e 6f 70 71 72 cb cc cd ce cf d0 |.jklmnopqr......| +000000a0 d1 7e 73 74 75 76 77 78 79 7a d2 d3 d4 d5 d6 d7 |.~stuvwxyz......| +000000b0 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 |................| +000000c0 7b 41 42 43 44 45 46 47 48 49 e8 e9 ea eb ec ed |{ABCDEFGHI......| +000000d0 7d 4a 4b 4c 4d 4e 4f 50 51 52 ee ef f0 f1 f2 f3 |}JKLMNOPQR......| +000000e0 5c 9f 53 54 55 56 57 58 59 5a f4 f5 f6 f7 f8 f9 |\.STUVWXYZ......| +000000f0 30 31 32 33 34 35 36 37 38 39 fa fb fc fd fe ff |0123456789......| +00000100 diff --git a/corebinutils/dd/ref.oldebcdic b/corebinutils/dd/ref.oldebcdic new file mode 100644 index 0000000000..122f463b5c --- /dev/null +++ b/corebinutils/dd/ref.oldebcdic @@ -0,0 +1,17 @@ +00000000 00 01 02 03 37 2d 2e 2f 16 05 25 0b 0c 0d 0e 0f |....7-./..%.....| +00000010 10 11 12 13 3c 3d 32 26 18 19 3f 27 1c 1d 1e 1f |....<=2&..?'....| +00000020 40 4f 7f 7b 5b 6c 50 7d 4d 5d 5c 4e 6b 60 4b 61 |@O.{[lP}M]\Nk`Ka| +00000030 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 7a 5e 4c 7e 6e 6f |..........z^L~no| +00000040 7c c1 c2 c3 c4 c5 c6 c7 c8 c9 d1 d2 d3 d4 d5 d6 ||...............| +00000050 d7 d8 d9 e2 e3 e4 e5 e6 e7 e8 e9 4a e0 5a 5f 6d |...........J.Z_m| +00000060 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 |y...............| +00000070 97 98 99 a2 a3 a4 a5 a6 a7 a8 a9 c0 6a d0 a1 07 |............j...| +00000080 20 21 22 23 24 15 06 17 28 29 2a 2b 2c 09 0a 1b | !"#$...()*+,...| +00000090 30 31 1a 33 34 35 36 08 38 39 3a 3b 04 14 3e e1 |01.3456.89:;..>.| +000000a0 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 |ABCDEFGHIQRSTUVW| +000000b0 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |XYbcdefghipqrstu| +000000c0 76 77 78 80 8a 8b 8c 8d 8e 8f 90 9a 9b 9c 9d 9e |vwx.............| +000000d0 9f a0 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 |................| +000000e0 b8 b9 ba bb bc bd be bf ca cb cc cd ce cf da db |................| +000000f0 dc dd de df ea eb ec ed ee ef fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.oldibm b/corebinutils/dd/ref.oldibm new file mode 100644 index 0000000000..3d05cf9a9e --- /dev/null +++ b/corebinutils/dd/ref.oldibm @@ -0,0 +1,17 @@ +00000000 00 01 02 03 37 2d 2e 2f 16 05 25 0b 0c 0d 0e 0f |....7-./..%.....| +00000010 10 11 12 13 3c 3d 32 26 18 19 3f 27 1c 1d 1e 1f |....<=2&..?'....| +00000020 40 5a 7f 7b 5b 6c 50 7d 4d 5d 5c 4e 6b 60 4b 61 |@Z.{[lP}M]\Nk`Ka| +00000030 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 7a 5e 4c 7e 6e 6f |..........z^L~no| +00000040 7c c1 c2 c3 c4 c5 c6 c7 c8 c9 d1 d2 d3 d4 d5 d6 ||...............| +00000050 d7 d8 d9 e2 e3 e4 e5 e6 e7 e8 e9 ad e0 bd 5f 6d |.............._m| +00000060 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 |y...............| +00000070 97 98 99 a2 a3 a4 a5 a6 a7 a8 a9 c0 4f d0 a1 07 |............O...| +00000080 20 21 22 23 24 15 06 17 28 29 2a 2b 2c 09 0a 1b | !"#$...()*+,...| +00000090 30 31 1a 33 34 35 36 08 38 39 3a 3b 04 14 3e e1 |01.3456.89:;..>.| +000000a0 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 |ABCDEFGHIQRSTUVW| +000000b0 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |XYbcdefghipqrstu| +000000c0 76 77 78 80 8a 8b 8c 8d 8e 8f 90 9a 9b 9c 9d 9e |vwx.............| +000000d0 9f a0 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 |................| +000000e0 b8 b9 ba bb bc bd be bf ca cb cc cd ce cf da db |................| +000000f0 dc dd de df ea eb ec ed ee ef fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.pareven b/corebinutils/dd/ref.pareven new file mode 100644 index 0000000000..3c7c240d6f --- /dev/null +++ b/corebinutils/dd/ref.pareven @@ -0,0 +1,17 @@ +00000000 00 81 82 03 84 05 06 87 88 09 0a 8b 0c 8d 8e 0f |................| +00000010 90 11 12 93 14 95 96 17 18 99 9a 1b 9c 1d 1e 9f |................| +00000020 a0 21 22 a3 24 a5 a6 27 28 a9 aa 2b ac 2d 2e af |.!".$..'(..+.-..| +00000030 30 b1 b2 33 b4 35 36 b7 b8 39 3a bb 3c bd be 3f |0..3.56..9:.<..?| +00000040 c0 41 42 c3 44 c5 c6 47 48 c9 ca 4b cc 4d 4e cf |.AB.D..GH..K.MN.| +00000050 50 d1 d2 53 d4 55 56 d7 d8 59 5a db 5c dd de 5f |P..S.UV..YZ.\.._| +00000060 60 e1 e2 63 e4 65 66 e7 e8 69 6a eb 6c ed ee 6f |`..c.ef..ij.l..o| +00000070 f0 71 72 f3 74 f5 f6 77 78 f9 fa 7b fc 7d 7e ff |.qr.t..wx..{.}~.| +00000080 00 81 82 03 84 05 06 87 88 09 0a 8b 0c 8d 8e 0f |................| +00000090 90 11 12 93 14 95 96 17 18 99 9a 1b 9c 1d 1e 9f |................| +000000a0 a0 21 22 a3 24 a5 a6 27 28 a9 aa 2b ac 2d 2e af |.!".$..'(..+.-..| +000000b0 30 b1 b2 33 b4 35 36 b7 b8 39 3a bb 3c bd be 3f |0..3.56..9:.<..?| +000000c0 c0 41 42 c3 44 c5 c6 47 48 c9 ca 4b cc 4d 4e cf |.AB.D..GH..K.MN.| +000000d0 50 d1 d2 53 d4 55 56 d7 d8 59 5a db 5c dd de 5f |P..S.UV..YZ.\.._| +000000e0 60 e1 e2 63 e4 65 66 e7 e8 69 6a eb 6c ed ee 6f |`..c.ef..ij.l..o| +000000f0 f0 71 72 f3 74 f5 f6 77 78 f9 fa 7b fc 7d 7e ff |.qr.t..wx..{.}~.| +00000100 diff --git a/corebinutils/dd/ref.parnone b/corebinutils/dd/ref.parnone new file mode 100644 index 0000000000..c6e394f59d --- /dev/null +++ b/corebinutils/dd/ref.parnone @@ -0,0 +1,17 @@ +00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| +00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................| +00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./| +00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?| +00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO| +00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\]^_| +00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno| +00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.| +00000080 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| +00000090 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................| +000000a0 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./| +000000b0 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?| +000000c0 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO| +000000d0 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\]^_| +000000e0 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |`abcdefghijklmno| +000000f0 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.| +00000100 diff --git a/corebinutils/dd/ref.parodd b/corebinutils/dd/ref.parodd new file mode 100644 index 0000000000..ada582f872 --- /dev/null +++ b/corebinutils/dd/ref.parodd @@ -0,0 +1,17 @@ +00000000 80 01 02 83 04 85 86 07 08 89 8a 0b 8c 0d 0e 8f |................| +00000010 10 91 92 13 94 15 16 97 98 19 1a 9b 1c 9d 9e 1f |................| +00000020 20 a1 a2 23 a4 25 26 a7 a8 29 2a ab 2c ad ae 2f | ..#.%&..)*.,../| +00000030 b0 31 32 b3 34 b5 b6 37 38 b9 ba 3b bc 3d 3e bf |.12.4..78..;.=>.| +00000040 40 c1 c2 43 c4 45 46 c7 c8 49 4a cb 4c cd ce 4f |@..C.EF..IJ.L..O| +00000050 d0 51 52 d3 54 d5 d6 57 58 d9 da 5b dc 5d 5e df |.QR.T..WX..[.]^.| +00000060 e0 61 62 e3 64 e5 e6 67 68 e9 ea 6b ec 6d 6e ef |.ab.d..gh..k.mn.| +00000070 70 f1 f2 73 f4 75 76 f7 f8 79 7a fb 7c fd fe 7f |p..s.uv..yz.|...| +00000080 80 01 02 83 04 85 86 07 08 89 8a 0b 8c 0d 0e 8f |................| +00000090 10 91 92 13 94 15 16 97 98 19 1a 9b 1c 9d 9e 1f |................| +000000a0 20 a1 a2 23 a4 25 26 a7 a8 29 2a ab 2c ad ae 2f | ..#.%&..)*.,../| +000000b0 b0 31 32 b3 34 b5 b6 37 38 b9 ba 3b bc 3d 3e bf |.12.4..78..;.=>.| +000000c0 40 c1 c2 43 c4 45 46 c7 c8 49 4a cb 4c cd ce 4f |@..C.EF..IJ.L..O| +000000d0 d0 51 52 d3 54 d5 d6 57 58 d9 da 5b dc 5d 5e df |.QR.T..WX..[.]^.| +000000e0 e0 61 62 e3 64 e5 e6 67 68 e9 ea 6b ec 6d 6e ef |.ab.d..gh..k.mn.| +000000f0 70 f1 f2 73 f4 75 76 f7 f8 79 7a fb 7c fd fe 7f |p..s.uv..yz.|...| +00000100 diff --git a/corebinutils/dd/ref.parset b/corebinutils/dd/ref.parset new file mode 100644 index 0000000000..742ed22642 --- /dev/null +++ b/corebinutils/dd/ref.parset @@ -0,0 +1,17 @@ +00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| +00000010 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................| +00000020 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |................| +00000030 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |................| +00000040 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |................| +00000050 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |................| +00000060 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................| +00000070 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................| +00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| +00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................| +000000a0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |................| +000000b0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |................| +000000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |................| +000000d0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |................| +000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................| +000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/ref.swab b/corebinutils/dd/ref.swab new file mode 100644 index 0000000000..07cf9ffafa --- /dev/null +++ b/corebinutils/dd/ref.swab @@ -0,0 +1,17 @@ +00000000 01 00 03 02 05 04 07 06 09 08 0b 0a 0d 0c 0f 0e |................| +00000010 11 10 13 12 15 14 17 16 19 18 1b 1a 1d 1c 1f 1e |................| +00000020 21 20 23 22 25 24 27 26 29 28 2b 2a 2d 2c 2f 2e |! #"%$'&)(+*-,/.| +00000030 31 30 33 32 35 34 37 36 39 38 3b 3a 3d 3c 3f 3e |1032547698;:=<?>| +00000040 41 40 43 42 45 44 47 46 49 48 4b 4a 4d 4c 4f 4e |A@CBEDGFIHKJMLON| +00000050 51 50 53 52 55 54 57 56 59 58 5b 5a 5d 5c 5f 5e |QPSRUTWVYX[Z]\_^| +00000060 61 60 63 62 65 64 67 66 69 68 6b 6a 6d 6c 6f 6e |a`cbedgfihkjmlon| +00000070 71 70 73 72 75 74 77 76 79 78 7b 7a 7d 7c 7f 7e |qpsrutwvyx{z}|.~| +00000080 81 80 83 82 85 84 87 86 89 88 8b 8a 8d 8c 8f 8e |................| +00000090 91 90 93 92 95 94 97 96 99 98 9b 9a 9d 9c 9f 9e |................| +000000a0 a1 a0 a3 a2 a5 a4 a7 a6 a9 a8 ab aa ad ac af ae |................| +000000b0 b1 b0 b3 b2 b5 b4 b7 b6 b9 b8 bb ba bd bc bf be |................| +000000c0 c1 c0 c3 c2 c5 c4 c7 c6 c9 c8 cb ca cd cc cf ce |................| +000000d0 d1 d0 d3 d2 d5 d4 d7 d6 d9 d8 db da dd dc df de |................| +000000e0 e1 e0 e3 e2 e5 e4 e7 e6 e9 e8 eb ea ed ec ef ee |................| +000000f0 f1 f0 f3 f2 f5 f4 f7 f6 f9 f8 fb fa fd fc ff fe |................| +00000100 diff --git a/corebinutils/dd/ref.ucase b/corebinutils/dd/ref.ucase new file mode 100644 index 0000000000..a761c99431 --- /dev/null +++ b/corebinutils/dd/ref.ucase @@ -0,0 +1,17 @@ +00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................| +00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................| +00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./| +00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?| +00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO| +00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\]^_| +00000060 60 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |`ABCDEFGHIJKLMNO| +00000070 50 51 52 53 54 55 56 57 58 59 5a 7b 7c 7d 7e 7f |PQRSTUVWXYZ{|}~.| +00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| +00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................| +000000a0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |................| +000000b0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |................| +000000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |................| +000000d0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |................| +000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................| +000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................| +00000100 diff --git a/corebinutils/dd/tests/test.sh b/corebinutils/dd/tests/test.sh new file mode 100644 index 0000000000..3d6392c692 --- /dev/null +++ b/corebinutils/dd/tests/test.sh @@ -0,0 +1,162 @@ +#!/bin/sh +set -eu + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +DD_BIN=${DD_BIN:-"$ROOT/out/dd"} +DD_GEN=${DD_GEN:-"$ROOT/out/dd-gen"} +TMPDIR=${TMPDIR:-/tmp} +WORKDIR=$(mktemp -d "$TMPDIR/dd-test.XXXXXX") +fifo_writer="" +dd_pid="" +trap ' + if [ -n "$dd_pid" ]; then + kill "$dd_pid" 2>/dev/null || true + wait "$dd_pid" 2>/dev/null || true + fi + if [ -n "$fifo_writer" ]; then + kill "$fifo_writer" 2>/dev/null || true + wait "$fifo_writer" 2>/dev/null || true + fi + rm -rf "$WORKDIR" +' EXIT INT TERM + +fail() { + printf '%s\n' "FAIL: $1" >&2 + exit 1 +} + +assert_eq() { + name=$1 + expected=$2 + actual=$3 + if [ "$expected" != "$actual" ]; then + printf '%s\n' "FAIL: $name" >&2 + printf '%s\n' "--- expected ---" >&2 + printf '%s\n' "$expected" >&2 + printf '%s\n' "--- actual ---" >&2 + printf '%s\n' "$actual" >&2 + exit 1 + fi +} + +assert_match() { + name=$1 + pattern=$2 + text=$3 + printf '%s\n' "$text" | grep -Eq "$pattern" || fail "$name" +} + +assert_file_eq() { + name=$1 + expected=$2 + actual=$3 + cmp "$expected" "$actual" >/dev/null 2>&1 || fail "$name" +} + +run_err() { + "$DD_BIN" "$@" 2>&1 || true +} + +[ -x "$DD_BIN" ] || fail "missing binary: $DD_BIN" +[ -x "$DD_GEN" ] || fail "missing generator: $DD_GEN" + +export LC_ALL=C + +usage_output=$(run_err bogus=1) +assert_match "unknown operand rejection" 'unknown operand bogus' "$usage_output" + +missing_value=$(run_err bs=) +assert_match "missing operand value rejection" 'no value specified for bs' "$missing_value" + +record_error=$(run_err cbs=8) +assert_match "cbs without record conversion rejection" 'cbs meaningless if not doing record operations' "$record_error" + +files_error=$(run_err files=2 if=/dev/zero of=/dev/null count=1 status=none) +assert_match "files on non-tape rejected" 'files is not supported for non-tape devices' "$files_error" + +printf 'abcdef' > "$WORKDIR/basic.in" +"$DD_BIN" if="$WORKDIR/basic.in" of="$WORKDIR/basic.out" bs=3 count=2 2>"$WORKDIR/basic.err" +assert_file_eq "basic copy" "$WORKDIR/basic.in" "$WORKDIR/basic.out" +assert_match "default summary emitted" '^2\+0 records in' "$(cat "$WORKDIR/basic.err")" + +printf '0123456789' > "$WORKDIR/seek.in" +printf 'zzzzzzzzzz' > "$WORKDIR/seek.out" +"$DD_BIN" if="$WORKDIR/seek.in" of="$WORKDIR/seek.out" ibs=2 obs=2 skip=1 seek=2 count=2 conv=notrunc status=none 2>"$WORKDIR/seek.err" +assert_eq "skip/seek/notrunc" "zzzz2345zz" "$(cat "$WORKDIR/seek.out")" +[ ! -s "$WORKDIR/seek.err" ] || fail "status=none should suppress summary output" + +"$DD_GEN" | "$DD_BIN" conv=swab status=none 2>/dev/null | hexdump -C > "$WORKDIR/swab.txt" +assert_file_eq "swab conversion reference" "$ROOT/ref.swab" "$WORKDIR/swab.txt" + +"$DD_GEN" 189284 | "$DD_BIN" ibs=16 obs=8 conv=sparse of="$WORKDIR/sparse.out" status=none 2>/dev/null +hexdump -C "$WORKDIR/sparse.out" > "$WORKDIR/sparse.txt" +assert_file_eq "sparse content reference" "$ROOT/ref.obs_zeroes" "$WORKDIR/sparse.txt" + +"$DD_GEN" 189284 > "$WORKDIR/regular.in" +"$DD_BIN" if="$WORKDIR/regular.in" of="$WORKDIR/regular.out" bs=16 status=none 2>/dev/null +sparse_blocks=$(stat -c '%b' "$WORKDIR/sparse.out") +regular_blocks=$(stat -c '%b' "$WORKDIR/regular.out") +[ "$sparse_blocks" -le "$regular_blocks" ] || fail "sparse output should not allocate more blocks than regular output" + +mkfifo "$WORKDIR/fullblock.fifo" +( + exec 3>"$WORKDIR/fullblock.fifo" + printf 'ab' >&3 + sleep 1 + printf 'cd' >&3 + exec 3>&- +) & +fifo_writer=$! +"$DD_BIN" if="$WORKDIR/fullblock.fifo" of="$WORKDIR/fullblock-short.out" bs=4 count=1 status=none 2>/dev/null +wait "$fifo_writer" || true +fifo_writer="" +assert_eq "short read without fullblock" "ab" "$(cat "$WORKDIR/fullblock-short.out")" + +rm -f "$WORKDIR/fullblock.fifo" +mkfifo "$WORKDIR/fullblock.fifo" +( + exec 3>"$WORKDIR/fullblock.fifo" + printf 'ab' >&3 + sleep 1 + printf 'cd' >&3 + exec 3>&- +) & +fifo_writer=$! +"$DD_BIN" if="$WORKDIR/fullblock.fifo" of="$WORKDIR/fullblock-full.out" bs=4 count=1 iflag=fullblock status=none 2>/dev/null +wait "$fifo_writer" || true +fifo_writer="" +assert_eq "fullblock fills requested block" "abcd" "$(cat "$WORKDIR/fullblock-full.out")" + +mkfifo "$WORKDIR/signal-read.fifo" +( + exec 3>"$WORKDIR/signal-read.fifo" + sleep 30 +) & +fifo_writer=$! +"$DD_BIN" if="$WORKDIR/signal-read.fifo" of=/dev/null 2>"$WORKDIR/signal-read.err" & +dd_pid=$! +sleep 1 +kill -USR1 "$dd_pid" +sleep 1 +kill -INT "$dd_pid" +read_rc=0 +wait "$dd_pid" || read_rc=$? +dd_pid="" +kill "$fifo_writer" 2>/dev/null || true +wait "$fifo_writer" 2>/dev/null || true +fifo_writer="" +[ "$read_rc" -gt 128 ] || fail "SIGINT during blocked read should terminate via signal" +assert_match "SIGUSR1 summary output" 'records in' "$(cat "$WORKDIR/signal-read.err")" + +mkfifo "$WORKDIR/signal-open.fifo" +"$DD_BIN" if="$WORKDIR/signal-open.fifo" of=/dev/null 2>"$WORKDIR/signal-open.err" & +dd_pid=$! +sleep 1 +kill -INT "$dd_pid" +open_rc=0 +wait "$dd_pid" || open_rc=$? +dd_pid="" +[ "$open_rc" -gt 128 ] || fail "SIGINT during blocked open should terminate via signal" +[ -s "$WORKDIR/signal-open.err" ] || fail "SIGINT during blocked open should emit diagnostics" + +printf '%s\n' "PASS" |
