Add dry run option to check if script is correct
[mfgtools.git] / libuuu / cmd.cpp
blob2f0e0ea60806f5e09a53616a6e4b316981a8dd26
1 /*
2 * Copyright 2018 NXP.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
32 #include <memory>
33 #include <string.h>
34 #include "cmd.h"
35 #include "libcomm.h"
36 #include "libuuu.h"
37 #include "config.h"
38 #include "trans.h"
39 #include "sdps.h"
40 #include <atomic>
41 #include "buffer.h"
42 #include "sdp.h"
43 #include "fastboot.h"
44 #include <sys/stat.h>
45 #include <thread>
47 #include <stdio.h>
48 #include <stdlib.h>
50 static CmdMap g_cmd_map;
51 static CmdObjCreateMap g_cmd_create_map;
52 static string g_cmd_list_file;
54 int parser_cmd_list_file(shared_ptr<FileBuffer> pbuff, CmdMap *pCmdMap = NULL);
56 template <class T>
57 void * create_object() { return new T; }
59 typedef void * (*FN)();
61 FN g_fn = create_object<int>;
64 int CmdBase::parser(char *p)
66 if (p != NULL)
67 m_cmd = p;
69 size_t pos = 0;
70 string param = get_next_param(m_cmd, pos);
72 if (param.find(':') != string::npos)
73 param = get_next_param(m_cmd, pos);
75 while (pos < m_cmd.size())
77 param = get_next_param(m_cmd, pos);
79 struct Param *pp = NULL;
80 for (size_t i = 0; i < m_param.size(); i++)
82 string key = string(m_param[i].key);
83 if (compare_str(param, key, m_param[i].ignore_case))
85 pp = &(m_param[i]);
86 break;
90 if (pp == NULL)
92 string err;
93 err = "unknown Option";
94 err += param;
95 set_last_err_string(err);
96 return -1;
99 if (pp->type == Param::e_uint32)
101 param = get_next_param(m_cmd, pos);
102 *(uint32_t*)pp->pData = str_to_uint(param);
105 if (pp->type == Param::e_string_filename)
107 param = get_next_param(m_cmd, pos);
108 *(string*)pp->pData = param;
110 if (!check_file_exist(param))
111 return -1;
114 if (pp->type == Param::e_string)
116 param = get_next_param(m_cmd, pos);
117 *(string*)pp->pData = param;
120 if (pp->type == Param::e_bool)
122 *(bool*)pp->pData = true;
125 if (pp->type == Param::e_null)
129 return 0;
132 int CmdBase::dump()
134 uuu_notify nt;
135 nt.type = uuu_notify::NOTIFY_CMD_INFO;
137 string str = m_cmd;
138 str += "\n";
139 nt.str = (char*)str.c_str();
140 call_notify(nt);
142 return 0;
145 int CmdList::run_all(CmdCtx *p, bool dry)
147 CmdList::iterator it;
148 int ret;
150 uuu_notify nt;
151 nt.type = uuu_notify::NOTIFY_CMD_TOTAL;
152 nt.total = size();
153 call_notify(nt);
155 int i = 0;
157 for (it = begin(); it != end(); it++, i++)
159 uuu_notify nt;
161 nt.type = uuu_notify::NOTIFY_CMD_INDEX;
162 nt.index = i;
163 call_notify(nt);
165 nt.type = uuu_notify::NOTIFY_CMD_START;
166 nt.str = (char *)(*it)->m_cmd.c_str();
167 call_notify(nt);
169 if (dry)
170 ret = (*it)->dump();
171 else
172 ret = (*it)->run(p);
174 nt.type = uuu_notify::NOTIFY_CMD_END;
175 nt.status = ret;
176 call_notify(nt);
177 if (ret)
178 return ret;
180 if ((*it)->m_lastcmd)
181 break;
183 return ret;
186 string get_next_param(string &cmd, size_t &pos, char sperate)
188 string str;
189 if (pos == string::npos)
190 return str;
191 if (pos >= cmd.size())
192 return str;
194 //trim left space
195 while (cmd[pos] == sperate && pos < cmd.size())
196 pos++;
198 bool quate = false;
199 size_t end = string::npos;
201 for (size_t s = pos; s < cmd.size(); s++)
203 if (cmd[s] == '"')
204 quate = !quate;
206 if (!quate && cmd[s] == sperate)
208 end = s;
209 break;
213 if (end == cmd.npos)
214 end = cmd.size();
216 str = cmd.substr(pos, end - pos);
217 pos = end + 1;
219 return str;
222 string remove_square_brackets(string &cmd)
224 size_t sz=cmd.find('[');
225 return cmd.substr(0, sz);
228 int get_string_in_square_brackets(string &cmd, string &context)
230 size_t start = cmd.find('[');
231 if (start == string::npos)
233 context.clear();
234 return 0;
237 size_t end = cmd.find(']', start);
238 if (end == string::npos)
240 set_last_err_string("missed ]");
241 return -1;
244 context = cmd.substr(start + 1, end - start - 1);
245 return 0;
248 uint32_t str_to_uint(string &str)
250 if (str.size() > 2)
252 if (str.substr(0, 2).compare("0x") == 0)
253 return strtoul(str.substr(2).c_str(), NULL, 16);
255 return strtoul(str.c_str(), NULL, 10);
258 template <class T> shared_ptr<CmdBase> new_cmd_obj(char *p)
260 return shared_ptr<CmdBase>(new T(p));
263 CmdObjCreateMap::CmdObjCreateMap()
265 (*this)["CFG:"] = new_cmd_obj<CfgCmd>;
267 (*this)["SDPS:BOOT"] = new_cmd_obj<SDPSCmd>;
269 (*this)["SDP:DCD"] = new_cmd_obj<SDPDcdCmd>;
270 (*this)["SDP:JUMP"] = new_cmd_obj<SDPJumpCmd>;
271 (*this)["SDP:RDMEM"] = new_cmd_obj<SDPReadMemCmd>;
272 (*this)["SDP:WRMEM"] = new_cmd_obj<SDPWriteMemCmd>;
273 (*this)["SDP:WRITE"] = new_cmd_obj<SDPWriteCmd>;
274 (*this)["SDP:STATUS"] = new_cmd_obj<SDPStatusCmd>;
275 (*this)["SDP:BOOT"] = new_cmd_obj<SDPBootCmd>;
276 (*this)["SDP:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
278 (*this)["SDPU:JUMP"] = new_cmd_obj<SDPJumpCmd>;
279 (*this)["SDPU:WRITE"] = new_cmd_obj<SDPWriteCmd>;
280 (*this)["SDPU:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
282 (*this)["SDPV:JUMP"] = new_cmd_obj<SDPJumpCmd>;
283 (*this)["SDPV:WRITE"] = new_cmd_obj<SDPWriteCmd>;
284 (*this)["SDPV:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
286 (*this)["FB:GETVAR"] = new_cmd_obj<FBGetVar>;
287 (*this)["FASTBOOT:GETVAR"] = new_cmd_obj<FBGetVar>;
288 (*this)["FB:UCMD"] = new_cmd_obj<FBUCmd>;
289 (*this)["FASTBOOT:UCMD"] = new_cmd_obj<FBUCmd>;
290 (*this)["FB:ACMD"] = new_cmd_obj<FBACmd>;
291 (*this)["FASTBOOT:ACMD"] = new_cmd_obj<FBACmd>;
292 (*this)["FB:DOWNLOAD"] = new_cmd_obj<FBDownload>;
293 (*this)["FASTBOOT:DOWNLOAD"] = new_cmd_obj<FBDownload>;
294 (*this)["FB:FLASH"] = new_cmd_obj<FBFlashCmd>;
295 (*this)["FASTBOOT:FLASH"] = new_cmd_obj<FBFlashCmd>;
296 (*this)["FB:ERASE"] = new_cmd_obj<FBEraseCmd>;
297 (*this)["FASTBOOT:ERASE"] = new_cmd_obj<FBEraseCmd>;
298 (*this)["FB:OEM"] = new_cmd_obj<FBOemCmd>;
299 (*this)["FASTBOOT:OEM"] = new_cmd_obj<FBOemCmd>;
300 (*this)["FB:FLASHING"] = new_cmd_obj<FBFlashingCmd>;
301 (*this)["FASTBOOT:FLASHING"] = new_cmd_obj<FBFlashingCmd>;
302 (*this)["FB:SET_ACTIVE"] = new_cmd_obj<FBSetActiveCmd>;
303 (*this)["FASTBOOT:SET_ACTIVE"] = new_cmd_obj<FBSetActiveCmd>;
305 (*this)["FBK:UCMD"] = new_cmd_obj<FBUCmd>;
306 (*this)["FBK:ACMD"] = new_cmd_obj<FBACmd>;
307 (*this)["FBK:SYNC"] = new_cmd_obj<FBSyncCmd>;
308 (*this)["FBK:UCP"] = new_cmd_obj<FBCopy>;
310 (*this)["_ALL:DONE"] = new_cmd_obj<CmdDone>;
311 (*this)["_ALL:DELAY"] = new_cmd_obj<CmdDelay>;
312 (*this)["_ALL:SH"] = new_cmd_obj<CmdShell>;
313 (*this)["_ALL:SHELL"] = new_cmd_obj<CmdShell>;
314 (*this)["_ALL:<"] = new_cmd_obj<CmdShell>;
318 shared_ptr<CmdBase> create_cmd_obj(string cmd)
320 string param;
321 size_t pos = 0;
322 param = get_next_param(cmd, pos, ':');
323 param = remove_square_brackets(param);
324 param += ":";
325 param = str_to_upper(param);
327 if (g_cmd_create_map.find(param) == g_cmd_create_map.end())
329 string s = param;
330 param = get_next_param(cmd, pos);
331 s += str_to_upper(param);
332 if (g_cmd_create_map.find(s) != g_cmd_create_map.end())
333 return g_cmd_create_map[s]((char*)cmd.c_str());
335 string commoncmd = "_ALL:";
336 commoncmd += str_to_upper(param);
337 if (g_cmd_create_map.find(commoncmd) != g_cmd_create_map.end())
338 return g_cmd_create_map[commoncmd]((char*)cmd.c_str());
340 else
342 return g_cmd_create_map[param]((char*)cmd.c_str());
345 string err;
346 err = "Unknown Command:";
347 err += cmd;
348 set_last_err_string(err);
349 return NULL;
352 int uuu_run_cmd(const char * cmd, int dry)
354 shared_ptr<CmdBase> p;
355 p = create_cmd_obj(cmd);
356 int ret;
358 if (p == NULL)
359 return -1;
361 uuu_notify nt;
362 nt.type = uuu_notify::NOTIFY_CMD_TOTAL;
363 nt.total = 1;
364 call_notify(nt);
366 nt.type = uuu_notify::NOTIFY_CMD_START;
367 nt.str = (char *)p->m_cmd.c_str();
368 call_notify(nt);
370 if (typeid(*p) != typeid(CfgCmd))
372 size_t pos = 0;
373 string c = cmd;
375 string pro = get_next_param(c, pos, ':');
376 pro = remove_square_brackets(pro);
377 pro += ":";
379 if (p->parser())
380 ret = -1;
381 else
383 if (dry)
385 ret = p->dump();
386 }else
388 CmdUsbCtx ctx;
389 ret = ctx.look_for_match_device(pro.c_str());
390 if (ret)
391 return ret;
393 ret = p->run(&ctx);
397 else
399 return ret = dry? p->dump() : p->run(NULL);
402 nt.type = uuu_notify::NOTIFY_CMD_END;
403 nt.status = ret;
404 call_notify(nt);
406 return ret;
409 int CmdDone::run(CmdCtx *)
411 uuu_notify nt;
412 nt.type = uuu_notify::NOTIFY_DONE;
413 call_notify(nt);
414 return 0;
417 int CmdDelay::parser(char * /*p*/)
419 size_t pos = 0;
420 string param = get_next_param(m_cmd, pos);
422 if (param.find(':') != string::npos)
423 param = get_next_param(m_cmd, pos);
425 if (str_to_upper(param) != "DELAY")
427 string err = "Unknown Commnd:";
428 err += param;
429 set_last_err_string(err);
430 return -1;
433 string ms = get_next_param(m_cmd, pos);
434 m_ms = str_to_uint(ms);
435 return 0;
438 int CmdDelay::run(CmdCtx *)
440 std::this_thread::sleep_for(std::chrono::milliseconds(m_ms));
441 return 0;
444 int CmdShell::parser(char * p)
446 if (p)
447 m_cmd = p;
449 size_t pos = 0;
450 string s;
452 if (parser_protocal(p, pos))
453 return -1;
455 m_protocal = m_cmd.substr(0, pos);
457 s = get_next_param(m_cmd, pos);
459 m_dyn = (s == "<");
461 if (pos != string::npos && pos < m_cmd.size())
462 m_shellcmd = m_cmd.substr(pos);
464 return 0;
467 int CmdShell::run(CmdCtx*)
469 #ifndef WIN32
470 #define _popen popen
471 #define _pclose pclose
472 #endif
473 FILE *pipe = _popen(m_shellcmd.c_str(), "r");
475 if (pipe == NULL)
477 string err = "failure popen: ";
478 err += m_shellcmd.c_str();
479 set_last_err_string(err);
480 return -1;
483 string str;
484 str.resize(256);
485 while (fgets((char*)str.c_str(), str.size(), pipe))
487 if (m_dyn)
489 string cmd;
490 cmd = m_protocal;
491 str.resize(strlen(str.c_str()));
492 cmd += ' ';
493 cmd += str;
495 size_t pos = cmd.find_first_of("\r\n");
496 if (pos != string::npos)
497 cmd = cmd.substr(0, pos);
499 return uuu_run_cmd(cmd.c_str(), 0);
501 uuu_notify nt;
502 nt.type = uuu_notify::NOTIFY_CMD_INFO;
503 nt.str = (char*)str.c_str();
504 call_notify(nt);
507 /* Close pipe and print return value of pPipe. */
508 if (feof(pipe))
510 int ret = _pclose(pipe);
511 string_ex str;
512 str.format("\nProcess returned %d\n", ret);;
513 if (ret)
515 set_last_err_string(str.c_str());
516 return ret;
519 else
521 set_last_err_string("Error: Failed to read the pipe to the end.\n");
522 return -1;
525 return 0;
528 int run_cmds(const char *procotal, CmdCtx *p)
530 CmdMap cmdmap, *pCmdMap;
532 if (!g_cmd_list_file.empty())
534 shared_ptr<FileBuffer> pbuff = get_file_buffer(g_cmd_list_file);
535 if (pbuff == NULL)
536 return -1;
537 if(parser_cmd_list_file(pbuff, &cmdmap))
538 return -1;
539 pCmdMap = &cmdmap;
541 else
543 pCmdMap = &g_cmd_map;
546 if (pCmdMap->find(procotal) == pCmdMap->end())
548 return 0;
551 return (*pCmdMap)[procotal]->run_all(p);
554 static int insert_one_cmd(const char * cmd, CmdMap *pCmdMap)
556 string s = cmd;
557 size_t pos = 0;
559 string pro = get_next_param(s, pos, ':');
560 pro = remove_square_brackets(pro);
561 pro += ":";
563 pro = str_to_upper(pro);
565 shared_ptr<CmdBase> p = create_cmd_obj(s);
566 if (p == NULL)
567 return -1;
569 if (p->parser())
570 return -1;
572 if (pCmdMap->find(pro) == pCmdMap->end())
574 shared_ptr<CmdList> list(new CmdList);
575 (*pCmdMap)[pro] = list;
578 (*pCmdMap)[pro]->push_back(p);
580 return 0;
584 static int added_default_boot_cmd(const char *filename)
586 string str;
588 str = "SDPS: boot -f ";
589 str += "\"";
590 str += filename;
591 str += "\"";
593 int ret = insert_one_cmd(str.c_str(), &g_cmd_map);
594 if (ret) return ret;
596 insert_one_cmd("SDPS: done", &g_cmd_map);
598 str = "SDP: boot -f ";
599 str += "\"";
600 str += filename;
601 str += "\"";
603 ret = insert_one_cmd(str.c_str(), &g_cmd_map);
604 if (ret) return ret;
606 insert_one_cmd("SDP: done", &g_cmd_map);
608 str = "SDPU: write -f ";
609 str += "\"";
610 str += filename;
611 str += "\"";
612 str += " -offset 0x57c00";
613 insert_one_cmd(str.c_str(), &g_cmd_map);
614 insert_one_cmd("SDPU: jump", &g_cmd_map);
615 insert_one_cmd("SDPU: done", &g_cmd_map);
617 str = "SDPV: write -f ";
618 str += "\"";
619 str += filename;
620 str += "\"";
621 str += " -skipspl";
622 insert_one_cmd(str.c_str(), &g_cmd_map);
623 insert_one_cmd("SDPV: jump", &g_cmd_map);
624 insert_one_cmd("SDPV: done", &g_cmd_map);
626 return 0;
629 int check_version(string str)
631 int x = 0;
632 int ver = 0;
633 for (size_t i = 0; i < str.size(); i++)
635 char c = str[i];
636 if (c >= '0' && c <= '9')
638 x *= 10;
639 x += c - '0';
641 if (c == '.' || i == str.size()-1 || c == '\n')
643 ver <<= 8;
644 ver += x;
645 x = 0;
649 int cur = uuu_get_version();
651 if (ver > cur)
653 string str;
654 str = "Current uuu version is too low, please download latest one";
655 set_last_err_string(str);
656 return -1;
658 return 0;
661 int uuu_run_cmd_script(const char * buff, int dry)
663 shared_ptr<FileBuffer> p(new FileBuffer);
664 p->m_data.resize(strlen(buff));
665 memcpy(p->m_data.data(), buff, strlen(buff));
666 return parser_cmd_list_file(p);
669 int parser_cmd_list_file(shared_ptr<FileBuffer> pbuff, CmdMap *pCmdMap)
671 char uuu_version[] = "uuu_version";
672 string str;
674 if (pCmdMap == NULL)
675 pCmdMap = &g_cmd_map;
677 pCmdMap->clear();
679 for (size_t i = 0; i < pbuff->size(); i++)
681 uint8_t c = pbuff->at(i);
682 if (c == '\r')
683 continue;
685 if(c != '\n')
686 str.push_back(c);
688 if (c == '\n' || c == 0 || i == pbuff->size() - 1)
690 if (str.substr(0, strlen(uuu_version)) == uuu_version)
692 if (check_version(str.substr(strlen(uuu_version), 10)))
694 return -1;
696 }else if (str.size() > 1)
698 if (str[0] != '#')
699 if (insert_one_cmd(str.c_str(), pCmdMap))
700 return -1;
702 str.clear();
705 return 0;
708 int uuu_auto_detect_file(const char *filename)
710 string_ex fn;
711 fn += remove_quota(filename);
712 fn.replace('\\', '/');
714 if (fn.empty())
715 fn += "./";
717 string oldfn =fn;
719 fn += "/uuu.auto";
720 shared_ptr<FileBuffer> buffer = get_file_buffer(fn);
721 if (buffer == NULL)
723 fn.clear();
724 fn += oldfn;
725 size_t pos = str_to_upper(fn).find("ZIP");
726 if(pos == string::npos || pos != fn.size() - 3)
728 pos = str_to_upper(fn).find("SDCARD");
729 if (pos == string::npos || pos != fn.size() - 6)
730 buffer = get_file_buffer(fn); //we don't try open a zip file here
733 if(buffer == NULL)
734 return -1;
737 string str= "uuu_version";
738 void *p1 = buffer->data();
739 void *p2 = (void*)str.data();
740 if (memcmp(p1, p2, str.size()) == 0)
742 size_t pos = fn.rfind('/');
743 if (pos != string::npos)
744 set_current_dir(fn.substr(0, pos + 1));
746 g_cmd_list_file = fn.substr(pos+1);
748 return parser_cmd_list_file(buffer);
751 //flash.bin or uboot.bin
752 return added_default_boot_cmd(fn.c_str());
755 int notify_done(uuu_notify nt, void *p)
757 if(nt.type == uuu_notify::NOTIFY_DONE)
758 *(std::atomic<int> *) p = 1;
759 if (nt.type == uuu_notify::NOTIFY_CMD_END && nt.status)
760 *(std::atomic<int> *) p = 1;
762 return 0;
764 int uuu_wait_uuu_finish(int deamon, int dry)
766 std::atomic<int> exit;
767 exit = 0;
769 if(dry) {
770 for(auto it=g_cmd_map.begin(); it != g_cmd_map.end(); it++)
772 for(auto cmd = it->second->begin(); cmd != it->second->end(); cmd++)
774 (*cmd)->dump();
777 return 0;
780 if (!deamon)
781 uuu_register_notify_callback(notify_done, &exit);
783 polling_usb(exit);
785 return 0;