]> git.zerfleddert.de Git - proxmark3-svn/blame - client/proxmark3.c
Merge remote-tracking branch 'upstream/master'
[proxmark3-svn] / client / proxmark3.c
CommitLineData
a553f267 1//-----------------------------------------------------------------------------
212ef3a0 2// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
a553f267 3// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
4//
5// This code is licensed to you under the terms of the GNU GPL, version 2 or,
6// at your option, any later version. See the LICENSE.txt file for the text of
7// the license.
8//-----------------------------------------------------------------------------
9// Main binary
10//-----------------------------------------------------------------------------
11
6658905f 12#include <stdio.h>
590f8ff9 13#include <stdlib.h>
6658905f 14#include <string.h>
7fe9b0b7 15#include <pthread.h>
8556b852 16#include <unistd.h>
6658905f 17#include <readline/readline.h>
18#include <readline/history.h>
9484ff3d 19
6658905f 20#include "proxmark3.h"
21#include "proxgui.h"
7fe9b0b7 22#include "cmdmain.h"
902cb3c0 23#include "uart.h"
902cb3c0 24#include "ui.h"
759c16b3 25#include "sleep.h"
57c69556 26#include "cmdparser.h"
8e074056 27#include "cmdhw.h"
4197a3f6 28#include "whereami.h"
29
902cb3c0 30
9492e0b0 31// a global mutex to prevent interlaced printing from different threads
32pthread_mutex_t print_lock;
33
902cb3c0 34static serial_port sp;
f0ba6342 35static UsbCommand txcmd;
c3385024 36volatile static bool txcmd_pending = false;
902cb3c0 37
38void SendCommand(UsbCommand *c) {
9484ff3d 39 #if 0
40 printf("Sending %d bytes\n", sizeof(UsbCommand));
41 #endif
42
43 if (offline) {
da9d456e 44 PrintAndLog("Sending bytes to proxmark failed - offline");
45 return;
46 }
07976a25
MHS
47 /**
48 The while-loop below causes hangups at times, when the pm3 unit is unresponsive
49 or disconnected. The main console thread is alive, but comm thread just spins here.
50 Not good.../holiman
51 **/
9484ff3d 52 while(txcmd_pending);
53 txcmd = *c;
54 txcmd_pending = true;
902cb3c0 55}
6658905f 56
902cb3c0 57struct receiver_arg {
9484ff3d 58 int run;
6658905f 59};
60
902cb3c0 61struct main_loop_arg {
9484ff3d 62 int usb_present;
63 char *script_cmds_file;
a60612db 64};
65
902cb3c0 66byte_t rx[0x1000000];
fe7bfa78 67byte_t* prx = rx;
902cb3c0 68
69static void *uart_receiver(void *targ) {
9484ff3d 70 struct receiver_arg *arg = (struct receiver_arg*)targ;
71 size_t rxlen;
72 size_t cmd_count;
73
74 while (arg->run) {
75 rxlen = sizeof(UsbCommand);
76 if (uart_receive(sp, prx, &rxlen)) {
77 prx += rxlen;
78 if (((prx-rx) % sizeof(UsbCommand)) != 0) {
79 continue;
80 }
81 cmd_count = (prx-rx) / sizeof(UsbCommand);
82
83 for (size_t i = 0; i < cmd_count; i++) {
84 UsbCommandReceived((UsbCommand*)(rx+(i*sizeof(UsbCommand))));
85 }
86 }
87 prx = rx;
88
89 if(txcmd_pending) {
90 if (!uart_send(sp, (byte_t*) &txcmd, sizeof(UsbCommand))) {
91 PrintAndLog("Sending bytes to proxmark failed");
92 }
93 txcmd_pending = false;
94 }
95 }
96
97 pthread_exit(NULL);
98 return NULL;
6658905f 99}
100
902cb3c0 101static void *main_loop(void *targ) {
9484ff3d 102 struct main_loop_arg *arg = (struct main_loop_arg*)targ;
103 struct receiver_arg rarg;
104 char *cmd = NULL;
105 pthread_t reader_thread;
902cb3c0 106
9484ff3d 107 if (arg->usb_present == 1) {
108 rarg.run = 1;
109 pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
8e074056 110 // cache Version information now:
111 CmdVersion(NULL);
9484ff3d 112 }
113
114 FILE *script_file = NULL;
115 char script_cmd_buf[256]; // iceman, needs lua script the same file_path_buffer as the rest
116
117 if (arg->script_cmds_file) {
118 script_file = fopen(arg->script_cmds_file, "r");
119 if (script_file) {
120 printf("using 'scripting' commands file %s\n", arg->script_cmds_file);
121 }
122 }
7fe9b0b7 123
8556b852 124 read_history(".history");
9484ff3d 125
126 while(1) {
127
128 // If there is a script file
129 if (script_file)
1f947c4b 130 {
9484ff3d 131 if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), script_file)) {
132 fclose(script_file);
133 script_file = NULL;
134 } else {
135 char *nl;
136 nl = strrchr(script_cmd_buf, '\r');
137 if (nl) *nl = '\0';
138
139 nl = strrchr(script_cmd_buf, '\n');
140 if (nl) *nl = '\0';
141
142 if ((cmd = (char*) malloc(strlen(script_cmd_buf) + 1)) != NULL) {
143 memset(cmd, 0, strlen(script_cmd_buf));
144 strcpy(cmd, script_cmd_buf);
145 printf("%s\n", cmd);
146 }
147 }
1f947c4b 148 }
149
9484ff3d 150 if (!script_file) {
9484ff3d 151 cmd = readline(PROXPROMPT);
9484ff3d 152 }
153
8556b852 154 if (cmd) {
9484ff3d 155
8556b852 156 while(cmd[strlen(cmd) - 1] == ' ')
9484ff3d 157 cmd[strlen(cmd) - 1] = 0x00;
8556b852
M
158
159 if (cmd[0] != 0x00) {
2487dfeb 160 int ret = CommandReceived(cmd);
161 add_history(cmd);
162 if (ret == 99) { // exit or quit
8556b852
M
163 break;
164 }
8556b852
M
165 }
166 free(cmd);
167 } else {
168 printf("\n");
169 break;
170 }
171 }
902cb3c0 172
51969283 173 write_history(".history");
902cb3c0 174
9484ff3d 175 if (arg->usb_present == 1) {
176 rarg.run = 0;
177 pthread_join(reader_thread, NULL);
178 }
179
180 if (script_file) {
181 fclose(script_file);
182 script_file = NULL;
183 }
184
185 ExitGraphics();
186 pthread_exit(NULL);
187 return NULL;
6658905f 188}
189
dec8e8bd 190static void dumpAllHelp(int markdown)
ae7aa73d 191{
dec8e8bd
PT
192 printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================");
193 printf("Some commands are available only if a Proxmark is actually connected.%s\n",markdown?" ":"");
6f5dd601 194 printf("Check column \"offline\" for their availability.\n");
ae7aa73d 195 printf("\n");
57c69556 196 command_t *cmds = getTopLevelCommandTable();
dec8e8bd 197 dumpCommandsRecursive(cmds, markdown);
ae7aa73d
PT
198}
199
4197a3f6 200static char *my_executable_path = NULL;
201static char *my_executable_directory = NULL;
202
203const char const *get_my_executable_path(void)
204{
205 return my_executable_path;
206}
207
208const char const *get_my_executable_directory(void)
209{
210 return my_executable_directory;
211}
212
213static void set_my_executable_path(void)
214{
215 int path_length = wai_getExecutablePath(NULL, 0, NULL);
216 if (path_length != -1) {
217 my_executable_path = (char*)malloc(path_length + 1);
218 int dirname_length = 0;
219 if (wai_getExecutablePath(my_executable_path, path_length, &dirname_length) != -1) {
220 my_executable_path[path_length] = '\0';
221 my_executable_directory = (char *)malloc(dirname_length + 2);
222 strncpy(my_executable_directory, my_executable_path, dirname_length+1);
223 }
224 }
225}
226
902cb3c0 227int main(int argc, char* argv[]) {
9492e0b0 228 srand(time(0));
125a98a1 229
9492e0b0 230 if (argc < 2) {
231 printf("syntax: %s <port>\n\n",argv[0]);
232 printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
dec8e8bd
PT
233 printf("help: %s -h\n\n", argv[0]);
234 printf("\tDump all interactive help at once\n");
235 printf("markdown: %s -m\n\n", argv[0]);
236 printf("\tDump all interactive help at once in markdown syntax\n");
9492e0b0 237 return 1;
238 }
dec8e8bd
PT
239 if (strcmp(argv[1], "-h") == 0) {
240 printf("syntax: %s <port>\n\n",argv[0]);
241 printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
242 dumpAllHelp(0);
243 return 0;
244 }
245 if (strcmp(argv[1], "-m") == 0) {
246 dumpAllHelp(1);
247 return 0;
248 }
4197a3f6 249
250 set_my_executable_path();
251
9492e0b0 252 // Make sure to initialize
253 struct main_loop_arg marg = {
254 .usb_present = 0,
255 .script_cmds_file = NULL
256 };
2487dfeb 257 pthread_t main_loop_threat;
1f947c4b 258
4890730a 259
9492e0b0 260 sp = uart_open(argv[1]);
261 if (sp == INVALID_SERIAL_PORT) {
262 printf("ERROR: invalid serial port\n");
263 marg.usb_present = 0;
264 offline = 1;
265 } else if (sp == CLAIMED_SERIAL_PORT) {
266 printf("ERROR: serial port is claimed by another process\n");
267 marg.usb_present = 0;
268 offline = 1;
269 } else {
270 marg.usb_present = 1;
271 offline = 0;
272 }
7fe9b0b7 273
9492e0b0 274 // If the user passed the filename of the 'script' to execute, get it
275 if (argc > 2 && argv[2]) {
ed77aabe 276 if (argv[2][0] == 'f' && //buzzy, if a word 'flush' passed, flush the output after every log entry.
277 argv[2][1] == 'l' &&
278 argv[2][2] == 'u' &&
279 argv[2][3] == 's' &&
280 argv[2][4] == 'h')
281 {
282 printf("Output will be flushed after every print.\n");
283 flushAfterWrite = 1;
284 }
285 else
9492e0b0 286 marg.script_cmds_file = argv[2];
287 }
ed77aabe 288
9492e0b0 289 // create a mutex to avoid interlacing print commands from our different threads
290 pthread_mutex_init(&print_lock, NULL);
7fe9b0b7 291
2487dfeb 292 pthread_create(&main_loop_threat, NULL, &main_loop, &marg);
9492e0b0 293 InitGraphics(argc, argv);
7fe9b0b7 294
9492e0b0 295 MainGraphics();
296
2487dfeb 297 pthread_join(main_loop_threat, NULL);
7fe9b0b7 298
9492e0b0 299 // Clean up the port
2487dfeb 300 if (offline == 0) {
301 uart_close(sp);
302 }
303
9492e0b0 304 // clean up mutex
305 pthread_mutex_destroy(&print_lock);
2487dfeb 306
307 exit(0);
6658905f 308}
Impressum, Datenschutz