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