11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993, 1994
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Keith Muller of the University of California, San Diego and Lance
71556Srgrimes * Visser of Convex Computer Corporation.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3535773Scharnier#if 0
3636007Scharnierstatic char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
3735773Scharnier#endif
381556Srgrimes#endif /* not lint */
3999109Sobrien#include <sys/cdefs.h>
4099109Sobrien__FBSDID("$FreeBSD: stable/10/bin/dd/args.c 321140 2017-07-18 17:36:25Z ngie $");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes
441556Srgrimes#include <err.h>
451556Srgrimes#include <errno.h>
46111629Smarkm#include <inttypes.h>
471556Srgrimes#include <limits.h>
48250469Seadler#include <signal.h>
491556Srgrimes#include <stdlib.h>
501556Srgrimes#include <string.h>
511556Srgrimes
521556Srgrimes#include "dd.h"
531556Srgrimes#include "extern.h"
541556Srgrimes
5590108Simpstatic int	c_arg(const void *, const void *);
5690108Simpstatic int	c_conv(const void *, const void *);
5790108Simpstatic void	f_bs(char *);
5890108Simpstatic void	f_cbs(char *);
5990108Simpstatic void	f_conv(char *);
6090108Simpstatic void	f_count(char *);
6190108Simpstatic void	f_files(char *);
62133762Srwatsonstatic void	f_fillchar(char *);
6390108Simpstatic void	f_ibs(char *);
6490108Simpstatic void	f_if(char *);
6590108Simpstatic void	f_obs(char *);
6690108Simpstatic void	f_of(char *);
6790108Simpstatic void	f_seek(char *);
6890108Simpstatic void	f_skip(char *);
69264577Sdelphijstatic void	f_status(char *);
70111629Smarkmstatic uintmax_t get_num(const char *);
7190108Simpstatic off_t	get_off_t(const char *);
721556Srgrimes
7351208Sgreenstatic const struct arg {
7454245Sgreen	const char *name;
7590108Simp	void (*f)(char *);
761556Srgrimes	u_int set, noset;
771556Srgrimes} args[] = {
781556Srgrimes	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
791556Srgrimes	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
801556Srgrimes	{ "conv",	f_conv,		0,	 0 },
811556Srgrimes	{ "count",	f_count,	C_COUNT, C_COUNT },
821556Srgrimes	{ "files",	f_files,	C_FILES, C_FILES },
83133762Srwatson	{ "fillchar",	f_fillchar,	C_FILL,	 C_FILL },
841556Srgrimes	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
851556Srgrimes	{ "if",		f_if,		C_IF,	 C_IF },
8657523Sgreen	{ "iseek",	f_skip,		C_SKIP,	 C_SKIP },
871556Srgrimes	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
881556Srgrimes	{ "of",		f_of,		C_OF,	 C_OF },
8957523Sgreen	{ "oseek",	f_seek,		C_SEEK,	 C_SEEK },
901556Srgrimes	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
911556Srgrimes	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
92264577Sdelphij	{ "status",	f_status,	C_STATUS,C_STATUS },
931556Srgrimes};
941556Srgrimes
951556Srgrimesstatic char *oper;
961556Srgrimes
971556Srgrimes/*
981556Srgrimes * args -- parse JCL syntax of dd.
991556Srgrimes */
1001556Srgrimesvoid
10190108Simpjcl(char **argv)
1021556Srgrimes{
1031556Srgrimes	struct arg *ap, tmp;
1041556Srgrimes	char *arg;
1051556Srgrimes
1061556Srgrimes	in.dbsz = out.dbsz = 512;
1071556Srgrimes
10819720Sphk	while ((oper = *++argv) != NULL) {
10930230Seivind		if ((oper = strdup(oper)) == NULL)
11048051Sgreen			errx(1, "unable to allocate space for the argument \"%s\"", *argv);
1111556Srgrimes		if ((arg = strchr(oper, '=')) == NULL)
1121556Srgrimes			errx(1, "unknown operand %s", oper);
1131556Srgrimes		*arg++ = '\0';
1141556Srgrimes		if (!*arg)
1151556Srgrimes			errx(1, "no value specified for %s", oper);
1161556Srgrimes		tmp.name = oper;
11748051Sgreen		if (!(ap = (struct arg *)bsearch(&tmp, args,
11848051Sgreen		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
11948051Sgreen		    c_arg)))
1201556Srgrimes			errx(1, "unknown operand %s", tmp.name);
1211556Srgrimes		if (ddflags & ap->noset)
12248051Sgreen			errx(1, "%s: illegal argument combination or already set",
12348051Sgreen			    tmp.name);
1241556Srgrimes		ddflags |= ap->set;
1251556Srgrimes		ap->f(arg);
1261556Srgrimes	}
1271556Srgrimes
1281556Srgrimes	/* Final sanity checks. */
1291556Srgrimes
1301556Srgrimes	if (ddflags & C_BS) {
1311556Srgrimes		/*
1321556Srgrimes		 * Bs is turned off by any conversion -- we assume the user
1331556Srgrimes		 * just wanted to set both the input and output block sizes
1341556Srgrimes		 * and didn't want the bs semantics, so we don't warn.
1351556Srgrimes		 */
13662311Sgreen		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
13762311Sgreen		    C_UNBLOCK))
1381556Srgrimes			ddflags &= ~C_BS;
1391556Srgrimes
1401556Srgrimes		/* Bs supersedes ibs and obs. */
14162311Sgreen		if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
1421556Srgrimes			warnx("bs supersedes ibs and obs");
1431556Srgrimes	}
1441556Srgrimes
1451556Srgrimes	/*
1461556Srgrimes	 * Ascii/ebcdic and cbs implies block/unblock.
1471556Srgrimes	 * Block/unblock requires cbs and vice-versa.
1481556Srgrimes	 */
14951249Sgreen	if (ddflags & (C_BLOCK | C_UNBLOCK)) {
1501556Srgrimes		if (!(ddflags & C_CBS))
1511556Srgrimes			errx(1, "record operations require cbs");
1521556Srgrimes		if (cbsz == 0)
1531556Srgrimes			errx(1, "cbs cannot be zero");
1541556Srgrimes		cfunc = ddflags & C_BLOCK ? block : unblock;
1551556Srgrimes	} else if (ddflags & C_CBS) {
15651249Sgreen		if (ddflags & (C_ASCII | C_EBCDIC)) {
1571556Srgrimes			if (ddflags & C_ASCII) {
1581556Srgrimes				ddflags |= C_UNBLOCK;
1591556Srgrimes				cfunc = unblock;
1601556Srgrimes			} else {
1611556Srgrimes				ddflags |= C_BLOCK;
1621556Srgrimes				cfunc = block;
1631556Srgrimes			}
1641556Srgrimes		} else
1651556Srgrimes			errx(1, "cbs meaningless if not doing record operations");
1661556Srgrimes	} else
1671556Srgrimes		cfunc = def;
1681556Srgrimes}
1691556Srgrimes
1701556Srgrimesstatic int
17190108Simpc_arg(const void *a, const void *b)
1721556Srgrimes{
1731556Srgrimes
17454278Sgreen	return (strcmp(((const struct arg *)a)->name,
17554278Sgreen	    ((const struct arg *)b)->name));
1761556Srgrimes}
1771556Srgrimes
1781556Srgrimesstatic void
17990108Simpf_bs(char *arg)
1801556Srgrimes{
181111629Smarkm	uintmax_t res;
1821556Srgrimes
18351208Sgreen	res = get_num(arg);
18451208Sgreen	if (res < 1 || res > SSIZE_MAX)
185112265Sru		errx(1, "bs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
18651208Sgreen	in.dbsz = out.dbsz = (size_t)res;
1871556Srgrimes}
1881556Srgrimes
1891556Srgrimesstatic void
19090108Simpf_cbs(char *arg)
1911556Srgrimes{
192111629Smarkm	uintmax_t res;
1931556Srgrimes
19451208Sgreen	res = get_num(arg);
19551208Sgreen	if (res < 1 || res > SSIZE_MAX)
196112265Sru		errx(1, "cbs must be between 1 and %jd", (intmax_t)SSIZE_MAX);
19751208Sgreen	cbsz = (size_t)res;
1981556Srgrimes}
1991556Srgrimes
2001556Srgrimesstatic void
20190108Simpf_count(char *arg)
2021556Srgrimes{
203111629Smarkm	intmax_t res;
2041556Srgrimes
205111629Smarkm	res = (intmax_t)get_num(arg);
206111629Smarkm	if (res < 0)
20751326Sgreen		errx(1, "count cannot be negative");
20889788Sgreen	if (res == 0)
209111629Smarkm		cpy_cnt = (uintmax_t)-1;
21089788Sgreen	else
211111629Smarkm		cpy_cnt = (uintmax_t)res;
2121556Srgrimes}
2131556Srgrimes
2141556Srgrimesstatic void
21590108Simpf_files(char *arg)
2161556Srgrimes{
2171556Srgrimes
21851137Sgreen	files_cnt = get_num(arg);
21951249Sgreen	if (files_cnt < 1)
220111629Smarkm		errx(1, "files must be between 1 and %jd", (uintmax_t)-1);
2211556Srgrimes}
2221556Srgrimes
2231556Srgrimesstatic void
224133762Srwatsonf_fillchar(char *arg)
225133762Srwatson{
226133762Srwatson
227133762Srwatson	if (strlen(arg) != 1)
228133762Srwatson		errx(1, "need exactly one fill char");
229133762Srwatson
230133762Srwatson	fill_char = arg[0];
231133762Srwatson}
232133762Srwatson
233133762Srwatsonstatic void
23490108Simpf_ibs(char *arg)
2351556Srgrimes{
236111629Smarkm	uintmax_t res;
2371556Srgrimes
23848051Sgreen	if (!(ddflags & C_BS)) {
23951208Sgreen		res = get_num(arg);
24051208Sgreen		if (res < 1 || res > SSIZE_MAX)
241112265Sru			errx(1, "ibs must be between 1 and %jd",
242112265Sru			    (intmax_t)SSIZE_MAX);
24351249Sgreen		in.dbsz = (size_t)res;
24448051Sgreen	}
2451556Srgrimes}
2461556Srgrimes
2471556Srgrimesstatic void
24890108Simpf_if(char *arg)
2491556Srgrimes{
2501556Srgrimes
2511556Srgrimes	in.name = arg;
2521556Srgrimes}
2531556Srgrimes
2541556Srgrimesstatic void
25590108Simpf_obs(char *arg)
2561556Srgrimes{
257111629Smarkm	uintmax_t res;
2581556Srgrimes
25948051Sgreen	if (!(ddflags & C_BS)) {
26051208Sgreen		res = get_num(arg);
26151208Sgreen		if (res < 1 || res > SSIZE_MAX)
262112265Sru			errx(1, "obs must be between 1 and %jd",
263112265Sru			    (intmax_t)SSIZE_MAX);
26451208Sgreen		out.dbsz = (size_t)res;
26548051Sgreen	}
2661556Srgrimes}
2671556Srgrimes
2681556Srgrimesstatic void
26990108Simpf_of(char *arg)
2701556Srgrimes{
2711556Srgrimes
2721556Srgrimes	out.name = arg;
2731556Srgrimes}
2741556Srgrimes
2751556Srgrimesstatic void
27690108Simpf_seek(char *arg)
2771556Srgrimes{
2781556Srgrimes
27989788Sgreen	out.offset = get_off_t(arg);
2801556Srgrimes}
2811556Srgrimes
2821556Srgrimesstatic void
28390108Simpf_skip(char *arg)
2841556Srgrimes{
2851556Srgrimes
28689788Sgreen	in.offset = get_off_t(arg);
2871556Srgrimes}
2881556Srgrimes
289264577Sdelphijstatic void
290264577Sdelphijf_status(char *arg)
291264577Sdelphij{
292264577Sdelphij
293264577Sdelphij	if (strcmp(arg, "none") == 0)
294264577Sdelphij		ddflags |= C_NOINFO;
295264577Sdelphij	else if (strcmp(arg, "noxfer") == 0)
296264577Sdelphij		ddflags |= C_NOXFER;
297264577Sdelphij	else
298264577Sdelphij		errx(1, "unknown status %s", arg);
299264577Sdelphij}
300264577Sdelphij
30151208Sgreenstatic const struct conv {
30254245Sgreen	const char *name;
3031556Srgrimes	u_int set, noset;
30451208Sgreen	const u_char *ctab;
3051556Srgrimes} clist[] = {
3061556Srgrimes	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
3071556Srgrimes	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
3081556Srgrimes	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
3091556Srgrimes	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
3101556Srgrimes	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
3111556Srgrimes	{ "noerror",	C_NOERROR,	0,		NULL },
3121556Srgrimes	{ "notrunc",	C_NOTRUNC,	0,		NULL },
3131556Srgrimes	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
3141556Srgrimes	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
3151556Srgrimes	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
31631120Sjoerg	{ "osync",	C_OSYNC,	C_BS,		NULL },
317126667Sphk	{ "pareven",	C_PAREVEN,	C_PARODD|C_PARSET|C_PARNONE, NULL},
318126667Sphk	{ "parnone",	C_PARNONE,	C_PARODD|C_PARSET|C_PAREVEN, NULL},
319126667Sphk	{ "parodd",	C_PARODD,	C_PAREVEN|C_PARSET|C_PARNONE, NULL},
320126667Sphk	{ "parset",	C_PARSET,	C_PARODD|C_PAREVEN|C_PARNONE, NULL},
32130312Sjoerg	{ "sparse",	C_SPARSE,	0,		NULL },
3221556Srgrimes	{ "swab",	C_SWAB,		0,		NULL },
3231556Srgrimes	{ "sync",	C_SYNC,		0,		NULL },
3241556Srgrimes	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
3251556Srgrimes	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
3261556Srgrimes};
3271556Srgrimes
3281556Srgrimesstatic void
32990108Simpf_conv(char *arg)
3301556Srgrimes{
3311556Srgrimes	struct conv *cp, tmp;
3321556Srgrimes
3331556Srgrimes	while (arg != NULL) {
3341556Srgrimes		tmp.name = strsep(&arg, ",");
33551208Sgreen		cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
33651208Sgreen		    sizeof(struct conv), c_conv);
33751208Sgreen		if (cp == NULL)
3381556Srgrimes			errx(1, "unknown conversion %s", tmp.name);
3391556Srgrimes		if (ddflags & cp->noset)
3401556Srgrimes			errx(1, "%s: illegal conversion combination", tmp.name);
3411556Srgrimes		ddflags |= cp->set;
3421556Srgrimes		if (cp->ctab)
3431556Srgrimes			ctab = cp->ctab;
3441556Srgrimes	}
3451556Srgrimes}
3461556Srgrimes
3471556Srgrimesstatic int
34890108Simpc_conv(const void *a, const void *b)
3491556Srgrimes{
3501556Srgrimes
35154278Sgreen	return (strcmp(((const struct conv *)a)->name,
35254278Sgreen	    ((const struct conv *)b)->name));
3531556Srgrimes}
3541556Srgrimes
3551556Srgrimes/*
356111629Smarkm * Convert an expression of the following forms to a uintmax_t.
3571556Srgrimes * 	1) A positive decimal number.
358132933Spjd *	2) A positive decimal number followed by a 'b' or 'B' (mult by 512).
359132933Spjd *	3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
360132933Spjd *	4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
361132933Spjd *	5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
362132933Spjd *	5) A positive decimal number followed by a 'w' or 'W' (mult by sizeof int).
363132933Spjd *	6) Two or more positive decimal numbers (with/without [BbKkMmGgWw])
364132933Spjd *	   separated by 'x' or 'X' (also '*' for backwards compatibility),
365132933Spjd *	   specifying the product of the indicated values.
3661556Srgrimes */
367111629Smarkmstatic uintmax_t
36890108Simpget_num(const char *val)
3691556Srgrimes{
370111629Smarkm	uintmax_t num, mult, prevnum;
3711556Srgrimes	char *expr;
3721556Srgrimes
37348051Sgreen	errno = 0;
37489788Sgreen	num = strtouq(val, &expr, 0);
37551208Sgreen	if (errno != 0)				/* Overflow or underflow. */
37648051Sgreen		err(1, "%s", oper);
37748051Sgreen
37851208Sgreen	if (expr == val)			/* No valid digits. */
3791556Srgrimes		errx(1, "%s: illegal numeric value", oper);
3801556Srgrimes
38189788Sgreen	mult = 0;
38251137Sgreen	switch (*expr) {
383132933Spjd	case 'B':
3841556Srgrimes	case 'b':
38589788Sgreen		mult = 512;
3861556Srgrimes		break;
387132933Spjd	case 'K':
3881556Srgrimes	case 'k':
38989788Sgreen		mult = 1 << 10;
3901556Srgrimes		break;
391132933Spjd	case 'M':
3921556Srgrimes	case 'm':
39389788Sgreen		mult = 1 << 20;
3941556Srgrimes		break;
395132933Spjd	case 'G':
39648051Sgreen	case 'g':
39789788Sgreen		mult = 1 << 30;
39848051Sgreen		break;
399132933Spjd	case 'W':
4001556Srgrimes	case 'w':
40189788Sgreen		mult = sizeof(int);
4021556Srgrimes		break;
40391079Smarkm	default:
40496383Sjedgar		;
4051556Srgrimes	}
4061556Srgrimes
40789788Sgreen	if (mult != 0) {
40889788Sgreen		prevnum = num;
40989788Sgreen		num *= mult;
41089788Sgreen		/* Check for overflow. */
41189788Sgreen		if (num / mult != prevnum)
41289788Sgreen			goto erange;
41389788Sgreen		expr++;
41489788Sgreen	}
41589788Sgreen
41651137Sgreen	switch (*expr) {
4171556Srgrimes		case '\0':
4181556Srgrimes			break;
4191556Srgrimes		case '*':			/* Backward compatible. */
420132933Spjd		case 'X':
4211556Srgrimes		case 'x':
42289788Sgreen			mult = get_num(expr + 1);
42389788Sgreen			prevnum = num;
42489788Sgreen			num *= mult;
42589788Sgreen			if (num / mult == prevnum)
42651137Sgreen				break;
42751137Sgreenerange:
42851137Sgreen			errx(1, "%s: %s", oper, strerror(ERANGE));
4291556Srgrimes		default:
4301556Srgrimes			errx(1, "%s: illegal numeric value", oper);
4311556Srgrimes	}
4321556Srgrimes	return (num);
4331556Srgrimes}
43451208Sgreen
43589788Sgreen/*
43689788Sgreen * Convert an expression of the following forms to an off_t.  This is the
43789788Sgreen * same as get_num(), but it uses signed numbers.
43889788Sgreen *
439111629Smarkm * The major problem here is that an off_t may not necessarily be a intmax_t.
44089788Sgreen */
44151208Sgreenstatic off_t
44290108Simpget_off_t(const char *val)
44351208Sgreen{
444111629Smarkm	intmax_t num, mult, prevnum;
44589788Sgreen	char *expr;
44651208Sgreen
44789788Sgreen	errno = 0;
44889788Sgreen	num = strtoq(val, &expr, 0);
44989788Sgreen	if (errno != 0)				/* Overflow or underflow. */
45089788Sgreen		err(1, "%s", oper);
45189788Sgreen
45289788Sgreen	if (expr == val)			/* No valid digits. */
45389788Sgreen		errx(1, "%s: illegal numeric value", oper);
45489788Sgreen
45589788Sgreen	mult = 0;
45689788Sgreen	switch (*expr) {
457132933Spjd	case 'B':
45889788Sgreen	case 'b':
45989788Sgreen		mult = 512;
46089788Sgreen		break;
461132933Spjd	case 'K':
46289788Sgreen	case 'k':
46389788Sgreen		mult = 1 << 10;
46489788Sgreen		break;
465132933Spjd	case 'M':
46689788Sgreen	case 'm':
46789788Sgreen		mult = 1 << 20;
46889788Sgreen		break;
469132933Spjd	case 'G':
47089788Sgreen	case 'g':
47189788Sgreen		mult = 1 << 30;
47289788Sgreen		break;
473132933Spjd	case 'W':
47489788Sgreen	case 'w':
47589788Sgreen		mult = sizeof(int);
47689788Sgreen		break;
47789788Sgreen	}
47889788Sgreen
47989788Sgreen	if (mult != 0) {
48089788Sgreen		prevnum = num;
48189788Sgreen		num *= mult;
48289788Sgreen		/* Check for overflow. */
48389788Sgreen		if ((prevnum > 0) != (num > 0) || num / mult != prevnum)
48489788Sgreen			goto erange;
48589788Sgreen		expr++;
48689788Sgreen	}
48789788Sgreen
48889788Sgreen	switch (*expr) {
48989788Sgreen		case '\0':
49089788Sgreen			break;
49189788Sgreen		case '*':			/* Backward compatible. */
492132933Spjd		case 'X':
49389788Sgreen		case 'x':
494111629Smarkm			mult = (intmax_t)get_off_t(expr + 1);
49589788Sgreen			prevnum = num;
49689788Sgreen			num *= mult;
49790331Sgreen			if ((prevnum > 0) == (num > 0) && num / mult == prevnum)
49889788Sgreen				break;
49989788Sgreenerange:
50089788Sgreen			errx(1, "%s: %s", oper, strerror(ERANGE));
50189788Sgreen		default:
50289788Sgreen			errx(1, "%s: illegal numeric value", oper);
50389788Sgreen	}
50489788Sgreen	return (num);
50551208Sgreen}
506