fix worst-case buffer sizes for non-blocking I/O
[unix-history] / usr / src / bin / dd / args.c
CommitLineData
ac894d30
KB
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
a08a4cd0
KB
6 * Keith Muller of the University of California, San Diego and Lance
7 * Visser of Convex Computer Corporation.
ac894d30
KB
8 *
9 * %sccs.include.redist.c%
10 */
11
12#ifndef lint
acb87732 13static char sccsid[] = "@(#)args.c 5.5 (Berkeley) %G%";
ac894d30
KB
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
25static u_long get_bsz __P((char *));
26
27static void f_bs __P((char *));
28static void f_cbs __P((char *));
29static void f_conv __P((char *));
30static void f_count __P((char *));
31static void f_files __P((char *));
32static void f_ibs __P((char *));
33static void f_if __P((char *));
34static void f_obs __P((char *));
35static void f_of __P((char *));
36static void f_seek __P((char *));
37static void f_skip __P((char *));
38
39static 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,
998e1ac9 45 "cbs", f_cbs, C_CBS, C_CBS,
ac894d30
KB
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
57static char *oper;
58
59/*
998e1ac9 60 * args -- parse JCL syntax of dd.
ac894d30
KB
61 */
62void
63jcl(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;
ac894d30
KB
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 */
acb87732 99 if (ddflags & (C_BLOCK|C_LCASE|C_SWAB|C_UCASE|C_UNBLOCK))
ac894d30
KB
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
998e1ac9
KB
107 /*
108 * Ascii/ebcdic and cbs implies block/unblock.
109 * Block/unblock requires cbs and vice-versa.
110 */
ac894d30 111 if (ddflags & (C_BLOCK|C_UNBLOCK)) {
998e1ac9
KB
112 if (!(ddflags & C_CBS))
113 err("record operations require cbs");
ac894d30 114 if (cbsz == 0)
998e1ac9
KB
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;
ac894d30
KB
132
133 if (in.dbsz == 0 || out.dbsz == 0)
134 err("buffer sizes cannot be zero");
135
998e1ac9
KB
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);
ac894d30
KB
145}
146
147static int
148c_arg(a, b)
149 const void *a, *b;
150{
151 return (strcmp(((struct arg *)a)->name, ((struct arg *)b)->name));
152}
153
154static void
155f_bs(arg)
156 char *arg;
157{
158 in.dbsz = out.dbsz = (int)get_bsz(arg);
159}
160
161static void
162f_cbs(arg)
163 char *arg;
164{
165 cbsz = (int)get_bsz(arg);
166}
167
168static void
169f_count(arg)
170 char *arg;
171{
172 cpy_cnt = (u_int)get_bsz(arg);
998e1ac9 173 if (!cpy_cnt)
ac894d30
KB
174 terminate(0);
175}
176
177static void
998e1ac9 178f_files(arg)
ac894d30
KB
179 char *arg;
180{
181 files_cnt = (int)get_bsz(arg);
182}
183
184static void
185f_ibs(arg)
186 char *arg;
187{
188 if (!(ddflags & C_BS))
189 in.dbsz = (int)get_bsz(arg);
190}
191
192static void
193f_if(arg)
194 char *arg;
195{
196 in.name = arg;
197}
198
199static void
200f_obs(arg)
201 char *arg;
202{
203 if (!(ddflags & C_BS))
204 out.dbsz = (int)get_bsz(arg);
205}
206
207static void
208f_of(arg)
209 char *arg;
210{
211 out.name = arg;
212}
213
214static void
215f_seek(arg)
216 char *arg;
217{
218 out.offset = (u_int)get_bsz(arg);
219}
220
221static void
222f_skip(arg)
223 char *arg;
224{
225 in.offset = (u_int)get_bsz(arg);
226}
227
ac894d30
KB
228static struct conv {
229 char *name;
ac894d30 230 u_int set, noset;
998e1ac9 231 u_char *ctab;
ac894d30 232} clist[] = {
998e1ac9
KB
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,
ac894d30
KB
247};
248
249static void
250f_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;
998e1ac9
KB
266 if (cp->ctab)
267 ctab = cp->ctab;
ac894d30
KB
268 }
269}
270
271static int
272c_conv(a, b)
273 const void *a, *b;
274{
275 return (strcmp(((struct conv *)a)->name, ((struct conv *)b)->name));
276}
277
ac894d30
KB
278/*
279 * Convert an expression of the following forms to an unsigned long.
280 * 1) A positive decimal number.
998e1ac9
KB
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).
ac894d30
KB
286 * seperated by x (also * for backwards compatibility), specifying
287 * the product of the indicated values.
288 */
289static u_long
290get_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;
0520b714
KB
317 case 'm':
318 t = num;
319 num *= 1048576;
320 if (t > num)
321 goto erange;
322 ++expr;
323 break;
998e1ac9 324 case 'w':
ac894d30
KB
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;
0520b714 336 case '*': /* Backward compatible. */
ac894d30 337 case 'x':
ac894d30
KB
338 t = num;
339 num *= get_bsz(expr + 1);
340 if (t > num)
341erange: err("%s: %s", oper, strerror(ERANGE));
342 break;
343 default:
344 err("%s: illegal numeric value", oper);
345 }
346 return(num);
347}