args.c revision 48051
13969Sjkh/*-
298943Sluigi * Copyright (c) 1991, 1993, 1994
33969Sjkh *	The Regents of the University of California.  All rights reserved.
498943Sluigi *
598943Sluigi * This code is derived from software contributed to Berkeley by
698943Sluigi * Keith Muller of the University of California, San Diego and Lance
798943Sluigi * Visser of Convex Computer Corporation.
898943Sluigi *
998943Sluigi * Redistribution and use in source and binary forms, with or without
1098943Sluigi * modification, are permitted provided that the following conditions
1198943Sluigi * are met:
123969Sjkh * 1. Redistributions of source code must retain the above copyright
1398943Sluigi *    notice, this list of conditions and the following disclaimer.
1498943Sluigi * 2. Redistributions in binary form must reproduce the above copyright
1598943Sluigi *    notice, this list of conditions and the following disclaimer in the
1698943Sluigi *    documentation and/or other materials provided with the distribution.
1798943Sluigi * 3. All advertising materials mentioning features or use of this software
1898943Sluigi *    must display the following acknowledgement:
1998943Sluigi *	This product includes software developed by the University of
2098943Sluigi *	California, Berkeley and its contributors.
2198943Sluigi * 4. Neither the name of the University nor the names of its contributors
2298943Sluigi *    may be used to endorse or promote products derived from this software
2398943Sluigi *    without specific prior written permission.
243969Sjkh *
2550477Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
263969Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
273969Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2898943Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2998943Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30100228Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
313969Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3298943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3398943Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3498943Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3598943Sluigi * SUCH DAMAGE.
3626359Sjulian */
3798943Sluigi
3898943Sluigi#ifndef lint
3998943Sluigi#if 0
4098943Sluigistatic char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
4198943Sluigi#endif
4298943Sluigistatic const char rcsid[] =
4326359Sjulian	"$Id: args.c,v 1.14 1999/05/08 10:20:05 kris Exp $";
4426359Sjulian#endif /* not lint */
4598943Sluigi
4698943Sluigi#include <sys/types.h>
4798943Sluigi
4898943Sluigi#include <err.h>
4998943Sluigi#include <errno.h>
5098943Sluigi#include <limits.h>
5198943Sluigi#include <stdlib.h>
5298943Sluigi#include <string.h>
5398943Sluigi
5498943Sluigi#include "dd.h"
5598943Sluigi#include "extern.h"
5698943Sluigi
5798943Sluigistatic int	c_arg __P((const void *, const void *));
5898943Sluigistatic int	c_conv __P((const void *, const void *));
5998943Sluigistatic void	f_bs __P((char *));
6098943Sluigistatic void	f_cbs __P((char *));
6198943Sluigistatic void	f_conv __P((char *));
6298943Sluigistatic void	f_count __P((char *));
6398943Sluigistatic void	f_files __P((char *));
6498943Sluigistatic void	f_ibs __P((char *));
6598943Sluigistatic void	f_if __P((char *));
6698943Sluigistatic void	f_obs __P((char *));
6798943Sluigistatic void	f_of __P((char *));
6898943Sluigistatic void	f_seek __P((char *));
6998943Sluigistatic void	f_skip __P((char *));
7098943Sluigistatic quad_t	get_bsz __P((char *));
7198943Sluigi
7298943Sluigistatic struct arg {
7398943Sluigi	char *name;
7498943Sluigi	void (*f) __P((char *));
7598943Sluigi	u_int set, noset;
7698943Sluigi} args[] = {
7798943Sluigi	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
7899475Sluigi	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
7998943Sluigi	{ "conv",	f_conv,		0,	 0 },
8098943Sluigi	{ "count",	f_count,	C_COUNT, C_COUNT },
8198943Sluigi	{ "files",	f_files,	C_FILES, C_FILES },
8298943Sluigi	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
8398943Sluigi	{ "if",		f_if,		C_IF,	 C_IF },
8498943Sluigi	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
8598943Sluigi	{ "of",		f_of,		C_OF,	 C_OF },
8698943Sluigi	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
8798943Sluigi	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
8898943Sluigi};
8998943Sluigi
9098943Sluigistatic char *oper;
9198943Sluigi
92112250Scjc/*
93112250Scjc * args -- parse JCL syntax of dd.
9498943Sluigi */
9598943Sluigivoid
9698943Sluigijcl(argv)
9798943Sluigi	char **argv;
9898943Sluigi{
9998943Sluigi	struct arg *ap, tmp;
10098943Sluigi	char *arg;
10198943Sluigi
10298943Sluigi	in.dbsz = out.dbsz = 512;
10398943Sluigi
10498943Sluigi	while ((oper = *++argv) != NULL) {
10598943Sluigi		if ((oper = strdup(oper)) == NULL)
10698943Sluigi			errx(1, "unable to allocate space for the argument \"%s\"", *argv);
10798943Sluigi		if ((arg = strchr(oper, '=')) == NULL)
10898943Sluigi			errx(1, "unknown operand %s", oper);
10998943Sluigi		*arg++ = '\0';
11098943Sluigi		if (!*arg)
11198943Sluigi			errx(1, "no value specified for %s", oper);
11298943Sluigi		tmp.name = oper;
11398943Sluigi		if (!(ap = (struct arg *)bsearch(&tmp, args,
11498943Sluigi		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
11598943Sluigi		    c_arg)))
11698943Sluigi			errx(1, "unknown operand %s", tmp.name);
11798943Sluigi		if (ddflags & ap->noset)
11826359Sjulian			errx(1, "%s: illegal argument combination or already set",
11926359Sjulian			    tmp.name);
12026359Sjulian		ddflags |= ap->set;
12198943Sluigi		ap->f(arg);
1223969Sjkh	}
12398943Sluigi
12498943Sluigi	/* Final sanity checks. */
12598943Sluigi
12698943Sluigi	if (ddflags & C_BS) {
12798943Sluigi		/*
12898943Sluigi		 * Bs is turned off by any conversion -- we assume the user
12998943Sluigi		 * just wanted to set both the input and output block sizes
13098943Sluigi		 * and didn't want the bs semantics, so we don't warn.
13198943Sluigi		 */
13298943Sluigi		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
13398943Sluigi			ddflags &= ~C_BS;
13498943Sluigi
13598943Sluigi		/* Bs supersedes ibs and obs. */
13698943Sluigi		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
13798943Sluigi			warnx("bs supersedes ibs and obs");
13898943Sluigi	}
13998943Sluigi
14098943Sluigi	/*
14198943Sluigi	 * Ascii/ebcdic and cbs implies block/unblock.
14298943Sluigi	 * Block/unblock requires cbs and vice-versa.
14398943Sluigi	 */
14498943Sluigi	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
14598943Sluigi		if (!(ddflags & C_CBS))
1463969Sjkh			errx(1, "record operations require cbs");
14798943Sluigi		if (cbsz == 0)
14898943Sluigi			errx(1, "cbs cannot be zero");
14998943Sluigi		cfunc = ddflags & C_BLOCK ? block : unblock;
15098943Sluigi	} else if (ddflags & C_CBS) {
15198943Sluigi		if (ddflags & (C_ASCII|C_EBCDIC)) {
15298943Sluigi			if (ddflags & C_ASCII) {
15398943Sluigi				ddflags |= C_UNBLOCK;
1543969Sjkh				cfunc = unblock;
15598943Sluigi			} else {
15698943Sluigi				ddflags |= C_BLOCK;
15798943Sluigi				cfunc = block;
15896245Sluigi			}
15998943Sluigi		} else
16098943Sluigi			errx(1, "cbs meaningless if not doing record operations");
16196245Sluigi	} else
16298943Sluigi		cfunc = def;
16396245Sluigi}
16498943Sluigi
16598943Sluigistatic int
16698943Sluigic_arg(a, b)
16798943Sluigi	const void *a, *b;
16898943Sluigi{
16998943Sluigi
17098943Sluigi	return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
17196245Sluigi}
17298943Sluigi
17398943Sluigistatic void
17498943Sluigif_bs(arg)
17598943Sluigi	char *arg;
17698943Sluigi{
17798943Sluigi	quad_t res = get_bsz(arg);
17898943Sluigi
17998943Sluigi	if (res < 1 || res > INT_MAX)
18084058Sluigi		errx(1, "bs must be between 1 and %d", INT_MAX);
18198943Sluigi	in.dbsz = out.dbsz = (int)res;
18298943Sluigi}
18398943Sluigi
18498943Sluigistatic void
18598943Sluigif_cbs(arg)
18698943Sluigi	char *arg;
18798943Sluigi{
18898943Sluigi	quad_t res = get_bsz(arg);
1893969Sjkh
19098943Sluigi	if (res < 1 || res > INT_MAX)
19198943Sluigi		errx(1, "cbs must be between 1 and %d", INT_MAX);
19298943Sluigi
19398943Sluigi	cbsz = (int)res;
19498943Sluigi}
19598943Sluigi
19698943Sluigistatic void
19785665Sjoef_count(arg)
19898943Sluigi	char *arg;
19998943Sluigi{
20098943Sluigi
20198943Sluigi	cpy_cnt = get_bsz(arg);
20298943Sluigi	if (!cpy_cnt)
20398943Sluigi		terminate(0);
20498943Sluigi	if (cpy_cnt < 0)
20598943Sluigi		errx(1, "count cannot be negative");
20685665Sjoe}
20798943Sluigi
20898943Sluigistatic void
20998943Sluigif_files(arg)
21098943Sluigi	char *arg;
21198943Sluigi{
21298943Sluigi	quad_t res = get_bsz(arg);
21398943Sluigi
21498943Sluigi	files_cnt = res;
21598943Sluigi}
21698943Sluigi
21798943Sluigistatic void
21898943Sluigif_ibs(arg)
21998943Sluigi	char *arg;
22098943Sluigi{
22198943Sluigi
22298943Sluigi	if (!(ddflags & C_BS)) {
22398943Sluigi		quad_t res = get_bsz(arg);
22498943Sluigi
22598943Sluigi		if (res < 1 || res > INT_MAX)
22698943Sluigi			errx(1, "ibs must be between 1 and %d", INT_MAX);
22798943Sluigi		in.dbsz = (int)res;
22898943Sluigi	}
22998943Sluigi}
23098943Sluigi
23198943Sluigistatic void
23298943Sluigif_if(arg)
23398943Sluigi	char *arg;
23498943Sluigi{
23598943Sluigi
23684058Sluigi	in.name = arg;
23784058Sluigi}
23884058Sluigi
23984058Sluigistatic void
24085665Sjoef_obs(arg)
24198943Sluigi	char *arg;
24298943Sluigi{
24349630Sluigi
24498943Sluigi	if (!(ddflags & C_BS)) {
24598943Sluigi		quad_t res = get_bsz(arg);
24698943Sluigi
24798943Sluigi		if (res < 1 || res > INT_MAX)
24898943Sluigi			errx(1, "ibs must be between 1 and %d", INT_MAX);
24998943Sluigi		out.dbsz = (int)res;
25098943Sluigi	}
25198943Sluigi}
25226359Sjulian
25385689Sjoestatic void
25498943Sluigif_of(arg)
25583725Sluigi	char *arg;
25698943Sluigi{
25798943Sluigi
25898943Sluigi	out.name = arg;
25983725Sluigi}
26098943Sluigi
26198943Sluigistatic void
26298943Sluigif_seek(arg)
26398943Sluigi	char *arg;
26498943Sluigi{
26598943Sluigi
26698943Sluigi	out.offset = get_bsz(arg);
26798943Sluigi}
26898943Sluigi
26998943Sluigistatic void
27098943Sluigif_skip(arg)
27198943Sluigi	char *arg;
27298943Sluigi{
27398943Sluigi
27498943Sluigi	in.offset = get_bsz(arg);
27598943Sluigi}
27683725Sluigi
27783725Sluigistatic struct conv {
27898943Sluigi	char *name;
279100004Sluigi	u_int set, noset;
280101628Sluigi	u_char *ctab;
281105899Smux} clist[] = {
28298943Sluigi	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
28398943Sluigi	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
28498943Sluigi	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
285101628Sluigi	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
286101628Sluigi	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
28798943Sluigi	{ "noerror",	C_NOERROR,	0,		NULL },
28898943Sluigi	{ "notrunc",	C_NOTRUNC,	0,		NULL },
28998943Sluigi	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
29098943Sluigi	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
29198943Sluigi	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
29298943Sluigi	{ "osync",	C_OSYNC,	C_BS,		NULL },
29398943Sluigi	{ "sparse",	C_SPARSE,	0,		NULL },
29498943Sluigi	{ "swab",	C_SWAB,		0,		NULL },
29598943Sluigi	{ "sync",	C_SYNC,		0,		NULL },
29698943Sluigi	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
29798943Sluigi	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
29898943Sluigi};
29998943Sluigi
30098943Sluigistatic void
30198943Sluigif_conv(arg)
3024277Sjkh	char *arg;
30398943Sluigi{
30498943Sluigi	struct conv *cp, tmp;
30557113Sluigi
30657113Sluigi	while (arg != NULL) {
30785665Sjoe		tmp.name = strsep(&arg, ",");
30885665Sjoe		if (!(cp = (struct conv *)bsearch(&tmp, clist,
30985665Sjoe		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
31085665Sjoe		    c_conv)))
31185665Sjoe			errx(1, "unknown conversion %s", tmp.name);
31285665Sjoe		if (ddflags & cp->noset)
31385665Sjoe			errx(1, "%s: illegal conversion combination", tmp.name);
31457113Sluigi		ddflags |= cp->set;
31557113Sluigi		if (cp->ctab)
31657113Sluigi			ctab = cp->ctab;
31757113Sluigi	}
31898943Sluigi}
31998943Sluigi
32098943Sluigistatic int
32198943Sluigic_conv(a, b)
32298943Sluigi	const void *a, *b;
32398943Sluigi{
32498943Sluigi
32598943Sluigi	return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name));
32698943Sluigi}
32798943Sluigi
32898943Sluigi/*
32985665Sjoe * Convert an expression of the following forms to a quad_t.
33085665Sjoe * 	1) A positive decimal number.
33185665Sjoe *	2) A positive decimal number followed by a b (mult by 512.)
332100004Sluigi *	3) A positive decimal number followed by a k (mult by 1 << 10.)
333100004Sluigi *	4) A positive decimal number followed by a m (mult by 1 << 20.)
334100004Sluigi *	5) A positive decimal number followed by a g (mult by 1 << 30.)
33598943Sluigi *	5) A positive decimal number followed by a w (mult by sizeof int.)
33698943Sluigi *	6) Two or more positive decimal numbers (with/without [bkmgw])
337105899Smux *	   separated by x (also * for backwards compatibility), specifying
33885665Sjoe *	   the product of the indicated values.
33957113Sluigi */
34057113Sluigistatic quad_t
34111119Sugenget_bsz(val)
34211119Sugen	char *val;
34385665Sjoe{
34485665Sjoe	quad_t num, t;
34585665Sjoe	char *expr;
34685665Sjoe
34711119Sugen	errno = 0;
34811119Sugen	num = strtoq(val, &expr, 0);
34961420Sdan	if (num == QUAD_MAX && errno)		/* Overflow. */
35061420Sdan		err(1, "%s", oper);
35185665Sjoe	/*
35285665Sjoe	 * XXX (BFF) - The checks in individual f_* functions are
35385665Sjoe	 * now redundant, but this is only temporary.
35485665Sjoe	 */
35585665Sjoe
35661420Sdan	if (expr == val || num < 0)		/* No digits or negative. */
35798943Sluigi		errx(1, "%s: illegal numeric value", oper);
35898943Sluigi
35961420Sdan	switch(*expr) {
3604277Sjkh	case 'b':
3614277Sjkh		t = num;
36255205Speter		num *= 512;
3635543Sugen		if (t > num)
36485665Sjoe			goto erange;
36585665Sjoe		++expr;
36685665Sjoe		break;
36754175Sarchie	case 'k':
3685543Sugen		t = num;
36998943Sluigi		num *= 1 << 10;
37098613Sluigi		if (t > num)
37198613Sluigi			goto erange;
37298613Sluigi		++expr;
37398613Sluigi		break;
37498613Sluigi	case 'm':
37598613Sluigi		t = num;
37698613Sluigi		num *= 1 << 20;
37798613Sluigi		if (t > num)
37898613Sluigi			goto erange;
37998613Sluigi		++expr;
38098613Sluigi		break;
38198613Sluigi	case 'g':
38298613Sluigi		t = num;
38398613Sluigi		num *= 1 << 30;
38498613Sluigi		if (t > num)
38598613Sluigi			goto erange;
38698613Sluigi		++expr;
38798613Sluigi		break;
38898613Sluigi	case 'w':
38998613Sluigi		t = num;
3905543Sugen		num *= sizeof(int);
3915543Sugen		if (t > num)
3925543Sugen			goto erange;
39338482Swollman		++expr;
39438482Swollman		break;
39598943Sluigi	}
39698943Sluigi
39798943Sluigi	switch(*expr) {
39898943Sluigi		case '\0':
39998613Sluigi			break;
40085665Sjoe		case '*':			/* Backward compatible. */
40185665Sjoe		case 'x':
40285665Sjoe			t = num;
40357113Sluigi			num *= get_bsz(expr + 1);
40457113Sluigi			if (t > num)
40586047Sluigierange:				errx(1, "%s: %s", oper, strerror(ERANGE));
40655205Speter			break;
4073969Sjkh		default:
40898943Sluigi			errx(1, "%s: illegal numeric value", oper);
409	}
410	return (num);
411}
412