14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1991, 1993, 1994 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego and Lance 74b88c807SRodney W. Grimes * Visser of Convex Computer Corporation. 84b88c807SRodney W. Grimes * 94b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 104b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 114b88c807SRodney W. Grimes * are met: 124b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 134b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 144b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 164b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 174b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 184b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 194b88c807SRodney W. Grimes * without specific prior written permission. 204b88c807SRodney W. Grimes * 214b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 224b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 234b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 244b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 254b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 264b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 274b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 284b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 294b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 304b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314b88c807SRodney W. Grimes * SUCH DAMAGE. 324b88c807SRodney W. Grimes */ 334b88c807SRodney W. Grimes 344b88c807SRodney W. Grimes #ifndef lint 35cbf6f7d3SPhilippe Charnier #if 0 361ba0e048SPhilippe Charnier static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; 37cbf6f7d3SPhilippe Charnier #endif 384b88c807SRodney W. Grimes #endif /* not lint */ 395eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 405eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 414b88c807SRodney W. Grimes 424b88c807SRodney W. Grimes #include <sys/types.h> 434b88c807SRodney W. Grimes 444b88c807SRodney W. Grimes #include <err.h> 454b88c807SRodney W. Grimes #include <errno.h> 467503d74fSMark Murray #include <inttypes.h> 474b88c807SRodney W. Grimes #include <limits.h> 484ac11639SEitan Adler #include <signal.h> 494b88c807SRodney W. Grimes #include <stdlib.h> 504b88c807SRodney W. Grimes #include <string.h> 514b88c807SRodney W. Grimes 524b88c807SRodney W. Grimes #include "dd.h" 534b88c807SRodney W. Grimes #include "extern.h" 544b88c807SRodney W. Grimes 55f9bcb0beSWarner Losh static int c_arg(const void *, const void *); 56f9bcb0beSWarner Losh static int c_conv(const void *, const void *); 57f9bcb0beSWarner Losh static void f_bs(char *); 58f9bcb0beSWarner Losh static void f_cbs(char *); 59f9bcb0beSWarner Losh static void f_conv(char *); 60f9bcb0beSWarner Losh static void f_count(char *); 61f9bcb0beSWarner Losh static void f_files(char *); 62e3edab4aSRobert Watson static void f_fillchar(char *); 63f9bcb0beSWarner Losh static void f_ibs(char *); 64f9bcb0beSWarner Losh static void f_if(char *); 65f9bcb0beSWarner Losh static void f_obs(char *); 66f9bcb0beSWarner Losh static void f_of(char *); 67f9bcb0beSWarner Losh static void f_seek(char *); 68f9bcb0beSWarner Losh static void f_skip(char *); 69c3f5e9c5SXin LI static void f_status(char *); 707503d74fSMark Murray static uintmax_t get_num(const char *); 71f9bcb0beSWarner Losh static off_t get_off_t(const char *); 724b88c807SRodney W. Grimes 7358687472SBrian Feldman static const struct arg { 7467f80d12SBrian Feldman const char *name; 75f9bcb0beSWarner Losh void (*f)(char *); 764b88c807SRodney W. Grimes u_int set, noset; 774b88c807SRodney W. Grimes } args[] = { 784b88c807SRodney W. Grimes { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 794b88c807SRodney W. Grimes { "cbs", f_cbs, C_CBS, C_CBS }, 804b88c807SRodney W. Grimes { "conv", f_conv, 0, 0 }, 814b88c807SRodney W. Grimes { "count", f_count, C_COUNT, C_COUNT }, 824b88c807SRodney W. Grimes { "files", f_files, C_FILES, C_FILES }, 83e3edab4aSRobert Watson { "fillchar", f_fillchar, C_FILL, C_FILL }, 844b88c807SRodney W. Grimes { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 854b88c807SRodney W. Grimes { "if", f_if, C_IF, C_IF }, 86a6d413e7SBrian Feldman { "iseek", f_skip, C_SKIP, C_SKIP }, 874b88c807SRodney W. Grimes { "obs", f_obs, C_OBS, C_BS|C_OBS }, 884b88c807SRodney W. Grimes { "of", f_of, C_OF, C_OF }, 89a6d413e7SBrian Feldman { "oseek", f_seek, C_SEEK, C_SEEK }, 904b88c807SRodney W. Grimes { "seek", f_seek, C_SEEK, C_SEEK }, 914b88c807SRodney W. Grimes { "skip", f_skip, C_SKIP, C_SKIP }, 92c3f5e9c5SXin LI { "status", f_status, C_STATUS,C_STATUS }, 934b88c807SRodney W. Grimes }; 944b88c807SRodney W. Grimes 954b88c807SRodney W. Grimes static char *oper; 964b88c807SRodney W. Grimes 974b88c807SRodney W. Grimes /* 984b88c807SRodney W. Grimes * args -- parse JCL syntax of dd. 994b88c807SRodney W. Grimes */ 1004b88c807SRodney W. Grimes void 101f9bcb0beSWarner Losh jcl(char **argv) 1024b88c807SRodney W. Grimes { 1034b88c807SRodney W. Grimes struct arg *ap, tmp; 1044b88c807SRodney W. Grimes char *arg; 1054b88c807SRodney W. Grimes 1064b88c807SRodney W. Grimes in.dbsz = out.dbsz = 512; 1074b88c807SRodney W. Grimes 108ad66f7eeSPoul-Henning Kamp while ((oper = *++argv) != NULL) { 1094c339742SEivind Eklund if ((oper = strdup(oper)) == NULL) 11054946e00SBrian Feldman errx(1, "unable to allocate space for the argument \"%s\"", *argv); 1114b88c807SRodney W. Grimes if ((arg = strchr(oper, '=')) == NULL) 1124b88c807SRodney W. Grimes errx(1, "unknown operand %s", oper); 1134b88c807SRodney W. Grimes *arg++ = '\0'; 1144b88c807SRodney W. Grimes if (!*arg) 1154b88c807SRodney W. Grimes errx(1, "no value specified for %s", oper); 1164b88c807SRodney W. Grimes tmp.name = oper; 11754946e00SBrian Feldman if (!(ap = (struct arg *)bsearch(&tmp, args, 11854946e00SBrian Feldman sizeof(args)/sizeof(struct arg), sizeof(struct arg), 11954946e00SBrian Feldman c_arg))) 1204b88c807SRodney W. Grimes errx(1, "unknown operand %s", tmp.name); 1214b88c807SRodney W. Grimes if (ddflags & ap->noset) 12254946e00SBrian Feldman errx(1, "%s: illegal argument combination or already set", 12354946e00SBrian Feldman tmp.name); 1244b88c807SRodney W. Grimes ddflags |= ap->set; 1254b88c807SRodney W. Grimes ap->f(arg); 1264b88c807SRodney W. Grimes } 1274b88c807SRodney W. Grimes 1284b88c807SRodney W. Grimes /* Final sanity checks. */ 1294b88c807SRodney W. Grimes 1304b88c807SRodney W. Grimes if (ddflags & C_BS) { 1314b88c807SRodney W. Grimes /* 1324b88c807SRodney W. Grimes * Bs is turned off by any conversion -- we assume the user 1334b88c807SRodney W. Grimes * just wanted to set both the input and output block sizes 1344b88c807SRodney W. Grimes * and didn't want the bs semantics, so we don't warn. 1354b88c807SRodney W. Grimes */ 136c15c898eSBrian Feldman if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 137c15c898eSBrian Feldman C_UNBLOCK)) 1384b88c807SRodney W. Grimes ddflags &= ~C_BS; 1394b88c807SRodney W. Grimes 1404b88c807SRodney W. Grimes /* Bs supersedes ibs and obs. */ 1414b88c807SRodney W. Grimes if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 1424b88c807SRodney W. Grimes warnx("bs supersedes ibs and obs"); 1434b88c807SRodney W. Grimes } 1444b88c807SRodney W. Grimes 1454b88c807SRodney W. Grimes /* 1464b88c807SRodney W. Grimes * Ascii/ebcdic and cbs implies block/unblock. 1474b88c807SRodney W. Grimes * Block/unblock requires cbs and vice-versa. 1484b88c807SRodney W. Grimes */ 1494b88c807SRodney W. Grimes if (ddflags & (C_BLOCK | C_UNBLOCK)) { 1504b88c807SRodney W. Grimes if (!(ddflags & C_CBS)) 1514b88c807SRodney W. Grimes errx(1, "record operations require cbs"); 1524b88c807SRodney W. Grimes if (cbsz == 0) 1534b88c807SRodney W. Grimes errx(1, "cbs cannot be zero"); 1544b88c807SRodney W. Grimes cfunc = ddflags & C_BLOCK ? block : unblock; 1554b88c807SRodney W. Grimes } else if (ddflags & C_CBS) { 1564b88c807SRodney W. Grimes if (ddflags & (C_ASCII | C_EBCDIC)) { 1574b88c807SRodney W. Grimes if (ddflags & C_ASCII) { 1584b88c807SRodney W. Grimes ddflags |= C_UNBLOCK; 1594b88c807SRodney W. Grimes cfunc = unblock; 1604b88c807SRodney W. Grimes } else { 1614b88c807SRodney W. Grimes ddflags |= C_BLOCK; 1624b88c807SRodney W. Grimes cfunc = block; 1634b88c807SRodney W. Grimes } 1644b88c807SRodney W. Grimes } else 1654b88c807SRodney W. Grimes errx(1, "cbs meaningless if not doing record operations"); 1664b88c807SRodney W. Grimes } else 1674b88c807SRodney W. Grimes cfunc = def; 1687599187eSBrian Feldman 16958687472SBrian Feldman /* 17058687472SBrian Feldman * Bail out if the calculation of a file offset would overflow. 17158687472SBrian Feldman */ 1727503d74fSMark Murray if (in.offset > OFF_MAX / (ssize_t)in.dbsz || 1737503d74fSMark Murray out.offset > OFF_MAX / (ssize_t)out.dbsz) 174f4cfd28bSKurt Jaeger errx(1, "seek offsets cannot be larger than %jd", 175f4cfd28bSKurt Jaeger (intmax_t)OFF_MAX); 1764b88c807SRodney W. Grimes } 1774b88c807SRodney W. Grimes 1784b88c807SRodney W. Grimes static int 179f9bcb0beSWarner Losh c_arg(const void *a, const void *b) 1804b88c807SRodney W. Grimes { 1814b88c807SRodney W. Grimes 182dd923702SBrian Feldman return (strcmp(((const struct arg *)a)->name, 183dd923702SBrian Feldman ((const struct arg *)b)->name)); 1844b88c807SRodney W. Grimes } 1854b88c807SRodney W. Grimes 1864b88c807SRodney W. Grimes static void 187f9bcb0beSWarner Losh f_bs(char *arg) 1884b88c807SRodney W. Grimes { 189f4cfd28bSKurt Jaeger uintmax_t res; 1904b88c807SRodney W. Grimes 191f4cfd28bSKurt Jaeger res = get_num(arg); 192f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 193f4cfd28bSKurt Jaeger errx(1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX); 194f4cfd28bSKurt Jaeger in.dbsz = out.dbsz = (size_t)res; 1954b88c807SRodney W. Grimes } 1964b88c807SRodney W. Grimes 1974b88c807SRodney W. Grimes static void 198f9bcb0beSWarner Losh f_cbs(char *arg) 1994b88c807SRodney W. Grimes { 200f4cfd28bSKurt Jaeger uintmax_t res; 2014b88c807SRodney W. Grimes 202f4cfd28bSKurt Jaeger res = get_num(arg); 203f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 204f4cfd28bSKurt Jaeger errx(1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX); 205f4cfd28bSKurt Jaeger cbsz = (size_t)res; 2064b88c807SRodney W. Grimes } 2074b88c807SRodney W. Grimes 2084b88c807SRodney W. Grimes static void 209f9bcb0beSWarner Losh f_count(char *arg) 2104b88c807SRodney W. Grimes { 211f4cfd28bSKurt Jaeger intmax_t res; 2124b88c807SRodney W. Grimes 213f4cfd28bSKurt Jaeger res = (intmax_t)get_num(arg); 214f4cfd28bSKurt Jaeger if (res < 0) 215f4cfd28bSKurt Jaeger errx(1, "count cannot be negative"); 216f4cfd28bSKurt Jaeger if (res == 0) 217f4cfd28bSKurt Jaeger cpy_cnt = (uintmax_t)-1; 218f4cfd28bSKurt Jaeger else 219f4cfd28bSKurt Jaeger cpy_cnt = (uintmax_t)res; 2204b88c807SRodney W. Grimes } 2214b88c807SRodney W. Grimes 2224b88c807SRodney W. Grimes static void 223f9bcb0beSWarner Losh f_files(char *arg) 2244b88c807SRodney W. Grimes { 2254b88c807SRodney W. Grimes 226e14f7e78SBrian Feldman files_cnt = get_num(arg); 2277599187eSBrian Feldman if (files_cnt < 1) 228f4cfd28bSKurt Jaeger errx(1, "files must be between 1 and %jd", (uintmax_t)-1); 2294b88c807SRodney W. Grimes } 2304b88c807SRodney W. Grimes 2314b88c807SRodney W. Grimes static void 232e3edab4aSRobert Watson f_fillchar(char *arg) 233e3edab4aSRobert Watson { 234e3edab4aSRobert Watson 235e3edab4aSRobert Watson if (strlen(arg) != 1) 236e3edab4aSRobert Watson errx(1, "need exactly one fill char"); 237e3edab4aSRobert Watson 238e3edab4aSRobert Watson fill_char = arg[0]; 239e3edab4aSRobert Watson } 240e3edab4aSRobert Watson 241e3edab4aSRobert Watson static void 242f9bcb0beSWarner Losh f_ibs(char *arg) 2434b88c807SRodney W. Grimes { 244f4cfd28bSKurt Jaeger uintmax_t res; 2454b88c807SRodney W. Grimes 24654946e00SBrian Feldman if (!(ddflags & C_BS)) { 247f4cfd28bSKurt Jaeger res = get_num(arg); 248f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 249f4cfd28bSKurt Jaeger errx(1, "ibs must be between 1 and %jd", 250f4cfd28bSKurt Jaeger (intmax_t)SSIZE_MAX); 251f4cfd28bSKurt Jaeger in.dbsz = (size_t)res; 25254946e00SBrian Feldman } 2534b88c807SRodney W. Grimes } 2544b88c807SRodney W. Grimes 2554b88c807SRodney W. Grimes static void 256f9bcb0beSWarner Losh f_if(char *arg) 2574b88c807SRodney W. Grimes { 2584b88c807SRodney W. Grimes 2594b88c807SRodney W. Grimes in.name = arg; 2604b88c807SRodney W. Grimes } 2614b88c807SRodney W. Grimes 2624b88c807SRodney W. Grimes static void 263f9bcb0beSWarner Losh f_obs(char *arg) 2644b88c807SRodney W. Grimes { 265f4cfd28bSKurt Jaeger uintmax_t res; 2664b88c807SRodney W. Grimes 26754946e00SBrian Feldman if (!(ddflags & C_BS)) { 268f4cfd28bSKurt Jaeger res = get_num(arg); 269f4cfd28bSKurt Jaeger if (res < 1 || res > SSIZE_MAX) 270f4cfd28bSKurt Jaeger errx(1, "obs must be between 1 and %jd", 271f4cfd28bSKurt Jaeger (intmax_t)SSIZE_MAX); 272f4cfd28bSKurt Jaeger out.dbsz = (size_t)res; 27354946e00SBrian Feldman } 2744b88c807SRodney W. Grimes } 2754b88c807SRodney W. Grimes 2764b88c807SRodney W. Grimes static void 277f9bcb0beSWarner Losh f_of(char *arg) 2784b88c807SRodney W. Grimes { 2794b88c807SRodney W. Grimes 2804b88c807SRodney W. Grimes out.name = arg; 2814b88c807SRodney W. Grimes } 2824b88c807SRodney W. Grimes 2834b88c807SRodney W. Grimes static void 284f9bcb0beSWarner Losh f_seek(char *arg) 2854b88c807SRodney W. Grimes { 2864b88c807SRodney W. Grimes 2874ed95537SBrian Feldman out.offset = get_off_t(arg); 2884b88c807SRodney W. Grimes } 2894b88c807SRodney W. Grimes 2904b88c807SRodney W. Grimes static void 291f9bcb0beSWarner Losh f_skip(char *arg) 2924b88c807SRodney W. Grimes { 2934b88c807SRodney W. Grimes 2944ed95537SBrian Feldman in.offset = get_off_t(arg); 2954b88c807SRodney W. Grimes } 2964b88c807SRodney W. Grimes 297c3f5e9c5SXin LI static void 298c3f5e9c5SXin LI f_status(char *arg) 299c3f5e9c5SXin LI { 300c3f5e9c5SXin LI 301c3f5e9c5SXin LI if (strcmp(arg, "none") == 0) 302c3f5e9c5SXin LI ddflags |= C_NOINFO; 303c3f5e9c5SXin LI else if (strcmp(arg, "noxfer") == 0) 304c3f5e9c5SXin LI ddflags |= C_NOXFER; 305c3f5e9c5SXin LI else 306c3f5e9c5SXin LI errx(1, "unknown status %s", arg); 307c3f5e9c5SXin LI } 308c3f5e9c5SXin LI 30958687472SBrian Feldman static const struct conv { 31067f80d12SBrian Feldman const char *name; 3114b88c807SRodney W. Grimes u_int set, noset; 31258687472SBrian Feldman const u_char *ctab; 3134b88c807SRodney W. Grimes } clist[] = { 3144b88c807SRodney W. Grimes { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 3154b88c807SRodney W. Grimes { "block", C_BLOCK, C_UNBLOCK, NULL }, 3164b88c807SRodney W. Grimes { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 3174b88c807SRodney W. Grimes { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 3184b88c807SRodney W. Grimes { "lcase", C_LCASE, C_UCASE, NULL }, 3194b88c807SRodney W. Grimes { "noerror", C_NOERROR, 0, NULL }, 3204b88c807SRodney W. Grimes { "notrunc", C_NOTRUNC, 0, NULL }, 3214b88c807SRodney W. Grimes { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 3224b88c807SRodney W. Grimes { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 3234b88c807SRodney W. Grimes { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 3244b88c807SRodney W. Grimes { "osync", C_OSYNC, C_BS, NULL }, 3256a3d33acSPoul-Henning Kamp { "pareven", C_PAREVEN, C_PARODD|C_PARSET|C_PARNONE, NULL}, 3266a3d33acSPoul-Henning Kamp { "parnone", C_PARNONE, C_PARODD|C_PARSET|C_PAREVEN, NULL}, 3276a3d33acSPoul-Henning Kamp { "parodd", C_PARODD, C_PAREVEN|C_PARSET|C_PARNONE, NULL}, 3286a3d33acSPoul-Henning Kamp { "parset", C_PARSET, C_PARODD|C_PAREVEN|C_PARNONE, NULL}, 3291898febeSJoerg Wunsch { "sparse", C_SPARSE, 0, NULL }, 3304b88c807SRodney W. Grimes { "swab", C_SWAB, 0, NULL }, 3314b88c807SRodney W. Grimes { "sync", C_SYNC, 0, NULL }, 3324b88c807SRodney W. Grimes { "ucase", C_UCASE, C_LCASE, NULL }, 3334b88c807SRodney W. Grimes { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 3344b88c807SRodney W. Grimes }; 3354b88c807SRodney W. Grimes 3364b88c807SRodney W. Grimes static void 337f9bcb0beSWarner Losh f_conv(char *arg) 3384b88c807SRodney W. Grimes { 3394b88c807SRodney W. Grimes struct conv *cp, tmp; 3404b88c807SRodney W. Grimes 3414b88c807SRodney W. Grimes while (arg != NULL) { 3424b88c807SRodney W. Grimes tmp.name = strsep(&arg, ","); 34358687472SBrian Feldman cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 34458687472SBrian Feldman sizeof(struct conv), c_conv); 34558687472SBrian Feldman if (cp == NULL) 3464b88c807SRodney W. Grimes errx(1, "unknown conversion %s", tmp.name); 3474b88c807SRodney W. Grimes if (ddflags & cp->noset) 3484b88c807SRodney W. Grimes errx(1, "%s: illegal conversion combination", tmp.name); 3494b88c807SRodney W. Grimes ddflags |= cp->set; 3504b88c807SRodney W. Grimes if (cp->ctab) 3514b88c807SRodney W. Grimes ctab = cp->ctab; 3524b88c807SRodney W. Grimes } 3534b88c807SRodney W. Grimes } 3544b88c807SRodney W. Grimes 3554b88c807SRodney W. Grimes static int 356f9bcb0beSWarner Losh c_conv(const void *a, const void *b) 3574b88c807SRodney W. Grimes { 3584b88c807SRodney W. Grimes 359dd923702SBrian Feldman return (strcmp(((const struct conv *)a)->name, 360dd923702SBrian Feldman ((const struct conv *)b)->name)); 3614b88c807SRodney W. Grimes } 3624b88c807SRodney W. Grimes 36366d082c8SEdward Tomasz Napierala static uintmax_t 36466d082c8SEdward Tomasz Napierala postfix_to_mult(const char expr) 36566d082c8SEdward Tomasz Napierala { 36666d082c8SEdward Tomasz Napierala uintmax_t mult; 36766d082c8SEdward Tomasz Napierala 36866d082c8SEdward Tomasz Napierala mult = 0; 36966d082c8SEdward Tomasz Napierala switch (expr) { 37066d082c8SEdward Tomasz Napierala case 'B': 37166d082c8SEdward Tomasz Napierala case 'b': 37266d082c8SEdward Tomasz Napierala mult = 512; 37366d082c8SEdward Tomasz Napierala break; 37466d082c8SEdward Tomasz Napierala case 'K': 37566d082c8SEdward Tomasz Napierala case 'k': 37666d082c8SEdward Tomasz Napierala mult = 1 << 10; 37766d082c8SEdward Tomasz Napierala break; 37866d082c8SEdward Tomasz Napierala case 'M': 37966d082c8SEdward Tomasz Napierala case 'm': 38066d082c8SEdward Tomasz Napierala mult = 1 << 20; 38166d082c8SEdward Tomasz Napierala break; 38266d082c8SEdward Tomasz Napierala case 'G': 38366d082c8SEdward Tomasz Napierala case 'g': 38466d082c8SEdward Tomasz Napierala mult = 1 << 30; 38566d082c8SEdward Tomasz Napierala break; 386e53d0abfSEdward Tomasz Napierala case 'T': 387e53d0abfSEdward Tomasz Napierala case 't': 388e53d0abfSEdward Tomasz Napierala mult = (uintmax_t)1 << 40; 389e53d0abfSEdward Tomasz Napierala break; 390e53d0abfSEdward Tomasz Napierala case 'P': 391e53d0abfSEdward Tomasz Napierala case 'p': 392e53d0abfSEdward Tomasz Napierala mult = (uintmax_t)1 << 50; 393e53d0abfSEdward Tomasz Napierala break; 39466d082c8SEdward Tomasz Napierala case 'W': 39566d082c8SEdward Tomasz Napierala case 'w': 39666d082c8SEdward Tomasz Napierala mult = sizeof(int); 39766d082c8SEdward Tomasz Napierala break; 39866d082c8SEdward Tomasz Napierala } 39966d082c8SEdward Tomasz Napierala 40066d082c8SEdward Tomasz Napierala return (mult); 40166d082c8SEdward Tomasz Napierala } 40266d082c8SEdward Tomasz Napierala 4034b88c807SRodney W. Grimes /* 4047503d74fSMark Murray * Convert an expression of the following forms to a uintmax_t. 4054b88c807SRodney W. Grimes * 1) A positive decimal number. 4061e1d03d7SPawel Jakub Dawidek * 2) A positive decimal number followed by a 'b' or 'B' (mult by 512). 4071e1d03d7SPawel Jakub Dawidek * 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10). 4081e1d03d7SPawel Jakub Dawidek * 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20). 4091e1d03d7SPawel Jakub Dawidek * 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30). 4101e1d03d7SPawel Jakub Dawidek * 5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int). 4111e1d03d7SPawel Jakub Dawidek * 6) Two or more positive decimal numbers (with/without [BbKkMmGgWw]) 4121e1d03d7SPawel Jakub Dawidek * separated by 'x' or 'X' (also '*' for backwards compatibility), 4131e1d03d7SPawel Jakub Dawidek * specifying the product of the indicated values. 4144b88c807SRodney W. Grimes */ 4157503d74fSMark Murray static uintmax_t 416f9bcb0beSWarner Losh get_num(const char *val) 4174b88c807SRodney W. Grimes { 4187503d74fSMark Murray uintmax_t num, mult, prevnum; 4194ed95537SBrian Feldman char *expr; 4204ed95537SBrian Feldman 4214ed95537SBrian Feldman errno = 0; 422*d8192361SEdward Tomasz Napierala num = strtoumax(val, &expr, 0); 4234ed95537SBrian Feldman if (errno != 0) /* Overflow or underflow. */ 4244ed95537SBrian Feldman err(1, "%s", oper); 4254ed95537SBrian Feldman 4264ed95537SBrian Feldman if (expr == val) /* No valid digits. */ 4274ed95537SBrian Feldman errx(1, "%s: illegal numeric value", oper); 4284ed95537SBrian Feldman 42966d082c8SEdward Tomasz Napierala mult = postfix_to_mult(*expr); 4304ed95537SBrian Feldman 4314ed95537SBrian Feldman if (mult != 0) { 4324ed95537SBrian Feldman prevnum = num; 4334ed95537SBrian Feldman num *= mult; 4344ed95537SBrian Feldman /* Check for overflow. */ 4354ed95537SBrian Feldman if (num / mult != prevnum) 4364ed95537SBrian Feldman goto erange; 4374ed95537SBrian Feldman expr++; 4384ed95537SBrian Feldman } 4394ed95537SBrian Feldman 4404ed95537SBrian Feldman switch (*expr) { 4414ed95537SBrian Feldman case '\0': 4424ed95537SBrian Feldman break; 4434ed95537SBrian Feldman case '*': /* Backward compatible. */ 4441e1d03d7SPawel Jakub Dawidek case 'X': 4454ed95537SBrian Feldman case 'x': 4464ed95537SBrian Feldman mult = get_num(expr + 1); 4474ed95537SBrian Feldman prevnum = num; 4484ed95537SBrian Feldman num *= mult; 4494ed95537SBrian Feldman if (num / mult == prevnum) 4504ed95537SBrian Feldman break; 4514ed95537SBrian Feldman erange: 4524ed95537SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 4534ed95537SBrian Feldman default: 4544ed95537SBrian Feldman errx(1, "%s: illegal numeric value", oper); 4554ed95537SBrian Feldman } 4564ed95537SBrian Feldman return (num); 4574ed95537SBrian Feldman } 4584ed95537SBrian Feldman 4594ed95537SBrian Feldman /* 4604ed95537SBrian Feldman * Convert an expression of the following forms to an off_t. This is the 4614ed95537SBrian Feldman * same as get_num(), but it uses signed numbers. 4624ed95537SBrian Feldman * 4637503d74fSMark Murray * The major problem here is that an off_t may not necessarily be a intmax_t. 4644ed95537SBrian Feldman */ 4654ed95537SBrian Feldman static off_t 466f9bcb0beSWarner Losh get_off_t(const char *val) 4674ed95537SBrian Feldman { 4687503d74fSMark Murray intmax_t num, mult, prevnum; 4694b88c807SRodney W. Grimes char *expr; 4704b88c807SRodney W. Grimes 47154946e00SBrian Feldman errno = 0; 472*d8192361SEdward Tomasz Napierala num = strtoimax(val, &expr, 0); 47358687472SBrian Feldman if (errno != 0) /* Overflow or underflow. */ 47454946e00SBrian Feldman err(1, "%s", oper); 47554946e00SBrian Feldman 47658687472SBrian Feldman if (expr == val) /* No valid digits. */ 4774b88c807SRodney W. Grimes errx(1, "%s: illegal numeric value", oper); 4784b88c807SRodney W. Grimes 47966d082c8SEdward Tomasz Napierala mult = postfix_to_mult(*expr); 4804b88c807SRodney W. Grimes 4814ed95537SBrian Feldman if (mult != 0) { 4824ed95537SBrian Feldman prevnum = num; 4834ed95537SBrian Feldman num *= mult; 4844ed95537SBrian Feldman /* Check for overflow. */ 4854ed95537SBrian Feldman if ((prevnum > 0) != (num > 0) || num / mult != prevnum) 4864ed95537SBrian Feldman goto erange; 4874ed95537SBrian Feldman expr++; 4884ed95537SBrian Feldman } 4894ed95537SBrian Feldman 4904b88c807SRodney W. Grimes switch (*expr) { 4914b88c807SRodney W. Grimes case '\0': 4924b88c807SRodney W. Grimes break; 4934b88c807SRodney W. Grimes case '*': /* Backward compatible. */ 4941e1d03d7SPawel Jakub Dawidek case 'X': 4954b88c807SRodney W. Grimes case 'x': 4967503d74fSMark Murray mult = (intmax_t)get_off_t(expr + 1); 4974ed95537SBrian Feldman prevnum = num; 4984ed95537SBrian Feldman num *= mult; 4992fb08072SBrian Feldman if ((prevnum > 0) == (num > 0) && num / mult == prevnum) 5004b88c807SRodney W. Grimes break; 501e14f7e78SBrian Feldman erange: 502e14f7e78SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 5034b88c807SRodney W. Grimes default: 5044b88c807SRodney W. Grimes errx(1, "%s: illegal numeric value", oper); 5054b88c807SRodney W. Grimes } 5064b88c807SRodney W. Grimes return (num); 5074b88c807SRodney W. Grimes } 508