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