args.c revision 51208
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 51208 1999-09-12 16:51:53Z green $"; 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 *)); 7051137Sgreenstatic quad_t get_num __P((char *)); 7151208Sgreenstatic off_t get_offset __P((char *)); 721556Srgrimes 7351208Sgreenstatic const struct arg { 741556Srgrimes char *name; 751556Srgrimes void (*f) __P((char *)); 761556Srgrimes u_int set, noset; 771556Srgrimes} args[] = { 781556Srgrimes { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC }, 791556Srgrimes { "cbs", f_cbs, C_CBS, C_CBS }, 801556Srgrimes { "conv", f_conv, 0, 0 }, 811556Srgrimes { "count", f_count, C_COUNT, C_COUNT }, 821556Srgrimes { "files", f_files, C_FILES, C_FILES }, 831556Srgrimes { "ibs", f_ibs, C_IBS, C_BS|C_IBS }, 841556Srgrimes { "if", f_if, C_IF, C_IF }, 851556Srgrimes { "obs", f_obs, C_OBS, C_BS|C_OBS }, 861556Srgrimes { "of", f_of, C_OF, C_OF }, 871556Srgrimes { "seek", f_seek, C_SEEK, C_SEEK }, 881556Srgrimes { "skip", f_skip, C_SKIP, C_SKIP }, 891556Srgrimes}; 901556Srgrimes 911556Srgrimesstatic char *oper; 921556Srgrimes 931556Srgrimes/* 941556Srgrimes * args -- parse JCL syntax of dd. 951556Srgrimes */ 961556Srgrimesvoid 971556Srgrimesjcl(argv) 981556Srgrimes char **argv; 991556Srgrimes{ 1001556Srgrimes struct arg *ap, tmp; 1011556Srgrimes char *arg; 1021556Srgrimes 1031556Srgrimes in.dbsz = out.dbsz = 512; 1041556Srgrimes 10519720Sphk while ((oper = *++argv) != NULL) { 10630230Seivind if ((oper = strdup(oper)) == NULL) 10748051Sgreen errx(1, "unable to allocate space for the argument \"%s\"", *argv); 1081556Srgrimes if ((arg = strchr(oper, '=')) == NULL) 1091556Srgrimes errx(1, "unknown operand %s", oper); 1101556Srgrimes *arg++ = '\0'; 1111556Srgrimes if (!*arg) 1121556Srgrimes errx(1, "no value specified for %s", oper); 1131556Srgrimes tmp.name = oper; 11448051Sgreen if (!(ap = (struct arg *)bsearch(&tmp, args, 11548051Sgreen sizeof(args)/sizeof(struct arg), sizeof(struct arg), 11648051Sgreen c_arg))) 1171556Srgrimes errx(1, "unknown operand %s", tmp.name); 1181556Srgrimes if (ddflags & ap->noset) 11948051Sgreen errx(1, "%s: illegal argument combination or already set", 12048051Sgreen tmp.name); 1211556Srgrimes ddflags |= ap->set; 1221556Srgrimes ap->f(arg); 1231556Srgrimes } 1241556Srgrimes 1251556Srgrimes /* Final sanity checks. */ 1261556Srgrimes 1271556Srgrimes if (ddflags & C_BS) { 1281556Srgrimes /* 1291556Srgrimes * Bs is turned off by any conversion -- we assume the user 1301556Srgrimes * just wanted to set both the input and output block sizes 1311556Srgrimes * and didn't want the bs semantics, so we don't warn. 1321556Srgrimes */ 1331556Srgrimes if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK)) 1341556Srgrimes ddflags &= ~C_BS; 1351556Srgrimes 1361556Srgrimes /* Bs supersedes ibs and obs. */ 1371556Srgrimes if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) 1381556Srgrimes warnx("bs supersedes ibs and obs"); 1391556Srgrimes } 1401556Srgrimes 1411556Srgrimes /* 1421556Srgrimes * Ascii/ebcdic and cbs implies block/unblock. 1431556Srgrimes * Block/unblock requires cbs and vice-versa. 1441556Srgrimes */ 1451556Srgrimes if (ddflags & (C_BLOCK|C_UNBLOCK)) { 1461556Srgrimes if (!(ddflags & C_CBS)) 1471556Srgrimes errx(1, "record operations require cbs"); 1481556Srgrimes if (cbsz == 0) 1491556Srgrimes errx(1, "cbs cannot be zero"); 1501556Srgrimes cfunc = ddflags & C_BLOCK ? block : unblock; 1511556Srgrimes } else if (ddflags & C_CBS) { 1521556Srgrimes if (ddflags & (C_ASCII|C_EBCDIC)) { 1531556Srgrimes if (ddflags & C_ASCII) { 1541556Srgrimes ddflags |= C_UNBLOCK; 1551556Srgrimes cfunc = unblock; 1561556Srgrimes } else { 1571556Srgrimes ddflags |= C_BLOCK; 1581556Srgrimes cfunc = block; 1591556Srgrimes } 1601556Srgrimes } else 1611556Srgrimes errx(1, "cbs meaningless if not doing record operations"); 1621556Srgrimes } else 1631556Srgrimes cfunc = def; 16451208Sgreen /* 16551208Sgreen * Bail out if the calculation of a file offset would overflow. 16651208Sgreen */ 16751208Sgreen if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz) 16851208Sgreen errx(1, "seek offsets cannot be larger than %qd", QUAD_MAX); 1691556Srgrimes} 1701556Srgrimes 1711556Srgrimesstatic int 1721556Srgrimesc_arg(a, b) 1731556Srgrimes const void *a, *b; 1741556Srgrimes{ 1751556Srgrimes 1761556Srgrimes return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name)); 1771556Srgrimes} 1781556Srgrimes 1791556Srgrimesstatic void 1801556Srgrimesf_bs(arg) 1811556Srgrimes char *arg; 1821556Srgrimes{ 18351208Sgreen quad_t res; 1841556Srgrimes 18551208Sgreen res = get_num(arg); 18651208Sgreen if (res < 1 || res > SSIZE_MAX) 18751208Sgreen errx(1, "bs must be between 1 and %d", SSIZE_MAX); 18851208Sgreen in.dbsz = out.dbsz = (size_t)res; 1891556Srgrimes} 1901556Srgrimes 1911556Srgrimesstatic void 1921556Srgrimesf_cbs(arg) 1931556Srgrimes char *arg; 1941556Srgrimes{ 19551208Sgreen quad_t res; 1961556Srgrimes 19751208Sgreen res = get_num(arg); 19851208Sgreen if (res < 1 || res > SSIZE_MAX) 19951208Sgreen errx(1, "cbs must be between 1 and %d", SSIZE_MAX); 20051208Sgreen cbsz = (size_t)res; 2011556Srgrimes} 2021556Srgrimes 2031556Srgrimesstatic void 2041556Srgrimesf_count(arg) 2051556Srgrimes char *arg; 2061556Srgrimes{ 2071556Srgrimes 20851137Sgreen cpy_cnt = get_num(arg); 20951137Sgreen 2101556Srgrimes if (!cpy_cnt) 2111556Srgrimes terminate(0); 2121556Srgrimes} 2131556Srgrimes 2141556Srgrimesstatic void 2151556Srgrimesf_files(arg) 2161556Srgrimes char *arg; 2171556Srgrimes{ 2181556Srgrimes 21951137Sgreen files_cnt = get_num(arg); 2201556Srgrimes} 2211556Srgrimes 2221556Srgrimesstatic void 2231556Srgrimesf_ibs(arg) 2241556Srgrimes char *arg; 2251556Srgrimes{ 22651208Sgreen quad_t res; 2271556Srgrimes 22848051Sgreen if (!(ddflags & C_BS)) { 22951208Sgreen res = get_num(arg); 23051208Sgreen if (res < 1 || res > SSIZE_MAX) 23148051Sgreen errx(1, "ibs must be between 1 and %d", INT_MAX); 23248051Sgreen in.dbsz = (int)res; 23348051Sgreen } 2341556Srgrimes} 2351556Srgrimes 2361556Srgrimesstatic void 2371556Srgrimesf_if(arg) 2381556Srgrimes char *arg; 2391556Srgrimes{ 2401556Srgrimes 2411556Srgrimes in.name = arg; 2421556Srgrimes} 2431556Srgrimes 2441556Srgrimesstatic void 2451556Srgrimesf_obs(arg) 2461556Srgrimes char *arg; 2471556Srgrimes{ 24851208Sgreen quad_t res; 2491556Srgrimes 25048051Sgreen if (!(ddflags & C_BS)) { 25151208Sgreen res = get_num(arg); 25251208Sgreen if (res < 1 || res > SSIZE_MAX) 25351208Sgreen errx(1, "obs must be between 1 and %d", SSIZE_MAX); 25451208Sgreen out.dbsz = (size_t)res; 25548051Sgreen } 2561556Srgrimes} 2571556Srgrimes 2581556Srgrimesstatic void 2591556Srgrimesf_of(arg) 2601556Srgrimes char *arg; 2611556Srgrimes{ 2621556Srgrimes 2631556Srgrimes out.name = arg; 2641556Srgrimes} 2651556Srgrimes 2661556Srgrimesstatic void 2671556Srgrimesf_seek(arg) 2681556Srgrimes char *arg; 2691556Srgrimes{ 2701556Srgrimes 27151208Sgreen out.offset = get_offset(arg); 2721556Srgrimes} 2731556Srgrimes 2741556Srgrimesstatic void 2751556Srgrimesf_skip(arg) 2761556Srgrimes char *arg; 2771556Srgrimes{ 2781556Srgrimes 27951208Sgreen in.offset = get_offset(arg); 2801556Srgrimes} 2811556Srgrimes 28251208Sgreenstatic const struct conv { 2831556Srgrimes char *name; 2841556Srgrimes u_int set, noset; 28551208Sgreen const u_char *ctab; 2861556Srgrimes} clist[] = { 2871556Srgrimes { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX }, 2881556Srgrimes { "block", C_BLOCK, C_UNBLOCK, NULL }, 2891556Srgrimes { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX }, 2901556Srgrimes { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX }, 2911556Srgrimes { "lcase", C_LCASE, C_UCASE, NULL }, 2921556Srgrimes { "noerror", C_NOERROR, 0, NULL }, 2931556Srgrimes { "notrunc", C_NOTRUNC, 0, NULL }, 2941556Srgrimes { "oldascii", C_ASCII, C_EBCDIC, e2a_32V }, 2951556Srgrimes { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V }, 2961556Srgrimes { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V }, 29731120Sjoerg { "osync", C_OSYNC, C_BS, NULL }, 29830312Sjoerg { "sparse", C_SPARSE, 0, NULL }, 2991556Srgrimes { "swab", C_SWAB, 0, NULL }, 3001556Srgrimes { "sync", C_SYNC, 0, NULL }, 3011556Srgrimes { "ucase", C_UCASE, C_LCASE, NULL }, 3021556Srgrimes { "unblock", C_UNBLOCK, C_BLOCK, NULL }, 3031556Srgrimes}; 3041556Srgrimes 3051556Srgrimesstatic void 3061556Srgrimesf_conv(arg) 3071556Srgrimes char *arg; 3081556Srgrimes{ 3091556Srgrimes struct conv *cp, tmp; 3101556Srgrimes 3111556Srgrimes while (arg != NULL) { 3121556Srgrimes tmp.name = strsep(&arg, ","); 31351208Sgreen cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), 31451208Sgreen sizeof(struct conv), c_conv); 31551208Sgreen if (cp == NULL) 3161556Srgrimes errx(1, "unknown conversion %s", tmp.name); 3171556Srgrimes if (ddflags & cp->noset) 3181556Srgrimes errx(1, "%s: illegal conversion combination", tmp.name); 3191556Srgrimes ddflags |= cp->set; 3201556Srgrimes if (cp->ctab) 3211556Srgrimes ctab = cp->ctab; 3221556Srgrimes } 3231556Srgrimes} 3241556Srgrimes 3251556Srgrimesstatic int 3261556Srgrimesc_conv(a, b) 3271556Srgrimes const void *a, *b; 3281556Srgrimes{ 3291556Srgrimes 3301556Srgrimes return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name)); 3311556Srgrimes} 3321556Srgrimes 3331556Srgrimes/* 33448051Sgreen * Convert an expression of the following forms to a quad_t. 3351556Srgrimes * 1) A positive decimal number. 33648051Sgreen * 2) A positive decimal number followed by a b (mult by 512.) 33748051Sgreen * 3) A positive decimal number followed by a k (mult by 1 << 10.) 33848051Sgreen * 4) A positive decimal number followed by a m (mult by 1 << 20.) 33948051Sgreen * 5) A positive decimal number followed by a g (mult by 1 << 30.) 34048051Sgreen * 5) A positive decimal number followed by a w (mult by sizeof int.) 34148051Sgreen * 6) Two or more positive decimal numbers (with/without [bkmgw]) 34246684Skris * separated by x (also * for backwards compatibility), specifying 3431556Srgrimes * the product of the indicated values. 3441556Srgrimes */ 34548051Sgreenstatic quad_t 34651137Sgreenget_num(val) 3471556Srgrimes char *val; 3481556Srgrimes{ 34948051Sgreen quad_t num, t; 3501556Srgrimes char *expr; 3511556Srgrimes 35248051Sgreen errno = 0; 35348026Sgreen num = strtoq(val, &expr, 0); 35451208Sgreen if (errno != 0) /* Overflow or underflow. */ 35548051Sgreen err(1, "%s", oper); 35648051Sgreen 35751208Sgreen if (expr == val) /* No valid digits. */ 3581556Srgrimes errx(1, "%s: illegal numeric value", oper); 3591556Srgrimes 36051137Sgreen switch (*expr) { 3611556Srgrimes case 'b': 3621556Srgrimes t = num; 3631556Srgrimes num *= 512; 3641556Srgrimes if (t > num) 3651556Srgrimes goto erange; 3661556Srgrimes ++expr; 3671556Srgrimes break; 3681556Srgrimes case 'k': 3691556Srgrimes t = num; 37048051Sgreen num *= 1 << 10; 3711556Srgrimes if (t > num) 3721556Srgrimes goto erange; 3731556Srgrimes ++expr; 3741556Srgrimes break; 3751556Srgrimes case 'm': 3761556Srgrimes t = num; 37748051Sgreen num *= 1 << 20; 3781556Srgrimes if (t > num) 3791556Srgrimes goto erange; 3801556Srgrimes ++expr; 3811556Srgrimes break; 38248051Sgreen case 'g': 38348051Sgreen t = num; 38448051Sgreen num *= 1 << 30; 38548051Sgreen if (t > num) 38648051Sgreen goto erange; 38748051Sgreen ++expr; 38848051Sgreen break; 3891556Srgrimes case 'w': 3901556Srgrimes t = num; 3911556Srgrimes num *= sizeof(int); 3921556Srgrimes if (t > num) 3931556Srgrimes goto erange; 3941556Srgrimes ++expr; 3951556Srgrimes break; 3961556Srgrimes } 3971556Srgrimes 39851137Sgreen switch (*expr) { 3991556Srgrimes case '\0': 4001556Srgrimes break; 4011556Srgrimes case '*': /* Backward compatible. */ 4021556Srgrimes case 'x': 4031556Srgrimes t = num; 40451137Sgreen num *= get_num(expr + 1); 40551137Sgreen if (t <= num) 40651137Sgreen break; 40751137Sgreenerange: 40851137Sgreen errx(1, "%s: %s", oper, strerror(ERANGE)); 4091556Srgrimes default: 4101556Srgrimes errx(1, "%s: illegal numeric value", oper); 4111556Srgrimes } 4121556Srgrimes return (num); 4131556Srgrimes} 41451208Sgreen 41551208Sgreenstatic off_t 41651208Sgreenget_offset(val) 41751208Sgreen char *val; 41851208Sgreen{ 41951208Sgreen quad_t num; 42051208Sgreen 42151208Sgreen num = get_num(val); 42251208Sgreen if (num > QUAD_MAX || num < 0) /* XXX quad_t != off_t */ 42351208Sgreen errx(1, "%s: illegal offset", oper); /* Too big/negative. */ 42451208Sgreen return ((off_t)num); 42551208Sgreen} 426