]> git.ipfire.org Git - thirdparty/util-linux.git/blob - text-utils/hexdump-display.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[thirdparty/util-linux.git] / text-utils / hexdump-display.c
1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "hexdump.h"
44 #include "xalloc.h"
45 #include "c.h"
46 #include "nls.h"
47 #include "colors.h"
48
49 static void doskip(const char *, int, struct hexdump *);
50 static u_char *get(struct hexdump *);
51
52 enum _vflag vflag = FIRST;
53
54 static off_t address; /* address/offset in stream */
55 static off_t eaddress; /* end address */
56
57 static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt)
58 {
59 register struct list_head *p;
60 register struct hexdump_clr *clr;
61 off_t offt;
62 int match;
63
64 list_for_each(p, pr->colorlist) {
65 clr = list_entry(p, struct hexdump_clr, colorlist);
66 offt = clr->offt;
67 match = 0;
68
69 /* no offset or offset outside this print unit */
70 if (offt < 0)
71 offt = address;
72 if (offt < address || offt + clr->range > address + bcnt)
73 continue;
74
75 /* match a string */
76 if (clr->str) {
77 if (pr->flags == F_ADDRESS) {
78 /* TODO */
79 }
80 else if (!strncmp(clr->str, (char *)bp + offt
81 - address, clr->range))
82 match = 1;
83 /* match a value */
84 } else if (clr->val != -1) {
85 int val = 0;
86 /* addresses are not part of the input, so we can't
87 * compare with the contents of bp */
88 if (pr->flags == F_ADDRESS) {
89 if (clr->val == address)
90 match = 1;
91 } else {
92 memcpy(&val, bp + offt - address, clr->range);
93 if (val == clr->val)
94 match = 1;
95 }
96 /* no conditions, only a color was specified */
97 } else
98 return clr->fmt;
99
100 /* return the format string or check for another */
101 if (match ^ clr->invert)
102 return clr->fmt;
103 }
104
105 /* no match */
106 return NULL;
107 }
108
109 static inline void
110 print(struct hexdump_pr *pr, unsigned char *bp) {
111
112 const char *color = NULL;
113
114 if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt)))
115 color_enable(color);
116
117 switch(pr->flags) {
118 case F_ADDRESS:
119 printf(pr->fmt, address);
120 break;
121 case F_BPAD:
122 printf(pr->fmt, "");
123 break;
124 case F_C:
125 conv_c(pr, bp);
126 break;
127 case F_CHAR:
128 printf(pr->fmt, *bp);
129 break;
130 case F_DBL:
131 {
132 double dval;
133 float fval;
134 switch(pr->bcnt) {
135 case 4:
136 memmove(&fval, bp, sizeof(fval));
137 printf(pr->fmt, fval);
138 break;
139 case 8:
140 memmove(&dval, bp, sizeof(dval));
141 printf(pr->fmt, dval);
142 break;
143 }
144 break;
145 }
146 case F_INT:
147 {
148 short sval; /* int16_t */
149 int ival; /* int32_t */
150 long long Lval; /* int64_t, int64_t */
151
152 switch(pr->bcnt) {
153 case 1:
154 printf(pr->fmt, (unsigned long long) *bp);
155 break;
156 case 2:
157 memmove(&sval, bp, sizeof(sval));
158 printf(pr->fmt, (unsigned long long) sval);
159 break;
160 case 4:
161 memmove(&ival, bp, sizeof(ival));
162 printf(pr->fmt, (unsigned long long) ival);
163 break;
164 case 8:
165 memmove(&Lval, bp, sizeof(Lval));
166 printf(pr->fmt, Lval);
167 break;
168 }
169 break;
170 }
171 case F_P:
172 printf(pr->fmt, isprint(*bp) ? *bp : '.');
173 break;
174 case F_STR:
175 printf(pr->fmt, (char *)bp);
176 break;
177 case F_TEXT:
178 printf("%s", pr->fmt);
179 break;
180 case F_U:
181 conv_u(pr, bp);
182 break;
183 case F_UINT:
184 {
185 unsigned short sval; /* u_int16_t */
186 unsigned int ival; /* u_int32_t */
187 unsigned long long Lval;/* u_int64_t, u_int64_t */
188
189 switch(pr->bcnt) {
190 case 1:
191 printf(pr->fmt, (unsigned long long) *bp);
192 break;
193 case 2:
194 memmove(&sval, bp, sizeof(sval));
195 printf(pr->fmt, (unsigned long long) sval);
196 break;
197 case 4:
198 memmove(&ival, bp, sizeof(ival));
199 printf(pr->fmt, (unsigned long long) ival);
200 break;
201 case 8:
202 memmove(&Lval, bp, sizeof(Lval));
203 printf(pr->fmt, Lval);
204 break;
205 }
206 break;
207 }
208 }
209 if (color) /* did we colorize something? */
210 color_disable();
211 }
212
213 static void bpad(struct hexdump_pr *pr)
214 {
215 static const char *spec = " -0+#";
216 char *p1, *p2;
217
218 /*
219 * remove all conversion flags; '-' is the only one valid
220 * with %s, and it's not useful here.
221 */
222 pr->flags = F_BPAD;
223 pr->cchar[0] = 's';
224 pr->cchar[1] = 0;
225
226 p1 = pr->fmt;
227 while (*p1 != '%')
228 ++p1;
229
230 p2 = ++p1;
231 while (*p1 && strchr(spec, *p1))
232 ++p1;
233
234 while ((*p2++ = *p1++))
235 ;
236 }
237
238 void display(struct hexdump *hex)
239 {
240 register struct list_head *fs;
241 register struct hexdump_fs *fss;
242 register struct hexdump_fu *fu;
243 register struct hexdump_pr *pr;
244 register int cnt;
245 register unsigned char *bp;
246 off_t saveaddress;
247 unsigned char savech = 0, *savebp;
248 struct list_head *p, *q, *r;
249
250 while ((bp = get(hex)) != NULL) {
251 fs = &hex->fshead; savebp = bp; saveaddress = address;
252
253 list_for_each(p, fs) {
254 fss = list_entry(p, struct hexdump_fs, fslist);
255
256 list_for_each(q, &fss->fulist) {
257 fu = list_entry(q, struct hexdump_fu, fulist);
258
259 if (fu->flags&F_IGNORE)
260 break;
261
262 cnt = fu->reps;
263
264 while (cnt) {
265 list_for_each(r, &fu->prlist) {
266 pr = list_entry(r, struct hexdump_pr, prlist);
267
268 if (eaddress && address >= eaddress
269 && !(pr->flags&(F_TEXT|F_BPAD)))
270 bpad(pr);
271
272 if (cnt == 1 && pr->nospace) {
273 savech = *pr->nospace;
274 *pr->nospace = '\0';
275 print(pr, bp);
276 *pr->nospace = savech;
277 } else
278 print(pr, bp);
279
280 address += pr->bcnt;
281 bp += pr->bcnt;
282 }
283 --cnt;
284 }
285 }
286 bp = savebp;
287 address = saveaddress;
288 }
289 }
290 if (endfu) {
291 /*
292 * if eaddress not set, error or file size was multiple of
293 * blocksize, and no partial block ever found.
294 */
295 if (!eaddress) {
296 if (!address)
297 return;
298 eaddress = address;
299 }
300 list_for_each (p, &endfu->prlist) {
301 const char *color = NULL;
302
303 pr = list_entry(p, struct hexdump_pr, prlist);
304 if (colors_wanted() && pr->colorlist
305 && (color = color_cond(pr, bp, pr->bcnt))) {
306 color_enable(color);
307 }
308
309 switch(pr->flags) {
310 case F_ADDRESS:
311 printf(pr->fmt, eaddress);
312 break;
313 case F_TEXT:
314 printf("%s", pr->fmt);
315 break;
316 }
317 if (color) /* did we highlight something? */
318 color_disable();
319 }
320 }
321 }
322
323 static char **_argv;
324
325 static u_char *
326 get(struct hexdump *hex)
327 {
328 static int ateof = 1;
329 static u_char *curp, *savp;
330 ssize_t n, need, nread;
331 u_char *tmpp;
332
333 if (!curp) {
334 curp = xcalloc(1, hex->blocksize);
335 savp = xcalloc(1, hex->blocksize);
336 } else {
337 tmpp = curp;
338 curp = savp;
339 savp = tmpp;
340 address += hex->blocksize;
341 }
342 need = hex->blocksize, nread = 0;
343 while (TRUE) {
344 /*
345 * if read the right number of bytes, or at EOF for one file,
346 * and no other files are available, zero-pad the rest of the
347 * block and set the end flag.
348 */
349 if (!hex->length || (ateof && !next(NULL, hex))) {
350 if (need == hex->blocksize)
351 goto retnul;
352 if (!need && vflag != ALL &&
353 !memcmp(curp, savp, nread)) {
354 if (vflag != DUP)
355 printf("*\n");
356 goto retnul;
357 }
358 if (need > 0)
359 memset((char *)curp + nread, 0, need);
360 eaddress = address + nread;
361 return(curp);
362 }
363 if (fileno(stdin) == -1) {
364 warnx(_("all input file arguments failed"));
365 goto retnul;
366 }
367 n = fread((char *)curp + nread, sizeof(unsigned char),
368 hex->length == -1 ? need : min(hex->length, need), stdin);
369 if (!n) {
370 if (ferror(stdin))
371 warn("%s", _argv[-1]);
372 ateof = 1;
373 continue;
374 }
375 ateof = 0;
376 if (hex->length != -1)
377 hex->length -= n;
378 if (!(need -= n)) {
379 if (vflag == ALL || vflag == FIRST ||
380 memcmp(curp, savp, hex->blocksize) != 0) {
381 if (vflag == DUP || vflag == FIRST)
382 vflag = WAIT;
383 return(curp);
384 }
385 if (vflag == WAIT)
386 printf("*\n");
387 vflag = DUP;
388 address += hex->blocksize;
389 need = hex->blocksize;
390 nread = 0;
391 }
392 else
393 nread += n;
394 }
395 retnul:
396 free (curp);
397 free (savp);
398 return NULL;
399 }
400
401 int next(char **argv, struct hexdump *hex)
402 {
403 static int done;
404 int statok;
405
406 if (argv) {
407 _argv = argv;
408 return(1);
409 }
410 while (TRUE) {
411 if (*_argv) {
412 if (!(freopen(*_argv, "r", stdin))) {
413 warn("%s", *_argv);
414 hex->exitval = EXIT_FAILURE;
415 ++_argv;
416 continue;
417 }
418 statok = done = 1;
419 } else {
420 if (done++)
421 return(0);
422 statok = 0;
423 }
424 if (hex->skip)
425 doskip(statok ? *_argv : "stdin", statok, hex);
426 if (*_argv)
427 ++_argv;
428 if (!hex->skip)
429 return(1);
430 }
431 /* NOTREACHED */
432 }
433
434 static void
435 doskip(const char *fname, int statok, struct hexdump *hex)
436 {
437 struct stat sbuf;
438
439 if (statok) {
440 if (fstat(fileno(stdin), &sbuf))
441 err(EXIT_FAILURE, "%s", fname);
442 if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) {
443 /* If size valid and skip >= size */
444 hex->skip -= sbuf.st_size;
445 address += sbuf.st_size;
446 return;
447 }
448 }
449 /* sbuf may be undefined here - do not test it */
450 if (fseek(stdin, hex->skip, SEEK_SET))
451 err(EXIT_FAILURE, "%s", fname);
452 address += hex->skip;
453 hex->skip = 0;
454 }