1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #ifndef lint
33 #if 0
34 static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
35 #endif
36 #endif /* not lint */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/capsicum.h>
42 #include <sys/conf.h>
43 #include <sys/ioctl.h>
44 #include <sys/stat.h>
45
46 #include <capsicum_helpers.h>
47 #include <ctype.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include "hexdump.h"
55
56 enum _vflag vflag = FIRST;
57
58 static off_t address; /* address/offset in stream */
59 static off_t eaddress; /* end address */
60
61 static void print(PR *, u_char *);
62 static void noseek(void);
63
64 void
display(void)65 display(void)
66 {
67 FS *fs;
68 FU *fu;
69 PR *pr;
70 int cnt;
71 u_char *bp;
72 off_t saveaddress;
73 u_char savech, *savebp;
74
75 savech = 0;
76 while ((bp = get()))
77 for (fs = fshead, savebp = bp, saveaddress = address; fs;
78 fs = fs->nextfs, bp = savebp, address = saveaddress)
79 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
80 if (fu->flags&F_IGNORE)
81 break;
82 for (cnt = fu->reps; cnt; --cnt)
83 for (pr = fu->nextpr; pr; address += pr->bcnt,
84 bp += pr->bcnt, pr = pr->nextpr) {
85 if (eaddress && address >= eaddress &&
86 !(pr->flags & (F_TEXT|F_BPAD)))
87 bpad(pr);
88 if (cnt == 1 && pr->nospace) {
89 savech = *pr->nospace;
90 *pr->nospace = '\0';
91 }
92 print(pr, bp);
93 if (cnt == 1 && pr->nospace)
94 *pr->nospace = savech;
95 }
96 }
97 if (endfu) {
98 /*
99 * If eaddress not set, error or file size was multiple of
100 * blocksize, and no partial block ever found.
101 */
102 if (!eaddress) {
103 if (!address)
104 return;
105 eaddress = address;
106 }
107 for (pr = endfu->nextpr; pr; pr = pr->nextpr)
108 switch(pr->flags) {
109 case F_ADDRESS:
110 (void)printf(pr->fmt, (quad_t)eaddress);
111 break;
112 case F_TEXT:
113 (void)printf("%s", pr->fmt);
114 break;
115 }
116 }
117 }
118
119 static void
print(PR * pr,u_char * bp)120 print(PR *pr, u_char *bp)
121 {
122 long double ldbl;
123 double f8;
124 float f4;
125 int16_t s2;
126 int8_t s8;
127 int32_t s4;
128 u_int16_t u2;
129 u_int32_t u4;
130 u_int64_t u8;
131
132 switch(pr->flags) {
133 case F_ADDRESS:
134 (void)printf(pr->fmt, (quad_t)address);
135 break;
136 case F_BPAD:
137 (void)printf(pr->fmt, "");
138 break;
139 case F_C:
140 conv_c(pr, bp, eaddress ? eaddress - address :
141 blocksize - address % blocksize);
142 break;
143 case F_CHAR:
144 (void)printf(pr->fmt, *bp);
145 break;
146 case F_DBL:
147 switch(pr->bcnt) {
148 case 4:
149 bcopy(bp, &f4, sizeof(f4));
150 (void)printf(pr->fmt, f4);
151 break;
152 case 8:
153 bcopy(bp, &f8, sizeof(f8));
154 (void)printf(pr->fmt, f8);
155 break;
156 default:
157 if (pr->bcnt == sizeof(long double)) {
158 bcopy(bp, &ldbl, sizeof(ldbl));
159 (void)printf(pr->fmt, ldbl);
160 }
161 break;
162 }
163 break;
164 case F_INT:
165 switch(pr->bcnt) {
166 case 1:
167 (void)printf(pr->fmt, (quad_t)(signed char)*bp);
168 break;
169 case 2:
170 bcopy(bp, &s2, sizeof(s2));
171 (void)printf(pr->fmt, (quad_t)s2);
172 break;
173 case 4:
174 bcopy(bp, &s4, sizeof(s4));
175 (void)printf(pr->fmt, (quad_t)s4);
176 break;
177 case 8:
178 bcopy(bp, &s8, sizeof(s8));
179 (void)printf(pr->fmt, s8);
180 break;
181 }
182 break;
183 case F_P:
184 (void)printf(pr->fmt, isprint(*bp) ? *bp : '.');
185 break;
186 case F_STR:
187 (void)printf(pr->fmt, (char *)bp);
188 break;
189 case F_TEXT:
190 (void)printf("%s", pr->fmt);
191 break;
192 case F_U:
193 conv_u(pr, bp);
194 break;
195 case F_UINT:
196 switch(pr->bcnt) {
197 case 1:
198 (void)printf(pr->fmt, (u_quad_t)*bp);
199 break;
200 case 2:
201 bcopy(bp, &u2, sizeof(u2));
202 (void)printf(pr->fmt, (u_quad_t)u2);
203 break;
204 case 4:
205 bcopy(bp, &u4, sizeof(u4));
206 (void)printf(pr->fmt, (u_quad_t)u4);
207 break;
208 case 8:
209 bcopy(bp, &u8, sizeof(u8));
210 (void)printf(pr->fmt, u8);
211 break;
212 }
213 break;
214 }
215 }
216
217 void
bpad(PR * pr)218 bpad(PR *pr)
219 {
220 static char const *spec = " -0+#";
221 char *p1, *p2;
222
223 /*
224 * Remove all conversion flags; '-' is the only one valid
225 * with %s, and it's not useful here.
226 */
227 pr->flags = F_BPAD;
228 pr->cchar[0] = 's';
229 pr->cchar[1] = '\0';
230 for (p1 = pr->fmt; *p1 != '%'; ++p1);
231 for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1);
232 while ((*p2++ = *p1++));
233 }
234
235 static char **_argv;
236
237 u_char *
get(void)238 get(void)
239 {
240 static int ateof = 1;
241 static u_char *curp, *savp;
242 int n;
243 int need, nread;
244 int valid_save = 0;
245 u_char *tmpp;
246
247 if (!curp) {
248 if ((curp = calloc(1, blocksize)) == NULL)
249 err(1, NULL);
250 if ((savp = calloc(1, blocksize)) == NULL)
251 err(1, NULL);
252 } else {
253 tmpp = curp;
254 curp = savp;
255 savp = tmpp;
256 address += blocksize;
257 valid_save = 1;
258 }
259 for (need = blocksize, nread = 0;;) {
260 /*
261 * if read the right number of bytes, or at EOF for one file,
262 * and no other files are available, zero-pad the rest of the
263 * block and set the end flag.
264 */
265 if (!length || (ateof && !next((char **)NULL))) {
266 if (odmode && address < skip)
267 errx(1, "cannot skip past end of input");
268 if (need == blocksize)
269 return((u_char *)NULL);
270 /*
271 * XXX bcmp() is not quite right in the presence
272 * of multibyte characters.
273 */
274 if (vflag != ALL &&
275 valid_save &&
276 bcmp(curp, savp, nread) == 0) {
277 if (vflag != DUP)
278 (void)printf("*\n");
279 return((u_char *)NULL);
280 }
281 bzero((char *)curp + nread, need);
282 eaddress = address + nread;
283 return(curp);
284 }
285 n = fread((char *)curp + nread, sizeof(u_char),
286 length == -1 ? need : MIN(length, need), stdin);
287 if (!n) {
288 if (ferror(stdin))
289 warn("%s", _argv[-1]);
290 ateof = 1;
291 continue;
292 }
293 ateof = 0;
294 if (length != -1)
295 length -= n;
296 if (!(need -= n)) {
297 /*
298 * XXX bcmp() is not quite right in the presence
299 * of multibyte characters.
300 */
301 if (vflag == ALL || vflag == FIRST ||
302 valid_save == 0 ||
303 bcmp(curp, savp, blocksize) != 0) {
304 if (vflag == DUP || vflag == FIRST)
305 vflag = WAIT;
306 return(curp);
307 }
308 if (vflag == WAIT)
309 (void)printf("*\n");
310 vflag = DUP;
311 address += blocksize;
312 need = blocksize;
313 nread = 0;
314 }
315 else
316 nread += n;
317 }
318 }
319
320 size_t
peek(u_char * buf,size_t nbytes)321 peek(u_char *buf, size_t nbytes)
322 {
323 size_t n, nread;
324 int c;
325
326 if (length != -1 && nbytes > (unsigned int)length)
327 nbytes = length;
328 nread = 0;
329 while (nread < nbytes && (c = getchar()) != EOF) {
330 *buf++ = c;
331 nread++;
332 }
333 n = nread;
334 while (n-- > 0) {
335 c = *--buf;
336 ungetc(c, stdin);
337 }
338 return (nread);
339 }
340
341 int
next(char ** argv)342 next(char **argv)
343 {
344 static int done;
345 int statok;
346
347 if (argv) {
348 _argv = argv;
349 return(1);
350 }
351 for (;;) {
352 if (*_argv) {
353 done = 1;
354 if (!(freopen(*_argv, "r", stdin))) {
355 warn("%s", *_argv);
356 exitval = 1;
357 ++_argv;
358 continue;
359 }
360 statok = 1;
361 } else {
362 if (done++)
363 return(0);
364 statok = 0;
365 }
366
367 if (caph_limit_stream(fileno(stdin), CAPH_READ) < 0)
368 err(1, "unable to restrict %s",
369 statok ? *_argv : "stdin");
370
371 /*
372 * We've opened our last input file; enter capsicum sandbox.
373 */
374 if (statok == 0 || *(_argv + 1) == NULL) {
375 if (caph_enter() < 0)
376 err(1, "unable to enter capability mode");
377 }
378
379 if (skip)
380 doskip(statok ? *_argv : "stdin", statok);
381 if (*_argv)
382 ++_argv;
383 if (!skip)
384 return(1);
385 }
386 /* NOTREACHED */
387 }
388
389 void
doskip(const char * fname,int statok)390 doskip(const char *fname, int statok)
391 {
392 int type;
393 struct stat sb;
394
395 if (statok) {
396 if (fstat(fileno(stdin), &sb))
397 err(1, "%s", fname);
398 if (S_ISREG(sb.st_mode) && skip > sb.st_size) {
399 address += sb.st_size;
400 skip -= sb.st_size;
401 return;
402 }
403 }
404 if (!statok || S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
405 noseek();
406 return;
407 }
408 if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
409 if (ioctl(fileno(stdin), FIODTYPE, &type))
410 err(1, "%s", fname);
411 /*
412 * Most tape drives don't support seeking,
413 * yet fseek() would succeed.
414 */
415 if (type & D_TAPE) {
416 noseek();
417 return;
418 }
419 }
420 if (fseeko(stdin, skip, SEEK_SET)) {
421 noseek();
422 return;
423 }
424 address += skip;
425 skip = 0;
426 }
427
428 static void
noseek(void)429 noseek(void)
430 {
431 int count;
432 for (count = 0; count < skip; ++count)
433 if (getchar() == EOF)
434 break;
435 address += count;
436 skip -= count;
437 }
438