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