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