1 /* vi: set sw=4 ts=4: */
2 /*
3  * od implementation for busybox
4  * Based on code from util-linux v 2.11l
5  *
6  * Copyright (c) 1990
7  * The Regents of the University of California.  All rights reserved.
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10  *
11  * Original copyright notice is retained at the end of this file.
12  */
13 //config:config OD
14 //config:	bool "od (11 kb)"
15 //config:	default y
16 //config:	help
17 //config:	od is used to dump binary files in octal and other formats.
18 
19 //applet:IF_OD(APPLET(od, BB_DIR_USR_BIN, BB_SUID_DROP))
20 
21 //kbuild:lib-$(CONFIG_OD) += od.o
22 
23 //usage:#if !ENABLE_DESKTOP
24 //usage:#define od_trivial_usage
25 //usage:       "[-aBbcDdeFfHhIiLlOovXx] [FILE]"
26 //usage:#define od_full_usage "\n\n"
27 //usage:       "Print FILE (or stdin) unambiguously, as octal bytes by default"
28 //usage:#endif
29 
30 #include "libbb.h"
31 #if ENABLE_DESKTOP
32 /* This one provides -t (busybox's own build script needs it) */
33 #include "od_bloaty.c"
34 #else
35 
36 #include "dump.h"
37 
38 static void
odoffset(dumper_t * dumper,int argc,char *** argvp)39 odoffset(dumper_t *dumper, int argc, char ***argvp)
40 {
41 	char *num, *p;
42 	int base;
43 	char *end;
44 
45 	/*
46 	 * The offset syntax of od(1) was genuinely bizarre.  First, if
47 	 * it started with a plus it had to be an offset.  Otherwise, if
48 	 * there were at least two arguments, a number or lower-case 'x'
49 	 * followed by a number makes it an offset.  By default it was
50 	 * octal; if it started with 'x' or '0x' it was hex.  If it ended
51 	 * in a '.', it was decimal.  If a 'b' or 'B' was appended, it
52 	 * multiplied the number by 512 or 1024 byte units.  There was
53 	 * no way to assign a block count to a hex offset.
54 	 *
55 	 * We assumes it's a file if the offset is bad.
56 	 */
57 	p = **argvp;
58 
59 	if (!p) {
60 		/* hey someone is probably piping to us ... */
61 		return;
62 	}
63 
64 	if ((*p != '+')
65 		&& (argc < 2
66 			|| (!isdigit(p[0])
67 				&& ((p[0] != 'x') || !isxdigit(p[1])))))
68 		return;
69 
70 	base = 0;
71 	/*
72 	 * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
73 	 * set base.
74 	 */
75 	if (p[0] == '+')
76 		++p;
77 	if (p[0] == 'x' && isxdigit(p[1])) {
78 		++p;
79 		base = 16;
80 	} else if (p[0] == '0' && p[1] == 'x') {
81 		p += 2;
82 		base = 16;
83 	}
84 
85 	/* skip over the number */
86 	if (base == 16)
87 		for (num = p; isxdigit(*p); ++p)
88 			continue;
89 	else
90 		for (num = p; isdigit(*p); ++p)
91 			continue;
92 
93 	/* check for no number */
94 	if (num == p)
95 		return;
96 
97 	/* if terminates with a '.', base is decimal */
98 	if (*p == '.') {
99 		if (base)
100 			return;
101 		base = 10;
102 	}
103 
104 	dumper->dump_skip = strtol(num, &end, base ? base : 8);
105 
106 	/* if end isn't the same as p, we got a non-octal digit */
107 	if (end != p)
108 		dumper->dump_skip = 0;
109 	else {
110 		if (*p) {
111 			if (*p == 'b') {
112 				dumper->dump_skip *= 512;
113 				++p;
114 			} else if (*p == 'B') {
115 				dumper->dump_skip *= 1024;
116 				++p;
117 			}
118 		}
119 		if (*p)
120 			dumper->dump_skip = 0;
121 		else {
122 			++*argvp;
123 			/*
124 			 * If the offset uses a non-octal base, the base of
125 			 * the offset is changed as well.  This isn't pretty,
126 			 * but it's easy.
127 			 */
128 #define TYPE_OFFSET 7
129 			{
130 				char x_or_d;
131 				if (base == 16) {
132 					x_or_d = 'x';
133 					goto DO_X_OR_D;
134 				}
135 				if (base == 10) {
136 					x_or_d = 'd';
137  DO_X_OR_D:
138 					dumper->fshead->nextfu->fmt[TYPE_OFFSET]
139 						= dumper->fshead->nextfs->nextfu->fmt[TYPE_OFFSET]
140 						= x_or_d;
141 				}
142 			}
143 		}
144 	}
145 }
146 
147 static const char *const add_strings[] = {
148 	"16/1 \"%3_u \" \"\\n\"",              /* a */
149 	"8/2 \" %06o \" \"\\n\"",              /* B, o */
150 	"16/1 \"%03o \" \"\\n\"",              /* b */
151 	"16/1 \"%3_c \" \"\\n\"",              /* c */
152 	"8/2 \"  %05u \" \"\\n\"",             /* d */
153 	"4/4 \"     %010u \" \"\\n\"",         /* D */
154 	"2/8 \"          %21.14e \" \"\\n\"",  /* e (undocumented in od), F */
155 	"4/4 \" %14.7e \" \"\\n\"",            /* f */
156 	"4/4 \"       %08x \" \"\\n\"",        /* H, X */
157 	"8/2 \"   %04x \" \"\\n\"",            /* h, x */
158 	"4/4 \"    %11d \" \"\\n\"",           /* I, L, l */
159 	"8/2 \" %6d \" \"\\n\"",               /* i */
160 	"4/4 \"    %011o \" \"\\n\"",          /* O */
161 };
162 
163 static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv";
164 
165 static const char od_o2si[] ALIGN1 = {
166 	0, 1, 2, 3, 5,
167 	4, 6, 6, 7, 8,
168 	9, 0xa, 0xb, 0xa, 0xa,
169 	0xb, 1, 8, 9,
170 };
171 
172 int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
od_main(int argc,char ** argv)173 int od_main(int argc, char **argv)
174 {
175 	int ch;
176 	int first = 1;
177 	char *p;
178 	dumper_t *dumper = alloc_dumper();
179 
180 	while ((ch = getopt(argc, argv, od_opts)) > 0) {
181 		if (ch == 'v') {
182 			dumper->dump_vflag = ALL;
183 		} else if (((p = strchr(od_opts, ch)) != NULL) && (*p != '\0')) {
184 			if (first) {
185 				first = 0;
186 				bb_dump_add(dumper, "\"%07.7_Ao\n\"");
187 				bb_dump_add(dumper, "\"%07.7_ao  \"");
188 			} else {
189 				bb_dump_add(dumper, "\"         \"");
190 			}
191 			bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]);
192 		} else {  /* P, p, s, w, or other unhandled */
193 			bb_show_usage();
194 		}
195 	}
196 	if (!dumper->fshead) {
197 		bb_dump_add(dumper, "\"%07.7_Ao\n\"");
198 		bb_dump_add(dumper, "\"%07.7_ao  \" 8/2 \"%06o \" \"\\n\"");
199 	}
200 
201 	argc -= optind;
202 	argv += optind;
203 
204 	odoffset(dumper, argc, &argv);
205 
206 	return bb_dump_dump(dumper, argv);
207 }
208 #endif /* ENABLE_DESKTOP */
209 
210 /*-
211  * Copyright (c) 1990 The Regents of the University of California.
212  * All rights reserved.
213  *
214  * Redistribution and use in source and binary forms, with or without
215  * modification, are permitted provided that the following conditions
216  * are met:
217  * 1. Redistributions of source code must retain the above copyright
218  *    notice, this list of conditions and the following disclaimer.
219  * 2. Redistributions in binary form must reproduce the above copyright
220  *    notice, this list of conditions and the following disclaimer in the
221  *    documentation and/or other materials provided with the distribution.
222  * 3. Neither the name of the University nor the names of its contributors
223  *    may be used to endorse or promote products derived from this software
224  *    without specific prior written permission.
225  *
226  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
227  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
230  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
234  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
236  * SUCH DAMAGE.
237  */
238