14b88c807SRodney W. Grimes /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 44b88c807SRodney W. Grimes * Copyright (c) 1991, 1993, 1994 54b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 64b88c807SRodney W. Grimes * 74b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 84b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego and Lance 94b88c807SRodney W. Grimes * Visser of Convex Computer Corporation. 104b88c807SRodney W. Grimes * 114b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 124b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 134b88c807SRodney W. Grimes * are met: 144b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 164b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 174b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 184b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 204b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 214b88c807SRodney W. Grimes * without specific prior written permission. 224b88c807SRodney W. Grimes * 234b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 244b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 254b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 264b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 274b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 284b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 294b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 304b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 314b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 324b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 334b88c807SRodney W. Grimes * SUCH DAMAGE. 344b88c807SRodney W. Grimes */ 354b88c807SRodney W. Grimes 364b88c807SRodney W. Grimes #ifndef lint 37cbf6f7d3SPhilippe Charnier #if 0 381ba0e048SPhilippe Charnier static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; 39cbf6f7d3SPhilippe Charnier #endif 404b88c807SRodney W. Grimes #endif /* not lint */ 415eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 425eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 434b88c807SRodney W. Grimes 44919156e3SMatt Macy #include <sys/param.h> 454b88c807SRodney W. Grimes 4677a798b3SAlan Somers #include <ctype.h> 474b88c807SRodney W. Grimes #include <err.h> 484b88c807SRodney W. Grimes #include <errno.h> 497503d74fSMark Murray #include <inttypes.h> 504b88c807SRodney W. Grimes #include <limits.h> 514ac11639SEitan Adler #include <signal.h> 524b88c807SRodney W. Grimes #include <stdlib.h> 534b88c807SRodney W. Grimes #include <string.h> 544b88c807SRodney W. Grimes 554b88c807SRodney W. Grimes #include "dd.h" 564b88c807SRodney W. Grimes #include "extern.h" 574b88c807SRodney W. Grimes 58f9bcb0beSWarner Losh static int c_arg(const void *, const void *); 59f9bcb0beSWarner Losh static int c_conv(const void *, const void *); 60b52c534bSMatt Macy static int c_iflag(const void *, const void *); 61919156e3SMatt Macy static int c_oflag(const void *, const void *); 62f9bcb0beSWarner Losh static void f_bs(char *); 63f9bcb0beSWarner Losh static void f_cbs(char *); 64f9bcb0beSWarner Losh static void f_conv(char *); 65f9bcb0beSWarner Losh static void f_count(char *); 66f9bcb0beSWarner Losh static void f_files(char *); 67e3edab4aSRobert Watson static void f_fillchar(char *); 68f9bcb0beSWarner Losh static void f_ibs(char *); 69f9bcb0beSWarner Losh static void f_if(char *); 70b52c534bSMatt Macy static void f_iflag(char *); 71f9bcb0beSWarner Losh static void f_obs(char *); 72f9bcb0beSWarner Losh static void f_of(char *); 73919156e3SMatt Macy static void f_oflag(char *); 74f9bcb0beSWarner Losh static void f_seek(char *); 75f9bcb0beSWarner Losh static void f_skip(char *); 7675e55112SEdward Tomasz Napierala static void f_speed(char *); 77c3f5e9c5SXin LI static void f_status(char *); 787503d74fSMark Murray static uintmax_t get_num(const char *); 79f9bcb0beSWarner Losh static off_t get_off_t(const char *); 804b88c807SRodney W. Grimes 8158687472SBrian Feldman static const struct arg { 8267f80d12SBrian Feldman const char *name; 83f9bcb0beSWarner Losh void (*f)(char *); 843b96efbdSMatt Macy uint64_t set, noset; 854b88c807SRodney W. Grimes } args[] = { 864b88c807SRodney W. Grimes { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 874b88c807SRodney W. Grimes { "cbs", f_cbs, C_CBS, C_CBS }, 884b88c807SRodney W. Grimes { "conv", f_conv, 0, 0 }, 894b88c807SRodney W. Grimes { "count", f_count, C_COUNT, C_COUNT }, 904b88c807SRodney W. Grimes { "files", f_files, C_FILES, C_FILES }, 91e3edab4aSRobert Watson { "fillchar", f_fillchar, C_FILL, C_FILL }, 924b88c807SRodney W. Grimes { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 934b88c807SRodney W. Grimes { "if", f_if, C_IF, C_IF }, 94b52c534bSMatt Macy { "iflag", f_iflag, 0, 0 }, 95a6d413e7SBrian Feldman { "iseek", f_skip, C_SKIP, C_SKIP }, 964b88c807SRodney W. Grimes { "obs", f_obs, C_OBS, C_BS|C_OBS }, 974b88c807SRodney W. Grimes { "of", f_of, C_OF, C_OF }, 98919156e3SMatt Macy { "oflag", f_oflag, 0, 0 }, 99a6d413e7SBrian Feldman { "oseek", f_seek, C_SEEK, C_SEEK }, 1004b88c807SRodney W. Grimes { "seek", f_seek, C_SEEK, C_SEEK }, 1014b88c807SRodney W. Grimes { "skip", f_skip, C_SKIP, C_SKIP }, 10275e55112SEdward Tomasz Napierala { "speed", f_speed, 0, 0 }, 103c3f5e9c5SXin LI { "status", f_status, C_STATUS,C_STATUS }, 1044b88c807SRodney W. Grimes }; 1054b88c807SRodney W. Grimes 1064b88c807SRodney W. Grimes static char *oper; 1074b88c807SRodney W. Grimes 1084b88c807SRodney W. Grimes /* 1094b88c807SRodney W. Grimes * args -- parse JCL syntax of dd. 1104b88c807SRodney W. Grimes */ 1114b88c807SRodney W. Grimes void 112f9bcb0beSWarner Losh jcl(char **argv) 1134b88c807SRodney W. Grimes { 1144b88c807SRodney W. Grimes struct arg *ap, tmp; 1154b88c807SRodney W. Grimes char *arg; 1164b88c807SRodney W. Grimes 1174b88c807SRodney W. Grimes in.dbsz = out.dbsz = 512; 1184b88c807SRodney W. Grimes 119ad66f7eeSPoul-Henning Kamp while ((oper = *++argv) != NULL) { 1204c339742SEivind Eklund if ((oper = strdup(oper)) == NULL) 12154946e00SBrian Feldman errx(1, "unable to allocate space for the argument \"%s\"", *argv); 1224b88c807SRodney W. Grimes if ((arg = strchr(oper, '=')) == NULL) 1234b88c807SRodney W. Grimes errx(1, "unknown operand %s", oper); 1244b88c807SRodney W. Grimes *arg++ = '\0'; 1254b88c807SRodney W. Grimes if (!*arg) 1264b88c807SRodney W. Grimes errx(1, "no value specified for %s", oper); 1274b88c807SRodney W. Grimes tmp.name = oper; 12854946e00SBrian Feldman if (!(ap = (struct arg *)bsearch(&tmp, args, 12954946e00SBrian Feldman sizeof(args)/sizeof(struct arg), sizeof(struct arg), 13054946e00SBrian Feldman c_arg))) 1314b88c807SRodney W. Grimes errx(1, "unknown operand %s", tmp.name); 1324b88c807SRodney W. Grimes if (ddflags & ap->noset) 13354946e00SBrian Feldman errx(1, "%s: illegal argument combination or already set", 13454946e00SBrian Feldman tmp.name); 1354b88c807SRodney W. Grimes ddflags |= ap->set; 1364b88c807SRodney W. Grimes ap->f(arg); 1374b88c807SRodney W. Grimes } 1384b88c807SRodney W. Grimes 1394b88c807SRodney W. Grimes /* Final sanity checks. */ 1404b88c807SRodney W. Grimes 1414b88c807SRodney W. Grimes if (ddflags & C_BS) { 1424b88c807SRodney W. Grimes /* 1434b88c807SRodney W. Grimes * Bs is turned off by any conversion -- we assume the user 1444b88c807SRodney W. Grimes * just wanted to set both the input and output block sizes 1454b88c807SRodney W. Grimes * and didn't want the bs semantics, so we don't warn. 1464b88c807SRodney W. Grimes */ 147c15c898eSBrian Feldman if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 148c15c898eSBrian Feldman C_UNBLOCK)) 1494b88c807SRodney W. Grimes ddflags &= ~C_BS; 1504b88c807SRodney W. Grimes 1514b88c807SRodney W. Grimes /* Bs supersedes ibs and obs. */ 1524b88c807SRodney W. Grimes if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 1534b88c807SRodney W. Grimes warnx("bs supersedes ibs and obs"); 1544b88c807SRodney W. Grimes } 1554b88c807SRodney W. Grimes 1564b88c807SRodney W. Grimes /* 1574b88c807SRodney W. Grimes * Ascii/ebcdic and cbs implies block/unblock. 1584b88c807SRodney W. Grimes * Block/unblock requires cbs and vice-versa. 1594b88c807SRodney W. Grimes */ 1604b88c807SRodney W. Grimes if (ddflags & (C_BLOCK | C_UNBLOCK)) { 1614b88c807SRodney W. Grimes if (!(ddflags & C_CBS)) 1624b88c807SRodney W. Grimes errx(1, "record operations require cbs"); 1634b88c807SRodney W. Grimes if (cbsz == 0) 1644b88c807SRodney W. Grimes errx(1, "cbs cannot be zero"); 1654b88c807SRodney W. Grimes cfunc = ddflags & C_BLOCK ? block : unblock; 1664b88c807SRodney W. Grimes } else if (ddflags & C_CBS) { 1674b88c807SRodney W. Grimes if (ddflags & (C_ASCII | C_EBCDIC)) { 1684b88c807SRodney W. Grimes if (ddflags & C_ASCII) { 1694b88c807SRodney W. Grimes ddflags |= C_UNBLOCK; 1704b88c807SRodney W. Grimes cfunc = unblock; 1714b88c807SRodney W. Grimes } else { 1724b88c807SRodney W. Grimes ddflags |= C_BLOCK; 1734b88c807SRodney W. Grimes cfunc = block; 1744b88c807SRodney W. Grimes } 1754b88c807SRodney W. Grimes } else 1764b88c807SRodney W. Grimes errx(1, "cbs meaningless if not doing record operations"); 1774b88c807SRodney W. Grimes } else 1784b88c807SRodney W. Grimes cfunc = def; 1794b88c807SRodney W. Grimes } 1804b88c807SRodney W. Grimes 1814b88c807SRodney W. Grimes static int 182f9bcb0beSWarner Losh c_arg(const void *a, const void *b) 1834b88c807SRodney W. Grimes { 1844b88c807SRodney W. Grimes 185dd923702SBrian Feldman return (strcmp(((const struct arg *)a)->name, 186dd923702SBrian Feldman ((const struct arg *)b)->name)); 1874b88c807SRodney W. Grimes } 1884b88c807SRodney W. Grimes 1894b88c807SRodney W. Grimes static void 190f9bcb0beSWarner Losh f_bs(char *arg) 1914b88c807SRodney W. Grimes { 192f4cfd28bSKurt Jaeger uintmax_t res; 1934b88c807SRodney W. Grimes 194f4cfd28bSKurt Jaeger res = get_num(arg); 195f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 1965ad496a2SAlan Somers errx(1, "bs must be between 1 and %zd", (ssize_t)SSIZE_MAX); 197f4cfd28bSKurt Jaeger in.dbsz = out.dbsz = (size_t)res; 1984b88c807SRodney W. Grimes } 1994b88c807SRodney W. Grimes 2004b88c807SRodney W. Grimes static void 201f9bcb0beSWarner Losh f_cbs(char *arg) 2024b88c807SRodney W. Grimes { 203f4cfd28bSKurt Jaeger uintmax_t res; 2044b88c807SRodney W. Grimes 205f4cfd28bSKurt Jaeger res = get_num(arg); 206f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 2075ad496a2SAlan Somers errx(1, "cbs must be between 1 and %zd", (ssize_t)SSIZE_MAX); 208f4cfd28bSKurt Jaeger cbsz = (size_t)res; 2094b88c807SRodney W. Grimes } 2104b88c807SRodney W. Grimes 2114b88c807SRodney W. Grimes static void 212f9bcb0beSWarner Losh f_count(char *arg) 2134b88c807SRodney W. Grimes { 21477a798b3SAlan Somers uintmax_t res; 2154b88c807SRodney W. Grimes 21677a798b3SAlan Somers res = get_num(arg); 21777a798b3SAlan Somers if (res == UINTMAX_MAX) 21877a798b3SAlan Somers errc(1, ERANGE, "%s", oper); 219f4cfd28bSKurt Jaeger if (res == 0) 22077a798b3SAlan Somers cpy_cnt = UINTMAX_MAX; 221f4cfd28bSKurt Jaeger else 22277a798b3SAlan Somers cpy_cnt = res; 2234b88c807SRodney W. Grimes } 2244b88c807SRodney W. Grimes 2254b88c807SRodney W. Grimes static void 226f9bcb0beSWarner Losh f_files(char *arg) 2274b88c807SRodney W. Grimes { 2284b88c807SRodney W. Grimes 229e14f7e78SBrian Feldman files_cnt = get_num(arg); 2307599187eSBrian Feldman if (files_cnt < 1) 23177a798b3SAlan Somers errx(1, "files must be between 1 and %zu", SIZE_MAX); 2324b88c807SRodney W. Grimes } 2334b88c807SRodney W. Grimes 2344b88c807SRodney W. Grimes static void 235e3edab4aSRobert Watson f_fillchar(char *arg) 236e3edab4aSRobert Watson { 237e3edab4aSRobert Watson 238e3edab4aSRobert Watson if (strlen(arg) != 1) 239e3edab4aSRobert Watson errx(1, "need exactly one fill char"); 240e3edab4aSRobert Watson 241e3edab4aSRobert Watson fill_char = arg[0]; 242e3edab4aSRobert Watson } 243e3edab4aSRobert Watson 244e3edab4aSRobert Watson static void 245f9bcb0beSWarner Losh f_ibs(char *arg) 2464b88c807SRodney W. Grimes { 247f4cfd28bSKurt Jaeger uintmax_t res; 2484b88c807SRodney W. Grimes 24954946e00SBrian Feldman if (!(ddflags & C_BS)) { 250f4cfd28bSKurt Jaeger res = get_num(arg); 251f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 25277a798b3SAlan Somers errx(1, "ibs must be between 1 and %zd", 2535ad496a2SAlan Somers (ssize_t)SSIZE_MAX); 254f4cfd28bSKurt Jaeger in.dbsz = (size_t)res; 25554946e00SBrian Feldman } 2564b88c807SRodney W. Grimes } 2574b88c807SRodney W. Grimes 2584b88c807SRodney W. Grimes static void 259f9bcb0beSWarner Losh f_if(char *arg) 2604b88c807SRodney W. Grimes { 2614b88c807SRodney W. Grimes 2624b88c807SRodney W. Grimes in.name = arg; 2634b88c807SRodney W. Grimes } 2644b88c807SRodney W. Grimes 265b52c534bSMatt Macy static const struct iflag { 266b52c534bSMatt Macy const char *name; 267b52c534bSMatt Macy uint64_t set, noset; 268b52c534bSMatt Macy } ilist[] = { 269*f4b4526fSRichard Scheffenegger { "direct", C_IDIRECT, 0 }, 270b52c534bSMatt Macy { "fullblock", C_IFULLBLOCK, C_SYNC }, 271b52c534bSMatt Macy }; 272b52c534bSMatt Macy 273b52c534bSMatt Macy static void 274b52c534bSMatt Macy f_iflag(char *arg) 275b52c534bSMatt Macy { 276b52c534bSMatt Macy struct iflag *ip, tmp; 277b52c534bSMatt Macy 278b52c534bSMatt Macy while (arg != NULL) { 279b52c534bSMatt Macy tmp.name = strsep(&arg, ","); 280b52c534bSMatt Macy ip = bsearch(&tmp, ilist, nitems(ilist), sizeof(struct iflag), 281b52c534bSMatt Macy c_iflag); 282b52c534bSMatt Macy if (ip == NULL) 283b52c534bSMatt Macy errx(1, "unknown iflag %s", tmp.name); 284b52c534bSMatt Macy if (ddflags & ip->noset) 285b52c534bSMatt Macy errx(1, "%s: illegal conversion combination", tmp.name); 286b52c534bSMatt Macy ddflags |= ip->set; 287b52c534bSMatt Macy } 288b52c534bSMatt Macy } 289b52c534bSMatt Macy 290b52c534bSMatt Macy static int 291b52c534bSMatt Macy c_iflag(const void *a, const void *b) 292b52c534bSMatt Macy { 293b52c534bSMatt Macy 294b52c534bSMatt Macy return (strcmp(((const struct iflag *)a)->name, 295b52c534bSMatt Macy ((const struct iflag *)b)->name)); 296b52c534bSMatt Macy } 297b52c534bSMatt Macy 2984b88c807SRodney W. Grimes static void 299f9bcb0beSWarner Losh f_obs(char *arg) 3004b88c807SRodney W. Grimes { 301f4cfd28bSKurt Jaeger uintmax_t res; 3024b88c807SRodney W. Grimes 30354946e00SBrian Feldman if (!(ddflags & C_BS)) { 304f4cfd28bSKurt Jaeger res = get_num(arg); 305f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 30677a798b3SAlan Somers errx(1, "obs must be between 1 and %zd", 3075ad496a2SAlan Somers (ssize_t)SSIZE_MAX); 308f4cfd28bSKurt Jaeger out.dbsz = (size_t)res; 30954946e00SBrian Feldman } 3104b88c807SRodney W. Grimes } 3114b88c807SRodney W. Grimes 3124b88c807SRodney W. Grimes static void 313f9bcb0beSWarner Losh f_of(char *arg) 3144b88c807SRodney W. Grimes { 3154b88c807SRodney W. Grimes 3164b88c807SRodney W. Grimes out.name = arg; 3174b88c807SRodney W. Grimes } 3184b88c807SRodney W. Grimes 3194b88c807SRodney W. Grimes static void 320f9bcb0beSWarner Losh f_seek(char *arg) 3214b88c807SRodney W. Grimes { 3224b88c807SRodney W. Grimes 3234ed95537SBrian Feldman out.offset = get_off_t(arg); 3244b88c807SRodney W. Grimes } 3254b88c807SRodney W. Grimes 3264b88c807SRodney W. Grimes static void 327f9bcb0beSWarner Losh f_skip(char *arg) 3284b88c807SRodney W. Grimes { 3294b88c807SRodney W. Grimes 3304ed95537SBrian Feldman in.offset = get_off_t(arg); 3314b88c807SRodney W. Grimes } 3324b88c807SRodney W. Grimes 333c3f5e9c5SXin LI static void 33475e55112SEdward Tomasz Napierala f_speed(char *arg) 33575e55112SEdward Tomasz Napierala { 33675e55112SEdward Tomasz Napierala 33775e55112SEdward Tomasz Napierala speed = get_num(arg); 33875e55112SEdward Tomasz Napierala } 33975e55112SEdward Tomasz Napierala 34075e55112SEdward Tomasz Napierala static void 341c3f5e9c5SXin LI f_status(char *arg) 342c3f5e9c5SXin LI { 343c3f5e9c5SXin LI 344c3f5e9c5SXin LI if (strcmp(arg, "none") == 0) 345c3f5e9c5SXin LI ddflags |= C_NOINFO; 346c3f5e9c5SXin LI else if (strcmp(arg, "noxfer") == 0) 347c3f5e9c5SXin LI ddflags |= C_NOXFER; 3484767c42cSKyle Evans else if (strcmp(arg, "progress") == 0) 3494767c42cSKyle Evans ddflags |= C_PROGRESS; 350c3f5e9c5SXin LI else 351c3f5e9c5SXin LI errx(1, "unknown status %s", arg); 352c3f5e9c5SXin LI } 353c3f5e9c5SXin LI 35458687472SBrian Feldman static const struct conv { 35567f80d12SBrian Feldman const char *name; 3563b96efbdSMatt Macy uint64_t set, noset; 35758687472SBrian Feldman const u_char *ctab; 3584b88c807SRodney W. Grimes } clist[] = { 3594b88c807SRodney W. Grimes { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 3604b88c807SRodney W. Grimes { "block", C_BLOCK, C_UNBLOCK, NULL }, 3614b88c807SRodney W. Grimes { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 3623b96efbdSMatt Macy { "fdatasync", C_FDATASYNC, 0, NULL }, 363ce1b19d8SMatt Macy { "fsync", C_FSYNC, 0, NULL }, 3644b88c807SRodney W. Grimes { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 3654b88c807SRodney W. Grimes { "lcase", C_LCASE, C_UCASE, NULL }, 3664b88c807SRodney W. Grimes { "noerror", C_NOERROR, 0, NULL }, 3674b88c807SRodney W. Grimes { "notrunc", C_NOTRUNC, 0, NULL }, 3684b88c807SRodney W. Grimes { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 3694b88c807SRodney W. Grimes { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 3704b88c807SRodney W. Grimes { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 3714b88c807SRodney W. Grimes { "osync", C_OSYNC, C_BS, NULL }, 3726a3d33acSPoul-Henning Kamp { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL}, 3736a3d33acSPoul-Henning Kamp { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL}, 3746a3d33acSPoul-Henning Kamp { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL}, 3756a3d33acSPoul-Henning Kamp { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, 3761898febeSJoerg Wunsch { "sparse", C_SPARSE, 0, NULL }, 3774b88c807SRodney W. Grimes { "swab", C_SWAB, 0, NULL }, 378b52c534bSMatt Macy { "sync", C_SYNC, C_IFULLBLOCK, NULL }, 3794b88c807SRodney W. Grimes { "ucase", C_UCASE, C_LCASE, NULL }, 3804b88c807SRodney W. Grimes { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 3814b88c807SRodney W. Grimes }; 3824b88c807SRodney W. Grimes 3834b88c807SRodney W. Grimes static void 384f9bcb0beSWarner Losh f_conv(char *arg) 3854b88c807SRodney W. Grimes { 3864b88c807SRodney W. Grimes struct conv *cp, tmp; 3874b88c807SRodney W. Grimes 3884b88c807SRodney W. Grimes while (arg != NULL) { 3894b88c807SRodney W. Grimes tmp.name = strsep(&arg, ","); 390919156e3SMatt Macy cp = bsearch(&tmp, clist, nitems(clist), sizeof(struct conv), 391919156e3SMatt Macy c_conv); 39258687472SBrian Feldman if (cp == NULL) 3934b88c807SRodney W. Grimes errx(1, "unknown conversion %s", tmp.name); 3944b88c807SRodney W. Grimes if (ddflags & cp->noset) 3954b88c807SRodney W. Grimes errx(1, "%s: illegal conversion combination", tmp.name); 3964b88c807SRodney W. Grimes ddflags |= cp->set; 3974b88c807SRodney W. Grimes if (cp->ctab) 3984b88c807SRodney W. Grimes ctab = cp->ctab; 3994b88c807SRodney W. Grimes } 4004b88c807SRodney W. Grimes } 4014b88c807SRodney W. Grimes 4024b88c807SRodney W. Grimes static int 403f9bcb0beSWarner Losh c_conv(const void *a, const void *b) 4044b88c807SRodney W. Grimes { 4054b88c807SRodney W. Grimes 406dd923702SBrian Feldman return (strcmp(((const struct conv *)a)->name, 407dd923702SBrian Feldman ((const struct conv *)b)->name)); 4084b88c807SRodney W. Grimes } 4094b88c807SRodney W. Grimes 410919156e3SMatt Macy static const struct oflag { 411919156e3SMatt Macy const char *name; 412919156e3SMatt Macy uint64_t set; 413919156e3SMatt Macy } olist[] = { 414*f4b4526fSRichard Scheffenegger { "direct", C_ODIRECT }, 415919156e3SMatt Macy { "fsync", C_OFSYNC }, 416919156e3SMatt Macy { "sync", C_OFSYNC }, 417919156e3SMatt Macy }; 418919156e3SMatt Macy 419919156e3SMatt Macy static void 420919156e3SMatt Macy f_oflag(char *arg) 421919156e3SMatt Macy { 422919156e3SMatt Macy struct oflag *op, tmp; 423919156e3SMatt Macy 424919156e3SMatt Macy while (arg != NULL) { 425919156e3SMatt Macy tmp.name = strsep(&arg, ","); 426919156e3SMatt Macy op = bsearch(&tmp, olist, nitems(olist), sizeof(struct oflag), 427919156e3SMatt Macy c_oflag); 428919156e3SMatt Macy if (op == NULL) 429919156e3SMatt Macy errx(1, "unknown open flag %s", tmp.name); 430919156e3SMatt Macy ddflags |= op->set; 431919156e3SMatt Macy } 432919156e3SMatt Macy } 433919156e3SMatt Macy 434919156e3SMatt Macy static int 435919156e3SMatt Macy c_oflag(const void *a, const void *b) 436919156e3SMatt Macy { 437919156e3SMatt Macy 438919156e3SMatt Macy return (strcmp(((const struct oflag *)a)->name, 439919156e3SMatt Macy ((const struct oflag *)b)->name)); 440919156e3SMatt Macy } 441919156e3SMatt Macy 442f3041442SEdward Tomasz Napierala static intmax_t 44366d082c8SEdward Tomasz Napierala postfix_to_mult(const char expr) 44466d082c8SEdward Tomasz Napierala { 445f3041442SEdward Tomasz Napierala intmax_t mult; 44666d082c8SEdward Tomasz Napierala 44766d082c8SEdward Tomasz Napierala mult = 0; 44866d082c8SEdward Tomasz Napierala switch (expr) { 44966d082c8SEdward Tomasz Napierala case 'B': 45066d082c8SEdward Tomasz Napierala case 'b': 45166d082c8SEdward Tomasz Napierala mult = 512; 45266d082c8SEdward Tomasz Napierala break; 45366d082c8SEdward Tomasz Napierala case 'K': 45466d082c8SEdward Tomasz Napierala case 'k': 45566d082c8SEdward Tomasz Napierala mult = 1 << 10; 45666d082c8SEdward Tomasz Napierala break; 45766d082c8SEdward Tomasz Napierala case 'M': 45866d082c8SEdward Tomasz Napierala case 'm': 45966d082c8SEdward Tomasz Napierala mult = 1 << 20; 46066d082c8SEdward Tomasz Napierala break; 46166d082c8SEdward Tomasz Napierala case 'G': 46266d082c8SEdward Tomasz Napierala case 'g': 46366d082c8SEdward Tomasz Napierala mult = 1 << 30; 46466d082c8SEdward Tomasz Napierala break; 465e53d0abfSEdward Tomasz Napierala case 'T': 466e53d0abfSEdward Tomasz Napierala case 't': 467e53d0abfSEdward Tomasz Napierala mult = (uintmax_t)1 << 40; 468e53d0abfSEdward Tomasz Napierala break; 469e53d0abfSEdward Tomasz Napierala case 'P': 470e53d0abfSEdward Tomasz Napierala case 'p': 471e53d0abfSEdward Tomasz Napierala mult = (uintmax_t)1 << 50; 472e53d0abfSEdward Tomasz Napierala break; 47366d082c8SEdward Tomasz Napierala case 'W': 47466d082c8SEdward Tomasz Napierala case 'w': 47566d082c8SEdward Tomasz Napierala mult = sizeof(int); 47666d082c8SEdward Tomasz Napierala break; 47766d082c8SEdward Tomasz Napierala } 47866d082c8SEdward Tomasz Napierala 47966d082c8SEdward Tomasz Napierala return (mult); 48066d082c8SEdward Tomasz Napierala } 48166d082c8SEdward Tomasz Napierala 4824b88c807SRodney W. Grimes /* 4837503d74fSMark Murray * Convert an expression of the following forms to a uintmax_t. 4844b88c807SRodney W. Grimes * 1) A positive decimal number. 4851e1d03d7SPawel Jakub Dawidek * 2) A positive decimal number followed by a 'b' or 'B' (mult by 512). 4861e1d03d7SPawel Jakub Dawidek * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). 4871e1d03d7SPawel Jakub Dawidek * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). 4881e1d03d7SPawel Jakub Dawidek * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). 489c075c8bbSEdward Tomasz Napierala * 6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40). 490c075c8bbSEdward Tomasz Napierala * 7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50). 491c075c8bbSEdward Tomasz Napierala * 8) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int). 492c075c8bbSEdward Tomasz Napierala * 9) Two or more positive decimal numbers (with/without [BbKkMmGgWw]) 4931e1d03d7SPawel Jakub Dawidek * separated by 'x' or 'X' (also '*' for backwards compatibility), 4941e1d03d7SPawel Jakub Dawidek * specifying the product of the indicated values. 4954b88c807SRodney W. Grimes */ 4967503d74fSMark Murray static uintmax_t 497f9bcb0beSWarner Losh get_num(const char *val) 4984b88c807SRodney W. Grimes { 4997503d74fSMark Murray uintmax_t num, mult, prevnum; 5004ed95537SBrian Feldman char *expr; 5014ed95537SBrian Feldman 5024ed95537SBrian Feldman errno = 0; 503d8192361SEdward Tomasz Napierala num = strtoumax(val, &expr, 0); 5044ed95537SBrian Feldman if (expr == val) /* No valid digits. */ 505674677bdSEdward Tomasz Napierala errx(1, "%s: invalid numeric value", oper); 506674677bdSEdward Tomasz Napierala if (errno != 0) 507674677bdSEdward Tomasz Napierala err(1, "%s", oper); 5084ed95537SBrian Feldman 50966d082c8SEdward Tomasz Napierala mult = postfix_to_mult(*expr); 5104ed95537SBrian Feldman 5114ed95537SBrian Feldman if (mult != 0) { 5124ed95537SBrian Feldman prevnum = num; 5134ed95537SBrian Feldman num *= mult; 5144ed95537SBrian Feldman /* Check for overflow. */ 5154ed95537SBrian Feldman if (num / mult != prevnum) 5164ed95537SBrian Feldman goto erange; 5174ed95537SBrian Feldman expr++; 5184ed95537SBrian Feldman } 5194ed95537SBrian Feldman 5204ed95537SBrian Feldman switch (*expr) { 5214ed95537SBrian Feldman case '\0': 5224ed95537SBrian Feldman break; 5234ed95537SBrian Feldman case '*': /* Backward compatible. */ 5241e1d03d7SPawel Jakub Dawidek case 'X': 5254ed95537SBrian Feldman case 'x': 5264ed95537SBrian Feldman mult = get_num(expr + 1); 5274ed95537SBrian Feldman prevnum = num; 5284ed95537SBrian Feldman num *= mult; 5294ed95537SBrian Feldman if (num / mult == prevnum) 5304ed95537SBrian Feldman break; 5314ed95537SBrian Feldman erange: 5324ed95537SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 5334ed95537SBrian Feldman default: 5344ed95537SBrian Feldman errx(1, "%s: illegal numeric value", oper); 5354ed95537SBrian Feldman } 5364ed95537SBrian Feldman return (num); 5374ed95537SBrian Feldman } 5384ed95537SBrian Feldman 5394ed95537SBrian Feldman /* 5404ed95537SBrian Feldman * Convert an expression of the following forms to an off_t. This is the 5414ed95537SBrian Feldman * same as get_num(), but it uses signed numbers. 5424ed95537SBrian Feldman * 5437503d74fSMark Murray * The major problem here is that an off_t may not necessarily be a intmax_t. 5444ed95537SBrian Feldman */ 5454ed95537SBrian Feldman static off_t 546f9bcb0beSWarner Losh get_off_t(const char *val) 5474ed95537SBrian Feldman { 5487503d74fSMark Murray intmax_t num, mult, prevnum; 5494b88c807SRodney W. Grimes char *expr; 5504b88c807SRodney W. Grimes 55154946e00SBrian Feldman errno = 0; 552d8192361SEdward Tomasz Napierala num = strtoimax(val, &expr, 0); 55358687472SBrian Feldman if (expr == val) /* No valid digits. */ 554674677bdSEdward Tomasz Napierala errx(1, "%s: invalid numeric value", oper); 555674677bdSEdward Tomasz Napierala if (errno != 0) 556674677bdSEdward Tomasz Napierala err(1, "%s", oper); 5574b88c807SRodney W. Grimes 55866d082c8SEdward Tomasz Napierala mult = postfix_to_mult(*expr); 5594b88c807SRodney W. Grimes 5604ed95537SBrian Feldman if (mult != 0) { 5614ed95537SBrian Feldman prevnum = num; 5624ed95537SBrian Feldman num *= mult; 5634ed95537SBrian Feldman /* Check for overflow. */ 5644ed95537SBrian Feldman if ((prevnum > 0) != (num > 0) || num / mult != prevnum) 5654ed95537SBrian Feldman goto erange; 5664ed95537SBrian Feldman expr++; 5674ed95537SBrian Feldman } 5684ed95537SBrian Feldman 5694b88c807SRodney W. Grimes switch (*expr) { 5704b88c807SRodney W. Grimes case '\0': 5714b88c807SRodney W. Grimes break; 5724b88c807SRodney W. Grimes case '*': /* Backward compatible. */ 5731e1d03d7SPawel Jakub Dawidek case 'X': 5744b88c807SRodney W. Grimes case 'x': 5757503d74fSMark Murray mult = (intmax_t)get_off_t(expr + 1); 5764ed95537SBrian Feldman prevnum = num; 5774ed95537SBrian Feldman num *= mult; 5782fb08072SBrian Feldman if ((prevnum > 0) == (num > 0) && num / mult == prevnum) 5794b88c807SRodney W. Grimes break; 580e14f7e78SBrian Feldman erange: 581e14f7e78SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 5824b88c807SRodney W. Grimes default: 5834b88c807SRodney W. Grimes errx(1, "%s: illegal numeric value", oper); 5844b88c807SRodney W. Grimes } 5854b88c807SRodney W. Grimes return (num); 5864b88c807SRodney W. Grimes } 587