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[] = "@(#)args.c 5.5 (Berkeley) 7/29/91"; 40 #endif /* not lint */ 41 42 #include <sys/types.h> 43 #include <limits.h> 44 #include <errno.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include "dd.h" 49 #include "extern.h" 50 51 static u_long get_bsz __P((char *)); 52 53 static void f_bs __P((char *)); 54 static void f_cbs __P((char *)); 55 static void f_conv __P((char *)); 56 static void f_count __P((char *)); 57 static void f_files __P((char *)); 58 static void f_ibs __P((char *)); 59 static void f_if __P((char *)); 60 static void f_obs __P((char *)); 61 static void f_of __P((char *)); 62 static void f_seek __P((char *)); 63 static void f_skip __P((char *)); 64 65 static struct arg { 66 char *name; 67 void (*f) __P((char *)); 68 u_int set, noset; 69 } args[] = { 70 "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS, 71 "cbs", f_cbs, C_CBS, C_CBS, 72 "conv", f_conv, 0, 0, 73 "count", f_count, C_COUNT, C_COUNT, 74 "files", f_files, C_FILES, C_FILES, 75 "ibs", f_ibs, C_IBS, C_BS|C_IBS, 76 "if", f_if, C_IF, C_IF, 77 "obs", f_obs, C_OBS, C_BS|C_OBS, 78 "of", f_of, C_OF, C_OF, 79 "seek", f_seek, C_SEEK, C_SEEK, 80 "skip", f_skip, C_SKIP, C_SKIP, 81 }; 82 83 static char *oper; 84 85 /* 86 * args -- parse JCL syntax of dd. 87 */ 88 void 89 jcl(argv) 90 register char **argv; 91 { 92 register struct arg *ap; 93 struct arg tmp; 94 char *arg; 95 static int c_arg __P((const void *, const void *)); 96 97 in.dbsz = out.dbsz = 512; 98 99 while (oper = *++argv) { 100 if ((arg = index(oper, '=')) == NULL) 101 err("unknown operand %s", oper); 102 *arg++ = '\0'; 103 if (!*arg) 104 err("no value specified for %s", oper); 105 tmp.name = oper; 106 if (!(ap = (struct arg *)bsearch(&tmp, args, 107 sizeof(args)/sizeof(struct arg), sizeof(struct arg), 108 c_arg))) 109 err("unknown operand %s", tmp.name); 110 if (ddflags & ap->noset) 111 err("%s: illegal argument combination or already set", 112 tmp.name); 113 ddflags |= ap->set; 114 ap->f(arg); 115 } 116 117 /* Final sanity checks. */ 118 119 if (ddflags & C_BS) { 120 /* 121 * Bs is turned off by any conversion -- we assume the user 122 * just wanted to set both the input and output block sizes 123 * and didn't want the bs semantics, so we don't warn. 124 */ 125 if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK)) 126 ddflags &= ~C_BS; 127 128 /* Bs supersedes ibs and obs. */ 129 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS)) 130 warn("bs supersedes ibs and obs"); 131 } 132 133 /* 134 * Ascii/ebcdic and cbs implies block/unblock. 135 * Block/unblock requires cbs and vice-versa. 136 */ 137 if (ddflags & (C_BLOCK|C_UNBLOCK)) { 138 if (!(ddflags & C_CBS)) 139 err("record operations require cbs"); 140 if (cbsz == 0) 141 err("cbs cannot be zero"); 142 cfunc = ddflags & C_BLOCK ? block : unblock; 143 } else if (ddflags & C_CBS) { 144 if (ddflags & (C_ASCII|C_EBCDIC)) { 145 if (ddflags & C_ASCII) { 146 ddflags |= C_UNBLOCK; 147 cfunc = unblock; 148 } else { 149 ddflags |= C_BLOCK; 150 cfunc = block; 151 } 152 } else 153 err("cbs meaningless if not doing record operations"); 154 if (cbsz == 0) 155 err("cbs cannot be zero"); 156 } else 157 cfunc = def; 158 159 if (in.dbsz == 0 || out.dbsz == 0) 160 err("buffer sizes cannot be zero"); 161 162 /* 163 * Read, write and seek calls take ints as arguments. Seek sizes 164 * could be larger if we wanted to do it in stages or check only 165 * regular files, but it's probably not worth it. 166 */ 167 if (in.dbsz > INT_MAX || out.dbsz > INT_MAX) 168 err("buffer sizes cannot be greater than %d", INT_MAX); 169 if (in.offset > INT_MAX / in.dbsz || out.offset > INT_MAX / out.dbsz) 170 err("seek offsets cannot be larger than %d", INT_MAX); 171 } 172 173 static int 174 c_arg(a, b) 175 const void *a, *b; 176 { 177 return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name)); 178 } 179 180 static void 181 f_bs(arg) 182 char *arg; 183 { 184 in.dbsz = out.dbsz = (int)get_bsz(arg); 185 } 186 187 static void 188 f_cbs(arg) 189 char *arg; 190 { 191 cbsz = (int)get_bsz(arg); 192 } 193 194 static void 195 f_count(arg) 196 char *arg; 197 { 198 cpy_cnt = (u_int)get_bsz(arg); 199 if (!cpy_cnt) 200 terminate(0); 201 } 202 203 static void 204 f_files(arg) 205 char *arg; 206 { 207 files_cnt = (int)get_bsz(arg); 208 } 209 210 static void 211 f_ibs(arg) 212 char *arg; 213 { 214 if (!(ddflags & C_BS)) 215 in.dbsz = (int)get_bsz(arg); 216 } 217 218 static void 219 f_if(arg) 220 char *arg; 221 { 222 in.name = arg; 223 } 224 225 static void 226 f_obs(arg) 227 char *arg; 228 { 229 if (!(ddflags & C_BS)) 230 out.dbsz = (int)get_bsz(arg); 231 } 232 233 static void 234 f_of(arg) 235 char *arg; 236 { 237 out.name = arg; 238 } 239 240 static void 241 f_seek(arg) 242 char *arg; 243 { 244 out.offset = (u_int)get_bsz(arg); 245 } 246 247 static void 248 f_skip(arg) 249 char *arg; 250 { 251 in.offset = (u_int)get_bsz(arg); 252 } 253 254 static struct conv { 255 char *name; 256 u_int set, noset; 257 u_char *ctab; 258 } clist[] = { 259 "ascii", C_ASCII, C_EBCDIC, e2a_POSIX, 260 "block", C_BLOCK, C_UNBLOCK, NULL, 261 "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX, 262 "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX, 263 "lcase", C_LCASE, C_UCASE, NULL, 264 "noerror", C_NOERROR, 0, NULL, 265 "notrunc", C_NOTRUNC, 0, NULL, 266 "oldascii", C_ASCII, C_EBCDIC, e2a_32V, 267 "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V, 268 "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V, 269 "swab", C_SWAB, 0, NULL, 270 "sync", C_SYNC, 0, NULL, 271 "ucase", C_UCASE, C_LCASE, NULL, 272 "unblock", C_UNBLOCK, C_BLOCK, NULL, 273 }; 274 275 static void 276 f_conv(arg) 277 char *arg; 278 { 279 register struct conv *cp; 280 struct conv tmp; 281 static int c_conv __P((const void *, const void *)); 282 283 while (arg != NULL) { 284 tmp.name = strsep(&arg, ","); 285 if (!(cp = (struct conv *)bsearch(&tmp, clist, 286 sizeof(clist)/sizeof(struct conv), sizeof(struct conv), 287 c_conv))) 288 err("unknown conversion %s", tmp.name); 289 if (ddflags & cp->noset) 290 err("%s: illegal conversion combination", tmp.name); 291 ddflags |= cp->set; 292 if (cp->ctab) 293 ctab = cp->ctab; 294 } 295 } 296 297 static int 298 c_conv(a, b) 299 const void *a, *b; 300 { 301 return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name)); 302 } 303 304 /* 305 * Convert an expression of the following forms to an unsigned long. 306 * 1) A positive decimal number. 307 * 2) A positive decimal number followed by a b (mult by 512). 308 * 3) A positive decimal number followed by a k (mult by 1024). 309 * 4) A positive decimal number followed by a m (mult by 512). 310 * 5) A positive decimal number followed by a w (mult by sizeof int) 311 * 6) Two or more positive decimal numbers (with/without k,b or w). 312 * seperated by x (also * for backwards compatibility), specifying 313 * the product of the indicated values. 314 */ 315 static u_long 316 get_bsz(val) 317 char *val; 318 { 319 char *expr; 320 u_long num, t; 321 322 num = strtoul(val, &expr, 0); 323 if (num == ULONG_MAX) /* Overflow. */ 324 err("%s: %s", oper, strerror(errno)); 325 if (expr == val) /* No digits. */ 326 err("%s: illegal numeric value", oper); 327 328 switch(*expr) { 329 case 'b': 330 t = num; 331 num *= 512; 332 if (t > num) 333 goto erange; 334 ++expr; 335 break; 336 case 'k': 337 t = num; 338 num *= 1024; 339 if (t > num) 340 goto erange; 341 ++expr; 342 break; 343 case 'm': 344 t = num; 345 num *= 1048576; 346 if (t > num) 347 goto erange; 348 ++expr; 349 break; 350 case 'w': 351 t = num; 352 num *= sizeof(int); 353 if (t > num) 354 goto erange; 355 ++expr; 356 break; 357 } 358 359 switch(*expr) { 360 case '\0': 361 break; 362 case '*': /* Backward compatible. */ 363 case 'x': 364 t = num; 365 num *= get_bsz(expr + 1); 366 if (t > num) 367 erange: err("%s: %s", oper, strerror(ERANGE)); 368 break; 369 default: 370 err("%s: illegal numeric value", oper); 371 } 372 return(num); 373 } 374