fix one too small
[RRG-proxmark3.git] / client / src / cmdmain.c
blob35dcfc39b1ae1cc9d57482d05958b7282665f49a
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Main command parser entry point
17 //-----------------------------------------------------------------------------
19 // ensure gmtime_r is available even with -std=c99; must be included before
20 #if !defined(_WIN32)
21 #define _POSIX_C_SOURCE 200112L
22 #endif
23 #include "cmdmain.h"
25 #include <string.h>
26 #include <ctype.h>
27 #include <time.h> // MingW
28 #include <stdlib.h> // calloc
30 #include "comms.h"
31 #include "cmdhf.h"
32 #include "cmddata.h"
33 #include "cmdhw.h"
34 #include "cmdlf.h"
35 #include "cmdnfc.h"
36 #include "cmdtrace.h"
37 #include "cmdscript.h"
38 #include "cmdcrc.h"
39 #include "cmdanalyse.h"
40 #include "emv/cmdemv.h" // EMV
41 #include "cmdflashmem.h" // rdv40 flashmem commands
42 #include "cmdpiv.h"
43 #include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
44 #include "cmdusart.h" // rdv40 FPC USART commands
45 #include "cmdwiegand.h" // wiegand commands
46 #include "ui.h"
47 #include "util_posix.h"
48 #include "commonutil.h" // ARRAYLEN
49 #include "preferences.h"
50 #include "cliparser.h"
52 static int CmdHelp(const char *Cmd);
54 static void AppendDate(char *s, size_t slen, const char *fmt) {
55 struct tm *ct, tm_buf;
56 time_t now = time(NULL);
57 #if defined(_WIN32)
58 ct = gmtime_s(&tm_buf, &now) == 0 ? &tm_buf : NULL;
59 #else
60 ct = gmtime_r(&now, &tm_buf);
61 #endif
62 if (fmt == NULL)
63 strftime(s, slen, "%Y-%m-%dT%H:%M:%SZ", ct); // ISO8601
64 else
65 strftime(s, slen, fmt, ct);
68 static int lf_search_plus(const char *Cmd) {
70 sample_config oldconfig;
71 memset(&oldconfig, 0, sizeof(sample_config));
73 int retval = lf_getconfig(&oldconfig);
75 if (retval != PM3_SUCCESS) {
76 PrintAndLogEx(ERR, "failed to get current device config");
77 return retval;
80 // Divisor : frequency(khz)
81 // 95 88 47 31 23
82 // 125.00 134.83 250.00 375.00 500.00
84 int16_t default_divisor[] = {95, 88, 47, 31, 23};
87 default LF config is set to:
88 decimation = 1
89 bits_per_sample = 8
90 averaging = YES
91 divisor = 95 (125kHz)
92 trigger_threshold = 0
93 samples_to_skip = 0
94 verbose = YES
96 sample_config config = {
97 .decimation = 1,
98 .bits_per_sample = 8,
99 .averaging = 1,
100 .trigger_threshold = 0,
101 .samples_to_skip = 0,
102 .verbose = false
105 // Iteration defaults
106 for (int i = 0; i < ARRAYLEN(default_divisor); ++i) {
108 if (kbd_enter_pressed()) {
109 PrintAndLogEx(INFO, "Keyboard pressed. Done.");
110 break;
112 // Try to change config!
113 uint32_t d;
114 d = config.divisor = default_divisor[i];
115 PrintAndLogEx(INFO, "--> trying ( " _GREEN_("%d.%02d kHz")" )", 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100));
117 retval = lf_setconfig(&config);
118 if (retval != PM3_SUCCESS)
119 break;
121 // The config for pm3 is changed, we can trying search!
122 retval = CmdLFfind(Cmd);
123 if (retval == PM3_SUCCESS)
124 break;
128 lf_setconfig(&oldconfig);
129 return retval;
132 static int CmdAuto(const char *Cmd) {
133 CLIParserContext *ctx;
134 CLIParserInit(&ctx, "auto",
135 "Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
136 "auto"
139 void *argtable[] = {
140 arg_param_begin,
141 arg_lit0("c", NULL, "Continue searching even after a first hit"),
142 arg_param_end
144 CLIExecWithReturn(ctx, Cmd, argtable, true);
145 bool exit_first = (arg_get_lit(ctx, 1) == false);
146 CLIParserFree(ctx);
148 PrintAndLogEx(INFO, "lf search");
149 int ret = CmdLFfind("");
150 if (ret == PM3_SUCCESS && exit_first)
151 return ret;
153 PrintAndLogEx(INFO, "hf search");
154 ret = CmdHFSearch("");
155 if (ret == PM3_SUCCESS && exit_first)
156 return ret;
158 PrintAndLogEx(INFO, "lf search - unknown");
159 ret = lf_search_plus("");
160 if (ret == PM3_SUCCESS && exit_first)
161 return ret;
163 if (ret != PM3_SUCCESS)
164 PrintAndLogEx(INFO, "Failed both LF / HF SEARCH,");
166 PrintAndLogEx(INFO, "Trying " _YELLOW_("`lf read`") " and save a trace for you");
168 CmdPlot("");
169 lf_read(false, 40000);
170 char *fname = calloc(100, sizeof(uint8_t));
171 AppendDate(fname, 100, "-f lf_unknown_%Y-%m-%d_%H:%M");
172 CmdSave(fname);
173 free(fname);
174 return PM3_SUCCESS;
177 int CmdRem(const char *Cmd) {
178 CLIParserContext *ctx;
179 CLIParserInit(&ctx, "rem",
180 "Add a text line in log file",
181 "rem my message -> adds a timestamp with `my message`"
184 void *argtable[] = {
185 arg_param_begin,
186 arg_strx1(NULL, NULL, NULL, "message line you want inserted"),
187 arg_param_end
189 CLIExecWithReturn(ctx, Cmd, argtable, false);
191 struct arg_str *foo = arg_get_str(ctx, 1);
192 size_t count = 0;
193 size_t len = 0;
194 do {
195 count += strlen(foo->sval[len]);
196 } while (len++ < (foo->count - 1));
198 char s[count + foo->count];
199 memset(s, 0, sizeof(s));
201 len = 0;
202 do {
203 snprintf(s + strlen(s), sizeof(s) - strlen(s), "%s ", foo->sval[len]);
204 } while (len++ < (foo->count - 1));
206 CLIParserFree(ctx);
207 char buf[22] = {0};
208 AppendDate(buf, sizeof(buf), NULL);
209 PrintAndLogEx(SUCCESS, "%s remark: %s", buf, s);
210 return PM3_SUCCESS;
213 static int CmdHints(const char *Cmd) {
215 CLIParserContext *ctx;
216 CLIParserInit(&ctx, "hints",
217 "Turn on/off hints",
218 "hints --on\n"
219 "hints -1\n"
222 void *argtable[] = {
223 arg_param_begin,
224 arg_lit0("1", "on", "turn on hints"),
225 arg_lit0("0", "off", "turn off hints"),
226 arg_param_end
228 CLIExecWithReturn(ctx, Cmd, argtable, true);
230 bool turn_on = arg_get_lit(ctx, 1);
231 bool turn_off = arg_get_lit(ctx, 2);
232 CLIParserFree(ctx);
234 if (turn_on && turn_off) {
235 PrintAndLogEx(ERR, "you can't turn off and on at the same time");
236 return PM3_EINVARG;
239 if (turn_off) {
240 g_session.show_hints = false;
241 } else if (turn_on) {
242 g_session.show_hints = true;
245 PrintAndLogEx(INFO, "Hints are %s", (g_session.show_hints) ? "ON" : "OFF");
246 return PM3_SUCCESS;
249 static int CmdMsleep(const char *Cmd) {
250 CLIParserContext *ctx;
251 CLIParserInit(&ctx, "msleep",
252 "Sleep for given amount of milliseconds",
253 "msleep -t 100"
256 void *argtable[] = {
257 arg_param_begin,
258 arg_int0("t", "ms", "<ms>", "time in milliseconds"),
259 arg_param_end
261 CLIExecWithReturn(ctx, Cmd, argtable, false);
262 uint32_t ms = arg_get_u32_def(ctx, 1, 0);
263 CLIParserFree(ctx);
265 if (ms == 0) {
266 PrintAndLogEx(ERR, "Specified invalid input. Can't be zero");
267 return PM3_EINVARG;
270 msleep(ms);
271 return PM3_SUCCESS;
274 static int CmdQuit(const char *Cmd) {
275 CLIParserContext *ctx;
276 CLIParserInit(&ctx, "quit",
277 "Quit the Proxmark3 client terminal",
278 "quit"
280 void *argtable[] = {
281 arg_param_begin,
282 arg_param_end
284 CLIExecWithReturn(ctx, Cmd, argtable, true);
285 CLIParserFree(ctx);
286 return PM3_EFATAL;
289 static int CmdRev(const char *Cmd) {
290 CmdCrc(Cmd);
291 return PM3_SUCCESS;
294 static int CmdPref(const char *Cmd) {
295 CmdPreferences(Cmd);
296 return PM3_SUCCESS;
299 static int CmdClear(const char *Cmd) {
300 CLIParserContext *ctx;
301 CLIParserInit(&ctx, "clear",
302 "Clear the Proxmark3 client terminal screen",
303 "clear -> clear the terminal screen\n"
304 "clear -b -> clear the terminal screen and the scrollback buffer"
306 void *argtable[] = {
307 arg_param_begin,
308 arg_lit0("b", "back", "also clear the scrollback buffer"),
309 arg_param_end
311 CLIExecWithReturn(ctx, Cmd, argtable, true);
312 bool scrollback = arg_get_lit(ctx, 1);
313 CLIParserFree(ctx);
315 if (!scrollback)
316 PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ "");
317 else
318 PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ _CLEAR_SCROLLBACK_ "");
320 return PM3_SUCCESS;
323 static command_t CommandTable[] = {
325 {"help", CmdHelp, AlwaysAvailable, "Use `" _YELLOW_("<command> help") "` for details of a command"},
326 {"prefs", CmdPref, AlwaysAvailable, "{ Edit client/device preferences... }"},
327 {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Technology") " -----------------------"},
328 {"analyse", CmdAnalyse, AlwaysAvailable, "{ Analyse utils... }"},
329 {"data", CmdData, AlwaysAvailable, "{ Plot window / data buffer manipulation... }"},
330 {"emv", CmdEMV, AlwaysAvailable, "{ EMV ISO-14443 / ISO-7816... }"},
331 {"hf", CmdHF, AlwaysAvailable, "{ High frequency commands... }"},
332 {"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
333 {"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
334 {"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
335 {"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
336 {"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
337 {"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
338 {"smart", CmdSmartcard, AlwaysAvailable, "{ Smart card ISO-7816 commands... }"},
339 {"script", CmdScript, AlwaysAvailable, "{ Scripting commands... }"},
340 {"trace", CmdTrace, AlwaysAvailable, "{ Trace manipulation... }"},
341 {"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
342 {"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
343 {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
344 {"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"},
345 {"clear", CmdClear, AlwaysAvailable, "Clear screen"},
346 {"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
347 {"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
348 {"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"},
349 {"quit", CmdQuit, AlwaysAvailable, ""},
350 {"exit", CmdQuit, AlwaysAvailable, "Exit program"},
351 {NULL, NULL, NULL, NULL}
354 static int CmdHelp(const char *Cmd) {
355 (void)Cmd; // Cmd is not used so far
356 CmdsHelp(CommandTable);
357 return PM3_SUCCESS;
360 //-----------------------------------------------------------------------------
361 // Entry point into our code: called whenever the user types a command and
362 // then presses Enter, which the full command line that they typed.
363 //-----------------------------------------------------------------------------
364 int CommandReceived(const char *Cmd) {
365 return CmdsParse(CommandTable, Cmd);
368 command_t *getTopLevelCommandTable(void) {
369 return CommandTable;