args.c revision 50471
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 * 3. All advertising materials mentioning features or use of this software
181556Srgrimes *    must display the following acknowledgement:
191556Srgrimes *	This product includes software developed by the University of
201556Srgrimes *	California, Berkeley and its contributors.
211556Srgrimes * 4. Neither the name of the University nor the names of its contributors
221556Srgrimes *    may be used to endorse or promote products derived from this software
231556Srgrimes *    without specific prior written permission.
241556Srgrimes *
251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351556Srgrimes * SUCH DAMAGE.
361556Srgrimes */
371556Srgrimes
381556Srgrimes#ifndef lint
3935773Scharnier#if 0
4036007Scharnierstatic char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
4135773Scharnier#endif
4235773Scharnierstatic const char rcsid[] =
4350471Speter  "$FreeBSD: head/bin/dd/args.c 50471 1999-08-27 23:15:48Z peter $";
441556Srgrimes#endif /* not lint */
451556Srgrimes
461556Srgrimes#include <sys/types.h>
471556Srgrimes
481556Srgrimes#include <err.h>
491556Srgrimes#include <errno.h>
501556Srgrimes#include <limits.h>
511556Srgrimes#include <stdlib.h>
521556Srgrimes#include <string.h>
531556Srgrimes
541556Srgrimes#include "dd.h"
551556Srgrimes#include "extern.h"
561556Srgrimes
571556Srgrimesstatic int	c_arg __P((const void *, const void *));
581556Srgrimesstatic int	c_conv __P((const void *, const void *));
591556Srgrimesstatic void	f_bs __P((char *));
601556Srgrimesstatic void	f_cbs __P((char *));
611556Srgrimesstatic void	f_conv __P((char *));
621556Srgrimesstatic void	f_count __P((char *));
631556Srgrimesstatic void	f_files __P((char *));
641556Srgrimesstatic void	f_ibs __P((char *));
651556Srgrimesstatic void	f_if __P((char *));
661556Srgrimesstatic void	f_obs __P((char *));
671556Srgrimesstatic void	f_of __P((char *));
681556Srgrimesstatic void	f_seek __P((char *));
691556Srgrimesstatic void	f_skip __P((char *));
7048051Sgreenstatic quad_t	get_bsz __P((char *));
711556Srgrimes
721556Srgrimesstatic struct arg {
731556Srgrimes	char *name;
741556Srgrimes	void (*f) __P((char *));
751556Srgrimes	u_int set, noset;
761556Srgrimes} args[] = {
771556Srgrimes	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
781556Srgrimes	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
791556Srgrimes	{ "conv",	f_conv,		0,	 0 },
801556Srgrimes	{ "count",	f_count,	C_COUNT, C_COUNT },
811556Srgrimes	{ "files",	f_files,	C_FILES, C_FILES },
821556Srgrimes	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
831556Srgrimes	{ "if",		f_if,		C_IF,	 C_IF },
841556Srgrimes	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
851556Srgrimes	{ "of",		f_of,		C_OF,	 C_OF },
861556Srgrimes	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
871556Srgrimes	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
881556Srgrimes};
891556Srgrimes
901556Srgrimesstatic char *oper;
911556Srgrimes
921556Srgrimes/*
931556Srgrimes * args -- parse JCL syntax of dd.
941556Srgrimes */
951556Srgrimesvoid
961556Srgrimesjcl(argv)
971556Srgrimes	char **argv;
981556Srgrimes{
991556Srgrimes	struct arg *ap, tmp;
1001556Srgrimes	char *arg;
1011556Srgrimes
1021556Srgrimes	in.dbsz = out.dbsz = 512;
1031556Srgrimes
10419720Sphk	while ((oper = *++argv) != NULL) {
10530230Seivind		if ((oper = strdup(oper)) == NULL)
10648051Sgreen			errx(1, "unable to allocate space for the argument \"%s\"", *argv);
1071556Srgrimes		if ((arg = strchr(oper, '=')) == NULL)
1081556Srgrimes			errx(1, "unknown operand %s", oper);
1091556Srgrimes		*arg++ = '\0';
1101556Srgrimes		if (!*arg)
1111556Srgrimes			errx(1, "no value specified for %s", oper);
1121556Srgrimes		tmp.name = oper;
11348051Sgreen		if (!(ap = (struct arg *)bsearch(&tmp, args,
11448051Sgreen		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
11548051Sgreen		    c_arg)))
1161556Srgrimes			errx(1, "unknown operand %s", tmp.name);
1171556Srgrimes		if (ddflags & ap->noset)
11848051Sgreen			errx(1, "%s: illegal argument combination or already set",
11948051Sgreen			    tmp.name);
1201556Srgrimes		ddflags |= ap->set;
1211556Srgrimes		ap->f(arg);
1221556Srgrimes	}
1231556Srgrimes
1241556Srgrimes	/* Final sanity checks. */
1251556Srgrimes
1261556Srgrimes	if (ddflags & C_BS) {
1271556Srgrimes		/*
1281556Srgrimes		 * Bs is turned off by any conversion -- we assume the user
1291556Srgrimes		 * just wanted to set both the input and output block sizes
1301556Srgrimes		 * and didn't want the bs semantics, so we don't warn.
1311556Srgrimes		 */
1321556Srgrimes		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
1331556Srgrimes			ddflags &= ~C_BS;
1341556Srgrimes
1351556Srgrimes		/* Bs supersedes ibs and obs. */
1361556Srgrimes		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
1371556Srgrimes			warnx("bs supersedes ibs and obs");
1381556Srgrimes	}
1391556Srgrimes
1401556Srgrimes	/*
1411556Srgrimes	 * Ascii/ebcdic and cbs implies block/unblock.
1421556Srgrimes	 * Block/unblock requires cbs and vice-versa.
1431556Srgrimes	 */
1441556Srgrimes	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
1451556Srgrimes		if (!(ddflags & C_CBS))
1461556Srgrimes			errx(1, "record operations require cbs");
1471556Srgrimes		if (cbsz == 0)
1481556Srgrimes			errx(1, "cbs cannot be zero");
1491556Srgrimes		cfunc = ddflags & C_BLOCK ? block : unblock;
1501556Srgrimes	} else if (ddflags & C_CBS) {
1511556Srgrimes		if (ddflags & (C_ASCII|C_EBCDIC)) {
1521556Srgrimes			if (ddflags & C_ASCII) {
1531556Srgrimes				ddflags |= C_UNBLOCK;
1541556Srgrimes				cfunc = unblock;
1551556Srgrimes			} else {
1561556Srgrimes				ddflags |= C_BLOCK;
1571556Srgrimes				cfunc = block;
1581556Srgrimes			}
1591556Srgrimes		} else
1601556Srgrimes			errx(1, "cbs meaningless if not doing record operations");
1611556Srgrimes	} else
1621556Srgrimes		cfunc = def;
1631556Srgrimes}
1641556Srgrimes
1651556Srgrimesstatic int
1661556Srgrimesc_arg(a, b)
1671556Srgrimes	const void *a, *b;
1681556Srgrimes{
1691556Srgrimes
1701556Srgrimes	return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
1711556Srgrimes}
1721556Srgrimes
1731556Srgrimesstatic void
1741556Srgrimesf_bs(arg)
1751556Srgrimes	char *arg;
1761556Srgrimes{
17748051Sgreen	quad_t res = get_bsz(arg);
1781556Srgrimes
17948051Sgreen	if (res < 1 || res > INT_MAX)
18048051Sgreen		errx(1, "bs must be between 1 and %d", INT_MAX);
18148051Sgreen	in.dbsz = out.dbsz = (int)res;
1821556Srgrimes}
1831556Srgrimes
1841556Srgrimesstatic void
1851556Srgrimesf_cbs(arg)
1861556Srgrimes	char *arg;
1871556Srgrimes{
18848051Sgreen	quad_t res = get_bsz(arg);
1891556Srgrimes
19048051Sgreen	if (res < 1 || res > INT_MAX)
19148051Sgreen		errx(1, "cbs must be between 1 and %d", INT_MAX);
19248051Sgreen
19348051Sgreen	cbsz = (int)res;
1941556Srgrimes}
1951556Srgrimes
1961556Srgrimesstatic void
1971556Srgrimesf_count(arg)
1981556Srgrimes	char *arg;
1991556Srgrimes{
2001556Srgrimes
20148051Sgreen	cpy_cnt = get_bsz(arg);
2021556Srgrimes	if (!cpy_cnt)
2031556Srgrimes		terminate(0);
20448051Sgreen	if (cpy_cnt < 0)
20548051Sgreen		errx(1, "count cannot be negative");
2061556Srgrimes}
2071556Srgrimes
2081556Srgrimesstatic void
2091556Srgrimesf_files(arg)
2101556Srgrimes	char *arg;
2111556Srgrimes{
21248051Sgreen	quad_t res = get_bsz(arg);
2131556Srgrimes
21448051Sgreen	files_cnt = res;
2151556Srgrimes}
2161556Srgrimes
2171556Srgrimesstatic void
2181556Srgrimesf_ibs(arg)
2191556Srgrimes	char *arg;
2201556Srgrimes{
2211556Srgrimes
22248051Sgreen	if (!(ddflags & C_BS)) {
22348051Sgreen		quad_t res = get_bsz(arg);
22448051Sgreen
22548051Sgreen		if (res < 1 || res > INT_MAX)
22648051Sgreen			errx(1, "ibs must be between 1 and %d", INT_MAX);
22748051Sgreen		in.dbsz = (int)res;
22848051Sgreen	}
2291556Srgrimes}
2301556Srgrimes
2311556Srgrimesstatic void
2321556Srgrimesf_if(arg)
2331556Srgrimes	char *arg;
2341556Srgrimes{
2351556Srgrimes
2361556Srgrimes	in.name = arg;
2371556Srgrimes}
2381556Srgrimes
2391556Srgrimesstatic void
2401556Srgrimesf_obs(arg)
2411556Srgrimes	char *arg;
2421556Srgrimes{
2431556Srgrimes
24448051Sgreen	if (!(ddflags & C_BS)) {
24548051Sgreen		quad_t res = get_bsz(arg);
24648051Sgreen
24748051Sgreen		if (res < 1 || res > INT_MAX)
24848051Sgreen			errx(1, "ibs must be between 1 and %d", INT_MAX);
24948051Sgreen		out.dbsz = (int)res;
25048051Sgreen	}
2511556Srgrimes}
2521556Srgrimes
2531556Srgrimesstatic void
2541556Srgrimesf_of(arg)
2551556Srgrimes	char *arg;
2561556Srgrimes{
2571556Srgrimes
2581556Srgrimes	out.name = arg;
2591556Srgrimes}
2601556Srgrimes
2611556Srgrimesstatic void
2621556Srgrimesf_seek(arg)
2631556Srgrimes	char *arg;
2641556Srgrimes{
2651556Srgrimes
26648026Sgreen	out.offset = get_bsz(arg);
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimesstatic void
2701556Srgrimesf_skip(arg)
2711556Srgrimes	char *arg;
2721556Srgrimes{
2731556Srgrimes
27448026Sgreen	in.offset = get_bsz(arg);
2751556Srgrimes}
2761556Srgrimes
2771556Srgrimesstatic struct conv {
2781556Srgrimes	char *name;
2791556Srgrimes	u_int set, noset;
2801556Srgrimes	u_char *ctab;
2811556Srgrimes} clist[] = {
2821556Srgrimes	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
2831556Srgrimes	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
2841556Srgrimes	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
2851556Srgrimes	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
2861556Srgrimes	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
2871556Srgrimes	{ "noerror",	C_NOERROR,	0,		NULL },
2881556Srgrimes	{ "notrunc",	C_NOTRUNC,	0,		NULL },
2891556Srgrimes	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
2901556Srgrimes	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
2911556Srgrimes	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
29231120Sjoerg	{ "osync",	C_OSYNC,	C_BS,		NULL },
29330312Sjoerg	{ "sparse",	C_SPARSE,	0,		NULL },
2941556Srgrimes	{ "swab",	C_SWAB,		0,		NULL },
2951556Srgrimes	{ "sync",	C_SYNC,		0,		NULL },
2961556Srgrimes	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
2971556Srgrimes	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
2981556Srgrimes};
2991556Srgrimes
3001556Srgrimesstatic void
3011556Srgrimesf_conv(arg)
3021556Srgrimes	char *arg;
3031556Srgrimes{
3041556Srgrimes	struct conv *cp, tmp;
3051556Srgrimes
3061556Srgrimes	while (arg != NULL) {
3071556Srgrimes		tmp.name = strsep(&arg, ",");
30848051Sgreen		if (!(cp = (struct conv *)bsearch(&tmp, clist,
30948051Sgreen		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
31048051Sgreen		    c_conv)))
3111556Srgrimes			errx(1, "unknown conversion %s", tmp.name);
3121556Srgrimes		if (ddflags & cp->noset)
3131556Srgrimes			errx(1, "%s: illegal conversion combination", tmp.name);
3141556Srgrimes		ddflags |= cp->set;
3151556Srgrimes		if (cp->ctab)
3161556Srgrimes			ctab = cp->ctab;
3171556Srgrimes	}
3181556Srgrimes}
3191556Srgrimes
3201556Srgrimesstatic int
3211556Srgrimesc_conv(a, b)
3221556Srgrimes	const void *a, *b;
3231556Srgrimes{
3241556Srgrimes
3251556Srgrimes	return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name));
3261556Srgrimes}
3271556Srgrimes
3281556Srgrimes/*
32948051Sgreen * Convert an expression of the following forms to a quad_t.
3301556Srgrimes * 	1) A positive decimal number.
33148051Sgreen *	2) A positive decimal number followed by a b (mult by 512.)
33248051Sgreen *	3) A positive decimal number followed by a k (mult by 1 << 10.)
33348051Sgreen *	4) A positive decimal number followed by a m (mult by 1 << 20.)
33448051Sgreen *	5) A positive decimal number followed by a g (mult by 1 << 30.)
33548051Sgreen *	5) A positive decimal number followed by a w (mult by sizeof int.)
33648051Sgreen *	6) Two or more positive decimal numbers (with/without [bkmgw])
33746684Skris *	   separated by x (also * for backwards compatibility), specifying
3381556Srgrimes *	   the product of the indicated values.
3391556Srgrimes */
34048051Sgreenstatic quad_t
3411556Srgrimesget_bsz(val)
3421556Srgrimes	char *val;
3431556Srgrimes{
34448051Sgreen	quad_t num, t;
3451556Srgrimes	char *expr;
3461556Srgrimes
34748051Sgreen	errno = 0;
34848026Sgreen	num = strtoq(val, &expr, 0);
34948051Sgreen	if (num == QUAD_MAX && errno)		/* Overflow. */
35048051Sgreen		err(1, "%s", oper);
35148051Sgreen	/*
35248051Sgreen	 * XXX (BFF) - The checks in individual f_* functions are
35348051Sgreen	 * now redundant, but this is only temporary.
35448051Sgreen	 */
35548051Sgreen
35648051Sgreen	if (expr == val || num < 0)		/* No digits or negative. */
3571556Srgrimes		errx(1, "%s: illegal numeric value", oper);
3581556Srgrimes
3591556Srgrimes	switch(*expr) {
3601556Srgrimes	case 'b':
3611556Srgrimes		t = num;
3621556Srgrimes		num *= 512;
3631556Srgrimes		if (t > num)
3641556Srgrimes			goto erange;
3651556Srgrimes		++expr;
3661556Srgrimes		break;
3671556Srgrimes	case 'k':
3681556Srgrimes		t = num;
36948051Sgreen		num *= 1 << 10;
3701556Srgrimes		if (t > num)
3711556Srgrimes			goto erange;
3721556Srgrimes		++expr;
3731556Srgrimes		break;
3741556Srgrimes	case 'm':
3751556Srgrimes		t = num;
37648051Sgreen		num *= 1 << 20;
3771556Srgrimes		if (t > num)
3781556Srgrimes			goto erange;
3791556Srgrimes		++expr;
3801556Srgrimes		break;
38148051Sgreen	case 'g':
38248051Sgreen		t = num;
38348051Sgreen		num *= 1 << 30;
38448051Sgreen		if (t > num)
38548051Sgreen			goto erange;
38648051Sgreen		++expr;
38748051Sgreen		break;
3881556Srgrimes	case 'w':
3891556Srgrimes		t = num;
3901556Srgrimes		num *= sizeof(int);
3911556Srgrimes		if (t > num)
3921556Srgrimes			goto erange;
3931556Srgrimes		++expr;
3941556Srgrimes		break;
3951556Srgrimes	}
3961556Srgrimes
3971556Srgrimes	switch(*expr) {
3981556Srgrimes		case '\0':
3991556Srgrimes			break;
4001556Srgrimes		case '*':			/* Backward compatible. */
4011556Srgrimes		case 'x':
4021556Srgrimes			t = num;
4031556Srgrimes			num *= get_bsz(expr + 1);
4041556Srgrimes			if (t > num)
4051556Srgrimeserange:				errx(1, "%s: %s", oper, strerror(ERANGE));
4061556Srgrimes			break;
4071556Srgrimes		default:
4081556Srgrimes			errx(1, "%s: illegal numeric value", oper);
4091556Srgrimes	}
4101556Srgrimes	return (num);
4111556Srgrimes}
412