args.c revision 1556
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
391556Srgrimesstatic char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
401556Srgrimes#endif /* not lint */
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes
441556Srgrimes#include <err.h>
451556Srgrimes#include <errno.h>
461556Srgrimes#include <limits.h>
471556Srgrimes#include <stdio.h>
481556Srgrimes#include <stdlib.h>
491556Srgrimes#include <string.h>
501556Srgrimes
511556Srgrimes#include "dd.h"
521556Srgrimes#include "extern.h"
531556Srgrimes
541556Srgrimesstatic int	c_arg __P((const void *, const void *));
551556Srgrimesstatic int	c_conv __P((const void *, const void *));
561556Srgrimesstatic void	f_bs __P((char *));
571556Srgrimesstatic void	f_cbs __P((char *));
581556Srgrimesstatic void	f_conv __P((char *));
591556Srgrimesstatic void	f_count __P((char *));
601556Srgrimesstatic void	f_files __P((char *));
611556Srgrimesstatic void	f_ibs __P((char *));
621556Srgrimesstatic void	f_if __P((char *));
631556Srgrimesstatic void	f_obs __P((char *));
641556Srgrimesstatic void	f_of __P((char *));
651556Srgrimesstatic void	f_seek __P((char *));
661556Srgrimesstatic void	f_skip __P((char *));
671556Srgrimesstatic u_long	get_bsz __P((char *));
681556Srgrimes
691556Srgrimesstatic struct arg {
701556Srgrimes	char *name;
711556Srgrimes	void (*f) __P((char *));
721556Srgrimes	u_int set, noset;
731556Srgrimes} args[] = {
741556Srgrimes	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
751556Srgrimes	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
761556Srgrimes	{ "conv",	f_conv,		0,	 0 },
771556Srgrimes	{ "count",	f_count,	C_COUNT, C_COUNT },
781556Srgrimes	{ "files",	f_files,	C_FILES, C_FILES },
791556Srgrimes	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
801556Srgrimes	{ "if",		f_if,		C_IF,	 C_IF },
811556Srgrimes	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
821556Srgrimes	{ "of",		f_of,		C_OF,	 C_OF },
831556Srgrimes	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
841556Srgrimes	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
851556Srgrimes};
861556Srgrimes
871556Srgrimesstatic char *oper;
881556Srgrimes
891556Srgrimes/*
901556Srgrimes * args -- parse JCL syntax of dd.
911556Srgrimes */
921556Srgrimesvoid
931556Srgrimesjcl(argv)
941556Srgrimes	char **argv;
951556Srgrimes{
961556Srgrimes	struct arg *ap, tmp;
971556Srgrimes	char *arg;
981556Srgrimes
991556Srgrimes	in.dbsz = out.dbsz = 512;
1001556Srgrimes
1011556Srgrimes	while (oper = *++argv) {
1021556Srgrimes		if ((arg = strchr(oper, '=')) == NULL)
1031556Srgrimes			errx(1, "unknown operand %s", oper);
1041556Srgrimes		*arg++ = '\0';
1051556Srgrimes		if (!*arg)
1061556Srgrimes			errx(1, "no value specified for %s", oper);
1071556Srgrimes		tmp.name = oper;
1081556Srgrimes		if (!(ap = (struct arg *)bsearch(&tmp, args,
1091556Srgrimes		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
1101556Srgrimes		    c_arg)))
1111556Srgrimes			errx(1, "unknown operand %s", tmp.name);
1121556Srgrimes		if (ddflags & ap->noset)
1131556Srgrimes			errx(1, "%s: illegal argument combination or already set",
1141556Srgrimes			    tmp.name);
1151556Srgrimes		ddflags |= ap->set;
1161556Srgrimes		ap->f(arg);
1171556Srgrimes	}
1181556Srgrimes
1191556Srgrimes	/* Final sanity checks. */
1201556Srgrimes
1211556Srgrimes	if (ddflags & C_BS) {
1221556Srgrimes		/*
1231556Srgrimes		 * Bs is turned off by any conversion -- we assume the user
1241556Srgrimes		 * just wanted to set both the input and output block sizes
1251556Srgrimes		 * and didn't want the bs semantics, so we don't warn.
1261556Srgrimes		 */
1271556Srgrimes		if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
1281556Srgrimes			ddflags &= ~C_BS;
1291556Srgrimes
1301556Srgrimes		/* Bs supersedes ibs and obs. */
1311556Srgrimes		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
1321556Srgrimes			warnx("bs supersedes ibs and obs");
1331556Srgrimes	}
1341556Srgrimes
1351556Srgrimes	/*
1361556Srgrimes	 * Ascii/ebcdic and cbs implies block/unblock.
1371556Srgrimes	 * Block/unblock requires cbs and vice-versa.
1381556Srgrimes	 */
1391556Srgrimes	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
1401556Srgrimes		if (!(ddflags & C_CBS))
1411556Srgrimes			errx(1, "record operations require cbs");
1421556Srgrimes		if (cbsz == 0)
1431556Srgrimes			errx(1, "cbs cannot be zero");
1441556Srgrimes		cfunc = ddflags & C_BLOCK ? block : unblock;
1451556Srgrimes	} else if (ddflags & C_CBS) {
1461556Srgrimes		if (ddflags & (C_ASCII|C_EBCDIC)) {
1471556Srgrimes			if (ddflags & C_ASCII) {
1481556Srgrimes				ddflags |= C_UNBLOCK;
1491556Srgrimes				cfunc = unblock;
1501556Srgrimes			} else {
1511556Srgrimes				ddflags |= C_BLOCK;
1521556Srgrimes				cfunc = block;
1531556Srgrimes			}
1541556Srgrimes		} else
1551556Srgrimes			errx(1, "cbs meaningless if not doing record operations");
1561556Srgrimes		if (cbsz == 0)
1571556Srgrimes			errx(1, "cbs cannot be zero");
1581556Srgrimes	} else
1591556Srgrimes		cfunc = def;
1601556Srgrimes
1611556Srgrimes	if (in.dbsz == 0 || out.dbsz == 0)
1621556Srgrimes		errx(1, "buffer sizes cannot be zero");
1631556Srgrimes
1641556Srgrimes	/*
1651556Srgrimes	 * Read, write and seek calls take ints as arguments.  Seek sizes
1661556Srgrimes	 * could be larger if we wanted to do it in stages or check only
1671556Srgrimes	 * regular files, but it's probably not worth it.
1681556Srgrimes	 */
1691556Srgrimes	if (in.dbsz > INT_MAX || out.dbsz > INT_MAX)
1701556Srgrimes		errx(1, "buffer sizes cannot be greater than %d", INT_MAX);
1711556Srgrimes	if (in.offset > INT_MAX / in.dbsz || out.offset > INT_MAX / out.dbsz)
1721556Srgrimes		errx(1, "seek offsets cannot be larger than %d", INT_MAX);
1731556Srgrimes}
1741556Srgrimes
1751556Srgrimesstatic int
1761556Srgrimesc_arg(a, b)
1771556Srgrimes	const void *a, *b;
1781556Srgrimes{
1791556Srgrimes
1801556Srgrimes	return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
1811556Srgrimes}
1821556Srgrimes
1831556Srgrimesstatic void
1841556Srgrimesf_bs(arg)
1851556Srgrimes	char *arg;
1861556Srgrimes{
1871556Srgrimes
1881556Srgrimes	in.dbsz = out.dbsz = (int)get_bsz(arg);
1891556Srgrimes}
1901556Srgrimes
1911556Srgrimesstatic void
1921556Srgrimesf_cbs(arg)
1931556Srgrimes	char *arg;
1941556Srgrimes{
1951556Srgrimes
1961556Srgrimes	cbsz = (int)get_bsz(arg);
1971556Srgrimes}
1981556Srgrimes
1991556Srgrimesstatic void
2001556Srgrimesf_count(arg)
2011556Srgrimes	char *arg;
2021556Srgrimes{
2031556Srgrimes
2041556Srgrimes	cpy_cnt = (u_int)get_bsz(arg);
2051556Srgrimes	if (!cpy_cnt)
2061556Srgrimes		terminate(0);
2071556Srgrimes}
2081556Srgrimes
2091556Srgrimesstatic void
2101556Srgrimesf_files(arg)
2111556Srgrimes	char *arg;
2121556Srgrimes{
2131556Srgrimes
2141556Srgrimes	files_cnt = (int)get_bsz(arg);
2151556Srgrimes}
2161556Srgrimes
2171556Srgrimesstatic void
2181556Srgrimesf_ibs(arg)
2191556Srgrimes	char *arg;
2201556Srgrimes{
2211556Srgrimes
2221556Srgrimes	if (!(ddflags & C_BS))
2231556Srgrimes		in.dbsz = (int)get_bsz(arg);
2241556Srgrimes}
2251556Srgrimes
2261556Srgrimesstatic void
2271556Srgrimesf_if(arg)
2281556Srgrimes	char *arg;
2291556Srgrimes{
2301556Srgrimes
2311556Srgrimes	in.name = arg;
2321556Srgrimes}
2331556Srgrimes
2341556Srgrimesstatic void
2351556Srgrimesf_obs(arg)
2361556Srgrimes	char *arg;
2371556Srgrimes{
2381556Srgrimes
2391556Srgrimes	if (!(ddflags & C_BS))
2401556Srgrimes		out.dbsz = (int)get_bsz(arg);
2411556Srgrimes}
2421556Srgrimes
2431556Srgrimesstatic void
2441556Srgrimesf_of(arg)
2451556Srgrimes	char *arg;
2461556Srgrimes{
2471556Srgrimes
2481556Srgrimes	out.name = arg;
2491556Srgrimes}
2501556Srgrimes
2511556Srgrimesstatic void
2521556Srgrimesf_seek(arg)
2531556Srgrimes	char *arg;
2541556Srgrimes{
2551556Srgrimes
2561556Srgrimes	out.offset = (u_int)get_bsz(arg);
2571556Srgrimes}
2581556Srgrimes
2591556Srgrimesstatic void
2601556Srgrimesf_skip(arg)
2611556Srgrimes	char *arg;
2621556Srgrimes{
2631556Srgrimes
2641556Srgrimes	in.offset = (u_int)get_bsz(arg);
2651556Srgrimes}
2661556Srgrimes
2671556Srgrimesstatic struct conv {
2681556Srgrimes	char *name;
2691556Srgrimes	u_int set, noset;
2701556Srgrimes	u_char *ctab;
2711556Srgrimes} clist[] = {
2721556Srgrimes	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
2731556Srgrimes	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
2741556Srgrimes	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
2751556Srgrimes	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
2761556Srgrimes	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
2771556Srgrimes	{ "noerror",	C_NOERROR,	0,		NULL },
2781556Srgrimes	{ "notrunc",	C_NOTRUNC,	0,		NULL },
2791556Srgrimes	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
2801556Srgrimes	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
2811556Srgrimes	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
2821556Srgrimes	{ "osync",	C_OSYNC,	C_BS,		NULL },
2831556Srgrimes	{ "swab",	C_SWAB,		0,		NULL },
2841556Srgrimes	{ "sync",	C_SYNC,		0,		NULL },
2851556Srgrimes	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
2861556Srgrimes	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
2871556Srgrimes};
2881556Srgrimes
2891556Srgrimesstatic void
2901556Srgrimesf_conv(arg)
2911556Srgrimes	char *arg;
2921556Srgrimes{
2931556Srgrimes	struct conv *cp, tmp;
2941556Srgrimes
2951556Srgrimes	while (arg != NULL) {
2961556Srgrimes		tmp.name = strsep(&arg, ",");
2971556Srgrimes		if (!(cp = (struct conv *)bsearch(&tmp, clist,
2981556Srgrimes		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
2991556Srgrimes		    c_conv)))
3001556Srgrimes			errx(1, "unknown conversion %s", tmp.name);
3011556Srgrimes		if (ddflags & cp->noset)
3021556Srgrimes			errx(1, "%s: illegal conversion combination", tmp.name);
3031556Srgrimes		ddflags |= cp->set;
3041556Srgrimes		if (cp->ctab)
3051556Srgrimes			ctab = cp->ctab;
3061556Srgrimes	}
3071556Srgrimes}
3081556Srgrimes
3091556Srgrimesstatic int
3101556Srgrimesc_conv(a, b)
3111556Srgrimes	const void *a, *b;
3121556Srgrimes{
3131556Srgrimes
3141556Srgrimes	return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name));
3151556Srgrimes}
3161556Srgrimes
3171556Srgrimes/*
3181556Srgrimes * Convert an expression of the following forms to an unsigned long.
3191556Srgrimes * 	1) A positive decimal number.
3201556Srgrimes *	2) A positive decimal number followed by a b (mult by 512).
3211556Srgrimes *	3) A positive decimal number followed by a k (mult by 1024).
3221556Srgrimes *	4) A positive decimal number followed by a m (mult by 512).
3231556Srgrimes *	5) A positive decimal number followed by a w (mult by sizeof int)
3241556Srgrimes *	6) Two or more positive decimal numbers (with/without k,b or w).
3251556Srgrimes *	   seperated by x (also * for backwards compatibility), specifying
3261556Srgrimes *	   the product of the indicated values.
3271556Srgrimes */
3281556Srgrimesstatic u_long
3291556Srgrimesget_bsz(val)
3301556Srgrimes	char *val;
3311556Srgrimes{
3321556Srgrimes	u_long num, t;
3331556Srgrimes	char *expr;
3341556Srgrimes
3351556Srgrimes	num = strtoul(val, &expr, 0);
3361556Srgrimes	if (num == ULONG_MAX)			/* Overflow. */
3371556Srgrimes		err(1, "%s", oper);
3381556Srgrimes	if (expr == val)			/* No digits. */
3391556Srgrimes		errx(1, "%s: illegal numeric value", oper);
3401556Srgrimes
3411556Srgrimes	switch(*expr) {
3421556Srgrimes	case 'b':
3431556Srgrimes		t = num;
3441556Srgrimes		num *= 512;
3451556Srgrimes		if (t > num)
3461556Srgrimes			goto erange;
3471556Srgrimes		++expr;
3481556Srgrimes		break;
3491556Srgrimes	case 'k':
3501556Srgrimes		t = num;
3511556Srgrimes		num *= 1024;
3521556Srgrimes		if (t > num)
3531556Srgrimes			goto erange;
3541556Srgrimes		++expr;
3551556Srgrimes		break;
3561556Srgrimes	case 'm':
3571556Srgrimes		t = num;
3581556Srgrimes		num *= 1048576;
3591556Srgrimes		if (t > num)
3601556Srgrimes			goto erange;
3611556Srgrimes		++expr;
3621556Srgrimes		break;
3631556Srgrimes	case 'w':
3641556Srgrimes		t = num;
3651556Srgrimes		num *= sizeof(int);
3661556Srgrimes		if (t > num)
3671556Srgrimes			goto erange;
3681556Srgrimes		++expr;
3691556Srgrimes		break;
3701556Srgrimes	}
3711556Srgrimes
3721556Srgrimes	switch(*expr) {
3731556Srgrimes		case '\0':
3741556Srgrimes			break;
3751556Srgrimes		case '*':			/* Backward compatible. */
3761556Srgrimes		case 'x':
3771556Srgrimes			t = num;
3781556Srgrimes			num *= get_bsz(expr + 1);
3791556Srgrimes			if (t > num)
3801556Srgrimeserange:				errx(1, "%s: %s", oper, strerror(ERANGE));
3811556Srgrimes			break;
3821556Srgrimes		default:
3831556Srgrimes			errx(1, "%s: illegal numeric value", oper);
3841556Srgrimes	}
3851556Srgrimes	return (num);
3861556Srgrimes}
387