1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Keith Muller of the University of California, San Diego and Lance 7 * Visser of Convex Computer Corporation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #ifndef lint 39 /*static char sccsid[] = "from: @(#)args.c 5.5 (Berkeley) 7/29/91";*/ 40 static char rcsid[] = "$Id: args.c,v 1.2 1993/08/01 19:00:12 mycroft Exp $"; 41 #endif /* not lint */ 42 43 #include <sys/types.h> 44 #include <limits.h> 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include "dd.h" 50 #include "extern.h" 51 52 static u_long get_bsz __P((char *)); 53 54 static void f_bs __P((char *)); 55 static void f_cbs __P((char *)); 56 static void f_conv __P((char *)); 57 static void f_count __P((char *)); 58 static void f_files __P((char *)); 59 static void f_ibs __P((char *)); 60 static void f_if __P((char *)); 61 static void f_obs __P((char *)); 62 static void f_of __P((char *)); 63 static void f_seek __P((char *)); 64 static void f_skip __P((char *)); 65 66 static struct arg { 67 char *name; 68 void (*f) __P((char *)); 69 u_int set, noset; 70 } args[] = { 71 "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS, 72 "cbs", f_cbs, C_CBS, C_CBS, 73 "conv", f_conv, 0, 0, 74 "count", f_count, C_COUNT, C_COUNT, 75 "files", f_files, C_FILES, C_FILES, 76 "ibs", f_ibs, C_IBS, C_BS|C_IBS, 77 "if", f_if, C_IF, C_IF, 78 "obs", f_obs, C_OBS, C_BS|C_OBS, 79 "of", f_of, C_OF, C_OF, 80 "seek", f_seek, C_SEEK, C_SEEK, 81 "skip", f_skip, C_SKIP, C_SKIP, 82 }; 83 84 static char *oper; 85 86 /* 87 * args -- parse JCL syntax of dd. 88 */ 89 void 90 jcl(argv) 91 register char **argv; 92 { 93 register struct arg *ap; 94 struct arg tmp; 95 char *arg; 96 static int c_arg __P((const void *, const void *)); 97 98 in.dbsz = out.dbsz = 512; 99 100 while (oper = *++argv) { 101 if ((arg = index(oper, '=')) == NULL) 102 err("unknown operand %s", oper); 103 *arg++ = '\0'; 104 if (!*arg) 105 err("no value specified for %s", oper); 106 tmp.name = oper; 107 if (!(ap = (struct arg *)bsearch(&tmp, args, 108 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 109 c_arg))) 110 err("unknown operand %s", tmp.name); 111 if (ddflags & ap->noset) 112 err("%s: illegal argument combination or already set", 113 tmp.name); 114 ddflags |= ap->set; 115 ap->f(arg); 116 } 117 118 /* Final sanity checks. */ 119 120 if (ddflags & C_BS) { 121 /* 122 * Bs is turned off by any conversion -- we assume the user 123 * just wanted to set both the input and output block sizes 124 * and didn't want the bs semantics, so we don't warn. 125 */ 126 if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK)) 127 ddflags &= ~C_BS; 128 129 /* Bs supersedes ibs and obs. */ 130 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) 131 warn("bs supersedes ibs and obs"); 132 } 133 134 /* 135 * Ascii/ebcdic and cbs implies block/unblock. 136 * Block/unblock requires cbs and vice-versa. 137 */ 138 if (ddflags & (C_BLOCK|C_UNBLOCK)) { 139 if (!(ddflags & C_CBS)) 140 err("record operations require cbs"); 141 if (cbsz == 0) 142 err("cbs cannot be zero"); 143 cfunc = ddflags & C_BLOCK ? block : unblock; 144 } else if (ddflags & C_CBS) { 145 if (ddflags & (C_ASCII|C_EBCDIC)) { 146 if (ddflags & C_ASCII) { 147 ddflags |= C_UNBLOCK; 148 cfunc = unblock; 149 } else { 150 ddflags |= C_BLOCK; 151 cfunc = block; 152 } 153 } else 154 err("cbs meaningless if not doing record operations"); 155 if (cbsz == 0) 156 err("cbs cannot be zero"); 157 } else 158 cfunc = def; 159 160 if (in.dbsz == 0 || out.dbsz == 0) 161 err("buffer sizes cannot be zero"); 162 163 /* 164 * Read, write and seek calls take ints as arguments. Seek sizes 165 * could be larger if we wanted to do it in stages or check only 166 * regular files, but it's probably not worth it. 167 */ 168 if (in.dbsz > INT_MAX || out.dbsz > INT_MAX) 169 err("buffer sizes cannot be greater than %d", INT_MAX); 170 if (in.offset > INT_MAX / in.dbsz || out.offset > INT_MAX / out.dbsz) 171 err("seek offsets cannot be larger than %d", INT_MAX); 172 } 173 174 static int 175 c_arg(a, b) 176 const void *a, *b; 177 { 178 return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name)); 179 } 180 181 static void 182 f_bs(arg) 183 char *arg; 184 { 185 in.dbsz = out.dbsz = (int)get_bsz(arg); 186 } 187 188 static void 189 f_cbs(arg) 190 char *arg; 191 { 192 cbsz = (int)get_bsz(arg); 193 } 194 195 static void 196 f_count(arg) 197 char *arg; 198 { 199 cpy_cnt = (u_int)get_bsz(arg); 200 if (!cpy_cnt) 201 terminate(0); 202 } 203 204 static void 205 f_files(arg) 206 char *arg; 207 { 208 files_cnt = (int)get_bsz(arg); 209 } 210 211 static void 212 f_ibs(arg) 213 char *arg; 214 { 215 if (!(ddflags & C_BS)) 216 in.dbsz = (int)get_bsz(arg); 217 } 218 219 static void 220 f_if(arg) 221 char *arg; 222 { 223 in.name = arg; 224 } 225 226 static void 227 f_obs(arg) 228 char *arg; 229 { 230 if (!(ddflags & C_BS)) 231 out.dbsz = (int)get_bsz(arg); 232 } 233 234 static void 235 f_of(arg) 236 char *arg; 237 { 238 out.name = arg; 239 } 240 241 static void 242 f_seek(arg) 243 char *arg; 244 { 245 out.offset = (u_int)get_bsz(arg); 246 } 247 248 static void 249 f_skip(arg) 250 char *arg; 251 { 252 in.offset = (u_int)get_bsz(arg); 253 } 254 255 static struct conv { 256 char *name; 257 u_int set, noset; 258 u_char *ctab; 259 } clist[] = { 260 "ascii", C_ASCII, C_EBCDIC, e2a_POSIX, 261 "block", C_BLOCK, C_UNBLOCK, NULL, 262 "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX, 263 "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX, 264 "lcase", C_LCASE, C_UCASE, NULL, 265 "noerror", C_NOERROR, 0, NULL, 266 "notrunc", C_NOTRUNC, 0, NULL, 267 "oldascii", C_ASCII, C_EBCDIC, e2a_32V, 268 "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V, 269 "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V, 270 "swab", C_SWAB, 0, NULL, 271 "sync", C_SYNC, 0, NULL, 272 "ucase", C_UCASE, C_LCASE, NULL, 273 "unblock", C_UNBLOCK, C_BLOCK, NULL, 274 }; 275 276 static void 277 f_conv(arg) 278 char *arg; 279 { 280 register struct conv *cp; 281 struct conv tmp; 282 static int c_conv __P((const void *, const void *)); 283 284 while (arg != NULL) { 285 tmp.name = strsep(&arg, ","); 286 if (!(cp = (struct conv *)bsearch(&tmp, clist, 287 sizeof(clist)/sizeof(struct conv), sizeof(struct conv), 288 c_conv))) 289 err("unknown conversion %s", tmp.name); 290 if (ddflags & cp->noset) 291 err("%s: illegal conversion combination", tmp.name); 292 ddflags |= cp->set; 293 if (cp->ctab) 294 ctab = cp->ctab; 295 } 296 } 297 298 static int 299 c_conv(a, b) 300 const void *a, *b; 301 { 302 return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name)); 303 } 304 305 /* 306 * Convert an expression of the following forms to an unsigned long. 307 * 1) A positive decimal number. 308 * 2) A positive decimal number followed by a b (mult by 512). 309 * 3) A positive decimal number followed by a k (mult by 1024). 310 * 4) A positive decimal number followed by a m (mult by 512). 311 * 5) A positive decimal number followed by a w (mult by sizeof int) 312 * 6) Two or more positive decimal numbers (with/without k,b or w). 313 * seperated by x (also * for backwards compatibility), specifying 314 * the product of the indicated values. 315 */ 316 static u_long 317 get_bsz(val) 318 char *val; 319 { 320 char *expr; 321 u_long num, t; 322 323 num = strtoul(val, &expr, 0); 324 if (num == ULONG_MAX) /* Overflow. */ 325 err("%s: %s", oper, strerror(errno)); 326 if (expr == val) /* No digits. */ 327 err("%s: illegal numeric value", oper); 328 329 switch(*expr) { 330 case 'b': 331 t = num; 332 num *= 512; 333 if (t > num) 334 goto erange; 335 ++expr; 336 break; 337 case 'k': 338 t = num; 339 num *= 1024; 340 if (t > num) 341 goto erange; 342 ++expr; 343 break; 344 case 'm': 345 t = num; 346 num *= 1048576; 347 if (t > num) 348 goto erange; 349 ++expr; 350 break; 351 case 'w': 352 t = num; 353 num *= sizeof(int); 354 if (t > num) 355 goto erange; 356 ++expr; 357 break; 358 } 359 360 switch(*expr) { 361 case '\0': 362 break; 363 case '*': /* Backward compatible. */ 364 case 'x': 365 t = num; 366 num *= get_bsz(expr + 1); 367 if (t > num) 368 erange: err("%s: %s", oper, strerror(ERANGE)); 369 break; 370 default: 371 err("%s: illegal numeric value", oper); 372 } 373 return(num); 374 } 375