Commit | Line | Data |
---|---|---|
cb955067 NW |
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 | } |