1235537Sgber/*-
2235537Sgber * Copyright (c) 2010-2012 Semihalf.
3235537Sgber * All rights reserved.
4235537Sgber *
5235537Sgber * Redistribution and use in source and binary forms, with or without
6235537Sgber * modification, are permitted provided that the following conditions
7235537Sgber * are met:
8235537Sgber * 1. Redistributions of source code must retain the above copyright
9235537Sgber *    notice, this list of conditions and the following disclaimer.
10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright
11235537Sgber *    notice, this list of conditions and the following disclaimer in the
12235537Sgber *    documentation and/or other materials provided with the distribution.
13235537Sgber *
14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235537Sgber * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235537Sgber * SUCH DAMAGE.
25235537Sgber */
26235537Sgber
27235537Sgber#include <sys/cdefs.h>
28235537Sgber__FBSDID("$FreeBSD$");
29235537Sgber
30235537Sgber#include <errno.h>
31235537Sgber#include <stdio.h>
32235537Sgber#include <stdlib.h>
33235537Sgber#include <string.h>
34235537Sgber#include <stdarg.h>
35235537Sgber#include <ctype.h>
36235537Sgber#include <sysexits.h>
37235537Sgber#include <libgeom.h>
38235537Sgber#include "nandtool.h"
39235537Sgber#include "usage.h"
40235537Sgber
41235537Sgberint usage(struct cmd_param *);
42235537Sgber
43235537Sgberstatic const struct {
44235537Sgber	const char	*name;
45235537Sgber	const char	*usage;
46235537Sgber	int		(*handler)(struct cmd_param *);
47235537Sgber} commands[] = {
48235537Sgber	{ "help", nand_help_usage, usage },
49235537Sgber	{ "read", nand_read_usage, nand_read },
50235537Sgber	{ "write", nand_write_usage, nand_write },
51235537Sgber	{ "erase", nand_erase_usage, nand_erase },
52235537Sgber	{ "readoob", nand_read_oob_usage, nand_read_oob },
53235537Sgber	{ "writeoob", nand_write_oob_usage, nand_write_oob },
54235537Sgber	{ "info", nand_info_usage, nand_info },
55235537Sgber	{ NULL, NULL, NULL },
56235537Sgber};
57235537Sgber
58235537Sgberstatic char *
59235537Sgber_param_get_stringx(struct cmd_param *params, const char *name, int doexit)
60235537Sgber{
61235537Sgber	int i;
62235537Sgber
63235537Sgber	for (i = 0; params[i].name[0] != '\0'; i++) {
64235537Sgber		if (!strcmp(params[i].name, name))
65235537Sgber			return params[i].value;
66235537Sgber	}
67235537Sgber
68235537Sgber	if (doexit) {
69235537Sgber		perrorf("Missing parameter %s", name);
70235537Sgber		exit(1);
71235537Sgber	}
72235537Sgber	return (NULL);
73235537Sgber}
74235537Sgber
75235537Sgberchar *
76235537Sgberparam_get_string(struct cmd_param *params, const char *name)
77235537Sgber{
78235537Sgber
79235537Sgber	return (_param_get_stringx(params, name, 0));
80235537Sgber}
81235537Sgber
82235537Sgberstatic int
83235537Sgber_param_get_intx(struct cmd_param *params, const char *name, int doexit)
84235537Sgber{
85235537Sgber	int ret;
86235537Sgber	char *str = _param_get_stringx(params, name, doexit);
87235537Sgber
88235537Sgber	if (!str)
89235537Sgber		return (-1);
90235537Sgber
91235537Sgber	errno = 0;
92235537Sgber	ret = (int)strtol(str, (char **)NULL, 10);
93235537Sgber	if (errno) {
94235537Sgber		if (doexit) {
95235537Sgber			perrorf("Invalid value for parameter %s", name);
96235537Sgber			exit(1);
97235537Sgber		}
98235537Sgber		return (-1);
99235537Sgber	}
100235537Sgber
101235537Sgber	return (ret);
102235537Sgber}
103235537Sgber
104235537Sgberint
105235537Sgberparam_get_intx(struct cmd_param *params, const char *name)
106235537Sgber{
107235537Sgber
108235537Sgber	return (_param_get_intx(params, name, 1));
109235537Sgber}
110235537Sgber
111235537Sgberint
112235537Sgberparam_get_int(struct cmd_param *params, const char *name)
113235537Sgber{
114235537Sgber
115235537Sgber	return (_param_get_intx(params, name, 0));
116235537Sgber}
117235537Sgber
118235537Sgberint
119235537Sgberparam_get_boolean(struct cmd_param *params, const char *name)
120235537Sgber{
121235537Sgber	char *str = param_get_string(params, name);
122235537Sgber
123235537Sgber	if (!str)
124235537Sgber		return (0);
125235537Sgber
126235537Sgber	if (!strcmp(str, "true") || !strcmp(str, "yes"))
127235537Sgber		return (1);
128235537Sgber
129235537Sgber	return (0);
130235537Sgber}
131235537Sgber
132235537Sgberint
133235537Sgberparam_has_value(struct cmd_param *params, const char *name)
134235537Sgber{
135235537Sgber	int i;
136235537Sgber
137235537Sgber	for (i = 0; params[i].name[0] != '\0'; i++) {
138235537Sgber		if (!strcmp(params[i].name, name))
139235537Sgber			return (1);
140235537Sgber	}
141235537Sgber
142235537Sgber	return (0);
143235537Sgber}
144235537Sgber
145235537Sgberint
146235537Sgberparam_get_count(struct cmd_param *params)
147235537Sgber{
148235537Sgber	int i;
149235537Sgber
150235537Sgber	for (i = 0; params[i].name[0] != '\0'; i++);
151235537Sgber
152235537Sgber	return (i);
153235537Sgber}
154235537Sgber
155235537Sgbervoid
156235537Sgberhexdumpoffset(uint8_t *buf, int length, int off)
157235537Sgber{
158235537Sgber	int i, j;
159235537Sgber	for (i = 0; i < length; i += 16) {
160235537Sgber		printf("%08x: ", off + i);
161235537Sgber
162235537Sgber		for (j = 0; j < 16; j++)
163235537Sgber			printf("%02x ", buf[i+j]);
164235537Sgber
165235537Sgber		printf("| ");
166235537Sgber
167235537Sgber		for (j = 0; j < 16; j++) {
168235537Sgber			printf("%c", isalnum(buf[i+j])
169235537Sgber			    ? buf[i+j]
170235537Sgber			    : '.');
171235537Sgber		}
172235537Sgber
173235537Sgber		printf("\n");
174235537Sgber	}
175235537Sgber}
176235537Sgber
177235537Sgbervoid
178235537Sgberhexdump(uint8_t *buf, int length)
179235537Sgber{
180235537Sgber
181235537Sgber	hexdumpoffset(buf, length, 0);
182235537Sgber}
183235537Sgber
184235537Sgbervoid *
185235537Sgberxmalloc(size_t len)
186235537Sgber{
187235537Sgber	void *ret = malloc(len);
188235537Sgber
189235537Sgber	if (!ret) {
190235537Sgber		fprintf(stderr, "Cannot allocate buffer of %zd bytes. "
191235537Sgber		    "Exiting.\n", len);
192235537Sgber		exit(EX_OSERR);
193235537Sgber	}
194235537Sgber
195235537Sgber	return (ret);
196235537Sgber}
197235537Sgber
198235537Sgbervoid
199235537Sgberperrorf(const char *format, ...)
200235537Sgber{
201235537Sgber	va_list args;
202235537Sgber
203235537Sgber	va_start(args, format);
204235537Sgber	vfprintf(stderr, format, args);
205235537Sgber	va_end(args);
206235537Sgber	fprintf(stderr, ": %s\n", strerror(errno));
207235537Sgber}
208235537Sgber
209235537Sgberint
210235537Sgberusage(struct cmd_param *params)
211235537Sgber{
212235537Sgber	int i;
213235537Sgber
214235537Sgber	if (!params || !param_get_count(params)) {
215235537Sgber		fprintf(stderr, "Usage: nandtool <command> [arguments...]\n");
216235537Sgber		fprintf(stderr, "Arguments are in form 'name=value'.\n\n");
217235537Sgber		fprintf(stderr, "Available commands:\n");
218235537Sgber
219235537Sgber		for (i = 0; commands[i].name != NULL; i++)
220235537Sgber			fprintf(stderr, "\t%s\n", commands[i].name);
221235537Sgber
222235537Sgber		fprintf(stderr, "\n");
223235537Sgber		fprintf(stderr, "For information about particular command, "
224235537Sgber		    "type:\n");
225235537Sgber		fprintf(stderr, "'nandtool help topic=<command>'\n");
226235537Sgber	} else if (param_has_value(params, "topic")) {
227235537Sgber		for (i = 0; commands[i].name != NULL; i++) {
228235537Sgber			if (!strcmp(param_get_string(params, "topic"),
229235537Sgber			    commands[i].name)) {
230235537Sgber				fprintf(stderr, commands[i].usage, "nandtool");
231235537Sgber				return (0);
232235537Sgber			}
233235537Sgber		}
234235537Sgber
235235537Sgber		fprintf(stderr, "No such command\n");
236235537Sgber		return (EX_SOFTWARE);
237235537Sgber	} else {
238235537Sgber		fprintf(stderr, "Wrong arguments given. Try: 'nandtool help'\n");
239235537Sgber	}
240235537Sgber
241235537Sgber	return (EX_USAGE);
242235537Sgber}
243235537Sgber
244235537Sgberint
245235537Sgbermain(int argc, const char *argv[])
246235537Sgber{
247235537Sgber	struct cmd_param *params;
248235537Sgber	int i, ret, idx;
249235537Sgber
250235537Sgber	if (argc < 2) {
251235537Sgber		usage(NULL);
252235537Sgber		return (0);
253235537Sgber	}
254235537Sgber
255235537Sgber	params = malloc(sizeof(struct cmd_param) * (argc - 1));
256235537Sgber
257235537Sgber	for (i = 2, idx = 0; i < argc; i++, idx++) {
258235537Sgber		if (sscanf(argv[i], "%63[^=]=%63s", params[idx].name,
259235537Sgber		    params[idx].value) < 2) {
260235537Sgber			fprintf(stderr, "Syntax error in argument %d. "
261235537Sgber			    "Argument should be in form 'name=value'.\n", i);
262235537Sgber			free(params);
263235537Sgber			return (-1);
264235537Sgber		}
265235537Sgber	}
266235537Sgber
267235537Sgber	params[idx].name[0] = '\0';
268235537Sgber	params[idx].value[0] = '\0';
269235537Sgber
270235537Sgber	for (i = 0; commands[i].name != NULL; i++) {
271235537Sgber		if (!strcmp(commands[i].name, argv[1])) {
272235537Sgber			ret = commands[i].handler(params);
273235537Sgber			free(params);
274235537Sgber			return (ret);
275235537Sgber		}
276235537Sgber	}
277235537Sgber
278235537Sgber	free(params);
279235537Sgber	fprintf(stderr, "Unknown command. Try '%s help'\n", argv[0]);
280235537Sgber
281235537Sgber	return (-1);
282235537Sgber}
283235537Sgber
284