You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Utility.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. // Utility.cpp
  2. //
  3. // Copyright (C) 2011, ARM Research Labs, LLC.
  4. // See www.armresearch.com for the copyright terms.
  5. //
  6. // This file implements the common functionality for the configuration
  7. // utilities.
  8. #include <cerrno>
  9. #include <cstring>
  10. #include <unistd.h>
  11. #include <pwd.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <stdexcept>
  15. #include <sstream>
  16. #include <iostream>
  17. #include <fstream>
  18. #include <vector>
  19. #include "Utility.hpp"
  20. using namespace std;
  21. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. // Configuration. ////////////////////////////////////////////////////////////////////////////////////////
  23. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. const std::string Utility::DirectorySeparator("/");
  25. /// SNF user name.
  26. const string SNFUserName = "snfuser";
  27. /// SNF group name.
  28. const string SNFGroupName = "snfuser";
  29. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  30. // End of configuration. /////////////////////////////////////////////////////////////////////////////////
  31. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  32. Utility::Utility() :
  33. DebugRequested(false), VerboseRequested(false), ExplainRequested(false), HelpRequested(false)
  34. {
  35. }
  36. bool
  37. Utility::FileExists(const std::string File) {
  38. bool Exists;
  39. std::ifstream Input;
  40. errno = 0;
  41. Input.open(File.c_str());
  42. if (ENOENT == errno) {
  43. Exists = false;
  44. } else {
  45. Exists = true;
  46. }
  47. Input.close();
  48. return Exists;
  49. }
  50. std::string
  51. Utility::ReadLastPartOfFile(std::string File, long Size) {
  52. if (!FileExists(File)) {
  53. return "";
  54. }
  55. std::ifstream Input;
  56. Input.open(File.c_str());
  57. if (!Input) {
  58. std::string Temp;
  59. Temp = "Error opening the file " + File;
  60. Temp += " to read from: ";
  61. Temp += strerror(errno);
  62. throw std::runtime_error(Temp);
  63. }
  64. std::streampos FileSize;
  65. FileSize = Input.tellg();
  66. Input.seekg(0, ios_base::end);
  67. FileSize = Input.tellg() - FileSize;
  68. if (FileSize > Size) {
  69. Input.seekg(-Size, ios_base::end);
  70. } else {
  71. Input.seekg(0, ios_base::beg);
  72. }
  73. std::ostringstream Output;
  74. if (!Input.eof()) { // Copy if there are characters.
  75. // Copying an empty file causes
  76. Output << Input.rdbuf(); // failbit to be set.
  77. }
  78. if (Output.bad() || Output.fail()) {
  79. std::string Temp;
  80. Temp = "Error reading last part of file " + File;
  81. Temp += ". Content read: '";
  82. Input.close();
  83. Temp += Output.str();
  84. Temp += "'";
  85. throw std::runtime_error(Temp);
  86. }
  87. Input.close();
  88. if (!Input) {
  89. std::string Temp;
  90. Temp = "Error closing the file " + File;
  91. Temp += " after reading: ";
  92. Temp += strerror(errno);
  93. throw std::runtime_error(Temp);
  94. }
  95. return Output.str();
  96. }
  97. void
  98. Utility::Copy(std::string From, std::string To) {
  99. if (Verbose()) {
  100. cout << "Copy " << From << " to " << To << "...";
  101. }
  102. if (!Explain()) {
  103. std::ifstream Input;
  104. Input.open(From.c_str());
  105. if (!Input) {
  106. std::string Temp;
  107. Temp = "Error opening the file " + From;
  108. Temp += " to read from: ";
  109. Temp += strerror(errno);
  110. throw std::runtime_error(Temp);
  111. }
  112. std::ofstream Output;
  113. Output.open(To.c_str(), std::ios::trunc);
  114. if (!Output) {
  115. std::string Temp;
  116. Temp = "Error opening the file " + To;
  117. Temp += " to copy to: ";
  118. Temp += strerror(errno);
  119. throw std::runtime_error(Temp);
  120. }
  121. if (!Input.eof()) { // Copy if there are characters.
  122. // Copying an empty file causes
  123. Output << Input.rdbuf(); // failbit to be set.
  124. }
  125. if (Output.bad() || Output.fail()) {
  126. std::string Temp;
  127. Temp = "Error copying " + From;
  128. Temp += " to " + To;
  129. Temp += ": ";
  130. Temp += strerror(errno);
  131. throw std::runtime_error(Temp);
  132. }
  133. Input.close();
  134. if (!Input) {
  135. std::string Temp;
  136. Temp = "Error closing the file " + From;
  137. Temp += ": ";
  138. Temp += strerror(errno);
  139. throw std::runtime_error(Temp);
  140. }
  141. Output.close();
  142. if (!Output) {
  143. std::string Temp;
  144. Temp = "Error closing the file " + To;
  145. Temp += ": ";
  146. Temp += strerror(errno);
  147. throw std::runtime_error(Temp);
  148. }
  149. }
  150. OutputVerboseEnd();
  151. }
  152. void
  153. Utility::SetOwnerGroup(std::string File) {
  154. struct passwd *SNFPasswd;
  155. uid_t SNFUid;
  156. struct group *SNFGroup;
  157. gid_t SNFGid;
  158. if (Verbose()) {
  159. cout << "Set owner:group of " << File << " to "
  160. << SNFUserName << ":" << SNFGroupName << "...";
  161. }
  162. if (!Explain()) {
  163. errno = 0;
  164. SNFPasswd = getpwnam(SNFUserName.c_str());
  165. if (SNFPasswd == 0) {
  166. string Temp;
  167. Temp = "Error getting info for Sniffer user " + SNFUserName;
  168. Temp += ": ";
  169. Temp += ((errno == 0) ? "No such user; create the user and try again." : strerror(errno));
  170. throw runtime_error(Temp);
  171. }
  172. SNFUid = SNFPasswd->pw_uid;
  173. SNFGid = SNFPasswd->pw_gid;
  174. if (chown(File.c_str(), SNFUid, SNFGid) != 0) {
  175. string Temp;
  176. Temp = "Error changing group and owner of file " + File;
  177. Temp += " to " + SNFUserName + ":" + SNFGroupName;
  178. Temp += ": ";
  179. Temp += strerror(errno);
  180. throw runtime_error(Temp);
  181. }
  182. }
  183. OutputVerboseEnd();
  184. }
  185. void
  186. Utility::SetMode(std::string File, mode_t mode) {
  187. if (Verbose()) {
  188. cout << "Set mode of " << File << " to "
  189. << std::oct << mode << "...";
  190. }
  191. if (!Explain()) {
  192. if (chmod(File.c_str(), mode) != 0) {
  193. ostringstream Temp;
  194. Temp << "Error changing permissions of file " << File
  195. << " to " << mode << ": " << strerror(errno);
  196. throw runtime_error(Temp.str());
  197. }
  198. }
  199. OutputVerboseEnd();
  200. }
  201. void
  202. Utility::MkDir(std::string &Dir) {
  203. if (Verbose()) {
  204. cout << "Create directory " << Dir << "...";
  205. }
  206. if (!Explain()) {
  207. if (mkdir(Dir.c_str(), 0) != 0) {
  208. ostringstream Temp;
  209. Temp << "Error creating directory " << Dir << ": " << strerror(errno);
  210. throw runtime_error(Temp.str());
  211. }
  212. }
  213. OutputVerboseEnd();
  214. }
  215. void
  216. Utility::ReplaceXmlAttribute(std::string *Content, std::string ElementName, std::string AttributeName, std::string AttributeValue) {
  217. bool FoundElement;
  218. FoundElement = false;
  219. std::string::size_type ElementContentBegin; // Index of start of the element content.
  220. std::string::size_type ElementContentEnd; // One past the end of the element content.
  221. ElementContentBegin = 0;
  222. while (!FoundElement) {
  223. ElementContentBegin = Content->find("<" + ElementName, ElementContentBegin); // Get indices of element content.
  224. ElementContentEnd = Content->find("</" + ElementName, ElementContentBegin);
  225. if (std::string::npos == ElementContentBegin) {
  226. std::string Temp;
  227. Temp = "Unable to find the start of element '" + ElementName;
  228. Temp += "'.";
  229. throw std::runtime_error(Temp);
  230. }
  231. // Check whether the element is in a comment.
  232. std::string::size_type PrevCommentBegin;
  233. std::string::size_type PrevCommentEnd;
  234. PrevCommentBegin = Content->rfind("<!--", ElementContentBegin);
  235. PrevCommentEnd = Content->rfind("-->", ElementContentBegin);
  236. if ( (PrevCommentBegin == std::string::npos) ||
  237. ( (PrevCommentEnd < ElementContentBegin) &&
  238. (PrevCommentEnd > PrevCommentBegin) ) ) {
  239. FoundElement = true;
  240. break; // Not in comment; continue processing.
  241. }
  242. ElementContentBegin++; // In comment; continue search.
  243. }
  244. if (std::string::npos != Content->find("<" + ElementName, ElementContentBegin + 1)) {
  245. std::string Temp;
  246. Temp = "Found two elements named '" + ElementName;
  247. Temp += "'; there must be only one.";
  248. throw std::runtime_error(Temp);
  249. }
  250. if (std::string::npos == ElementContentEnd) {
  251. ElementContentEnd = Content->find("/>", ElementContentBegin);
  252. }
  253. if (std::string::npos == ElementContentEnd){
  254. std::string Temp;
  255. Temp = "Unable to find the end of element '" + ElementName;
  256. Temp += "'.";
  257. throw std::runtime_error(Temp);
  258. }
  259. ElementContentBegin += ElementName.length() + 1; // Skip element name.
  260. std::string::size_type ProvisionalAttributeNameBegin = ElementContentBegin;
  261. std::string::size_type AttributeNameBegin ;
  262. bool FoundAttribute = false;
  263. std::string PrevChar;
  264. while (ProvisionalAttributeNameBegin < ElementContentEnd) { // Find start of attribute name.
  265. ProvisionalAttributeNameBegin = Content->find(AttributeName, ProvisionalAttributeNameBegin);
  266. if ( (ProvisionalAttributeNameBegin == std::string::npos) || (ProvisionalAttributeNameBegin >= ElementContentEnd) ) {
  267. break;
  268. }
  269. PrevChar = Content->at(ProvisionalAttributeNameBegin - 1);
  270. if (std::string::npos == PrevChar.find_first_not_of(" \t\r\n")) { // Check for whitespace before the attribute.
  271. if (FoundAttribute) {
  272. std::string Temp;
  273. Temp = "Found two attributes named '" + AttributeName;
  274. Temp += "' in element '" + ElementName;
  275. Temp += "'; there must be only one.";
  276. throw std::runtime_error(Temp);
  277. }
  278. FoundAttribute = true;
  279. AttributeNameBegin = ProvisionalAttributeNameBegin;
  280. }
  281. ProvisionalAttributeNameBegin = ProvisionalAttributeNameBegin + AttributeName.length(); // Skip.
  282. }
  283. if (!FoundAttribute) {
  284. std::string Temp;
  285. Temp = "Unable to find the attribute '" + AttributeName;
  286. Temp += "' in element '" + ElementName;
  287. Temp += "'.";
  288. throw std::runtime_error(Temp);
  289. }
  290. std::string::size_type EqualIndex; // Index of "=".
  291. std::string::size_type DelimiterIndex; // Index of delimiter of attribute value.
  292. std::string DelimiterValue; // Attribute value delimiter value.
  293. std::string::size_type AttributeValueBegin; // Index of start of attribute value.
  294. std::string::size_type AttributeValueEnd; // One past the end of the attribute value.
  295. EqualIndex = // Get index of first delimiter.
  296. Content->find_first_not_of(" \t\r\n", AttributeNameBegin + AttributeName.length());
  297. if ( (EqualIndex == std::string::npos) || (EqualIndex >= ElementContentEnd) ) {
  298. std::string Temp;
  299. Temp = "Unable to find \"=\" after '" + AttributeName;
  300. Temp += "' in element '" + ElementName;
  301. Temp += "'.";
  302. throw std::runtime_error(Temp);
  303. }
  304. DelimiterIndex = // Get index of first delimiter.
  305. Content->find_first_not_of(" \t\r\n", EqualIndex + 1);
  306. if ( (DelimiterIndex == std::string::npos) || (DelimiterIndex >= ElementContentEnd) ) {
  307. std::string Temp;
  308. Temp = "Unable to find start of value of attribute '" + AttributeName;
  309. Temp += "' in element '" + ElementName;
  310. Temp += "'.";
  311. throw std::runtime_error(Temp);
  312. }
  313. DelimiterValue = Content->at(DelimiterIndex);
  314. AttributeValueBegin = DelimiterIndex + 1;
  315. AttributeValueEnd = Content->find(DelimiterValue, AttributeValueBegin);
  316. if ( (AttributeValueEnd == std::string::npos) || (AttributeValueEnd >= ElementContentEnd) ) {
  317. std::string Temp;
  318. Temp = "Unable to find the end of the value of '" + AttributeName;
  319. Temp += "' in element '" + ElementName;
  320. Temp += "'.";
  321. throw std::runtime_error(Temp);
  322. }
  323. Content->replace(AttributeValueBegin,
  324. AttributeValueEnd - AttributeValueBegin,
  325. "");
  326. Content->insert(AttributeValueBegin, AttributeValue);
  327. }
  328. bool
  329. Utility::CheckForString(std::string Line, std::string SearchString) {
  330. string::size_type Indx;
  331. Indx = Line.find_first_not_of(" \t"); // Trim leading whitespace.
  332. if (string::npos != Indx) {
  333. Line = Line.substr(Indx);
  334. }
  335. if (Line.substr(0, SearchString.length()) == SearchString) {
  336. return true;
  337. }
  338. return false;
  339. }
  340. std::string
  341. Utility::Trim(std::string String) {
  342. std::string Whitespace(" \n\r\t");
  343. std::string::size_type End = String.find_last_not_of(Whitespace);
  344. if (End == std::string::npos) {
  345. return std::string();
  346. }
  347. std::string::size_type Start = String.find_first_not_of(Whitespace);
  348. if (Start == std::string::npos) {
  349. Start = 0;
  350. }
  351. return String.substr(Start, (End - Start) + 1);
  352. }
  353. void
  354. Utility::SetDebug(bool Mode) {
  355. DebugRequested = Mode;
  356. }
  357. bool
  358. Utility::Debug() {
  359. return DebugRequested;
  360. }
  361. void
  362. Utility::SetVerbose(bool Mode) {
  363. VerboseRequested = Mode;
  364. }
  365. bool
  366. Utility::Verbose() {
  367. return (VerboseRequested || ExplainRequested);
  368. }
  369. void
  370. Utility::SetExplain(bool Mode) {
  371. ExplainRequested = Mode;
  372. }
  373. bool
  374. Utility::Explain() {
  375. return ExplainRequested;
  376. }
  377. void
  378. Utility::SetHelp(bool Mode) {
  379. HelpRequested = Mode;
  380. }
  381. bool
  382. Utility::Help() {
  383. return HelpRequested;
  384. }
  385. void
  386. Utility::OutputVerboseEnd() {
  387. if (Verbose() && !Explain()) {
  388. cout << "done.\n";
  389. } else if (Explain()) {
  390. cout << "\n";
  391. }
  392. }