1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
19 #include "proxmark3.h"
25 #include <libgen.h> // basename
29 #include "usart_defs.h"
30 #include "util_posix.h"
37 #include "fileutils.h"
39 #include "preferences.h"
40 #include "commonutil.h"
47 static int mainret
= PM3_ESOFT
;
51 #define BANNERMSG2 " [ :coffee: ]"
54 typedef enum LogoMode
{ UTF8
, ANSI
, ASCII
} LogoMode
;
56 static void showBanner_logo(LogoMode mode
) {
59 const char *sq
= "\xE2\x96\x88"; // square block
60 const char *tr
= "\xE2\x95\x97"; // top right corner
61 const char *tl
= "\xE2\x95\x94"; // top left corner
62 const char *br
= "\xE2\x95\x9D"; // bottom right corner
63 const char *bl
= "\xE2\x95\x9A"; // bottom left corner
64 const char *hl
= "\xE2\x95\x90"; // horiz line
65 const char *vl
= "\xE2\x95\x91"; // vert line
68 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
69 sq
, sq
, sq
, sq
, sq
, sq
, tr
, __
, sq
, sq
, sq
, tr
, __
, __
, __
, sq
, sq
, sq
, tr
, sq
, sq
, sq
, sq
, sq
, tr
, __
);
70 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
71 sq
, sq
, tl
, hl
, hl
, sq
, sq
, tr
, sq
, sq
, sq
, sq
, tr
, __
, sq
, sq
, sq
, sq
, vl
, bl
, hl
, hl
, hl
, sq
, sq
, tr
);
72 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
73 sq
, sq
, sq
, sq
, sq
, sq
, tl
, br
, sq
, sq
, tl
, sq
, sq
, sq
, sq
, tl
, sq
, sq
, vl
, __
, sq
, sq
, sq
, sq
, tl
, br
);
74 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
75 sq
, sq
, tl
, hl
, hl
, hl
, br
, __
, sq
, sq
, vl
, bl
, sq
, sq
, tl
, br
, sq
, sq
, vl
, __
, bl
, hl
, hl
, sq
, sq
, tr
);
76 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG1
,
77 sq
, sq
, vl
, __
, __
, __
, __
, __
, sq
, sq
, vl
, __
, bl
, hl
, br
, __
, sq
, sq
, vl
, sq
, sq
, sq
, sq
, sq
, tl
, br
);
78 PrintAndLogEx(NORMAL
, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG2
,
79 bl
, hl
, br
, __
, __
, __
, __
, __
, bl
, hl
, br
, __
, __
, __
, __
, __
, bl
, hl
, br
, bl
, hl
, hl
, hl
, hl
, br
, __
);
83 PrintAndLogEx(NORMAL
, " " _CYAN_("8888888b. 888b d888 .d8888b. "));
84 PrintAndLogEx(NORMAL
, " " _CYAN_("888 Y88b 8888b d8888 d88P Y88b "));
85 PrintAndLogEx(NORMAL
, " " _CYAN_("888 888 88888b.d88888 .d88P "));
86 PrintAndLogEx(NORMAL
, " " _CYAN_("888 d88P 888Y88888P888 8888\" "));
87 PrintAndLogEx(NORMAL
, " " _CYAN_("8888888P\" 888 Y888P 888 \"Y8b. "));
88 PrintAndLogEx(NORMAL
, " " _CYAN_("888 888 Y8P 888 888 888 "));
89 PrintAndLogEx(NORMAL
, " " _CYAN_("888 888 \" 888 Y88b d88P") " " BANNERMSG1
);
90 PrintAndLogEx(NORMAL
, " " _CYAN_("888 888 888 \"Y8888P\"") " " BANNERMSG2
);
94 PrintAndLogEx(NORMAL
, " 8888888b. 888b d888 .d8888b. ");
95 PrintAndLogEx(NORMAL
, " 888 Y88b 8888b d8888 d88P Y88b ");
96 PrintAndLogEx(NORMAL
, " 888 888 88888b.d88888 .d88P ");
97 PrintAndLogEx(NORMAL
, " 888 d88P 888Y88888P888 8888\" ");
98 PrintAndLogEx(NORMAL
, " 8888888P\" 888 Y888P 888 \"Y8b. ");
99 PrintAndLogEx(NORMAL
, " 888 888 Y8P 888 888 888 ");
100 PrintAndLogEx(NORMAL
, " 888 888 \" 888 Y88b d88P " BANNERMSG1
);
101 PrintAndLogEx(NORMAL
, " 888 888 888 \"Y8888P\" " BANNERMSG2
);
105 PrintAndLogEx(NORMAL
, "");
106 PrintAndLogEx(NORMAL
, BANNERMSG3
);
109 static uint8_t detect_current_lang(void) {
111 const char *lang
= setlocale(LC_ALL
, "");
115 if (memcmp(lang
, "fr", 2) == 0) {
118 if (memcmp(lang
, "es", 2) == 0) {
125 static const char *get_quote(void) {
127 const char *quotes_en
[] = {
128 "Fund creativity, empower dreams",
129 "Invest in open innovation",
130 "Donate, empower, grow, sustain",
131 "Back global innovation today",
132 "Fuel open source revolution",
133 "Contribute funds, drive progress",
134 "Sponsor innovation, build tomorrow",
135 "Consider supporting: fund innovation",
136 "Your donation fuels progress",
137 "Empower dreams with your support",
138 "Join us: finance creative freedom",
139 "Make an impact: donate today",
140 "Help us drive open innovation",
141 "Your support, our future",
142 "Invest in a better tomorrow",
143 "Every contribution powers change",
144 "Support us, shape the future",
145 "Ignite change: support open-source creativity",
146 "Together, we can innovate without limits",
149 const char *quotes_fr
[] = {
150 "Financez la créativité, donnez pouvoir aux rêves",
151 "Investissez dans l'innovation ouverte",
152 "Donnez, habilitez, croissez, soutenez",
153 "Soutenez l'innovation mondiale aujourd'hui",
154 "Alimentez la révolution open source",
155 "Contribuez financièrement, poussez le progrès",
156 "Parrainez l'innovation, construisez demain",
157 "Envisagez de soutenir : financez l'innovation",
158 "Votre don alimente le progrès",
159 "Donnez pouvoir aux rêves avec votre soutien",
160 "Rejoignez-nous : financez la liberté créative",
161 "Faites une différence : donnez aujourd'hui",
162 "Aidez-nous à stimuler l'innovation ouverte",
163 "Votre soutien, notre avenir",
164 "Investissez dans un meilleur demain",
165 "Chaque contribution favorise le changement",
166 "Soutenez-nous, façonnez l'avenir",
167 "Allumez le changement : soutenez la créativité open-source",
168 "Ensemble, nous pouvons innover sans limites",
171 const char *quotes_es
[] = {
172 "Financia la creatividad, empodera sueños",
173 "Invierte en innovación abierta",
174 "Dona, empodera, crece, sostén",
175 "Apoya la innovación global hoy",
176 "Impulsa la revolución de código abierto",
177 "Contribuye fondos, impulsa el progreso",
178 "Patrocina la innovación, construye el mañana",
179 "Considera apoyar: financia la innovación",
180 "Tu donación impulsa el progreso",
181 "Empodera sueños con tu apoyo",
182 "Únete a nosotros: financia la libertad creativa",
183 "Haz un impacto: dona hoy",
184 "Ayúdanos a impulsar la innovación abierta",
185 "Tu apoyo, nuestro futuro",
186 "Invierte en un mejor mañana",
187 "Cada contribución impulsa el cambio",
188 "Apóyanos, forma el futuro",
189 "Enciende el cambio: apoya la creatividad de código abierto",
190 "Juntos, podemos innovar sin límites",
193 srand((uint32_t)time(NULL
));
194 int r
= rand() % ARRAYLEN(quotes_en
);
196 uint8_t lang
= detect_current_lang();
208 static void showBanner(void) {
209 uint8_t old_printAndLog
= g_printAndLog
;
210 g_printAndLog
&= PRINTANDLOG_PRINT
;
211 PrintAndLogEx(NORMAL
, "\n");
214 if (GetConsoleCP() == 65001) {
215 // If on Windows and using UTF-8 then we need utf-8 ascii art for banner.
216 showBanner_logo(UTF8
);
218 showBanner_logo(ANSI
);
220 #elif defined(__linux__) || defined(__APPLE__)
221 showBanner_logo(ANSI
);
223 showBanner_logo(ASCII
);
226 PrintAndLogEx(NORMAL
, "");
227 PrintAndLogEx(NORMAL
, " [ " _YELLOW_("%s!")" ]", get_quote());
228 PrintAndLogEx(NORMAL
, " Patreon - https://www.patreon.com/iceman1001/");
229 PrintAndLogEx(NORMAL
, " Paypal - https://www.paypal.me/iceman1001/");
230 PrintAndLogEx(NORMAL
, "");
231 // PrintAndLogEx(NORMAL, " Monero");
232 // PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
233 PrintAndLogEx(NORMAL
, "");
235 g_printAndLog
= old_printAndLog
;
239 static const char *prompt_dev
= "";
240 static const char *prompt_ctx
= "";
241 static const char *prompt_net
= "";
244 static void prompt_set(void) {
245 if (g_session
.pm3_present
) {
247 switch (g_conn
.send_via_ip
) {
249 prompt_net
= PROXPROMPT_NET_TCPV4
;
252 prompt_net
= PROXPROMPT_NET_TCPV6
;
255 prompt_net
= PROXPROMPT_NET_UDPV4
;
258 prompt_net
= PROXPROMPT_NET_UDPV6
;
261 prompt_net
= PROXPROMPT_NET_NONE
;
267 if (g_conn
.send_via_fpc_usart
)
268 prompt_dev
= PROXPROMPT_DEV_FPC
;
270 prompt_dev
= PROXPROMPT_DEV_USB
;
273 prompt_dev
= PROXPROMPT_DEV_OFFLINE
;
277 static void prompt_compose(char *buf
, size_t buflen
, const char *promptctx
, const char *promptdev
, const char *promptnet
, bool no_newline
) {
279 snprintf(buf
, buflen
- 1, PROXPROMPT_COMPOSE
, promptdev
, promptnet
, promptctx
);
281 snprintf(buf
, buflen
- 1, "\r \r" PROXPROMPT_COMPOSE
, promptdev
, promptnet
, promptctx
);
285 static bool c_update_reconnect_prompt
= false;
287 // This function is hooked via RL_EVENT_HOOK.
288 static int check_comm(void) {
289 // If communications thread goes down. Device disconnected then this should hook up PM3 again.
290 if (IsCommunicationThreadDead() && g_session
.pm3_present
) {
292 #ifndef HAVE_READLINE
293 PrintAndLogEx(INFO
, _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n");
295 prompt_dev
= PROXPROMPT_DEV_OFFLINE
;
296 char prompt
[PROXPROMPT_MAX_SIZE
] = {0};
297 prompt_compose(prompt
, sizeof(prompt
), prompt_ctx
, prompt_dev
, prompt_net
, false);
298 char prompt_filtered
[PROXPROMPT_MAX_SIZE
] = {0};
299 memcpy_filter_ansi(prompt_filtered
, prompt
, sizeof(prompt_filtered
), !g_session
.supports_colors
);
300 pm3line_update_prompt(prompt_filtered
);
301 CloseProxmark(g_session
.current_device
);
302 StartReconnectProxmark();
303 c_update_reconnect_prompt
= true;
306 if (c_update_reconnect_prompt
&& IsReconnectedOk() && g_session
.pm3_present
) {
310 char prompt
[PROXPROMPT_MAX_SIZE
] = {0};
311 prompt_compose(prompt
, sizeof(prompt
), prompt_ctx
, prompt_dev
, prompt_net
, false);
312 char prompt_filtered
[PROXPROMPT_MAX_SIZE
] = {0};
313 memcpy_filter_ansi(prompt_filtered
, prompt
, sizeof(prompt_filtered
), !g_session
.supports_colors
);
314 pm3line_update_prompt(prompt_filtered
);
315 c_update_reconnect_prompt
= false;
323 static bool DetectWindowsAnsiSupport(void) {
324 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
325 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
328 // disable colors if stdin or stdout are redirected
329 if ((! g_session
.stdinOnTTY
) || (! g_session
.stdoutOnTTY
))
332 HANDLE hOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
334 GetConsoleMode(hOut
, &dwMode
);
336 //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set
337 if ((dwMode
& ENABLE_VIRTUAL_TERMINAL_PROCESSING
))
340 dwMode
|= ENABLE_VIRTUAL_TERMINAL_PROCESSING
;
342 return SetConsoleMode(hOut
, dwMode
) ? true : false;
346 // first slot is always NULL, indicating absence of script when idx=0
347 static FILE *cmdscriptfile
[MAX_NESTED_CMDSCRIPT
+ 1] = {0};
348 static uint8_t cmdscriptfile_idx
= 0;
349 static bool cmdscriptfile_stayafter
= false;
351 int push_cmdscriptfile(char *path
, bool stayafter
) {
352 if (cmdscriptfile_idx
== MAX_NESTED_CMDSCRIPT
) {
353 PrintAndLogEx(ERR
, "Too many nested scripts, skipping %s\n", path
);
357 FILE *f
= fopen(path
, "r");
361 if (cmdscriptfile_idx
== 0)
362 cmdscriptfile_stayafter
= stayafter
;
364 cmdscriptfile
[++cmdscriptfile_idx
] = f
;
368 static FILE *current_cmdscriptfile(void) {
369 return cmdscriptfile
[cmdscriptfile_idx
];
372 static bool pop_cmdscriptfile(void) {
373 fclose(cmdscriptfile
[cmdscriptfile_idx
]);
374 cmdscriptfile
[cmdscriptfile_idx
--] = NULL
;
375 if (cmdscriptfile_idx
== 0)
376 return cmdscriptfile_stayafter
;
381 // Main thread of PM3 Client
383 #ifdef __has_attribute
384 #if __has_attribute(force_align_arg_pointer)
385 __attribute__((force_align_arg_pointer
))
388 main_loop(const char *script_cmds_file
, char *script_cmd
, bool stayInCommandLoop
) {
391 bool execCommand
= (script_cmd
!= NULL
);
392 bool fromInteractive
= false;
393 uint16_t script_cmd_len
= 0;
395 script_cmd_len
= strlen(script_cmd
);
396 str_creplace(script_cmd
, script_cmd_len
, ';', '\0');
398 bool stdinOnPipe
= !isatty(STDIN_FILENO
);
399 char script_cmd_buf
[256] = {0x00}; // iceman, needs lua script the same file_path_buffer as the rest
401 // cache Version information now:
402 if (execCommand
|| script_cmds_file
|| stdinOnPipe
)
403 pm3_version(false, false);
407 if (script_cmds_file
) {
410 int res
= searchFile(&path
, CMD_SCRIPTS_SUBDIR
, script_cmds_file
, ".cmd", false);
411 if (res
== PM3_SUCCESS
) {
412 if (push_cmdscriptfile(path
, stayInCommandLoop
) == PM3_SUCCESS
)
413 PrintAndLogEx(SUCCESS
, "executing commands from file: %s\n", path
);
415 PrintAndLogEx(ERR
, "could not open " _YELLOW_("%s") "...", path
);
420 g_session
.history_path
= NULL
;
421 if (g_session
.incognito
) {
422 PrintAndLogEx(INFO
, "No history will be recorded");
424 if (searchHomeFilePath(&g_session
.history_path
, NULL
, PROXHISTORY
, true) != PM3_SUCCESS
) {
425 g_session
.history_path
= NULL
;
426 PrintAndLogEx(ERR
, "No history will be recorded");
428 if (pm3line_load_history(g_session
.history_path
) != PM3_SUCCESS
) {
429 PrintAndLogEx(INFO
, "No previous history could be loaded");
434 // loops every time enter is pressed...
437 bool printprompt
= false;
442 // If there is a script file
443 if (current_cmdscriptfile()) {
446 memset(script_cmd_buf
, 0, sizeof(script_cmd_buf
));
449 if (fgets(script_cmd_buf
, sizeof(script_cmd_buf
), current_cmdscriptfile()) == NULL
) {
450 if (pop_cmdscriptfile() == false) {
456 prompt_ctx
= PROXPROMPT_CTX_SCRIPTFILE
;
459 str_cleanrn(script_cmd_buf
, sizeof(script_cmd_buf
));
461 cmd
= str_dup(script_cmd_buf
);
467 // If there is a script command
469 prompt_ctx
= stdinOnPipe
? PROXPROMPT_CTX_STDIN
: PROXPROMPT_CTX_SCRIPTCMD
;
471 cmd
= str_dup(script_cmd
);
472 if ((cmd
!= NULL
) && (! fromInteractive
))
475 uint16_t len
= strlen(script_cmd
) + 1;
478 if (script_cmd_len
== len
- 1)
481 script_cmd_len
-= len
;
483 // exit after exec command
484 if (script_cmd
&& !stayInCommandLoop
)
487 // if there is a pipe from stdin
490 memset(script_cmd_buf
, 0, sizeof(script_cmd_buf
));
492 if (fgets(script_cmd_buf
, sizeof(script_cmd_buf
), stdin
) == NULL
) {
493 PrintAndLogEx(ERR
, "STDIN unexpected end, exit...");
497 stayInCommandLoop
= true;
498 fromInteractive
= false;
499 script_cmd
= script_cmd_buf
;
500 script_cmd_len
= strlen(script_cmd
);
501 str_creplace(script_cmd
, script_cmd_len
, ';', '\0');
503 str_cleanrn(script_cmd
, script_cmd_len
);
506 pm3line_check(check_comm
);
507 prompt_ctx
= PROXPROMPT_CTX_INTERACTIVE
;
508 char prompt
[PROXPROMPT_MAX_SIZE
] = {0};
509 prompt_compose(prompt
, sizeof(prompt
), prompt_ctx
, prompt_dev
, prompt_net
, true);
510 char prompt_filtered
[PROXPROMPT_MAX_SIZE
] = {0};
511 memcpy_filter_ansi(prompt_filtered
, prompt
, sizeof(prompt_filtered
), !g_session
.supports_colors
);
512 g_pendingPrompt
= true;
513 script_cmd
= pm3line_read(prompt_filtered
);
515 //Check if color support needs to be enabled again in case the window buffer did change
516 g_session
.supports_colors
= DetectWindowsAnsiSupport();
518 if (script_cmd
!= NULL
) {
520 stayInCommandLoop
= true;
521 fromInteractive
= true;
522 script_cmd_len
= strlen(script_cmd
);
523 str_creplace(script_cmd
, script_cmd_len
, ';', '\0');
525 str_cleanrn(script_cmd
, script_cmd_len
);
537 size_t l
= strlen(cmd
);
538 while (l
> 0 && isspace(cmd
[l
- 1])) {
543 while ((cmd
[off
] != '\0') && isspace(cmd
[off
])) {
547 for (size_t i
= 0; i
< strlen(cmd
) - off
; i
++) {
548 cmd
[i
] = cmd
[i
+ off
];
551 cmd
[strlen(cmd
) - off
] = '\0';
553 if (cmd
[0] != '\0') {
554 uint8_t old_printAndLog
= g_printAndLog
;
556 g_printAndLog
&= ~PRINTANDLOG_PRINT
;
558 char prompt
[PROXPROMPT_MAX_SIZE
] = {0};
559 prompt_compose(prompt
, sizeof(prompt
), prompt_ctx
, prompt_dev
, prompt_net
, true);
560 // always filter RL magic separators if not using readline
561 char prompt_filtered
[PROXPROMPT_MAX_SIZE
] = {0};
562 memcpy_filter_rlmarkers(prompt_filtered
, prompt
, sizeof(prompt_filtered
));
563 PrintAndLogEx(NORMAL
, "%s%s", prompt_filtered
, cmd
);
564 g_printAndLog
= old_printAndLog
;
566 // add to history if not from a script
567 if (!current_cmdscriptfile()) {
568 pm3line_add_history(cmd
);
571 g_pendingPrompt
= false;
572 mainret
= CommandReceived(cmd
);
575 if (mainret
== PM3_EFATAL
)
581 PrintAndLogEx(NORMAL
, "\n");
582 if (script_cmds_file
&& stayInCommandLoop
)
583 stayInCommandLoop
= false;
589 if (g_session
.pm3_present
) {
590 clearCommandBuffer();
591 SendCommandNG(CMD_QUIT_SESSION
, NULL
, 0);
592 msleep(100); // Make sure command is sent before killing client
595 while (current_cmdscriptfile()) {
599 pm3line_flush_history();
608 static void dumpAllHelp(int markdown
, bool full_help
) {
609 g_session
.help_dump_mode
= true;
610 PrintAndLogEx(NORMAL
, "\n%sProxmark3 command dump%s\n\n", markdown
? "# " : "", markdown
? "" : "\n======================");
611 PrintAndLogEx(NORMAL
, "Some commands are available only if a Proxmark3 is actually connected.%s\n", markdown
? " " : "");
612 PrintAndLogEx(NORMAL
, "Check column \"offline\" for their availability.\n");
613 PrintAndLogEx(NORMAL
, "\n");
614 command_t
*cmds
= getTopLevelCommandTable();
615 dumpCommandsRecursive(cmds
, markdown
, full_help
);
616 g_session
.help_dump_mode
= false;
617 PrintAndLogEx(NORMAL
, "Full help dump done.");
621 static char *my_executable_path
= NULL
;
622 static char *my_executable_directory
= NULL
;
624 const char *get_my_executable_path(void) {
625 return my_executable_path
;
628 const char *get_my_executable_directory(void) {
629 return my_executable_directory
;
632 static void set_my_executable_path(void) {
633 int path_length
= wai_getExecutablePath(NULL
, 0, NULL
);
634 if (path_length
== -1)
637 my_executable_path
= (char *)calloc(path_length
+ 1, sizeof(uint8_t));
638 int dirname_length
= 0;
639 if (wai_getExecutablePath(my_executable_path
, path_length
, &dirname_length
) != -1) {
640 my_executable_path
[path_length
] = '\0';
641 my_executable_directory
= (char *)calloc(dirname_length
+ 2, sizeof(uint8_t));
642 strncpy(my_executable_directory
, my_executable_path
, dirname_length
+ 1);
643 my_executable_directory
[dirname_length
+ 1] = '\0';
647 static const char *my_user_directory
= NULL
;
648 // static char _cwd_Buffer [FILENAME_MAX] = {0};
650 const char *get_my_user_directory(void) {
651 return my_user_directory
;
654 static void set_my_user_directory(void) {
655 /* my_user_directory = getenv("HOME");
657 // if not found, default to current directory
658 if (my_user_directory == NULL) {
659 my_user_directory = GetCurrentDir(_cwd_Buffer, sizeof(_cwd_Buffer));
660 // change all slashes to / (windows should not care...
661 for (int i = 0; i < strlen(_cwd_Buffer); i++)
662 if (_cwd_Buffer[i] == '\\') _cwd_Buffer[i] = '/';
663 // my_user_directory = ".";
666 my_user_directory
= getenv("HOME");
668 // if not found, default to current directory
669 if (my_user_directory
== NULL
) {
671 uint16_t pathLen
= FILENAME_MAX
; // should be a good starting point
672 char *cwd_buffer
= (char *)calloc(pathLen
, sizeof(uint8_t));
673 if (cwd_buffer
== NULL
) {
674 PrintAndLogEx(WARNING
, "failed to allocate memory");
678 while (GetCurrentDir(cwd_buffer
, pathLen
) == NULL
) {
679 if (errno
== ERANGE
) { // Need bigger buffer
680 pathLen
+= 10; // if buffer was too small add 10 characters and try again
681 char *tmp
= realloc(cwd_buffer
, pathLen
);
683 PrintAndLogEx(WARNING
, "failed to allocate memory");
694 for (int i
= 0; i
< strlen(cwd_buffer
); i
++) {
695 if (cwd_buffer
[i
] == '\\') {
700 my_user_directory
= cwd_buffer
;
705 static void show_help(bool showFullHelp
, char *exec_name
) {
707 PrintAndLogEx(NORMAL
, "\nsyntax: %s [-h|-t|-m|--fulltext]", exec_name
);
709 PrintAndLogEx(NORMAL
, " %s [[-p] <port>] [-b] [-w] [-f] [-c <command>]|[-l <lua_script_file>]|[-y <python_script_file>]|[-s <cmd_script_file>] [-i] [-d <0|1|2>]", exec_name
);
711 PrintAndLogEx(NORMAL
, " %s [[-p] <port>] [-b] [-w] [-f] [-c <command>]|[-l <lua_script_file>]|[-s <cmd_script_file>] [-i] [-d <0|1|2>]", exec_name
);
712 #endif // HAVE_PYTHON
713 PrintAndLogEx(NORMAL
, " %s [-p] <port> --flash [--unlock-bootloader] [--image <imagefile>]+ [-w] [-f] [-d <0|1|2>]", exec_name
);
717 PrintAndLogEx(NORMAL
, "\nCommon options:");
718 PrintAndLogEx(NORMAL
, " -h/--help this help");
719 PrintAndLogEx(NORMAL
, " -v/--version print client version");
720 PrintAndLogEx(NORMAL
, " -p/--port serial port to connect to");
721 PrintAndLogEx(NORMAL
, " -w/--wait 20sec waiting the serial port to appear in the OS");
722 PrintAndLogEx(NORMAL
, " -f/--flush output will be flushed after every print");
723 PrintAndLogEx(NORMAL
, " -d/--debug <0|1|2> set debugmode");
724 PrintAndLogEx(NORMAL
, "\nOptions in client mode:");
725 PrintAndLogEx(NORMAL
, " -t/--text dump all interactive command list at once");
726 PrintAndLogEx(NORMAL
, " --fulltext dump all interactive command's help at once");
727 PrintAndLogEx(NORMAL
, " -m/--markdown dump all interactive command list at once in markdown syntax");
728 PrintAndLogEx(NORMAL
, " -b/--baud serial port speed (only needed for physical UART, not for USB-CDC or BT)");
729 PrintAndLogEx(NORMAL
, " -c/--command <command> execute one Proxmark3 command (or several separated by ';').");
730 PrintAndLogEx(NORMAL
, " -l/--lua <lua_script_file> execute Lua script.");
732 // Technically, --lua and --py are identical and interexchangeable
733 PrintAndLogEx(NORMAL
, " -y/--py <python_script_file> execute Python script.");
734 #endif // HAVE_PYTHON
735 PrintAndLogEx(NORMAL
, " -s/--script-file <cmd_script_file> script file with one Proxmark3 command per line");
736 PrintAndLogEx(NORMAL
, " -i/--interactive enter interactive mode after executing the script or the command");
737 PrintAndLogEx(NORMAL
, " --incognito do not use history, prefs file nor log files");
738 PrintAndLogEx(NORMAL
, " --ncpu <num_cores> override number of CPU cores");
739 PrintAndLogEx(NORMAL
, "\nOptions in flasher mode:");
740 PrintAndLogEx(NORMAL
, " --flash flash Proxmark3, requires at least one --image");
741 PrintAndLogEx(NORMAL
, " --reboot-to-bootloader reboot Proxmark3 into bootloader mode");
742 PrintAndLogEx(NORMAL
, " --unlock-bootloader Enable flashing of bootloader area *DANGEROUS* (need --flash)");
743 PrintAndLogEx(NORMAL
, " --force Enable flashing even if firmware seems to not match client version");
744 PrintAndLogEx(NORMAL
, " --image <imagefile> image to flash. Can be specified several times.");
745 PrintAndLogEx(NORMAL
, "\nOptions in memory dump mode:");
746 PrintAndLogEx(NORMAL
, " --dumpmem <dumpfile> dumps Proxmark3 flash memory to file");
747 PrintAndLogEx(NORMAL
, " --dumpaddr <address> starting address for dump, default 0");
748 PrintAndLogEx(NORMAL
, " --dumplen <length> number of bytes to dump, default 512KB");
749 PrintAndLogEx(NORMAL
, " --dumpraw raw address mode: dump from anywhere, not just flash");
750 PrintAndLogEx(NORMAL
, "\nExamples:");
751 PrintAndLogEx(NORMAL
, "\n to run Proxmark3 client:\n");
752 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -- runs the pm3 client", exec_name
);
753 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -f -- flush output every time", exec_name
);
754 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -w -- wait for serial port", exec_name
);
755 PrintAndLogEx(NORMAL
, " %s -- runs the pm3 client in OFFLINE mode", exec_name
);
756 PrintAndLogEx(NORMAL
, "\n to execute different commands from terminal:\n");
757 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -c \"hf mf chk --1k\" -- execute cmd and quit client", exec_name
);
758 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -l hf_read -- execute Lua script `hf_read` and quit client", exec_name
);
759 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" -s mycmds.txt -- execute each pm3 cmd in file and quit client", exec_name
);
760 PrintAndLogEx(NORMAL
, "\n to flash fullimage and bootloader:\n");
761 PrintAndLogEx(NORMAL
, " %s "SERIAL_PORT_EXAMPLE_H
" --flash --unlock-bootloader --image bootrom.elf --image fullimage.elf", exec_name
);
763 PrintAndLogEx(NORMAL
, "\nNote (Linux):\nif the flasher gets stuck in 'Waiting for Proxmark3 to reappear on <DEVICE>',");
764 PrintAndLogEx(NORMAL
, "you need to blacklist Proxmark3 for modem-manager - see documentation for more details:");
765 PrintAndLogEx(NORMAL
, "* https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md");
766 PrintAndLogEx(NORMAL
, "\nMore info on flashing procedure from the official Proxmark3 wiki:");
767 PrintAndLogEx(NORMAL
, "* https://github.com/Proxmark/proxmark3/wiki/Gentoo%%20Linux");
768 PrintAndLogEx(NORMAL
, "* https://github.com/Proxmark/proxmark3/wiki/Ubuntu%%20Linux");
769 PrintAndLogEx(NORMAL
, "* https://github.com/Proxmark/proxmark3/wiki/OSX\n");
774 static int dumpmem_to_file(const char *filename
, uint32_t addr
, uint32_t len
, bool raw
, bool in_bootloader
) {
776 uint8_t *buffer
= calloc(len
, sizeof(uint8_t));
777 if (buffer
== NULL
) {
778 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
782 int res
= PM3_EUNDEF
;
784 DeviceMemType_t type
= raw
? MCU_MEM
: MCU_FLASH
;
785 if (GetFromDevice(type
, buffer
, len
, addr
, NULL
, 0, NULL
, 1000, true)) {
787 readlen
= len
; // GetFromDevice does not report the actual number of bytes received.
790 if (res
== PM3_SUCCESS
) {
791 res
= saveFile(filename
, ".bin", buffer
, readlen
);
792 if (res
!= PM3_SUCCESS
) {
793 PrintAndLogEx(ERR
, "error writing to file "_YELLOW_("%s"), filename
);
801 static int dumpmem_pm3(char *serial_port_name
, const char *filename
, uint32_t addr
, uint32_t len
, bool raw
) {
802 int ret
= PM3_EUNDEF
;
803 bool in_bootloader
= false;
805 if (serial_port_name
== NULL
) {
806 PrintAndLogEx(ERR
, "You must specify a port.\n");
810 if (OpenProxmark(&g_session
.current_device
, serial_port_name
, true, 60, true, FLASHMODE_SPEED
)) {
811 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
814 PrintAndLogEx(ERR
, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name
);
819 // Determine if we're talking to a bootloader or main firmware.
820 SendCommandBL(CMD_DEVICE_INFO
, 0, 0, 0, NULL
, 0);
821 PacketResponseNG resp
;
822 if (WaitForResponseTimeout(CMD_UNKNOWN
, &resp
, 1000) == false) {
823 PrintAndLogEx(ERR
, "Could not get device info.");
826 uint32_t dev_info
= resp
.oldarg
[0];
827 in_bootloader
= (dev_info
& DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM
) != 0;
829 if ((dev_info
& DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM
) != 0) {
830 PrintAndLogEx(INFO
, "Device is running the bootloader.");
832 PrintAndLogEx(ERR
, "Device is running the bootloader, but the bootloader"
833 " doesn't understand the READ MEM command.");
838 PrintAndLogEx(SUCCESS
, "Dump requested from address "_YELLOW_("%u")", length "_YELLOW_("%u")"%s.",
839 addr
, len
, raw
? ", in raw address mode" : "");
841 PrintAndLogEx(SUCCESS
, _CYAN_("Memory dumping to file..."));
842 ret
= dumpmem_to_file(filename
, addr
, len
, raw
, in_bootloader
);
843 if (ret
!= PM3_SUCCESS
) {
846 PrintAndLogEx(NORMAL
, "");
849 clearCommandBuffer();
851 g_session
.current_device
->g_conn
->run
= false;
852 SendCommandOLD(CMD_PING
, 0, 0, 0, NULL
, 0);
854 SendCommandNG(CMD_QUIT_SESSION
, NULL
, 0);
857 CloseProxmark(g_session
.current_device
);
860 if (ret
== PM3_SUCCESS
)
861 PrintAndLogEx(SUCCESS
, _CYAN_("All done"));
862 else if (ret
== PM3_EOPABORTED
)
863 PrintAndLogEx(FAILED
, "Aborted by user");
865 PrintAndLogEx(ERR
, "Aborted on error %u", ret
);
869 static int flash_pm3(char *serial_port_name
, uint8_t num_files
, const char *filenames
[FLASH_MAX_FILES
], bool can_write_bl
, bool force
) {
871 int ret
= PM3_EUNDEF
;
872 flash_file_t files
[FLASH_MAX_FILES
];
873 memset(files
, 0, sizeof(files
));
875 if (serial_port_name
== NULL
) {
876 PrintAndLogEx(ERR
, "You must specify a port.\n");
880 for (int i
= 0 ; i
< num_files
; ++i
) {
882 ret
= searchFile(&path
, FIRMWARES_SUBDIR
, filenames
[i
], ".elf", true);
883 if (ret
!= PM3_SUCCESS
) {
884 ret
= searchFile(&path
, BOOTROM_SUBDIR
, filenames
[i
], ".elf", true);
886 if (ret
!= PM3_SUCCESS
) {
887 // Last try, let the error msg be displayed if not found
888 ret
= searchFile(&path
, FULLIMAGE_SUBDIR
, filenames
[i
], ".elf", false);
890 if (ret
!= PM3_SUCCESS
) {
893 files
[i
].filename
= path
;
896 PrintAndLogEx(SUCCESS
, "About to use the following file%s:", num_files
> 1 ? "s" : "");
897 for (int i
= 0 ; i
< num_files
; ++i
) {
898 PrintAndLogEx(SUCCESS
, " "_YELLOW_("%s"), files
[i
].filename
);
901 for (int i
= 0 ; i
< num_files
; ++i
) {
902 ret
= flash_load(&files
[i
], force
);
903 if (ret
!= PM3_SUCCESS
) {
906 PrintAndLogEx(NORMAL
, "");
909 if (OpenProxmark(&g_session
.current_device
, serial_port_name
, true, 60, true, FLASHMODE_SPEED
)) {
910 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
913 PrintAndLogEx(ERR
, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name
);
918 uint32_t max_allowed
= 0;
919 ret
= flash_start_flashing(can_write_bl
, serial_port_name
, &max_allowed
);
920 if (ret
!= PM3_SUCCESS
) {
927 for (int i
= 0 ; i
< num_files
; ++i
) {
928 ret
= flash_prepare(&files
[i
], can_write_bl
, max_allowed
* ONE_KB
);
929 if (ret
!= PM3_SUCCESS
) {
932 PrintAndLogEx(NORMAL
, "");
935 PrintAndLogEx(SUCCESS
, _CYAN_("Flashing..."));
937 for (int i
= 0; i
< num_files
; i
++) {
938 ret
= flash_write(&files
[i
]);
939 if (ret
!= PM3_SUCCESS
) {
942 PrintAndLogEx(NORMAL
, "");
946 if (ret
!= PM3_SUCCESS
)
947 PrintAndLogEx(WARNING
, "The flashing procedure failed, follow the suggested steps!");
948 ret
= flash_stop_flashing();
949 CloseProxmark(g_session
.current_device
);
951 for (int i
= 0 ; i
< num_files
; ++i
) {
952 flash_free(&files
[i
]);
954 if (ret
== PM3_SUCCESS
)
955 PrintAndLogEx(SUCCESS
, _CYAN_("All done"));
956 else if (ret
== PM3_EOPABORTED
)
957 PrintAndLogEx(FAILED
, "Aborted by user");
959 PrintAndLogEx(ERR
, "Aborted on error");
960 PrintAndLogEx(INFO
, "\nHave a nice day!");
964 static int reboot_bootloader_pm3(char *serial_port_name
) {
965 if (serial_port_name
== NULL
) {
966 PrintAndLogEx(ERR
, "You must specify a port.\n");
970 if (OpenProxmark(&g_session
.current_device
, serial_port_name
, true, 60, true, FLASHMODE_SPEED
) == false) {
971 PrintAndLogEx(ERR
, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name
);
975 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
976 return flash_reboot_bootloader(serial_port_name
, true);
981 void pm3_init(void) {
984 g_session
.pm3_present
= false;
985 g_session
.help_dump_mode
= false;
986 g_session
.incognito
= false;
987 g_session
.supports_colors
= false;
988 g_session
.emoji_mode
= EMO_ALTTEXT
;
989 g_session
.stdinOnTTY
= false;
990 g_session
.stdoutOnTTY
= false;
992 // set global variables soon enough to get the log path
993 set_my_executable_path();
994 set_my_user_directory();
999 int main(int argc
, char *argv
[]) {
1001 bool waitCOMPort
= false;
1002 bool addScriptExec
= false;
1003 bool stayInCommandLoop
= false;
1004 char *script_cmds_file
= NULL
;
1005 char *script_cmd
= NULL
;
1011 char exec_name
[100] = {0};
1012 strncpy(exec_name
, basename(argv
[0]), sizeof(exec_name
) - 1);
1014 bool flash_mode
= false;
1015 bool reboot_bootloader_mode
= false;
1016 bool flash_can_write_bl
= false;
1017 bool flash_force
= false;
1018 bool debug_mode_forced
= false;
1019 int flash_num_files
= 0;
1020 const char *flash_filenames
[FLASH_MAX_FILES
];
1021 bool dumpmem_mode
= false;
1022 const char *dumpmem_filename
= NULL
;
1023 uint32_t dumpmem_addr
= 0;
1024 uint32_t dumpmem_len
= 512 * 1024;
1025 bool dumpmem_raw
= false;
1027 // color management:
1028 // 1. default = no color
1029 // 2. enable colors if OS seems to support colors and if stdin/stdout aren't redirected
1030 // 3. load prefs if available, overwrite colors choice if needed
1031 // 4. disable colors anyway if stdin/stdout are redirected
1033 // For info, grep --color=auto is doing sth like this, plus test getenv("TERM") != "dumb":
1034 // struct stat tmp_stat;
1035 // if ((fstat (STDOUT_FILENO, &tmp_stat) == 0) && (S_ISCHR (tmp_stat.st_mode)) && isatty(STDIN_FILENO))
1036 g_session
.stdinOnTTY
= isatty(STDIN_FILENO
);
1037 g_session
.stdoutOnTTY
= isatty(STDOUT_FILENO
);
1038 g_session
.supports_colors
= false;
1039 g_session
.emoji_mode
= EMO_ALTTEXT
;
1040 if (g_session
.stdinOnTTY
&& g_session
.stdoutOnTTY
) {
1041 #if defined(__linux__) || defined(__APPLE__)
1042 g_session
.supports_colors
= true;
1043 g_session
.emoji_mode
= EMO_EMOJI
;
1044 #elif defined(_WIN32)
1045 g_session
.supports_colors
= DetectWindowsAnsiSupport();
1046 g_session
.emoji_mode
= EMO_ALTTEXT
;
1049 for (int i
= 1; i
< argc
; i
++) {
1051 if (argv
[i
][0] != '-') {
1052 // For backward compatibility we accept direct port
1054 // We got already one
1055 PrintAndLogEx(ERR
, _RED_("ERROR:") " cannot parse command line. We got " _YELLOW_("%s") " as port and now we got also: " _YELLOW_("%s") "\n", port
, argv
[i
]);
1056 show_help(false, exec_name
);
1064 if (strcmp(argv
[i
], "-p") == 0 || strcmp(argv
[i
], "--port") == 0) {
1065 if (i
+ 1 == argc
) {
1066 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing port specification after -p\n");
1067 show_help(false, exec_name
);
1071 // We got already one
1072 PrintAndLogEx(ERR
, _RED_("ERROR:") " cannot parse command line. We got " _YELLOW_("%s") " as port and now we got also: " _YELLOW_("%s") "\n", port
, argv
[i
+ 1]);
1073 show_help(false, exec_name
);
1081 if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
1082 g_printAndLog
= PRINTANDLOG_PRINT
;
1083 show_help(true, exec_name
);
1088 if (strcmp(argv
[i
], "-t") == 0 || strcmp(argv
[i
], "--text") == 0) {
1089 g_printAndLog
= PRINTANDLOG_PRINT
;
1090 show_help(false, exec_name
);
1091 dumpAllHelp(0, false);
1096 if (strcmp(argv
[i
], "--fulltext") == 0) {
1097 g_printAndLog
= PRINTANDLOG_PRINT
;
1098 show_help(false, exec_name
);
1099 dumpAllHelp(0, true);
1104 if (strcmp(argv
[i
], "-m") == 0 || strcmp(argv
[i
], "--markdown") == 0) {
1105 g_printAndLog
= PRINTANDLOG_PRINT
;
1106 dumpAllHelp(1, false);
1109 // print client version
1110 if (strcmp(argv
[i
], "-v") == 0 || strcmp(argv
[i
], "--version") == 0) {
1111 pm3_version(true, true);
1116 if (strcmp(argv
[i
], "-d") == 0 || strcmp(argv
[i
], "--debug") == 0) {
1117 if (i
+ 1 == argc
) {
1118 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing debugmode specification after -d\n");
1119 show_help(false, exec_name
);
1122 int demod
= atoi(argv
[i
+ 1]);
1123 if (demod
< 0 || demod
> 2) {
1124 PrintAndLogEx(ERR
, _RED_("ERROR:") " invalid debugmode: -d " _YELLOW_("%s") "\n", argv
[i
+ 1]);
1127 g_debugMode
= demod
;
1128 debug_mode_forced
= true;
1134 if (strcmp(argv
[i
], "-f") == 0 || strcmp(argv
[i
], "--flush") == 0) {
1135 SetFlushAfterWrite(true);
1136 PrintAndLogEx(INFO
, "Output will be flushed after every print.\n");
1141 if (strcmp(argv
[i
], "-b") == 0 || strcmp(argv
[i
], "--baud") == 0) {
1142 if (i
+ 1 == argc
) {
1143 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing baud specification after -b\n");
1144 show_help(false, exec_name
);
1147 uint64_t tmpspeed
= strtoul(argv
[i
+ 1], NULL
, 10);
1148 if ((tmpspeed
== ULONG_MAX
) || (tmpspeed
== 0)) {
1149 PrintAndLogEx(ERR
, _RED_("ERROR:") " invalid baudrate: -b " _YELLOW_("%s") "\n", argv
[i
+ 1]);
1158 if (strcmp(argv
[i
], "-w") == 0 || strcmp(argv
[i
], "--wait") == 0) {
1163 // execute pm3 command
1164 if (strcmp(argv
[i
], "-c") == 0 || strcmp(argv
[i
], "--command") == 0) {
1165 if (i
+ 1 == argc
) {
1166 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing command specification after -c\n");
1167 show_help(false, exec_name
);
1170 script_cmd
= argv
[++i
];
1174 // execute pm3 command file
1175 if (strcmp(argv
[i
], "-s") == 0 || strcmp(argv
[i
], "--script-file") == 0) {
1176 if (i
+ 1 == argc
|| strlen(argv
[i
+ 1]) == 0) {
1177 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing script file specification after -s\n");
1178 show_help(false, exec_name
);
1181 script_cmds_file
= argv
[++i
];
1185 // execute Lua script
1186 if (strcmp(argv
[i
], "-l") == 0 || strcmp(argv
[i
], "--lua") == 0) {
1187 if (i
+ 1 == argc
|| strlen(argv
[i
+ 1]) == 0) {
1188 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing Lua script specification after --lua\n");
1189 show_help(false, exec_name
);
1192 script_cmd
= argv
[++i
];
1193 if (script_cmd
== NULL
|| strlen(script_cmd
) == 0) {
1196 addScriptExec
= true;
1200 // execute Python script
1201 if (strcmp(argv
[i
], "-y") == 0 || strcmp(argv
[i
], "--py") == 0) {
1202 if (i
+ 1 == argc
|| strlen(argv
[i
+ 1]) == 0) {
1203 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing Python script specification after --py\n");
1204 show_help(false, exec_name
);
1207 script_cmd
= argv
[++i
];
1208 if (script_cmd
== NULL
|| strlen(script_cmd
) == 0) {
1211 addScriptExec
= true;
1214 #endif // HAVE_PYTHON
1215 // go to interactive instead of quitting after a script/command
1216 if (strcmp(argv
[i
], "-i") == 0 || strcmp(argv
[i
], "--interactive") == 0) {
1217 stayInCommandLoop
= true;
1221 // do not use history nor log files
1222 if (strcmp(argv
[i
], "--incognito") == 0) {
1223 g_session
.incognito
= true;
1228 if (strcmp(argv
[i
], "--dumpmem") == 0) {
1229 dumpmem_mode
= true;
1230 if (i
+ 1 == argc
) {
1231 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing file specification after --dumpmem\n");
1232 show_help(false, exec_name
);
1235 dumpmem_filename
= argv
[++i
];
1238 if (strcmp(argv
[i
], "--dumpaddr") == 0) {
1239 if (i
+ 1 == argc
) {
1240 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing address specification after -dumpaddr\n");
1241 show_help(false, exec_name
);
1244 uint32_t tmpaddr
= strtoul(argv
[i
+ 1], NULL
, 0);
1245 dumpmem_addr
= tmpaddr
;
1249 if (strcmp(argv
[i
], "--dumplen") == 0) {
1250 if (i
+ 1 == argc
) {
1251 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing address specification after -dumplen\n");
1252 show_help(false, exec_name
);
1255 uint32_t tmplen
= strtoul(argv
[i
+ 1], NULL
, 0);
1256 dumpmem_len
= tmplen
;
1260 if (strcmp(argv
[i
], "--dumpraw") == 0) {
1266 if (strcmp(argv
[i
], "--flash") == 0) {
1272 if (strcmp(argv
[i
], "--reboot-to-bootloader") == 0) {
1273 reboot_bootloader_mode
= true;
1277 // unlock bootloader area
1278 if (strcmp(argv
[i
], "--unlock-bootloader") == 0) {
1279 flash_can_write_bl
= true;
1283 // force flash even if firmware seems to not match client version
1284 if (strcmp(argv
[i
], "--force") == 0) {
1290 if (strcmp(argv
[i
], "--image") == 0) {
1291 if (flash_num_files
== FLASH_MAX_FILES
) {
1292 PrintAndLogEx(ERR
, _RED_("ERROR:") " too many --image, please use it max %i times\n", FLASH_MAX_FILES
);
1295 if (i
+ 1 == argc
) {
1296 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing image specification after --image\n");
1297 show_help(false, exec_name
);
1300 flash_filenames
[flash_num_files
++] = argv
[++i
];
1304 if (strcmp(argv
[i
], "--ncpu") == 0) {
1305 if (i
+ 1 == argc
) {
1306 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing CPU number specification after --ncpu\n");
1307 show_help(false, exec_name
);
1310 long int ncpus
= strtol(argv
[i
+ 1], NULL
, 10);
1311 const int detected_cpus
= detect_num_CPUs();
1312 if (ncpus
< 0 || ncpus
>= detected_cpus
) {
1313 PrintAndLogEx(ERR
, _RED_("ERROR:") " invalid number of CPU cores: --ncpu " _YELLOW_("%s") " (available: %d)\n", argv
[i
+ 1], detected_cpus
);
1321 // We got an unknown parameter
1322 PrintAndLogEx(ERR
, _RED_("ERROR:") " invalid parameter: " _YELLOW_("%s") "\n", argv
[i
]);
1323 show_help(false, exec_name
);
1327 // Load Settings and assign
1328 // This will allow the command line to override the settings.json values
1330 // quick patch for debug level
1331 if (! debug_mode_forced
)
1332 g_debugMode
= g_session
.client_debug_level
;
1333 // settings_save ();
1336 // even if prefs, we disable colors if stdin or stdout is not a TTY
1337 if ((! g_session
.stdinOnTTY
) || (! g_session
.stdoutOnTTY
)) {
1338 g_session
.supports_colors
= false;
1339 g_session
.emoji_mode
= EMO_ALTTEXT
;
1342 // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway
1344 speed
= USART_BAUD_RATE
;
1347 dumpmem_pm3(port
, dumpmem_filename
, dumpmem_addr
, dumpmem_len
, dumpmem_raw
);
1352 flash_pm3(port
, flash_num_files
, flash_filenames
, flash_can_write_bl
, flash_force
);
1356 if (reboot_bootloader_mode
) {
1357 reboot_bootloader_pm3(port
);
1362 while (script_cmd
[strlen(script_cmd
) - 1] == ' ')
1363 script_cmd
[strlen(script_cmd
) - 1] = 0x00;
1365 if (strlen(script_cmd
) == 0) {
1367 PrintAndLogEx(ERR
, _RED_("ERROR:") " execute command: " _YELLOW_("command not found") ".\n");
1370 if (addScriptExec
) {
1371 // add "script run " to command
1372 int len
= strlen(script_cmd
) + 11 + 1;
1373 char *ctmp
= (char *) calloc(len
, sizeof(uint8_t));
1375 memset(ctmp
, 0, len
);
1376 strcpy(ctmp
, "script run ");
1377 strcpy(&ctmp
[11], script_cmd
);
1382 PrintAndLogEx(SUCCESS
, "execute command from commandline: " _YELLOW_("%s") "\n", script_cmd
);
1386 // try to open USB connection to Proxmark
1388 OpenProxmark(&g_session
.current_device
, port
, waitCOMPort
, 20, false, speed
);
1391 if (g_session
.pm3_present
&& (TestProxmark(g_session
.current_device
) != PM3_SUCCESS
)) {
1392 PrintAndLogEx(ERR
, _RED_("ERROR:") " cannot communicate with the Proxmark3\n");
1393 CloseProxmark(g_session
.current_device
);
1396 if ((port
!= NULL
) && (!g_session
.pm3_present
)) {
1400 if (!g_session
.pm3_present
) {
1401 PrintAndLogEx(INFO
, _YELLOW_("OFFLINE") " mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name
);
1404 // ascii art only in interactive client
1405 if (!script_cmds_file
&& !script_cmd
&& g_session
.stdinOnTTY
&& g_session
.stdoutOnTTY
&& !dumpmem_mode
&& !flash_mode
&& !reboot_bootloader_mode
) {
1409 // Save settings if not loaded from settings json file.
1410 // Doing this here will ensure other checks and updates are saved to over rule default
1411 // e.g. Linux color use check
1412 if ((!g_session
.preferences_loaded
) && (!g_session
.incognito
)) {
1413 PrintAndLogEx(INFO
, "Creating initial preferences file"); // json save reports file name, so just info msg here
1414 preferences_save(); // Save defaults
1415 g_session
.preferences_loaded
= true;
1417 // Set device debug level
1418 PrintAndLogEx(INFO,"setting device debug loglevel");
1419 if (g_session.pm3_present) {
1420 SendCommandNG(CMD_SET_DBGMODE, &g_session.device_debug_level, 1);
1421 PacketResponseNG resp;
1422 if (WaitForResponseTimeout(CMD_SET_DBGMODE, &resp, 2000) == false)
1423 PrintAndLogEx (INFO,"failed to set device debug loglevel");
1426 PrintAndLogEx(WARNING,"Proxmark3 not ready to set debug level");
1432 # if defined(_WIN32)
1433 InitGraphics(argc
, argv
, script_cmds_file
, script_cmd
, stayInCommandLoop
);
1436 // for *nix distro's, check environment variable to verify a display
1437 const char *display
= getenv("DISPLAY");
1438 if (display
&& strlen(display
) > 1) {
1439 InitGraphics(argc
, argv
, script_cmds_file
, script_cmd
, stayInCommandLoop
);
1442 main_loop(script_cmds_file
, script_cmd
, stayInCommandLoop
);
1447 main_loop(script_cmds_file
, script_cmd
, stayInCommandLoop
);
1450 // Clean up the port
1451 if (g_session
.pm3_present
) {
1452 CloseProxmark(g_session
.current_device
);
1455 // Plot/Overlay moved or resized
1456 if (g_session
.window_changed
) {