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