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