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 * 3. All advertising materials mentioning features or use of this software 184b88c807SRodney W. Grimes * must display the following acknowledgement: 194b88c807SRodney W. Grimes * This product includes software developed by the University of 204b88c807SRodney W. Grimes * California, Berkeley and its contributors. 214b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 224b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 234b88c807SRodney W. Grimes * without specific prior written permission. 244b88c807SRodney W. Grimes * 254b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 264b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 274b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 284b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 294b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 304b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 314b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 324b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 334b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 344b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 354b88c807SRodney W. Grimes * SUCH DAMAGE. 364b88c807SRodney W. Grimes */ 374b88c807SRodney W. Grimes 384b88c807SRodney W. Grimes #ifndef lint 39cbf6f7d3SPhilippe Charnier #if 0 401ba0e048SPhilippe Charnier static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94"; 41cbf6f7d3SPhilippe Charnier #endif 42cbf6f7d3SPhilippe Charnier static const char rcsid[] = 432a456239SPeter Wemm "$FreeBSD$"; 444b88c807SRodney W. Grimes #endif /* not lint */ 454b88c807SRodney W. Grimes 464b88c807SRodney W. Grimes #include <sys/types.h> 474b88c807SRodney W. Grimes 484b88c807SRodney W. Grimes #include <err.h> 494b88c807SRodney W. Grimes #include <errno.h> 504b88c807SRodney W. Grimes #include <limits.h> 514b88c807SRodney W. Grimes #include <stdlib.h> 524b88c807SRodney W. Grimes #include <string.h> 534b88c807SRodney W. Grimes 544b88c807SRodney W. Grimes #include "dd.h" 554b88c807SRodney W. Grimes #include "extern.h" 564b88c807SRodney W. Grimes 57f9bcb0beSWarner Losh static int c_arg(const void *, const void *); 58f9bcb0beSWarner Losh static int c_conv(const void *, const void *); 59f9bcb0beSWarner Losh static void f_bs(char *); 60f9bcb0beSWarner Losh static void f_cbs(char *); 61f9bcb0beSWarner Losh static void f_conv(char *); 62f9bcb0beSWarner Losh static void f_count(char *); 63f9bcb0beSWarner Losh static void f_files(char *); 64f9bcb0beSWarner Losh static void f_ibs(char *); 65f9bcb0beSWarner Losh static void f_if(char *); 66f9bcb0beSWarner Losh static void f_obs(char *); 67f9bcb0beSWarner Losh static void f_of(char *); 68f9bcb0beSWarner Losh static void f_seek(char *); 69f9bcb0beSWarner Losh static void f_skip(char *); 70f9bcb0beSWarner Losh static u_quad_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 }, 834b88c807SRodney W. Grimes { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 844b88c807SRodney W. Grimes { "if", f_if, C_IF, C_IF }, 85a6d413e7SBrian Feldman { "iseek", f_skip, C_SKIP, C_SKIP }, 864b88c807SRodney W. Grimes { "obs", f_obs, C_OBS, C_BS|C_OBS }, 874b88c807SRodney W. Grimes { "of", f_of, C_OF, C_OF }, 88a6d413e7SBrian Feldman { "oseek", f_seek, C_SEEK, C_SEEK }, 894b88c807SRodney W. Grimes { "seek", f_seek, C_SEEK, C_SEEK }, 904b88c807SRodney W. Grimes { "skip", f_skip, C_SKIP, C_SKIP }, 914b88c807SRodney W. Grimes }; 924b88c807SRodney W. Grimes 934b88c807SRodney W. Grimes static char *oper; 944b88c807SRodney W. Grimes 954b88c807SRodney W. Grimes /* 964b88c807SRodney W. Grimes * args -- parse JCL syntax of dd. 974b88c807SRodney W. Grimes */ 984b88c807SRodney W. Grimes void 99f9bcb0beSWarner Losh jcl(char **argv) 1004b88c807SRodney W. Grimes { 1014b88c807SRodney W. Grimes struct arg *ap, tmp; 1024b88c807SRodney W. Grimes char *arg; 1034b88c807SRodney W. Grimes 1044b88c807SRodney W. Grimes in.dbsz = out.dbsz = 512; 1054b88c807SRodney W. Grimes 106ad66f7eeSPoul-Henning Kamp while ((oper = *++argv) != NULL) { 1074c339742SEivind Eklund if ((oper = strdup(oper)) == NULL) 10854946e00SBrian Feldman errx(1, "unable to allocate space for the argument \"%s\"", *argv); 1094b88c807SRodney W. Grimes if ((arg = strchr(oper, '=')) == NULL) 1104b88c807SRodney W. Grimes errx(1, "unknown operand %s", oper); 1114b88c807SRodney W. Grimes *arg++ = '\0'; 1124b88c807SRodney W. Grimes if (!*arg) 1134b88c807SRodney W. Grimes errx(1, "no value specified for %s", oper); 1144b88c807SRodney W. Grimes tmp.name = oper; 11554946e00SBrian Feldman if (!(ap = (struct arg *)bsearch(&tmp, args, 11654946e00SBrian Feldman sizeof(args)/sizeof(struct arg), sizeof(struct arg), 11754946e00SBrian Feldman c_arg))) 1184b88c807SRodney W. Grimes errx(1, "unknown operand %s", tmp.name); 1194b88c807SRodney W. Grimes if (ddflags & ap->noset) 12054946e00SBrian Feldman errx(1, "%s: illegal argument combination or already set", 12154946e00SBrian Feldman tmp.name); 1224b88c807SRodney W. Grimes ddflags |= ap->set; 1234b88c807SRodney W. Grimes ap->f(arg); 1244b88c807SRodney W. Grimes } 1254b88c807SRodney W. Grimes 1264b88c807SRodney W. Grimes /* Final sanity checks. */ 1274b88c807SRodney W. Grimes 1284b88c807SRodney W. Grimes if (ddflags & C_BS) { 1294b88c807SRodney W. Grimes /* 1304b88c807SRodney W. Grimes * Bs is turned off by any conversion -- we assume the user 1314b88c807SRodney W. Grimes * just wanted to set both the input and output block sizes 1324b88c807SRodney W. Grimes * and didn't want the bs semantics, so we don't warn. 1334b88c807SRodney W. Grimes */ 134c15c898eSBrian Feldman if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE | 135c15c898eSBrian Feldman C_UNBLOCK)) 1364b88c807SRodney W. Grimes ddflags &= ~C_BS; 1374b88c807SRodney W. Grimes 1384b88c807SRodney W. Grimes /* Bs supersedes ibs and obs. */ 1394b88c807SRodney W. Grimes if (ddflags & C_BS && ddflags & (C_IBS | C_OBS)) 1404b88c807SRodney W. Grimes warnx("bs supersedes ibs and obs"); 1414b88c807SRodney W. Grimes } 1424b88c807SRodney W. Grimes 1434b88c807SRodney W. Grimes /* 1444b88c807SRodney W. Grimes * Ascii/ebcdic and cbs implies block/unblock. 1454b88c807SRodney W. Grimes * Block/unblock requires cbs and vice-versa. 1464b88c807SRodney W. Grimes */ 1474b88c807SRodney W. Grimes if (ddflags & (C_BLOCK | C_UNBLOCK)) { 1484b88c807SRodney W. Grimes if (!(ddflags & C_CBS)) 1494b88c807SRodney W. Grimes errx(1, "record operations require cbs"); 1504b88c807SRodney W. Grimes if (cbsz == 0) 1514b88c807SRodney W. Grimes errx(1, "cbs cannot be zero"); 1524b88c807SRodney W. Grimes cfunc = ddflags & C_BLOCK ? block : unblock; 1534b88c807SRodney W. Grimes } else if (ddflags & C_CBS) { 1544b88c807SRodney W. Grimes if (ddflags & (C_ASCII | C_EBCDIC)) { 1554b88c807SRodney W. Grimes if (ddflags & C_ASCII) { 1564b88c807SRodney W. Grimes ddflags |= C_UNBLOCK; 1574b88c807SRodney W. Grimes cfunc = unblock; 1584b88c807SRodney W. Grimes } else { 1594b88c807SRodney W. Grimes ddflags |= C_BLOCK; 1604b88c807SRodney W. Grimes cfunc = block; 1614b88c807SRodney W. Grimes } 1624b88c807SRodney W. Grimes } else 1634b88c807SRodney W. Grimes errx(1, "cbs meaningless if not doing record operations"); 1644b88c807SRodney W. Grimes } else 1654b88c807SRodney W. Grimes cfunc = def; 1667599187eSBrian Feldman 16758687472SBrian Feldman /* 16858687472SBrian Feldman * Bail out if the calculation of a file offset would overflow. 16958687472SBrian Feldman */ 17058687472SBrian Feldman if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz) 17158687472SBrian Feldman errx(1, "seek offsets cannot be larger than %qd", QUAD_MAX); 1724b88c807SRodney W. Grimes } 1734b88c807SRodney W. Grimes 1744b88c807SRodney W. Grimes static int 175f9bcb0beSWarner Losh c_arg(const void *a, const void *b) 1764b88c807SRodney W. Grimes { 1774b88c807SRodney W. Grimes 178dd923702SBrian Feldman return (strcmp(((const struct arg *)a)->name, 179dd923702SBrian Feldman ((const struct arg *)b)->name)); 1804b88c807SRodney W. Grimes } 1814b88c807SRodney W. Grimes 1824b88c807SRodney W. Grimes static void 183f9bcb0beSWarner Losh f_bs(char *arg) 1844b88c807SRodney W. Grimes { 1854ed95537SBrian Feldman u_quad_t res; 1864b88c807SRodney W. Grimes 18758687472SBrian Feldman res = get_num(arg); 18858687472SBrian Feldman if (res < 1 || res > SSIZE_MAX) 18958687472SBrian Feldman errx(1, "bs must be between 1 and %d", SSIZE_MAX); 19058687472SBrian Feldman in.dbsz = out.dbsz = (size_t)res; 1914b88c807SRodney W. Grimes } 1924b88c807SRodney W. Grimes 1934b88c807SRodney W. Grimes static void 194f9bcb0beSWarner Losh f_cbs(char *arg) 1954b88c807SRodney W. Grimes { 1964ed95537SBrian Feldman u_quad_t res; 1974b88c807SRodney W. Grimes 19858687472SBrian Feldman res = get_num(arg); 19958687472SBrian Feldman if (res < 1 || res > SSIZE_MAX) 20058687472SBrian Feldman errx(1, "cbs must be between 1 and %d", SSIZE_MAX); 20158687472SBrian Feldman cbsz = (size_t)res; 2024b88c807SRodney W. Grimes } 2034b88c807SRodney W. Grimes 2044b88c807SRodney W. Grimes static void 205f9bcb0beSWarner Losh f_count(char *arg) 2064b88c807SRodney W. Grimes { 2074ed95537SBrian Feldman u_quad_t res; 2084b88c807SRodney W. Grimes 2094ed95537SBrian Feldman res = get_num(arg); 2104ed95537SBrian Feldman if ((quad_t)res < 0) 2111838cf56SBrian Feldman errx(1, "count cannot be negative"); 2124ed95537SBrian Feldman if (res == 0) 2135ff6541eSBrian Feldman cpy_cnt = -1; 2144ed95537SBrian Feldman else 2154ed95537SBrian Feldman cpy_cnt = (quad_t)res; 2164b88c807SRodney W. Grimes } 2174b88c807SRodney W. Grimes 2184b88c807SRodney W. Grimes static void 219f9bcb0beSWarner Losh f_files(char *arg) 2204b88c807SRodney W. Grimes { 2214b88c807SRodney W. Grimes 222e14f7e78SBrian Feldman files_cnt = get_num(arg); 2237599187eSBrian Feldman if (files_cnt < 1) 2247599187eSBrian Feldman errx(1, "files must be between 1 and %qd", QUAD_MAX); 2254b88c807SRodney W. Grimes } 2264b88c807SRodney W. Grimes 2274b88c807SRodney W. Grimes static void 228f9bcb0beSWarner Losh f_ibs(char *arg) 2294b88c807SRodney W. Grimes { 2304ed95537SBrian Feldman u_quad_t res; 2314b88c807SRodney W. Grimes 23254946e00SBrian Feldman if (!(ddflags & C_BS)) { 23358687472SBrian Feldman res = get_num(arg); 23458687472SBrian Feldman if (res < 1 || res > SSIZE_MAX) 2357599187eSBrian Feldman errx(1, "ibs must be between 1 and %d", SSIZE_MAX); 2367599187eSBrian Feldman in.dbsz = (size_t)res; 23754946e00SBrian Feldman } 2384b88c807SRodney W. Grimes } 2394b88c807SRodney W. Grimes 2404b88c807SRodney W. Grimes static void 241f9bcb0beSWarner Losh f_if(char *arg) 2424b88c807SRodney W. Grimes { 2434b88c807SRodney W. Grimes 2444b88c807SRodney W. Grimes in.name = arg; 2454b88c807SRodney W. Grimes } 2464b88c807SRodney W. Grimes 2474b88c807SRodney W. Grimes static void 248f9bcb0beSWarner Losh f_obs(char *arg) 2494b88c807SRodney W. Grimes { 2504ed95537SBrian Feldman u_quad_t res; 2514b88c807SRodney W. Grimes 25254946e00SBrian Feldman if (!(ddflags & C_BS)) { 25358687472SBrian Feldman res = get_num(arg); 25458687472SBrian Feldman if (res < 1 || res > SSIZE_MAX) 25558687472SBrian Feldman errx(1, "obs must be between 1 and %d", SSIZE_MAX); 25658687472SBrian Feldman out.dbsz = (size_t)res; 25754946e00SBrian Feldman } 2584b88c807SRodney W. Grimes } 2594b88c807SRodney W. Grimes 2604b88c807SRodney W. Grimes static void 261f9bcb0beSWarner Losh f_of(char *arg) 2624b88c807SRodney W. Grimes { 2634b88c807SRodney W. Grimes 2644b88c807SRodney W. Grimes out.name = arg; 2654b88c807SRodney W. Grimes } 2664b88c807SRodney W. Grimes 2674b88c807SRodney W. Grimes static void 268f9bcb0beSWarner Losh f_seek(char *arg) 2694b88c807SRodney W. Grimes { 2704b88c807SRodney W. Grimes 2714ed95537SBrian Feldman out.offset = get_off_t(arg); 2724b88c807SRodney W. Grimes } 2734b88c807SRodney W. Grimes 2744b88c807SRodney W. Grimes static void 275f9bcb0beSWarner Losh f_skip(char *arg) 2764b88c807SRodney W. Grimes { 2774b88c807SRodney W. Grimes 2784ed95537SBrian Feldman in.offset = get_off_t(arg); 2794b88c807SRodney W. Grimes } 2804b88c807SRodney W. Grimes 28158687472SBrian Feldman static const struct conv { 28267f80d12SBrian Feldman const char *name; 2834b88c807SRodney W. Grimes u_int set, noset; 28458687472SBrian Feldman const u_char *ctab; 2854b88c807SRodney W. Grimes } clist[] = { 2864b88c807SRodney W. Grimes { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 2874b88c807SRodney W. Grimes { "block", C_BLOCK, C_UNBLOCK, NULL }, 2884b88c807SRodney W. Grimes { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 2894b88c807SRodney W. Grimes { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 2904b88c807SRodney W. Grimes { "lcase", C_LCASE, C_UCASE, NULL }, 2914b88c807SRodney W. Grimes { "noerror", C_NOERROR, 0, NULL }, 2924b88c807SRodney W. Grimes { "notrunc", C_NOTRUNC, 0, NULL }, 2934b88c807SRodney W. Grimes { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 2944b88c807SRodney W. Grimes { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 2954b88c807SRodney W. Grimes { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 2964b88c807SRodney W. Grimes { "osync", C_OSYNC, C_BS, NULL }, 2971898febeSJoerg Wunsch { "sparse", C_SPARSE, 0, NULL }, 2984b88c807SRodney W. Grimes { "swab", C_SWAB, 0, NULL }, 2994b88c807SRodney W. Grimes { "sync", C_SYNC, 0, NULL }, 3004b88c807SRodney W. Grimes { "ucase", C_UCASE, C_LCASE, NULL }, 3014b88c807SRodney W. Grimes { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 3024b88c807SRodney W. Grimes }; 3034b88c807SRodney W. Grimes 3044b88c807SRodney W. Grimes static void 305f9bcb0beSWarner Losh f_conv(char *arg) 3064b88c807SRodney W. Grimes { 3074b88c807SRodney W. Grimes struct conv *cp, tmp; 3084b88c807SRodney W. Grimes 3094b88c807SRodney W. Grimes while (arg != NULL) { 3104b88c807SRodney W. Grimes tmp.name = strsep(&arg, ","); 31158687472SBrian Feldman cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 31258687472SBrian Feldman sizeof(struct conv), c_conv); 31358687472SBrian Feldman if (cp == NULL) 3144b88c807SRodney W. Grimes errx(1, "unknown conversion %s", tmp.name); 3154b88c807SRodney W. Grimes if (ddflags & cp->noset) 3164b88c807SRodney W. Grimes errx(1, "%s: illegal conversion combination", tmp.name); 3174b88c807SRodney W. Grimes ddflags |= cp->set; 3184b88c807SRodney W. Grimes if (cp->ctab) 3194b88c807SRodney W. Grimes ctab = cp->ctab; 3204b88c807SRodney W. Grimes } 3214b88c807SRodney W. Grimes } 3224b88c807SRodney W. Grimes 3234b88c807SRodney W. Grimes static int 324f9bcb0beSWarner Losh c_conv(const void *a, const void *b) 3254b88c807SRodney W. Grimes { 3264b88c807SRodney W. Grimes 327dd923702SBrian Feldman return (strcmp(((const struct conv *)a)->name, 328dd923702SBrian Feldman ((const struct conv *)b)->name)); 3294b88c807SRodney W. Grimes } 3304b88c807SRodney W. Grimes 3314b88c807SRodney W. Grimes /* 3324ed95537SBrian Feldman * Convert an expression of the following forms to a u_quad_t. 3334b88c807SRodney W. Grimes * 1) A positive decimal number. 3344ed95537SBrian Feldman * 2) A positive decimal number followed by a b (mult by 512). 3354ed95537SBrian Feldman * 3) A positive decimal number followed by a k (mult by 1 << 10). 3364ed95537SBrian Feldman * 4) A positive decimal number followed by a m (mult by 1 << 20). 3374ed95537SBrian Feldman * 5) A positive decimal number followed by a g (mult by 1 << 30). 3384ed95537SBrian Feldman * 5) A positive decimal number followed by a w (mult by sizeof int). 33954946e00SBrian Feldman * 6) Two or more positive decimal numbers (with/without [bkmgw]) 34046be34b9SKris Kennaway * separated by x (also * for backwards compatibility), specifying 3414b88c807SRodney W. Grimes * the product of the indicated values. 3424b88c807SRodney W. Grimes */ 3434ed95537SBrian Feldman static u_quad_t 344f9bcb0beSWarner Losh get_num(const char *val) 3454b88c807SRodney W. Grimes { 3464ed95537SBrian Feldman u_quad_t num, mult, prevnum; 3474ed95537SBrian Feldman char *expr; 3484ed95537SBrian Feldman 3494ed95537SBrian Feldman errno = 0; 3504ed95537SBrian Feldman num = strtouq(val, &expr, 0); 3514ed95537SBrian Feldman if (errno != 0) /* Overflow or underflow. */ 3524ed95537SBrian Feldman err(1, "%s", oper); 3534ed95537SBrian Feldman 3544ed95537SBrian Feldman if (expr == val) /* No valid digits. */ 3554ed95537SBrian Feldman errx(1, "%s: illegal numeric value", oper); 3564ed95537SBrian Feldman 3574ed95537SBrian Feldman mult = 0; 3584ed95537SBrian Feldman switch (*expr) { 3594ed95537SBrian Feldman case 'b': 3604ed95537SBrian Feldman mult = 512; 3614ed95537SBrian Feldman break; 3624ed95537SBrian Feldman case 'k': 3634ed95537SBrian Feldman mult = 1 << 10; 3644ed95537SBrian Feldman break; 3654ed95537SBrian Feldman case 'm': 3664ed95537SBrian Feldman mult = 1 << 20; 3674ed95537SBrian Feldman break; 3684ed95537SBrian Feldman case 'g': 3694ed95537SBrian Feldman mult = 1 << 30; 3704ed95537SBrian Feldman break; 3714ed95537SBrian Feldman case 'w': 3724ed95537SBrian Feldman mult = sizeof(int); 3734ed95537SBrian Feldman break; 3744ed95537SBrian Feldman } 3754ed95537SBrian Feldman 3764ed95537SBrian Feldman if (mult != 0) { 3774ed95537SBrian Feldman prevnum = num; 3784ed95537SBrian Feldman num *= mult; 3794ed95537SBrian Feldman /* Check for overflow. */ 3804ed95537SBrian Feldman if (num / mult != prevnum) 3814ed95537SBrian Feldman goto erange; 3824ed95537SBrian Feldman expr++; 3834ed95537SBrian Feldman } 3844ed95537SBrian Feldman 3854ed95537SBrian Feldman switch (*expr) { 3864ed95537SBrian Feldman case '\0': 3874ed95537SBrian Feldman break; 3884ed95537SBrian Feldman case '*': /* Backward compatible. */ 3894ed95537SBrian Feldman case 'x': 3904ed95537SBrian Feldman mult = get_num(expr + 1); 3914ed95537SBrian Feldman prevnum = num; 3924ed95537SBrian Feldman num *= mult; 3934ed95537SBrian Feldman if (num / mult == prevnum) 3944ed95537SBrian Feldman break; 3954ed95537SBrian Feldman erange: 3964ed95537SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 3974ed95537SBrian Feldman default: 3984ed95537SBrian Feldman errx(1, "%s: illegal numeric value", oper); 3994ed95537SBrian Feldman } 4004ed95537SBrian Feldman return (num); 4014ed95537SBrian Feldman } 4024ed95537SBrian Feldman 4034ed95537SBrian Feldman /* 4044ed95537SBrian Feldman * Convert an expression of the following forms to an off_t. This is the 4054ed95537SBrian Feldman * same as get_num(), but it uses signed numbers. 4064ed95537SBrian Feldman * 4074ed95537SBrian Feldman * The major problem here is that an off_t may not necessarily be a quad_t. 4084ed95537SBrian Feldman * The right thing to do would be to use intmax_t when available and then 4094ed95537SBrian Feldman * cast down to an off_t, if possible. 4104ed95537SBrian Feldman */ 4114ed95537SBrian Feldman static off_t 412f9bcb0beSWarner Losh get_off_t(const char *val) 4134ed95537SBrian Feldman { 4144ed95537SBrian Feldman quad_t num, mult, prevnum; 4154b88c807SRodney W. Grimes char *expr; 4164b88c807SRodney W. Grimes 41754946e00SBrian Feldman errno = 0; 418767bc8adSBrian Feldman num = strtoq(val, &expr, 0); 41958687472SBrian Feldman if (errno != 0) /* Overflow or underflow. */ 42054946e00SBrian Feldman err(1, "%s", oper); 42154946e00SBrian Feldman 42258687472SBrian Feldman if (expr == val) /* No valid digits. */ 4234b88c807SRodney W. Grimes errx(1, "%s: illegal numeric value", oper); 4244b88c807SRodney W. Grimes 4254ed95537SBrian Feldman mult = 0; 4264b88c807SRodney W. Grimes switch (*expr) { 4274b88c807SRodney W. Grimes case 'b': 4284ed95537SBrian Feldman mult = 512; 4294b88c807SRodney W. Grimes break; 4304b88c807SRodney W. Grimes case 'k': 4314ed95537SBrian Feldman mult = 1 << 10; 4324b88c807SRodney W. Grimes break; 4334b88c807SRodney W. Grimes case 'm': 4344ed95537SBrian Feldman mult = 1 << 20; 43554946e00SBrian Feldman break; 43654946e00SBrian Feldman case 'g': 4374ed95537SBrian Feldman mult = 1 << 30; 4384b88c807SRodney W. Grimes break; 4394b88c807SRodney W. Grimes case 'w': 4404ed95537SBrian Feldman mult = sizeof(int); 4414b88c807SRodney W. Grimes break; 4424b88c807SRodney W. Grimes } 4434b88c807SRodney W. Grimes 4444ed95537SBrian Feldman if (mult != 0) { 4454ed95537SBrian Feldman prevnum = num; 4464ed95537SBrian Feldman num *= mult; 4474ed95537SBrian Feldman /* Check for overflow. */ 4484ed95537SBrian Feldman if ((prevnum > 0) != (num > 0) || num / mult != prevnum) 4494ed95537SBrian Feldman goto erange; 4504ed95537SBrian Feldman expr++; 4514ed95537SBrian Feldman } 4524ed95537SBrian Feldman 4534b88c807SRodney W. Grimes switch (*expr) { 4544b88c807SRodney W. Grimes case '\0': 4554b88c807SRodney W. Grimes break; 4564b88c807SRodney W. Grimes case '*': /* Backward compatible. */ 4574b88c807SRodney W. Grimes case 'x': 4584ed95537SBrian Feldman mult = (quad_t)get_off_t(expr + 1); 4594ed95537SBrian Feldman prevnum = num; 4604ed95537SBrian Feldman num *= mult; 4612fb08072SBrian Feldman if ((prevnum > 0) == (num > 0) && num / mult == prevnum) 4624b88c807SRodney W. Grimes break; 463e14f7e78SBrian Feldman erange: 464e14f7e78SBrian Feldman errx(1, "%s: %s", oper, strerror(ERANGE)); 4654b88c807SRodney W. Grimes default: 4664b88c807SRodney W. Grimes errx(1, "%s: illegal numeric value", oper); 4674b88c807SRodney W. Grimes } 4684b88c807SRodney W. Grimes return (num); 4694b88c807SRodney W. Grimes } 470