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