1/*-
2 * Copyright (c) 2010-2012 Semihalf.
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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: releng/11.0/usr.sbin/nandtool/nandtool.c 235537 2012-05-17 10:11:18Z gber $");
29
30#include <errno.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdarg.h>
35#include <ctype.h>
36#include <sysexits.h>
37#include <libgeom.h>
38#include "nandtool.h"
39#include "usage.h"
40
41int usage(struct cmd_param *);
42
43static const struct {
44	const char	*name;
45	const char	*usage;
46	int		(*handler)(struct cmd_param *);
47} commands[] = {
48	{ "help", nand_help_usage, usage },
49	{ "read", nand_read_usage, nand_read },
50	{ "write", nand_write_usage, nand_write },
51	{ "erase", nand_erase_usage, nand_erase },
52	{ "readoob", nand_read_oob_usage, nand_read_oob },
53	{ "writeoob", nand_write_oob_usage, nand_write_oob },
54	{ "info", nand_info_usage, nand_info },
55	{ NULL, NULL, NULL },
56};
57
58static char *
59_param_get_stringx(struct cmd_param *params, const char *name, int doexit)
60{
61	int i;
62
63	for (i = 0; params[i].name[0] != '\0'; i++) {
64		if (!strcmp(params[i].name, name))
65			return params[i].value;
66	}
67
68	if (doexit) {
69		perrorf("Missing parameter %s", name);
70		exit(1);
71	}
72	return (NULL);
73}
74
75char *
76param_get_string(struct cmd_param *params, const char *name)
77{
78
79	return (_param_get_stringx(params, name, 0));
80}
81
82static int
83_param_get_intx(struct cmd_param *params, const char *name, int doexit)
84{
85	int ret;
86	char *str = _param_get_stringx(params, name, doexit);
87
88	if (!str)
89		return (-1);
90
91	errno = 0;
92	ret = (int)strtol(str, (char **)NULL, 10);
93	if (errno) {
94		if (doexit) {
95			perrorf("Invalid value for parameter %s", name);
96			exit(1);
97		}
98		return (-1);
99	}
100
101	return (ret);
102}
103
104int
105param_get_intx(struct cmd_param *params, const char *name)
106{
107
108	return (_param_get_intx(params, name, 1));
109}
110
111int
112param_get_int(struct cmd_param *params, const char *name)
113{
114
115	return (_param_get_intx(params, name, 0));
116}
117
118int
119param_get_boolean(struct cmd_param *params, const char *name)
120{
121	char *str = param_get_string(params, name);
122
123	if (!str)
124		return (0);
125
126	if (!strcmp(str, "true") || !strcmp(str, "yes"))
127		return (1);
128
129	return (0);
130}
131
132int
133param_has_value(struct cmd_param *params, const char *name)
134{
135	int i;
136
137	for (i = 0; params[i].name[0] != '\0'; i++) {
138		if (!strcmp(params[i].name, name))
139			return (1);
140	}
141
142	return (0);
143}
144
145int
146param_get_count(struct cmd_param *params)
147{
148	int i;
149
150	for (i = 0; params[i].name[0] != '\0'; i++);
151
152	return (i);
153}
154
155void
156hexdumpoffset(uint8_t *buf, int length, int off)
157{
158	int i, j;
159	for (i = 0; i < length; i += 16) {
160		printf("%08x: ", off + i);
161
162		for (j = 0; j < 16; j++)
163			printf("%02x ", buf[i+j]);
164
165		printf("| ");
166
167		for (j = 0; j < 16; j++) {
168			printf("%c", isalnum(buf[i+j])
169			    ? buf[i+j]
170			    : '.');
171		}
172
173		printf("\n");
174	}
175}
176
177void
178hexdump(uint8_t *buf, int length)
179{
180
181	hexdumpoffset(buf, length, 0);
182}
183
184void *
185xmalloc(size_t len)
186{
187	void *ret = malloc(len);
188
189	if (!ret) {
190		fprintf(stderr, "Cannot allocate buffer of %zd bytes. "
191		    "Exiting.\n", len);
192		exit(EX_OSERR);
193	}
194
195	return (ret);
196}
197
198void
199perrorf(const char *format, ...)
200{
201	va_list args;
202
203	va_start(args, format);
204	vfprintf(stderr, format, args);
205	va_end(args);
206	fprintf(stderr, ": %s\n", strerror(errno));
207}
208
209int
210usage(struct cmd_param *params)
211{
212	int i;
213
214	if (!params || !param_get_count(params)) {
215		fprintf(stderr, "Usage: nandtool <command> [arguments...]\n");
216		fprintf(stderr, "Arguments are in form 'name=value'.\n\n");
217		fprintf(stderr, "Available commands:\n");
218
219		for (i = 0; commands[i].name != NULL; i++)
220			fprintf(stderr, "\t%s\n", commands[i].name);
221
222		fprintf(stderr, "\n");
223		fprintf(stderr, "For information about particular command, "
224		    "type:\n");
225		fprintf(stderr, "'nandtool help topic=<command>'\n");
226	} else if (param_has_value(params, "topic")) {
227		for (i = 0; commands[i].name != NULL; i++) {
228			if (!strcmp(param_get_string(params, "topic"),
229			    commands[i].name)) {
230				fprintf(stderr, commands[i].usage, "nandtool");
231				return (0);
232			}
233		}
234
235		fprintf(stderr, "No such command\n");
236		return (EX_SOFTWARE);
237	} else {
238		fprintf(stderr, "Wrong arguments given. Try: 'nandtool help'\n");
239	}
240
241	return (EX_USAGE);
242}
243
244int
245main(int argc, const char *argv[])
246{
247	struct cmd_param *params;
248	int i, ret, idx;
249
250	if (argc < 2) {
251		usage(NULL);
252		return (0);
253	}
254
255	params = malloc(sizeof(struct cmd_param) * (argc - 1));
256
257	for (i = 2, idx = 0; i < argc; i++, idx++) {
258		if (sscanf(argv[i], "%63[^=]=%63s", params[idx].name,
259		    params[idx].value) < 2) {
260			fprintf(stderr, "Syntax error in argument %d. "
261			    "Argument should be in form 'name=value'.\n", i);
262			free(params);
263			return (-1);
264		}
265	}
266
267	params[idx].name[0] = '\0';
268	params[idx].value[0] = '\0';
269
270	for (i = 0; commands[i].name != NULL; i++) {
271		if (!strcmp(commands[i].name, argv[1])) {
272			ret = commands[i].handler(params);
273			free(params);
274			return (ret);
275		}
276	}
277
278	free(params);
279	fprintf(stderr, "Unknown command. Try '%s help'\n", argv[0]);
280
281	return (-1);
282}
283
284