deploy.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "deploy.hpp"
  14. #include "environment.hpp"
  15. #include "jptree.hpp"
  16. #include "jexcept.hpp"
  17. #include "jencrypt.hpp"
  18. #include "xslprocessor.hpp"
  19. #include "DeploymentEngine.hpp"
  20. #include "ThorDeploymentEngine.hpp"
  21. #include "EspDeploymentEngine.hpp"
  22. #include "dalideploymentengine.hpp"
  23. #include "RoxieDeploymentEngine.hpp"
  24. #include "configgenengine.hpp"
  25. #include "espconfiggenengine.hpp"
  26. #include "thorconfiggenengine.hpp"
  27. //---------------------------------------------------------------------------
  28. // CEnvironmentDeploymentEngine
  29. //---------------------------------------------------------------------------
  30. class CEnvironmentDeploymentEngine : public CInterface, implements IEnvDeploymentEngine
  31. {
  32. public:
  33. IMPLEMENT_IINTERFACE;
  34. //---------------------------------------------------------------------------
  35. // CEnvironmentDeploymentEngine
  36. //---------------------------------------------------------------------------
  37. CEnvironmentDeploymentEngine(IConstEnvironment &environment, IDeploymentCallback& callback,
  38. IPropertyTree* pSelectedComponents)
  39. : m_environment(environment),
  40. m_transform(NULL),
  41. m_abort(false),
  42. m_espModuleCount(0),
  43. m_tempFileCount(0),
  44. m_bLinuxDeployment(false),
  45. m_bInteractiveMode(true)
  46. {
  47. m_pCallback.set(&callback);
  48. m_validateAllXsl.clear().append("validateAll.xsl");
  49. if (pSelectedComponents)
  50. {
  51. initXML(pSelectedComponents);
  52. Owned<IPropertyTreeIterator> it = pSelectedComponents->getElements("*");
  53. ForEach(*it)
  54. {
  55. IPropertyTree* pComponent = &it->query();
  56. IDeploymentEngine* pEngine = addProcess(pComponent->queryName(), pComponent->queryProp("@name"));
  57. Owned<IPropertyTreeIterator> iter = pComponent->getElements("*");
  58. if (iter->first())
  59. {
  60. pEngine->resetInstances();
  61. ForEach(*iter)
  62. {
  63. IPropertyTree* pChild = &iter->query();
  64. const char* tagName = pChild->queryName();
  65. const char* instName = pChild->queryProp("@name");
  66. pEngine->addInstance(tagName, instName);
  67. //determine if this is linux deployment
  68. if (!m_bLinuxDeployment)
  69. {
  70. const char* computer = pChild->queryProp("@computer");
  71. IConstMachineInfo* pMachine = environment.getMachine(computer);
  72. if (pMachine->getOS() == MachineOsLinux)
  73. m_bLinuxDeployment = true;
  74. }
  75. }
  76. }
  77. else if (!m_bLinuxDeployment)//another previously added engine already does not have linux instance
  78. {
  79. //some components like thor and hole clusters don't show their instances in the
  80. //deployment wizard so detect if they have any linux instance.
  81. const IArrayOf<IPropertyTree>& instances = pEngine->getInstances();
  82. if (instances.ordinality() > 0)
  83. {
  84. Owned<IConstMachineInfo> machine = m_environment.getMachine(instances.item(0).queryProp("@computer"));
  85. if (machine && machine->getOS() == MachineOsLinux)
  86. m_bLinuxDeployment = true;
  87. }
  88. }
  89. }
  90. }
  91. #ifdef _WINDOWS
  92. EnumerateNetworkConnections();
  93. #endif
  94. }
  95. //---------------------------------------------------------------------------
  96. // ~CEnvironmentDeploymentEngine
  97. //---------------------------------------------------------------------------
  98. virtual ~CEnvironmentDeploymentEngine()
  99. {
  100. //delete all temporary files generated during deployemnt
  101. int count = m_tempFiles.length();
  102. int i;
  103. for (i = 0; i < count; i++)
  104. if (!DeleteFile(m_tempFiles.item(i)))
  105. WARNLOG("Couldn't delete file %s", m_tempFiles.item(i));
  106. count = m_tempDirs.length();
  107. for (i = 0; i < count; i++)
  108. deleteRecursive(m_tempDirs.item(i));
  109. m_processes.kill(); // must do this before destroying deplyCallback and deployLog
  110. m_pDeployLog.clear(); // this causes the log file to be written
  111. m_pCallback.clear();
  112. termXML();
  113. }
  114. void deleteRecursive(const char* path)
  115. {
  116. Owned<IFile> pDir = createIFile(path);
  117. if (pDir->exists())
  118. {
  119. if (pDir->isDirectory())
  120. {
  121. Owned<IDirectoryIterator> it = pDir->directoryFiles(NULL, false, true);
  122. ForEach(*it)
  123. {
  124. StringBuffer name;
  125. it->getName(name);
  126. StringBuffer childPath(path);
  127. childPath.append(PATHSEPCHAR);
  128. childPath.append(name);
  129. deleteRecursive(childPath.str());
  130. }
  131. }
  132. pDir->remove();
  133. }
  134. }
  135. //---------------------------------------------------------------------------
  136. // addProcess
  137. //---------------------------------------------------------------------------
  138. IDeploymentEngine* addProcess(const char* processType, const char* processName)
  139. {
  140. assertex(processType);
  141. assertex(processName);
  142. StringBuffer xpath;
  143. xpath.appendf("Software/%s[@name='%s']", processType, processName);
  144. Owned<IPropertyTree> tree = &m_environment.getPTree();
  145. IPropertyTree* pComponent = tree->queryPropTree(xpath.str());
  146. if (!pComponent)
  147. throw MakeStringException(0, "%s with name %s was not found!", processType, processName);
  148. IDeploymentEngine* deployEngine;
  149. if (strcmp(processType, "DaliServerProcess")==0)
  150. deployEngine = new CDaliDeploymentEngine(*this, *m_pCallback, *pComponent);
  151. else if (strcmp(processType, "ThorCluster")==0)
  152. deployEngine = new CThorDeploymentEngine(*this, *m_pCallback, *pComponent);
  153. else if (strcmp(processType, "RoxieCluster")==0)
  154. deployEngine = new CRoxieDeploymentEngine(*this, *m_pCallback, *pComponent);
  155. else if (strcmp(processType, "EspProcess")==0)
  156. deployEngine = new CEspDeploymentEngine(*this, *m_pCallback, *pComponent);
  157. else
  158. deployEngine = new CDeploymentEngine(*this, *m_pCallback, *pComponent, "Instance", true);
  159. assertex(deployEngine);
  160. deployEngine->setXsl(m_processor, m_transform);
  161. m_processes.append(*deployEngine); // array releases members when destroyed
  162. return deployEngine;
  163. }
  164. //---------------------------------------------------------------------------
  165. // setSshAccount
  166. //---------------------------------------------------------------------------
  167. void setSshAccount(const char* userid, const char* password)
  168. {
  169. m_sSshUserid = userid;
  170. m_sSshPassword = password;
  171. }
  172. //---------------------------------------------------------------------------
  173. // isLinuxDeployment
  174. //---------------------------------------------------------------------------
  175. bool isLinuxDeployment() const
  176. {
  177. return m_bLinuxDeployment;
  178. }
  179. //---------------------------------------------------------------------------
  180. // start
  181. //---------------------------------------------------------------------------
  182. void start()
  183. {
  184. ForEachItemIn(idx, m_processes)
  185. {
  186. m_processes.item(idx).start();
  187. }
  188. }
  189. //---------------------------------------------------------------------------
  190. // stop
  191. //---------------------------------------------------------------------------
  192. void stop()
  193. {
  194. ForEachItemInRev(idx, m_processes)
  195. {
  196. m_processes.item(idx).stop();
  197. }
  198. }
  199. //---------------------------------------------------------------------------
  200. // stripXsltMessage
  201. //---------------------------------------------------------------------------
  202. void stripXsltMessage(StringBuffer& msg)
  203. {
  204. //for better readability of msg, remove redundant prefix of "[XSLT warning: ", if present
  205. const char* pattern = "[ElemMessageTerminateException: ";
  206. const int len =sizeof("[ElemMessageTerminateException: ")-1;
  207. if (!strncmp(msg, pattern, len))
  208. msg.remove(0, len);
  209. //remove the excessive info about XSLT context when this was thrown
  210. const char* begin = msg.str();
  211. const char* end = strstr(begin, "(file:");
  212. if (end)
  213. msg.setLength(end-begin);
  214. }
  215. //---------------------------------------------------------------------------
  216. // check
  217. //---------------------------------------------------------------------------
  218. void check()
  219. {
  220. if (m_pCallback->getAbortStatus())
  221. throw MakeStringException(0, "User abort");
  222. bool valid = false;
  223. m_nValidationErrors = 0;
  224. StringBuffer outputXml;
  225. Owned<IXslFunction> externalFunction;
  226. externalFunction.setown(m_transform->createExternalFunction("validationMessage", validationMessageFromXSLT));
  227. m_transform->setExternalFunction(SEISINT_NAMESPACE, externalFunction.get(), true);
  228. m_transform->loadXslFromFile(m_validateAllXsl.str());
  229. m_transform->setUserData(this);
  230. try
  231. {
  232. m_transform->transform( outputXml );
  233. m_transform->closeResultTarget();
  234. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, m_transform->getMessages());
  235. if (!m_nValidationErrors)//this may get filled in by the external function
  236. valid = true;
  237. }
  238. catch (IException* e)
  239. {
  240. StringBuffer msg;
  241. e->errorMessage(msg);
  242. e->Release();
  243. stripXsltMessage(msg);
  244. m_sValidationErrors.append(msg);
  245. }
  246. catch (...)
  247. {
  248. m_sValidationErrors.appendf("Validation failed: Unspecified XSL error!");
  249. }
  250. m_transform->setExternalFunction(SEISINT_NAMESPACE, externalFunction.get(), false);
  251. m_transform->setUserData(NULL);
  252. if (!valid)
  253. {
  254. const char* errors = m_sValidationErrors.str();
  255. if (!errors || !*errors)
  256. errors = "Continue?";
  257. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Preliminary validation failed!");
  258. while ( !m_pCallback->processException(NULL, NULL, NULL, NULL, errors, "Preliminary validation failed!", NULL) )
  259. ;
  260. valid = true; //ignore validation errors
  261. }
  262. if (valid)
  263. {
  264. ForEachItemIn(idx, m_processes)
  265. m_processes.item(idx).check();
  266. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  267. }
  268. }
  269. //---------------------------------------------------------------------------
  270. // compare
  271. //---------------------------------------------------------------------------
  272. void compare(unsigned mode)
  273. {
  274. ForEachItemIn(idx, m_processes)
  275. {
  276. m_processes.item(idx).compare(mode);
  277. }
  278. }
  279. //---------------------------------------------------------------------------
  280. // deploy
  281. //---------------------------------------------------------------------------
  282. void deploy(unsigned flags, bool useTempDir)
  283. {
  284. m_tempFileCount = m_espModuleCount = 0;
  285. if (flags != DEFLAGS_NONE)
  286. {
  287. ForEachItemIn(idx, m_processes)
  288. {
  289. m_processes.item(idx).deploy(flags, useTempDir);
  290. }
  291. }
  292. }
  293. //---------------------------------------------------------------------------
  294. // deploy
  295. //---------------------------------------------------------------------------
  296. void deploy(unsigned flags, BackupMode backupMode, bool bStop, bool bStart)
  297. {
  298. switch (backupMode)
  299. {
  300. case DEBACKUP_NONE:
  301. if (bStop)
  302. stop();
  303. deploy(flags, false);
  304. if (bStart)
  305. start();
  306. break;
  307. case DEBACKUP_COPY:
  308. backupDirs();
  309. if (bStop)
  310. stop();
  311. deploy(flags, false);
  312. if (bStart)
  313. start();
  314. break;
  315. case DEBACKUP_RENAME:
  316. deploy(flags, true);
  317. if (bStop)
  318. stop();
  319. renameDirs();
  320. if (bStart)
  321. start();
  322. break;
  323. default:
  324. assertex(false);
  325. }
  326. }
  327. //---------------------------------------------------------------------------
  328. // renameDirs
  329. //---------------------------------------------------------------------------
  330. void renameDirs()
  331. {
  332. ForEachItemIn(idx, m_processes)
  333. {
  334. m_processes.item(idx).renameDirs();
  335. }
  336. }
  337. //---------------------------------------------------------------------------
  338. // backupDirs
  339. //---------------------------------------------------------------------------
  340. void backupDirs()
  341. {
  342. ForEachItemIn(idx, m_processes)
  343. {
  344. m_processes.item(idx).backupDirs();
  345. }
  346. }
  347. //---------------------------------------------------------------------------
  348. // abort
  349. //---------------------------------------------------------------------------
  350. void abort()
  351. {
  352. m_abort = true;
  353. ForEachItemIn(idx, m_processes)
  354. {
  355. m_processes.item(idx).abort();
  356. }
  357. }
  358. //---------------------------------------------------------------------------
  359. // archive
  360. //---------------------------------------------------------------------------
  361. void archive(const char* filename)
  362. {
  363. if (!filename || !*filename) return;
  364. if (m_abort)
  365. {
  366. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Aborted!");
  367. throw MakeStringException(0, "User abort");
  368. }
  369. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Archiving environment data to %s...", filename);
  370. Owned<IPropertyTree> tree = &m_environment.getPTree();
  371. StringBuffer xml;
  372. toXML(tree, xml);
  373. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Archive File", NULL, NULL, NULL, NULL,
  374. filename, "", "", "", false);
  375. task->createFile(xml.str());
  376. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  377. if (task->getAbort())
  378. throw MakeStringException(0, "User abort");
  379. Owned<IFile> pFile = createIFile(filename);
  380. pFile->setReadOnly(true);
  381. }
  382. //---------------------------------------------------------------------------
  383. // setLog
  384. //---------------------------------------------------------------------------
  385. void setLog(const char* filename, const char* envname)
  386. {
  387. if (!filename || !*filename) return;
  388. m_pDeployLog.setown(createDeployLog(*m_pCallback, filename, envname));
  389. }
  390. //---------------------------------------------------------------------------
  391. // initXML
  392. //---------------------------------------------------------------------------
  393. void initXML(IPropertyTree* pSelectedComponents)
  394. {
  395. if (m_abort)
  396. throw MakeStringException(0, "User abort");
  397. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Loading environment...");
  398. m_processor.setown(getXslProcessor());
  399. m_transform.setown(m_processor->createXslTransform());
  400. //decrypt external function is no longer used by any xslt
  401. //
  402. //m_externalFunction.setown(m_transform->createExternalFunction("decrypt", decrypt));
  403. //m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), true);
  404. Owned<IPropertyTree> tree = &m_environment.getPTree();
  405. IPropertyTree* pDeploy = tree->queryPropTree("DeployComponents");
  406. if (pDeploy)
  407. tree->removeTree(pDeploy);
  408. pDeploy = tree->addPropTree("DeployComponents", createPTreeFromIPT(pSelectedComponents));
  409. StringBuffer xml;
  410. toXML(tree, xml);
  411. tree->removeTree(pDeploy);
  412. if (m_transform->setXmlSource(xml.str(), xml.length()) != 0)
  413. throw MakeStringException(0, "Invalid environment XML string");
  414. }
  415. //---------------------------------------------------------------------------
  416. // termXML
  417. //---------------------------------------------------------------------------
  418. void termXML()
  419. {
  420. //decrypt external function is no longer used by any xslt
  421. //
  422. //m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), false);
  423. m_externalFunction.clear();
  424. m_transform.clear();
  425. m_processor.clear();
  426. }
  427. //---------------------------------------------------------------------------
  428. // incrementTempFileCount
  429. //---------------------------------------------------------------------------
  430. virtual int incrementTempFileCount()
  431. {
  432. return ++m_tempFileCount;
  433. }
  434. //---------------------------------------------------------------------------
  435. // incrementEspModuleCount
  436. //---------------------------------------------------------------------------
  437. virtual int incrementEspModuleCount()
  438. {
  439. return ++m_espModuleCount;
  440. }
  441. //---------------------------------------------------------------------------
  442. // validationMessageFromXSLT
  443. //---------------------------------------------------------------------------
  444. static void validationMessageFromXSLT(StringBuffer &ret, const char *in, IXslTransform* pTransform)
  445. {
  446. CEnvironmentDeploymentEngine* pEnvDepEngine = (CEnvironmentDeploymentEngine*) pTransform->getUserData();
  447. IDeploymentCallback* pCallback = pEnvDepEngine->m_pCallback;
  448. //input 'in' has format of the form [type]:[compType]:[compName]:[message]
  449. //type is either 'error' or 'warning' and any of the other parts may be empty strings
  450. //
  451. StringArray sArray;
  452. sArray.appendList(in, ":");
  453. if (sArray.ordinality() != 4)
  454. {
  455. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "%s", in);
  456. return;
  457. }
  458. const char* msgType = sArray.item(0);
  459. const char* compType = sArray.item(1);
  460. const char* compName = sArray.item(2);
  461. const char* msg = sArray.item(3);
  462. if (compType && !*compType)
  463. compType = NULL;
  464. if (compName && !*compName)
  465. compName = NULL;
  466. StatusType statusType;
  467. if (!stricmp(msgType, "error"))
  468. {
  469. statusType = STATUS_ERROR;
  470. pEnvDepEngine->m_nValidationErrors++;
  471. if (!compType || !compName)//if this error is not being reported under a particular component in tree
  472. pEnvDepEngine->m_sValidationErrors.append(msg).append("\n");
  473. }
  474. else if (!strnicmp(msgType, "warn", 4))
  475. statusType = STATUS_WARN;
  476. else if (!stricmp(msgType, "OK"))
  477. statusType = STATUS_OK;
  478. else if (!strnicmp(msgType, "inc", 3))
  479. statusType = STATUS_INCOMPLETE;
  480. else statusType = !stricmp(msgType, "normal") ? STATUS_NORMAL : STATUS_ERROR;
  481. try
  482. {
  483. if (pCallback)
  484. pCallback->printStatus( statusType,
  485. compType,
  486. compName,
  487. NULL,
  488. "%s", msg);
  489. }
  490. catch (IException* e)
  491. {
  492. StringBuffer buf;
  493. e->errorMessage(buf);
  494. e->Release();
  495. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "%s", buf.str());
  496. }
  497. catch(...)
  498. {
  499. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "Unknown exception!");
  500. }
  501. }
  502. //---------------------------------------------------------------------------
  503. // getCallback
  504. //---------------------------------------------------------------------------
  505. virtual IDeploymentCallback& getCallback() const
  506. {
  507. return *m_pCallback;
  508. }
  509. //---------------------------------------------------------------------------
  510. // setInteractiveMode
  511. //---------------------------------------------------------------------------
  512. virtual void setInteractiveMode(bool bSet)
  513. {
  514. m_bInteractiveMode = bSet;
  515. }
  516. //---------------------------------------------------------------------------
  517. // getEnvironment
  518. //---------------------------------------------------------------------------
  519. IConstEnvironment& getEnvironment() const
  520. {
  521. return m_environment;
  522. }
  523. //---------------------------------------------------------------------------
  524. // getInteractiveMode
  525. //---------------------------------------------------------------------------
  526. virtual bool getInteractiveMode() const
  527. {
  528. return m_bInteractiveMode;
  529. }
  530. //---------------------------------------------------------------------------
  531. // getDeployLog
  532. //---------------------------------------------------------------------------
  533. virtual IDeployLog* getDeployLog()
  534. {
  535. return m_pDeployLog ? m_pDeployLog.getLink() : NULL;
  536. }
  537. //---------------------------------------------------------------------------
  538. // addTempFile
  539. //---------------------------------------------------------------------------
  540. virtual void addTempFile(const char* filePath)
  541. {
  542. if (filePath)
  543. m_tempFiles.append(filePath);
  544. }
  545. //---------------------------------------------------------------------------
  546. // addTempDirectory
  547. //---------------------------------------------------------------------------
  548. virtual void addTempDirectory(const char* dirPath)
  549. {
  550. if (dirPath)
  551. m_tempDirs.append(dirPath);
  552. }
  553. //---------------------------------------------------------------------------
  554. // setDeployToFolder
  555. //---------------------------------------------------------------------------
  556. virtual void setDeployToFolder(const char* path)
  557. {
  558. StringBuffer machineName;
  559. StringBuffer localPath;
  560. StringBuffer tail;
  561. StringBuffer ext;
  562. if (splitUNCFilename(path, &machineName, &localPath, &tail, &ext))
  563. {
  564. const char* hostName = machineName.str() + 2;
  565. Owned<IConstMachineInfo> machine = m_environment.getMachine(hostName);
  566. if (!machine)
  567. throw MakeStringException(-1, "The computer '%s' used for deployment folder is undefined!", hostName);
  568. StringAttr netAddress;
  569. StringAttrAdaptor adaptor(netAddress);
  570. machine->getNetAddress(adaptor);
  571. if (!netAddress.get() || !*netAddress.get())
  572. throw MakeStringException(-1,
  573. "The computer '%s' used for deployment folder does not have any network address defined!", hostName);
  574. StringBuffer uncPath(PATHSEPSTR PATHSEPSTR);
  575. uncPath.append( netAddress.get() );
  576. if (*localPath.str() != PATHSEPCHAR)
  577. uncPath.append( PATHSEPCHAR );
  578. uncPath.append( localPath );//note that the path ends with PATHSEPCHAR
  579. uncPath.append( tail );
  580. uncPath.append( ext );
  581. m_sDeployToFolder.set( uncPath.str() );
  582. getAccountInfo(hostName, m_sDeployToUser, m_sDeployToPswd);
  583. }
  584. else
  585. m_sDeployToFolder.set( path );
  586. /*
  587. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Create Directory", NULL, NULL, NULL, NULL, m_sDeployToFolder.get());
  588. m_pCallback->printStatus(task);
  589. task->createDirectory();
  590. m_pCallback->printStatus(task);
  591. */
  592. }
  593. //---------------------------------------------------------------------------
  594. // getDeployToFolder
  595. //---------------------------------------------------------------------------
  596. virtual const char* getDeployToFolder() const
  597. {
  598. return m_sDeployToFolder.get();
  599. }
  600. //---------------------------------------------------------------------------
  601. // getDeployToAccountInfo
  602. //---------------------------------------------------------------------------
  603. virtual void getDeployToAccountInfo(const char*& user, const char*& pswd) const
  604. {
  605. user = m_sDeployToUser.get();
  606. pswd = m_sDeployToPswd.get();
  607. }
  608. //---------------------------------------------------------------------------
  609. // lookupNetAddress
  610. //---------------------------------------------------------------------------
  611. StringAttr& lookupNetAddress(StringAttr& str, const char* computer) const
  612. {
  613. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  614. if (machine)
  615. {
  616. StringAttrAdaptor adaptor(str);
  617. machine->getNetAddress(adaptor);
  618. }
  619. return str;
  620. }
  621. //---------------------------------------------------------------------------
  622. // lookupMachineOS
  623. //---------------------------------------------------------------------------
  624. EnvMachineOS lookupMachineOS(IPropertyTree& node) const
  625. {
  626. Owned<IConstMachineInfo> machine = m_environment.getMachine(node.queryProp("@computer"));
  627. return machine ? machine->getOS() : MachineOsUnknown;
  628. }
  629. //---------------------------------------------------------------------------
  630. // getAccountInfo
  631. //---------------------------------------------------------------------------
  632. void getAccountInfo(const char* computer, StringAttr& user, StringAttr& pwd) const
  633. {
  634. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  635. if (machine)
  636. {
  637. Owned<IConstDomainInfo> domain = machine->getDomain();
  638. if (!domain)
  639. throw MakeStringException(-1, "The computer '%s' does not have any domain information!", computer);
  640. StringBuffer x;
  641. if (machine->getOS() == MachineOsW2K)
  642. {
  643. domain->getName(StringBufferAdaptor(x));
  644. if (x.length())
  645. x.append(PATHSEPCHAR);
  646. }
  647. domain->getAccountInfo(StringBufferAdaptor(x), StringAttrAdaptor(pwd));
  648. user.set(x.str());
  649. }
  650. else
  651. throw MakeStringException(-1, "The computer '%s' is undefined!", computer);
  652. }
  653. //---------------------------------------------------------------------------
  654. // getSSHAccountInfo
  655. //---------------------------------------------------------------------------
  656. void getSSHAccountInfo(const char* computer, StringAttr& user, StringAttr& sshKeyFile, StringAttr& sshKeyPassphrase) const
  657. {
  658. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  659. if (machine)
  660. {
  661. Owned<IConstDomainInfo> domain = machine->getDomain();
  662. if (!domain)
  663. throw MakeStringException(-1, "The computer '%s' does not have any domain information!", computer);
  664. StringBuffer x;
  665. if (machine->getOS() == MachineOsW2K)
  666. {
  667. domain->getName(StringBufferAdaptor(x));
  668. if (x.length())
  669. x.append(PATHSEPCHAR);
  670. }
  671. domain->getSSHAccountInfo(StringBufferAdaptor(x), StringAttrAdaptor(sshKeyFile), StringAttrAdaptor(sshKeyPassphrase));
  672. user.set(x.str());
  673. }
  674. else
  675. throw MakeStringException(-1, "The computer '%s' is undefined!", computer);
  676. }
  677. virtual void setSourceDaliAddress( const char* addr )
  678. {
  679. m_sSrcDaliAddress.set( addr );
  680. }
  681. virtual const char* getSourceDaliAddress()
  682. {
  683. return m_sSrcDaliAddress.get();
  684. }
  685. virtual IArrayOf<IDeploymentEngine>& queryProcesses() { return m_processes; }
  686. #ifdef _WINDOWS
  687. void NetErrorHandler(DWORD dwResult)
  688. {
  689. StringBuffer out;
  690. formatSystemError(out, dwResult);
  691. out.insert(0, "Failed to enumerate existing network connections:\n");
  692. while ( !m_pCallback->processException(NULL, NULL, NULL, NULL, out, "Network Error", NULL) )
  693. ;
  694. }
  695. bool EnumerateNetworkConnections()
  696. {
  697. DWORD dwResult;
  698. HANDLE hEnum;
  699. DWORD cbBuffer = 16384; // 16K is a good size
  700. DWORD cEntries = -1; // enumerate all possible entries
  701. LPNETRESOURCE lpnr; // pointer to enumerated structures
  702. //
  703. // Call the WNetOpenEnum function to begin the enumeration.
  704. //
  705. dwResult = WNetOpenEnum(RESOURCE_CONNECTED, // connected network resources
  706. RESOURCETYPE_ANY,// all resources
  707. 0, // enumerate all resources
  708. NULL, // NULL first time the function is called
  709. &hEnum); // handle to the resource
  710. if (dwResult != NO_ERROR)
  711. {
  712. NetErrorHandler(dwResult);
  713. return false;
  714. }
  715. //
  716. // Call the GlobalAlloc function to allocate resources.
  717. //
  718. lpnr = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
  719. do
  720. {
  721. ZeroMemory(lpnr, cbBuffer);
  722. // Call the WNetEnumResource function to continue
  723. // the enumeration.
  724. //
  725. dwResult = WNetEnumResource( hEnum, // resource handle
  726. &cEntries, // defined locally as -1
  727. lpnr, // LPNETRESOURCE
  728. &cbBuffer); // buffer size
  729. // If the call succeeds, loop through the structures.
  730. //
  731. if (dwResult == NO_ERROR)
  732. {
  733. StringBuffer networkPath;
  734. for (DWORD i = 0; i < cEntries; i++)
  735. if (lpnr[i].lpRemoteName)
  736. {
  737. // make a valid UNC path to connect to and see if we are not already connected
  738. if (CDeploymentEngine::stripTrailingDirsFromUNCPath(lpnr[i].lpRemoteName, networkPath.clear()) &&
  739. m_persistentConnections.find( networkPath.str() ) == m_persistentConnections.end())
  740. {
  741. //::MessageBox(NULL, networkPath.str(), lpnr[i].lpRemoteName, MB_OK);
  742. m_persistentConnections.insert( networkPath.str() );
  743. }
  744. }
  745. }
  746. else if (dwResult != ERROR_NO_MORE_ITEMS)
  747. {
  748. NetErrorHandler(dwResult);
  749. break;
  750. }
  751. }
  752. while (dwResult != ERROR_NO_MORE_ITEMS);
  753. GlobalFree((HGLOBAL)lpnr); // free the memory
  754. dwResult = WNetCloseEnum(hEnum); // end the enumeration
  755. if (dwResult != NO_ERROR)
  756. {
  757. NetErrorHandler(dwResult);
  758. return false;
  759. }
  760. return true;
  761. }
  762. #endif//WINDOWS
  763. virtual bool IsPersistentConnection(const char* networkPath) const
  764. {
  765. return m_persistentConnections.find( networkPath ) != m_persistentConnections.end();
  766. }
  767. protected:
  768. IArrayOf<IDeploymentEngine> m_processes;
  769. IConstEnvironment& m_environment;
  770. Owned<IDeploymentCallback> m_pCallback;
  771. Owned<IXslProcessor> m_processor;
  772. Owned<IXslTransform> m_transform;
  773. Owned<IXslFunction> m_externalFunction;
  774. Owned<IDeployLog> m_pDeployLog;
  775. set<string> m_persistentConnections;
  776. int m_espModuleCount;
  777. int m_tempFileCount;
  778. bool m_abort;
  779. bool m_bLinuxDeployment;
  780. bool m_bInteractiveMode;
  781. StringBuffer m_sSshUserid;
  782. StringBuffer m_sSshPassword;
  783. StringBuffer m_validateAllXsl;
  784. unsigned int m_nValidationErrors;
  785. StringBuffer m_sValidationErrors;
  786. StringArray m_tempFiles;
  787. StringArray m_tempDirs;
  788. StringAttr m_sDeployToFolder;
  789. StringAttr m_sDeployToUser;
  790. StringAttr m_sDeployToPswd;
  791. StringAttr m_sSrcDaliAddress;
  792. };
  793. class CConfigGenMgr : public CEnvironmentDeploymentEngine
  794. {
  795. public:
  796. IMPLEMENT_IINTERFACE;
  797. //---------------------------------------------------------------------------
  798. // CConfigGenMgr
  799. //---------------------------------------------------------------------------
  800. CConfigGenMgr(IConstEnvironment& environment, IDeploymentCallback& callback,
  801. IPropertyTree* pSelectedComponents, const char* inputDir, const char* outputDir, const char* compName, const char* compType, const char* ipAddr)
  802. : CEnvironmentDeploymentEngine(environment, callback, NULL),
  803. m_inDir(inputDir),
  804. m_outDir(outputDir),
  805. m_compName(compName),
  806. m_compType(compType),
  807. m_hostIpAddr(ipAddr)
  808. {
  809. m_validateAllXsl.clear().append(inputDir);
  810. if (m_validateAllXsl.length() > 0 &&
  811. m_validateAllXsl.charAt(m_validateAllXsl.length() - 1) != PATHSEPCHAR)
  812. m_validateAllXsl.append(PATHSEPCHAR);
  813. m_validateAllXsl.append("validateAll.xsl");
  814. Owned<IPropertyTree> pSelComps;
  815. if (!pSelectedComponents)
  816. {
  817. Owned<IPropertyTree> pEnvTree = &m_environment.getPTree();
  818. pSelComps.setown(getInstances(pEnvTree, compName, compType, ipAddr));
  819. pSelectedComponents = pSelComps;
  820. }
  821. initXML(pSelectedComponents);
  822. {
  823. Owned<IPropertyTreeIterator> it = pSelectedComponents->getElements("*");
  824. ForEach(*it)
  825. {
  826. IPropertyTree* pComponent = &it->query();
  827. IDeploymentEngine* pEngine = addProcess(pComponent->queryName(), pComponent->queryProp("@name"));
  828. Owned<IPropertyTreeIterator> iter = pComponent->getElements("*");
  829. if (iter->first())
  830. {
  831. pEngine->resetInstances();
  832. ForEach(*iter)
  833. {
  834. IPropertyTree* pChild = &iter->query();
  835. const char* tagName = pChild->queryName();
  836. const char* instName = pChild->queryProp("@name");
  837. pEngine->addInstance(tagName, instName);
  838. //determine if this is linux deployment
  839. if (!m_bLinuxDeployment)
  840. {
  841. const char* computer = pChild->queryProp("@computer");
  842. Owned<IConstMachineInfo> pMachine = environment.getMachine(computer);
  843. if (!pMachine)
  844. throw MakeStringException(0, "Invalid Environment file. Instance '%s' of '%s' references a computer '%s' that has not been defined!", pChild->queryProp("@name"), pComponent->queryProp("@name"), computer);
  845. else if (pMachine->getOS() == MachineOsLinux)
  846. m_bLinuxDeployment = true;
  847. }
  848. }
  849. }
  850. else if (!m_bLinuxDeployment)//another previously added engine already does not have linux instance
  851. {
  852. //some components like thor and hole clusters don't show their instances in the
  853. //deployment wizard so detect if they have any linux instance.
  854. const IArrayOf<IPropertyTree>& instances = pEngine->getInstances();
  855. if (instances.ordinality() > 0)
  856. {
  857. Owned<IConstMachineInfo> machine;// = m_environment.getMachine(instances.item(0).queryProp("@computer"));
  858. if (machine && machine->getOS() == MachineOsLinux)
  859. m_bLinuxDeployment = true;
  860. }
  861. }
  862. }
  863. }
  864. }
  865. //---------------------------------------------------------------------------
  866. // addProcess
  867. //---------------------------------------------------------------------------
  868. IDeploymentEngine* addProcess(const char* processType, const char* processName)
  869. {
  870. assertex(processType);
  871. assertex(processName);
  872. StringBuffer xpath;
  873. xpath.appendf("Software/%s[@name='%s']", processType, processName);
  874. Owned<IPropertyTree> tree = &m_environment.getPTree();
  875. IPropertyTree* pComponent = tree->queryPropTree(xpath.str());
  876. if (!pComponent)
  877. throw MakeStringException(0, "%s with name %s was not found!", processType, processName);
  878. IDeploymentEngine* deployEngine;
  879. if (strcmp(processType, "RoxieCluster")==0)
  880. deployEngine = new CConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir, "*");
  881. else if (strcmp(processType, "ThorCluster")==0)
  882. deployEngine = new CThorConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir);
  883. else if (strcmp(processType, "EspProcess")==0)
  884. deployEngine = new CEspConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir);
  885. else
  886. deployEngine = new CConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir, "Instance", true);
  887. assertex(deployEngine);
  888. deployEngine->setXsl(m_processor, m_transform);
  889. m_processes.append(*deployEngine); // array releases members when destroyed
  890. return deployEngine;
  891. }
  892. void deploy(unsigned flags, BackupMode backupMode, bool bStop, bool bStart)
  893. {
  894. switch (backupMode)
  895. {
  896. case DEBACKUP_NONE:
  897. check();
  898. CEnvironmentDeploymentEngine::deploy(flags, false);
  899. break;
  900. case DEBACKUP_COPY:
  901. throw MakeStringException(-1, "Invalid option Backup copy while generating configurations");
  902. case DEBACKUP_RENAME:
  903. throw MakeStringException(-1, "Invalid option Backup rename while generating configurations");
  904. default:
  905. throw MakeStringException(-1, "Invalid option while generating configurations");
  906. }
  907. }
  908. private:
  909. StringBuffer m_inDir;
  910. StringBuffer m_outDir;
  911. StringBuffer m_compName;
  912. StringBuffer m_compType;
  913. StringBuffer m_hostIpAddr;
  914. };
  915. //---------------------------------------------------------------------------
  916. // Factory functions
  917. //---------------------------------------------------------------------------
  918. IEnvDeploymentEngine* createEnvDeploymentEngine(IConstEnvironment& environment,
  919. IDeploymentCallback& callback,
  920. IPropertyTree* pSelectedComponents)
  921. {
  922. try
  923. {
  924. return new CEnvironmentDeploymentEngine(environment, callback, pSelectedComponents);
  925. }
  926. catch (IException* e)
  927. {
  928. throw e;
  929. }
  930. catch(...)
  931. {
  932. throw MakeStringException(-1, "Unknown exception!");
  933. }
  934. }
  935. IEnvDeploymentEngine* createConfigGenMgr(IConstEnvironment& env,
  936. IDeploymentCallback& callback,
  937. IPropertyTree* pSelectedComponents,
  938. const char* inputDir,
  939. const char* outputDir,
  940. const char* compName,
  941. const char* compType,
  942. const char* ipAddr)
  943. {
  944. try
  945. {
  946. StringBuffer inDir(inputDir);
  947. if (inDir.length() && inDir.charAt(inDir.length() - 1) != PATHSEPCHAR)
  948. inDir.append(PATHSEPCHAR);
  949. StringBuffer outDir(outputDir);
  950. if (outDir.length() && outDir.charAt(outDir.length() - 1) != PATHSEPCHAR)
  951. outDir.append(PATHSEPCHAR);
  952. return new CConfigGenMgr(env, callback, pSelectedComponents, inDir.str(), outDir.str(), compName, compType, ipAddr);
  953. }
  954. catch (IException* e)
  955. {
  956. throw e;
  957. }
  958. catch(...)
  959. {
  960. throw MakeStringException(-1, "Unknown exception!");
  961. }
  962. }
  963. bool matchDeployAddress(const char *searchIP, const char *envIP)
  964. {
  965. if (searchIP && envIP && *searchIP && *envIP)
  966. {
  967. IpAddress ip(envIP);
  968. if (strcmp(searchIP, ".")==0)
  969. return ip.isLocal();
  970. else
  971. {
  972. IpAddress ip2(searchIP);
  973. return ip.ipequals(ip2);
  974. }
  975. }
  976. return false;
  977. }
  978. IPropertyTree* getInstances(const IPropertyTree* pEnvRoot, const char* compName,
  979. const char* compType, const char* ipAddr, bool listall)
  980. {
  981. Owned<IPropertyTree> pSelComps(createPTree("SelectedComponents"));
  982. Owned<IPropertyTreeIterator> iter = pEnvRoot->getElements("Software/*");
  983. const char* instanceNodeNames[] = { "Instance", "RoxieServerProcess" };
  984. const char* logDirNames[] = { "@logDir", "@LogDir", "@dfuLogDir", "@eclLogDir" };
  985. ForEach(*iter)
  986. {
  987. IPropertyTree* pComponent = &iter->query();
  988. const char* type = pComponent->queryName();
  989. if (stricmp(type, "Topology")!=0 && stricmp(type, "Directories")!=0 &&
  990. ((!compName && !compType) || (compName && !strcmp(pComponent->queryProp("@name"), compName)) ||
  991. (!compName && compType && !strcmp(pComponent->queryProp("@buildSet"), compType))))
  992. {
  993. const char* name = pComponent->queryProp("@name");
  994. const char* build = pComponent->queryProp("@build");
  995. const char* buildSet= pComponent->queryProp("@buildSet");
  996. const char* logDir = NULL;
  997. if (listall)
  998. for (int i = 0; i < sizeof(logDirNames)/sizeof(char*); i++)
  999. {
  1000. logDir = pComponent->queryProp(logDirNames[i]);
  1001. if (logDir)
  1002. break;
  1003. }
  1004. StringBuffer sXPath;
  1005. sXPath.appendf("Programs/Build[@name='%s']/BuildSet[@name='%s']/@deployable", build, buildSet);
  1006. const char* deployable = pEnvRoot->queryProp(sXPath.str());
  1007. //either the @deployable does not exist or it is not one of 'no', 'false' or '0'
  1008. if (!deployable ||
  1009. (strcmp(deployable, "no") != 0 && strcmp(deployable, "false") != 0 && strcmp(deployable, "0") != 0))
  1010. {
  1011. IPropertyTree* pSelComp = NULL;
  1012. Owned<IPropertyTreeIterator> iterInst = pComponent->getElements("*", iptiter_sort);
  1013. bool bAdded = false;
  1014. ForEach(*iterInst)
  1015. {
  1016. IPropertyTree* pInst = &iterInst->query();
  1017. const char* computer = pInst->queryProp("@computer");
  1018. const char* netAddr = pInst->queryProp("@netAddress");
  1019. if (!computer || !*computer || !strcmp("Notes", pInst->queryName()))
  1020. continue;
  1021. if (!strcmp(buildSet, "thor"))
  1022. {
  1023. sXPath.clear().appendf("Hardware/Computer[@name=\"%s\"]", computer);
  1024. IPropertyTree* pComputer = pEnvRoot->queryPropTree(sXPath.str());
  1025. if (pComputer == NULL)
  1026. throw MakeStringException(-1,"XPATH: %s is invalid.\n(Did you configure the Hardware?)", sXPath.str());
  1027. netAddr = pComputer->queryProp("@netAddress");
  1028. if (matchDeployAddress(ipAddr, netAddr) ||
  1029. (!ipAddr && netAddr && *netAddr))
  1030. {
  1031. if (!bAdded)
  1032. {
  1033. pSelComp = pSelComps->addPropTree(pComponent->queryName(), createPTree());
  1034. pSelComp->addProp("@name", name);
  1035. pSelComp->addProp("@buildSet", buildSet);
  1036. pSelComp->addProp("@logDir", logDir);
  1037. bAdded = true;
  1038. }
  1039. if (listall)
  1040. {
  1041. IPropertyTree* pInstance = pSelComp->addPropTree(pInst->queryName(), createPTree());
  1042. pInstance->addProp("@name", pInst->queryProp("@name"));
  1043. pInstance->addProp("@computer", computer);
  1044. pInstance->addProp("@netAddress", netAddr);
  1045. }
  1046. }
  1047. }
  1048. else if (matchDeployAddress(ipAddr, netAddr) ||
  1049. (!ipAddr && netAddr && *netAddr))
  1050. {
  1051. if (!bAdded)
  1052. {
  1053. pSelComp = pSelComps->addPropTree(pComponent->queryName(), createPTree());
  1054. pSelComp->addProp("@name", name);
  1055. pSelComp->addProp("@buildSet", buildSet);
  1056. pSelComp->addProp("@logDir", logDir);
  1057. bAdded = true;
  1058. }
  1059. StringBuffer sb(pInst->queryName());
  1060. for (UINT i=0; i<sizeof(instanceNodeNames) / sizeof(instanceNodeNames[0]); i++)
  1061. if (!strcmp(sb.str(), instanceNodeNames[i]))
  1062. {
  1063. //allow multiple instances but do not allow roxie servers more than once per computer
  1064. if (listall || sb.str()[0] != 'R' || !pSelComp->queryPropTree(StringBuffer().appendf("*[@computer=\"%s\"]", computer)))
  1065. {
  1066. IPropertyTree* pInstance = pSelComp->addPropTree(sb.str(), createPTree());
  1067. pInstance->addProp("@name", pInst->queryProp("@name"));
  1068. pInstance->addProp("@computer", pInst->queryProp("@computer"));
  1069. pInstance->addProp("@port", pInst->queryProp("@port"));
  1070. pInstance->addProp("@netAddress", pInst->queryProp("@netAddress"));
  1071. const char* directory = pInst->queryProp(sb.str()[0]=='R' ? "@dataDirectory" : "@directory");
  1072. if (directory && *directory)
  1073. pInstance->addProp("@directory", directory);
  1074. }
  1075. break;
  1076. }
  1077. }
  1078. }
  1079. }
  1080. }
  1081. }
  1082. return pSelComps.getLink();
  1083. }
  1084. //---------------------------------------------------------------------------
  1085. // Module Globals
  1086. //---------------------------------------------------------------------------
  1087. const char* findFileExtension(const char* pszPath)
  1088. {
  1089. const char* lastSlash = pathTail(pszPath);
  1090. return strrchr(lastSlash ? lastSlash : pszPath, '.');
  1091. }
  1092. void removeTrailingPathSepChar(char* pszPath)
  1093. {
  1094. if (pszPath)
  1095. {
  1096. char* lastChar = pszPath + strlen(pszPath) - 1;
  1097. if (isPathSepChar(*lastChar))
  1098. *lastChar = '\0';
  1099. }
  1100. }
  1101. void stripNetAddr(const char* dir, StringBuffer& destpath, StringBuffer& destip, bool makeLinux)
  1102. {
  1103. destpath.clear().append(dir);
  1104. if (dir[0] == '\\' && dir[1] == '\\' && strlen(dir) > 2)
  1105. {
  1106. destip.clear().append(strchr(dir + 2, '\\') - (dir + 2), dir + 2);
  1107. destpath.clear().append(strchr(dir + 2, '\\'));
  1108. }
  1109. if (makeLinux)
  1110. destpath.replace('\\', '/');
  1111. }
  1112. //returns temp path that ends with path sep
  1113. //
  1114. #ifdef _WIN32
  1115. extern DWORD getLastError() { return ::GetLastError(); }
  1116. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  1117. {
  1118. ::GetTempPath(bufsize, tempPath);
  1119. ::GetLongPathName(tempPath, tempPath, bufsize);
  1120. if (subdir && *subdir)
  1121. {
  1122. const int len = strlen(tempPath);
  1123. char* p = tempPath + len;
  1124. strcpy(p, subdir);
  1125. p += strlen(subdir);
  1126. *p++ = '\\';
  1127. *p = '\0';
  1128. }
  1129. }
  1130. #else//Linux specifics follow
  1131. extern DWORD getLastError() { return errno; }
  1132. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  1133. {
  1134. assert(bufsize > 5);
  1135. strcpy(tempPath, "/tmp/");
  1136. if (subdir && *subdir)
  1137. {
  1138. strcat(tempPath, subdir);
  1139. strcat(tempPath, "/");
  1140. }
  1141. }
  1142. #endif