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