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