xref: /openbsd-src/bin/dd/args.c (revision bce29b5c6b7d6167bb1d5f976a0ba717a3c61973)
1*bce29b5cSbluhm /*	$OpenBSD: args.c,v 1.31 2019/02/16 10:54:00 bluhm Exp $	*/
27f82c603Sniklas /*	$NetBSD: args.c,v 1.7 1996/03/01 01:18:58 jtc Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1991, 1993, 1994
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Keith Muller of the University of California, San Diego and Lance
10df930be7Sderaadt  * Visser of Convex Computer Corporation.
11df930be7Sderaadt  *
12df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
13df930be7Sderaadt  * modification, are permitted provided that the following conditions
14df930be7Sderaadt  * are met:
15df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
16df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
17df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
18df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
19df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
2029295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
21df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
22df930be7Sderaadt  *    without specific prior written permission.
23df930be7Sderaadt  *
24df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df930be7Sderaadt  * SUCH DAMAGE.
35df930be7Sderaadt  */
36df930be7Sderaadt 
37df930be7Sderaadt #include <sys/types.h>
38e4cb6409Shugh #include <sys/time.h>
39df930be7Sderaadt 
40df930be7Sderaadt #include <err.h>
41df930be7Sderaadt #include <errno.h>
42df930be7Sderaadt #include <limits.h>
43df930be7Sderaadt #include <stdio.h>
44df930be7Sderaadt #include <stdlib.h>
45df930be7Sderaadt #include <string.h>
46df930be7Sderaadt 
47df930be7Sderaadt #include "dd.h"
48df930be7Sderaadt #include "extern.h"
49df930be7Sderaadt 
50c72b5b24Smillert static int	c_arg(const void *, const void *);
51c72b5b24Smillert static void	f_bs(char *);
52c72b5b24Smillert static void	f_cbs(char *);
53c72b5b24Smillert static void	f_conv(char *);
54c72b5b24Smillert static void	f_count(char *);
55c72b5b24Smillert static void	f_files(char *);
56c72b5b24Smillert static void	f_ibs(char *);
57c72b5b24Smillert static void	f_if(char *);
58c72b5b24Smillert static void	f_obs(char *);
59c72b5b24Smillert static void	f_of(char *);
60c72b5b24Smillert static void	f_seek(char *);
61c72b5b24Smillert static void	f_skip(char *);
621f29dce2Sbluhm static void	f_status(char *);
63c72b5b24Smillert static size_t	get_bsz(char *);
64c72b5b24Smillert static off_t	get_off(char *);
65df930be7Sderaadt 
66f3959517Sderaadt static const struct arg {
67a7237831Sdhill 	const char *name;
68c72b5b24Smillert 	void (*f)(char *);
69df930be7Sderaadt 	u_int set, noset;
70df930be7Sderaadt } args[] = {
71df930be7Sderaadt 	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
72df930be7Sderaadt 	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
73df930be7Sderaadt 	{ "conv",	f_conv,		0,	 0 },
74df930be7Sderaadt 	{ "count",	f_count,	C_COUNT, C_COUNT },
75df930be7Sderaadt 	{ "files",	f_files,	C_FILES, C_FILES },
76df930be7Sderaadt 	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
77df930be7Sderaadt 	{ "if",		f_if,		C_IF,	 C_IF },
78df930be7Sderaadt 	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
79df930be7Sderaadt 	{ "of",		f_of,		C_OF,	 C_OF },
80df930be7Sderaadt 	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
81df930be7Sderaadt 	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
821f29dce2Sbluhm 	{ "status",	f_status,	C_STATUS,C_STATUS },
83df930be7Sderaadt };
84df930be7Sderaadt 
85df930be7Sderaadt static char *oper;
86df930be7Sderaadt 
87df930be7Sderaadt /*
88df930be7Sderaadt  * args -- parse JCL syntax of dd.
89df930be7Sderaadt  */
90df930be7Sderaadt void
jcl(char ** argv)9128416801Sderaadt jcl(char **argv)
92df930be7Sderaadt {
93df930be7Sderaadt 	struct arg *ap, tmp;
94df930be7Sderaadt 	char *arg;
95df930be7Sderaadt 
96df930be7Sderaadt 	in.dbsz = out.dbsz = 512;
97df930be7Sderaadt 
984b4540bbScheloha 	while (*++argv != NULL) {
994b4540bbScheloha 		if ((oper = strdup(*argv)) == NULL)
1004b4540bbScheloha 			err(1, NULL);
101df930be7Sderaadt 		if ((arg = strchr(oper, '=')) == NULL)
102df930be7Sderaadt 			errx(1, "unknown operand %s", oper);
103df930be7Sderaadt 		*arg++ = '\0';
104df930be7Sderaadt 		if (!*arg)
105df930be7Sderaadt 			errx(1, "no value specified for %s", oper);
106df930be7Sderaadt 		tmp.name = oper;
107df930be7Sderaadt 		if (!(ap = (struct arg *)bsearch(&tmp, args,
108df930be7Sderaadt 		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
109df930be7Sderaadt 		    c_arg)))
110df930be7Sderaadt 			errx(1, "unknown operand %s", tmp.name);
111df930be7Sderaadt 		if (ddflags & ap->noset)
112df930be7Sderaadt 			errx(1, "%s: illegal argument combination or already set",
113df930be7Sderaadt 			    tmp.name);
114df930be7Sderaadt 		ddflags |= ap->set;
115df930be7Sderaadt 		ap->f(arg);
1164b4540bbScheloha 		free(oper);
117df930be7Sderaadt 	}
118df930be7Sderaadt 
119df930be7Sderaadt 	/* Final sanity checks. */
120df930be7Sderaadt 
121df930be7Sderaadt 	if (ddflags & C_BS) {
122df930be7Sderaadt 		/*
123df930be7Sderaadt 		 * Bs is turned off by any conversion -- we assume the user
124df930be7Sderaadt 		 * just wanted to set both the input and output block sizes
125df930be7Sderaadt 		 * and didn't want the bs semantics, so we don't warn.
126df930be7Sderaadt 		 */
127df930be7Sderaadt 		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
128df930be7Sderaadt 			ddflags &= ~C_BS;
129df930be7Sderaadt 
130df930be7Sderaadt 		/* Bs supersedes ibs and obs. */
131df930be7Sderaadt 		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
132df930be7Sderaadt 			warnx("bs supersedes ibs and obs");
133df930be7Sderaadt 	}
134df930be7Sderaadt 
135df930be7Sderaadt 	/*
136df930be7Sderaadt 	 * Ascii/ebcdic and cbs implies block/unblock.
137df930be7Sderaadt 	 * Block/unblock requires cbs and vice-versa.
138df930be7Sderaadt 	 */
139df930be7Sderaadt 	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
140df930be7Sderaadt 		if (!(ddflags & C_CBS))
141df930be7Sderaadt 			errx(1, "record operations require cbs");
142df930be7Sderaadt 		if (cbsz == 0)
143df930be7Sderaadt 			errx(1, "cbs cannot be zero");
144df930be7Sderaadt 		cfunc = ddflags & C_BLOCK ? block : unblock;
145df930be7Sderaadt 	} else if (ddflags & C_CBS) {
146df930be7Sderaadt 		if (ddflags & (C_ASCII|C_EBCDIC)) {
147df930be7Sderaadt 			if (ddflags & C_ASCII) {
148df930be7Sderaadt 				ddflags |= C_UNBLOCK;
149df930be7Sderaadt 				cfunc = unblock;
150df930be7Sderaadt 			} else {
151df930be7Sderaadt 				ddflags |= C_BLOCK;
152df930be7Sderaadt 				cfunc = block;
153df930be7Sderaadt 			}
154df930be7Sderaadt 		} else
155df930be7Sderaadt 			errx(1, "cbs meaningless if not doing record operations");
156df930be7Sderaadt 		if (cbsz == 0)
157df930be7Sderaadt 			errx(1, "cbs cannot be zero");
158df930be7Sderaadt 	} else
159df930be7Sderaadt 		cfunc = def;
160df930be7Sderaadt 
161df930be7Sderaadt 	if (in.dbsz == 0 || out.dbsz == 0)
162df930be7Sderaadt 		errx(1, "buffer sizes cannot be zero");
163df930be7Sderaadt 
164df930be7Sderaadt 	/*
165f6ff413cSmillert 	 * Read and write take size_t's as arguments.  Lseek, however,
166a43a44b4Stedu 	 * takes an off_t.
167df930be7Sderaadt 	 */
1685d23a6e7Sray 	if (cbsz > SSIZE_MAX || in.dbsz > SSIZE_MAX || out.dbsz > SSIZE_MAX)
1695d23a6e7Sray 		errx(1, "buffer sizes cannot be greater than %zd",
1705d23a6e7Sray 		    (ssize_t)SSIZE_MAX);
171a43a44b4Stedu 	if (in.offset > LLONG_MAX / in.dbsz || out.offset > LLONG_MAX / out.dbsz)
172a43a44b4Stedu 		errx(1, "seek offsets cannot be larger than %lld", LLONG_MAX);
173df930be7Sderaadt }
174df930be7Sderaadt 
175df930be7Sderaadt static int
c_arg(const void * a,const void * b)17628416801Sderaadt c_arg(const void *a, const void *b)
177df930be7Sderaadt {
178df930be7Sderaadt 
179df930be7Sderaadt 	return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
180df930be7Sderaadt }
181df930be7Sderaadt 
182df930be7Sderaadt static void
f_bs(char * arg)18328416801Sderaadt f_bs(char *arg)
184df930be7Sderaadt {
185df930be7Sderaadt 
186f6ff413cSmillert 	in.dbsz = out.dbsz = get_bsz(arg);
187df930be7Sderaadt }
188df930be7Sderaadt 
189df930be7Sderaadt static void
f_cbs(char * arg)19028416801Sderaadt f_cbs(char *arg)
191df930be7Sderaadt {
192df930be7Sderaadt 
193f6ff413cSmillert 	cbsz = get_bsz(arg);
194df930be7Sderaadt }
195df930be7Sderaadt 
196df930be7Sderaadt static void
f_count(char * arg)19728416801Sderaadt f_count(char *arg)
198df930be7Sderaadt {
199df930be7Sderaadt 
2009c9e0865Smillert 	if ((cpy_cnt = get_bsz(arg)) == 0)
2019c9e0865Smillert 		cpy_cnt = (size_t)-1;
202df930be7Sderaadt }
203df930be7Sderaadt 
204df930be7Sderaadt static void
f_files(char * arg)20528416801Sderaadt f_files(char *arg)
206df930be7Sderaadt {
207df930be7Sderaadt 
208f6ff413cSmillert 	files_cnt = get_bsz(arg);
209df930be7Sderaadt }
210df930be7Sderaadt 
211df930be7Sderaadt static void
f_ibs(char * arg)21228416801Sderaadt f_ibs(char *arg)
213df930be7Sderaadt {
214df930be7Sderaadt 
215df930be7Sderaadt 	if (!(ddflags & C_BS))
216f6ff413cSmillert 		in.dbsz = get_bsz(arg);
217df930be7Sderaadt }
218df930be7Sderaadt 
219df930be7Sderaadt static void
f_if(char * arg)22028416801Sderaadt f_if(char *arg)
221df930be7Sderaadt {
2224b4540bbScheloha 	if ((in.name = strdup(arg)) == NULL)
2234b4540bbScheloha 		err(1, NULL);
224df930be7Sderaadt }
225df930be7Sderaadt 
226df930be7Sderaadt static void
f_obs(char * arg)22728416801Sderaadt f_obs(char *arg)
228df930be7Sderaadt {
229df930be7Sderaadt 
230df930be7Sderaadt 	if (!(ddflags & C_BS))
231f6ff413cSmillert 		out.dbsz = get_bsz(arg);
232df930be7Sderaadt }
233df930be7Sderaadt 
234df930be7Sderaadt static void
f_of(char * arg)23528416801Sderaadt f_of(char *arg)
236df930be7Sderaadt {
2374b4540bbScheloha 	if ((out.name = strdup(arg)) == NULL)
2384b4540bbScheloha 		err(1, NULL);
239df930be7Sderaadt }
240df930be7Sderaadt 
241df930be7Sderaadt static void
f_seek(char * arg)24228416801Sderaadt f_seek(char *arg)
243df930be7Sderaadt {
244df930be7Sderaadt 
245f6ff413cSmillert 	out.offset = get_off(arg);
246df930be7Sderaadt }
247df930be7Sderaadt 
248df930be7Sderaadt static void
f_skip(char * arg)24928416801Sderaadt f_skip(char *arg)
250df930be7Sderaadt {
251df930be7Sderaadt 
252f6ff413cSmillert 	in.offset = get_off(arg);
253df930be7Sderaadt }
254df930be7Sderaadt 
2551f29dce2Sbluhm static void
f_status(char * arg)2561f29dce2Sbluhm f_status(char *arg)
2571f29dce2Sbluhm {
2581f29dce2Sbluhm 
2591f29dce2Sbluhm 	if (strcmp(arg, "none") == 0)
2601f29dce2Sbluhm 		ddflags |= C_NOINFO;
2611f29dce2Sbluhm 	else if (strcmp(arg, "noxfer") == 0)
2621f29dce2Sbluhm 		ddflags |= C_NOXFER;
2631f29dce2Sbluhm 	else
2641f29dce2Sbluhm 		errx(1, "unknown status %s", arg);
2651f29dce2Sbluhm }
2661f29dce2Sbluhm 
267df930be7Sderaadt 
268f3959517Sderaadt static const struct conv {
269a7237831Sdhill 	const char *name;
270df930be7Sderaadt 	u_int set, noset;
2717f82c603Sniklas 	const u_char *ctab;
272df930be7Sderaadt } clist[] = {
273dc3be576Stedu #ifndef	NO_CONV
274df930be7Sderaadt 	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
275df930be7Sderaadt 	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
276df930be7Sderaadt 	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
277*bce29b5cSbluhm 	{ "fsync",	C_FSYNC,	0,		NULL },
278df930be7Sderaadt 	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
279df930be7Sderaadt 	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
280df930be7Sderaadt 	{ "osync",	C_OSYNC,	C_BS,		NULL },
281df930be7Sderaadt 	{ "swab",	C_SWAB,		0,		NULL },
282df930be7Sderaadt 	{ "sync",	C_SYNC,		0,		NULL },
283df930be7Sderaadt 	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
284df930be7Sderaadt 	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
285dc3be576Stedu #endif
286dc3be576Stedu 	{ "noerror",	C_NOERROR,	0,		NULL },
287dc3be576Stedu 	{ "notrunc",	C_NOTRUNC,	0,		NULL },
288dc3be576Stedu 	{ NULL,		0,		0,		NULL }
289df930be7Sderaadt };
290df930be7Sderaadt 
291df930be7Sderaadt static void
f_conv(char * arg)29228416801Sderaadt f_conv(char *arg)
293df930be7Sderaadt {
294dc3be576Stedu 	const struct conv *cp;
295dc3be576Stedu 	const char *name;
296df930be7Sderaadt 
297df930be7Sderaadt 	while (arg != NULL) {
298dc3be576Stedu 		name = strsep(&arg, ",");
299dc3be576Stedu 		for (cp = &clist[0]; cp->name; cp++)
300dc3be576Stedu 			if (strcmp(name, cp->name) == 0)
301dc3be576Stedu 				break;
302dc3be576Stedu 		if (!cp->name)
303dc3be576Stedu 			errx(1, "unknown conversion %s", name);
304df930be7Sderaadt 		if (ddflags & cp->noset)
305dc3be576Stedu 			errx(1, "%s: illegal conversion combination", name);
306df930be7Sderaadt 		ddflags |= cp->set;
307df930be7Sderaadt 		if (cp->ctab)
308df930be7Sderaadt 			ctab = cp->ctab;
309df930be7Sderaadt 	}
310df930be7Sderaadt }
311df930be7Sderaadt 
312df930be7Sderaadt /*
313f6ff413cSmillert  * Convert an expression of the following forms to a size_t
3143058619eStedu  *	1) A positive decimal number, optionally followed by
3153058619eStedu  *		b - multiply by 512.
3163058619eStedu  *		k, m or g - multiply by 1024 each.
3173058619eStedu  *		w - multiply by sizeof int
3183058619eStedu  *	2) Two or more of the above, separated by x
3193058619eStedu  *	   (or * for backwards compatibility), specifying
320df930be7Sderaadt  *	   the product of the indicated values.
321df930be7Sderaadt  */
322f6ff413cSmillert static size_t
get_bsz(char * val)32328416801Sderaadt get_bsz(char *val)
324df930be7Sderaadt {
325f6ff413cSmillert 	size_t num, t;
326df930be7Sderaadt 	char *expr;
327df930be7Sderaadt 
32860e2b159Sschwarze 	if (strchr(val, '-'))
32960e2b159Sschwarze 		errx(1, "%s: illegal numeric value", oper);
33060e2b159Sschwarze 
33160e2b159Sschwarze 	errno = 0;
332df930be7Sderaadt 	num = strtoul(val, &expr, 0);
33360e2b159Sschwarze 	if (num == ULONG_MAX && errno == ERANGE)	/* Overflow. */
334df930be7Sderaadt 		err(1, "%s", oper);
335df930be7Sderaadt 	if (expr == val)			/* No digits. */
336df930be7Sderaadt 		errx(1, "%s: illegal numeric value", oper);
337df930be7Sderaadt 
338df930be7Sderaadt 	switch(*expr) {
339df930be7Sderaadt 	case 'b':
340df930be7Sderaadt 		t = num;
341df930be7Sderaadt 		num *= 512;
342df930be7Sderaadt 		if (t > num)
343df930be7Sderaadt 			goto erange;
344df930be7Sderaadt 		++expr;
345df930be7Sderaadt 		break;
3463058619eStedu 	case 'g':
3473058619eStedu 	case 'G':
348df930be7Sderaadt 		t = num;
349df930be7Sderaadt 		num *= 1024;
350df930be7Sderaadt 		if (t > num)
351df930be7Sderaadt 			goto erange;
3523058619eStedu 		/* fallthrough */
353df930be7Sderaadt 	case 'm':
354e168cee8Snicm 	case 'M':
355df930be7Sderaadt 		t = num;
3563058619eStedu 		num *= 1024;
3573058619eStedu 		if (t > num)
3583058619eStedu 			goto erange;
3593058619eStedu 		/* fallthrough */
3603058619eStedu 	case 'k':
3613058619eStedu 	case 'K':
3623058619eStedu 		t = num;
3633058619eStedu 		num *= 1024;
364df930be7Sderaadt 		if (t > num)
365df930be7Sderaadt 			goto erange;
366df930be7Sderaadt 		++expr;
367df930be7Sderaadt 		break;
368df930be7Sderaadt 	case 'w':
369df930be7Sderaadt 		t = num;
370df930be7Sderaadt 		num *= sizeof(int);
371df930be7Sderaadt 		if (t > num)
372df930be7Sderaadt 			goto erange;
373df930be7Sderaadt 		++expr;
374df930be7Sderaadt 		break;
375df930be7Sderaadt 	}
376df930be7Sderaadt 
377df930be7Sderaadt 	switch(*expr) {
378df930be7Sderaadt 		case '\0':
379df930be7Sderaadt 			break;
380df930be7Sderaadt 		case '*':			/* Backward compatible. */
381df930be7Sderaadt 		case 'x':
382df930be7Sderaadt 			t = num;
383df930be7Sderaadt 			num *= get_bsz(expr + 1);
384df930be7Sderaadt 			if (t > num)
3853058619eStedu 				goto erange;
386df930be7Sderaadt 			break;
387df930be7Sderaadt 		default:
388df930be7Sderaadt 			errx(1, "%s: illegal numeric value", oper);
389df930be7Sderaadt 	}
390df930be7Sderaadt 	return (num);
3913058619eStedu erange:
392cd5cfea9Sguenther 	errc(1, ERANGE, "%s", oper);
393df930be7Sderaadt }
394f6ff413cSmillert 
395f6ff413cSmillert /*
396f6ff413cSmillert  * Convert an expression of the following forms to an off_t
3973058619eStedu  *	1) A positive decimal number, optionally followed by
3983058619eStedu  *		b - multiply by 512.
3993058619eStedu  *		k, m or g - multiply by 1024 each.
4003058619eStedu  *		w - multiply by sizeof int
4013058619eStedu  *	2) Two or more of the above, separated by x
4023058619eStedu  *	   (or * for backwards compatibility), specifying
403f6ff413cSmillert  *	   the product of the indicated values.
404f6ff413cSmillert  */
405f6ff413cSmillert static off_t
get_off(char * val)40628416801Sderaadt get_off(char *val)
407f6ff413cSmillert {
408f6ff413cSmillert 	off_t num, t;
409f6ff413cSmillert 	char *expr;
410f6ff413cSmillert 
411153396c3Sschwarze 	errno = 0;
412a43a44b4Stedu 	num = strtoll(val, &expr, 0);
413153396c3Sschwarze 	if (num == LLONG_MAX && errno == ERANGE)	/* Overflow. */
414f6ff413cSmillert 		err(1, "%s", oper);
415f6ff413cSmillert 	if (expr == val)			/* No digits. */
416f6ff413cSmillert 		errx(1, "%s: illegal numeric value", oper);
417f6ff413cSmillert 
418f6ff413cSmillert 	switch(*expr) {
419f6ff413cSmillert 	case 'b':
420f6ff413cSmillert 		t = num;
421f6ff413cSmillert 		num *= 512;
422f6ff413cSmillert 		if (t > num)
423f6ff413cSmillert 			goto erange;
424f6ff413cSmillert 		++expr;
425f6ff413cSmillert 		break;
4263058619eStedu 	case 'g':
4273058619eStedu 	case 'G':
428f6ff413cSmillert 		t = num;
429f6ff413cSmillert 		num *= 1024;
430f6ff413cSmillert 		if (t > num)
431f6ff413cSmillert 			goto erange;
4323058619eStedu 		/* fallthrough */
433f6ff413cSmillert 	case 'm':
434e168cee8Snicm 	case 'M':
435f6ff413cSmillert 		t = num;
4363058619eStedu 		num *= 1024;
4373058619eStedu 		if (t > num)
4383058619eStedu 			goto erange;
4393058619eStedu 		/* fallthrough */
4403058619eStedu 	case 'k':
4413058619eStedu 	case 'K':
4423058619eStedu 		t = num;
4433058619eStedu 		num *= 1024;
444f6ff413cSmillert 		if (t > num)
445f6ff413cSmillert 			goto erange;
446f6ff413cSmillert 		++expr;
447f6ff413cSmillert 		break;
448f6ff413cSmillert 	case 'w':
449f6ff413cSmillert 		t = num;
450f6ff413cSmillert 		num *= sizeof(int);
451f6ff413cSmillert 		if (t > num)
452f6ff413cSmillert 			goto erange;
453f6ff413cSmillert 		++expr;
454f6ff413cSmillert 		break;
455f6ff413cSmillert 	}
456f6ff413cSmillert 
457f6ff413cSmillert 	switch(*expr) {
458f6ff413cSmillert 		case '\0':
459f6ff413cSmillert 			break;
460f6ff413cSmillert 		case '*':			/* Backward compatible. */
461f6ff413cSmillert 		case 'x':
462f6ff413cSmillert 			t = num;
463f6ff413cSmillert 			num *= get_off(expr + 1);
464f6ff413cSmillert 			if (t > num)
4653058619eStedu 				goto erange;
466f6ff413cSmillert 			break;
467f6ff413cSmillert 		default:
468f6ff413cSmillert 			errx(1, "%s: illegal numeric value", oper);
469f6ff413cSmillert 	}
470f6ff413cSmillert 	return (num);
4713058619eStedu erange:
472cd5cfea9Sguenther 	errc(1, ERANGE, "%s", oper);
473f6ff413cSmillert }
474