Aktualizr
C++ SOTA Client
utils.cc
1 #include "utilities/utils.h"
2 
3 #include <stdio.h>
4 #include <algorithm>
5 #include <cstdlib>
6 #include <fstream>
7 #include <iomanip>
8 #include <iostream>
9 #include <random>
10 #include <sstream>
11 #include <stdexcept>
12 #include <string>
13 
14 #include <archive.h>
15 #include <archive_entry.h>
16 #include <arpa/inet.h>
17 #include <fcntl.h>
18 #include <ifaddrs.h>
19 #include <netinet/in.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 #include <boost/algorithm/string.hpp>
24 #include <boost/archive/iterators/base64_from_binary.hpp>
25 #include <boost/archive/iterators/binary_from_base64.hpp>
26 #include <boost/archive/iterators/remove_whitespace.hpp>
27 #include <boost/archive/iterators/transform_width.hpp>
28 #include <boost/filesystem.hpp>
29 #include <boost/uuid/random_generator.hpp>
30 #include <boost/uuid/uuid_io.hpp>
31 
32 #include "logging/logging.h"
33 
34 const char *adverbs[] = {
35  "adorable", "acidic", "ample", "aromatic", "artistic", "attractive", "basic", "beautiful",
36  "best", "blissful", "bubbly", "celebrated", "cheap", "chilly", "cloudy", "colorful",
37  "colossal", "complete", "conventional", "costly", "creamy", "crisp", "dense", "double",
38  "dry", "easy", "every", "exotic", "expert", "fake", "fabulous", "fast",
39  "fine", "firm", "first", "flaky", "flat", "fluffy", "frozen", "generous",
40  "giant", "glass", "glorious", "golden", "good", "grand", "great", "half",
41  "happy", "hard", "healthy", "heavy", "hot", "huge", "humble", "ideal",
42  "icy", "incredible", "interesting", "joyous", "juicy", "jumbo", "large", "late",
43  "lavish", "leafy", "lean", "light", "lovely", "marvelous", "mature", "modern",
44  "modest", "neat", "new", "nice", "nifty", "nutty", "oily", "ornate",
45  "perfect", "plain", "posh", "pretty", "prime", "proper", "pure", "quick",
46  "raw", "real", "rich", "ripe", "safe", "salty", "several", "short",
47  "simple", "slim", "slow", "smooth", "soft", "solid", "speedy", "spotless",
48  "strong", "stylish", "subtle", "super", "sweet", "tasty", "tempting", "tender",
49  "terrific", "thick", "thin", "tidy", "tiny", "twin", "ultimate", "unique",
50  "uniform", "unusual", "valuable", "vast", "warm", "wavy", "wet", "whole",
51  "wide", "wild", "wooden", "young"};
52 
53 const char *names[] = {"Allerlei",
54  "Apfelkuchen",
55  "Backerbsen",
56  "Baumkuchen",
57  "Beetenbartsch",
58  "Berliner",
59  "Bethmaennchen",
60  "Biersuppe",
61  "Birnenfladen",
62  "Bohnen",
63  "Bratapfel",
64  "Bratkartoffeln",
65  "Brezel",
66  "Broetchen",
67  "Butterkuchen",
68  "Currywurst",
69  "Dampfnudel",
70  "Dibbelabbes",
71  "Eierkuchen",
72  "Eintopf",
73  "Erbsensuppe",
74  "Flaedlesuppe",
75  "Flammkuchen",
76  "Fliederbeersuppe",
77  "Franzbroetchen",
78  "Funkenkuechlein",
79  "Gedadschde",
80  "Gemueseschnitzel",
81  "Germknoedel",
82  "Gerstensuppe",
83  "Griessbrei",
84  "Gruenkohl",
85  "Gruetze",
86  "Gummibaerchen",
87  "Gurkensalat",
88  "Habermus",
89  "Haddekuche",
90  "Hagebuttenmark",
91  "Handkaese",
92  "Herrencreme",
93  "Hoorische",
94  "Kaesekuchen",
95  "Kaiserschmarrn",
96  "Kartoffelpueree",
97  "Kartoffelpuffer",
98  "Kartoffelsalat",
99  "Kastanien",
100  "Kichererbsen",
101  "Kirschenmichel",
102  "Kirschtorte",
103  "Klaben",
104  "Kloesse",
105  "Kluntjes",
106  "Knaeckebrot",
107  "Kniekuechle",
108  "Knoedel",
109  "Kohlroulade",
110  "Krautfleckerl",
111  "Kuerbiskernbrot",
112  "Kuerbissuppe",
113  "Lebkuchen",
114  "Linsen",
115  "Loeffelerbsen",
116  "Magenbrot",
117  "Marillenknoedel",
118  "Maroni",
119  "Marsch",
120  "Marzipan",
121  "Maultaschen",
122  "Milliramstrudel",
123  "Mischbrot",
124  "Mohnnudeln",
125  "Mohnpielen",
126  "Mohnzelten",
127  "Muesli",
128  "Nussecke",
129  "Nusstorte",
130  "Palatschinke",
131  "Pellkartoffeln",
132  "Pfannkuchen",
133  "Pfefferkuchen",
134  "Pillekuchen",
135  "Pommes",
136  "Poschweck",
137  "Powidltascherl",
138  "Printen",
139  "Prinzregententorte",
140  "Pumpernickel",
141  "Punschkrapfen",
142  "Quarkkeulchen",
143  "Quetschkartoffeln",
144  "Raclette",
145  "Radi",
146  "Reibekuchen",
147  "Reinling",
148  "Riebel",
149  "Roeggelchen",
150  "Roesti",
151  "Sauerkraut",
152  "Schmalzkuchen",
153  "Schmorgurken",
154  "Schnippelbohnen",
155  "Schoeberl",
156  "Schrippe",
157  "Schupfnudel",
158  "Schuxen",
159  "Schwammerlsuppe",
160  "Schweineohren",
161  "Sonnenblumenkernbrot",
162  "Spaetzle",
163  "Spaghettieis",
164  "Spargel",
165  "Spekulatius",
166  "Springerle",
167  "Spritzkuchen",
168  "Stampfkartoffeln",
169  "Sterz",
170  "Stollen",
171  "Streuselkuchen",
172  "Tilsit",
173  "Toastbrot",
174  "Topfenstrudel",
175  "Vollkornbrot",
176  "Wibele",
177  "Wickelkloesse",
178  "Zimtwaffeln",
179  "Zwetschkenroester",
180  "Zwiebelkuchen"};
181 
182 typedef boost::archive::iterators::base64_from_binary<
183  boost::archive::iterators::transform_width<std::string::const_iterator, 6, 8> >
184  base64_text;
185 
186 typedef boost::archive::iterators::transform_width<
187  boost::archive::iterators::binary_from_base64<
188  boost::archive::iterators::remove_whitespace<std::string::const_iterator> >,
189  8, 6>
190  base64_to_bin;
191 
192 std::string Utils::fromBase64(std::string base64_string) {
193  int64_t paddingChars = std::count(base64_string.begin(), base64_string.end(), '=');
194  std::replace(base64_string.begin(), base64_string.end(), '=', 'A');
195  std::string result(base64_to_bin(base64_string.begin()), base64_to_bin(base64_string.end()));
196  result.erase(result.end() - paddingChars, result.end());
197  return result;
198 }
199 
200 std::string Utils::toBase64(const std::string &tob64) {
201  std::string b64sig(base64_text(tob64.begin()), base64_text(tob64.end()));
202  b64sig.append((3 - tob64.length() % 3) % 3, '=');
203  return b64sig;
204 }
205 
206 // Strip leading and trailing quotes
207 std::string Utils::stripQuotes(const std::string &value) {
208  std::string res = value;
209  res.erase(std::remove(res.begin(), res.end(), '\"'), res.end());
210  return res;
211 }
212 
213 // Add leading and trailing quotes
214 std::string Utils::addQuotes(const std::string &value) { return "\"" + value + "\""; }
215 
216 std::string Utils::extractField(const std::string &in, unsigned int field_id) {
217  std::string out;
218  auto it = in.begin();
219 
220  // skip spaces
221  for (; it != in.end() && (isspace(*it) != 0); it++) {
222  ;
223  }
224  for (unsigned int k = 0; k < field_id; k++) {
225  bool empty = true;
226  for (; it != in.end() && (isspace(*it) == 0); it++) {
227  empty = false;
228  }
229  if (empty) {
230  throw std::runtime_error("No such field " + std::to_string(field_id));
231  }
232  for (; it != in.end() && (isspace(*it) != 0); it++) {
233  ;
234  }
235  }
236 
237  for (; it != in.end() && (isspace(*it) == 0); it++) {
238  out += *it;
239  }
240  return out;
241 }
242 
243 Json::Value Utils::parseJSON(const std::string &json_str) {
244  Json::Reader reader;
245  Json::Value json_value;
246  reader.parse(json_str, json_value);
247  return json_value;
248 }
249 
250 Json::Value Utils::parseJSONFile(const boost::filesystem::path &filename) {
251  std::ifstream path_stream(filename.c_str());
252  std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
253  return Utils::parseJSON(content);
254 }
255 
256 std::string Utils::genPrettyName() {
257  std::random_device urandom;
258 
259  std::uniform_int_distribution<> adverbs_dist(0, (sizeof(adverbs) / sizeof(char *)) - 1);
260  std::uniform_int_distribution<> nouns_dist(0, (sizeof(names) / sizeof(char *)) - 1);
261  std::uniform_int_distribution<> digits(0, 999);
262  std::stringstream pretty_name;
263  pretty_name << adverbs[adverbs_dist(urandom)];
264  pretty_name << "-";
265  pretty_name << names[nouns_dist(urandom)];
266  pretty_name << "-";
267  pretty_name << digits(urandom);
268  std::string res = pretty_name.str();
269  std::transform(res.begin(), res.end(), res.begin(), ::tolower);
270  return res;
271 }
272 
273 std::string Utils::readFile(const boost::filesystem::path &filename) {
274  boost::filesystem::path tmpFilename = filename;
275  tmpFilename += ".new";
276 
277  if (boost::filesystem::exists(tmpFilename)) {
278  LOG_WARNING << tmpFilename << " was found on FS, removing";
279  boost::filesystem::remove(tmpFilename);
280  }
281  std::ifstream path_stream(filename.c_str());
282  std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
283  return content;
284 }
285 
286 static constexpr size_t BSIZE = 20 * 512;
287 
289  std::istream &is;
290  std::array<char, BSIZE> buf;
291 };
292 
293 static ssize_t read_cb(struct archive *a, void *client_data, const void **buffer) {
294  auto s = reinterpret_cast<archive_state *>(client_data);
295  if (s->is.fail()) {
296  archive_set_error(a, -1, "unable to read from stream");
297  return 0;
298  }
299  if (s->is.eof()) {
300  return 0;
301  }
302  s->is.read(s->buf.data(), BSIZE);
303  if (!s->is.eof() && s->is.fail()) {
304  archive_set_error(a, -1, "unable to read from stream");
305  return 0;
306  }
307  *buffer = s->buf.data();
308 
309  return s->is.gcount();
310 }
311 
312 void Utils::writeFile(const boost::filesystem::path &filename, const std::string &content, bool create_directories) {
313  // also replace the target file atomically by creating filename.new and
314  // renaming it to the target file name
315  boost::filesystem::path tmpFilename = filename;
316  tmpFilename += ".new";
317 
318  if (create_directories) {
319  boost::filesystem::create_directories(filename.parent_path());
320  }
321  std::ofstream file(tmpFilename.c_str());
322  if (!file.good()) {
323  throw std::runtime_error(std::string("Error opening file ") + tmpFilename.string());
324  }
325  file << content;
326  file.close();
327 
328  boost::filesystem::rename(tmpFilename, filename);
329 }
330 
331 void Utils::writeFile(const boost::filesystem::path &filename, const Json::Value &content, bool create_directories) {
332  Utils::writeFile(filename, jsonToStr(content), create_directories);
333 }
334 
335 std::string Utils::jsonToStr(const Json::Value &json) {
336  std::stringstream ss;
337  ss << json;
338  return ss.str();
339 }
340 
341 std::string Utils::jsonToCanonicalStr(const Json::Value &json) { return Json::FastWriter().write(json); }
342 
343 Json::Value Utils::getHardwareInfo() {
344  std::string result;
345  const int exit_code = shell("lshw -json", &result);
346 
347  if (exit_code != 0) {
348  LOG_WARNING << "Could not execute lshw (is it installed?).";
349  return Json::Value();
350  }
351  const Json::Value parsed = Utils::parseJSON(result);
352  return (parsed.isArray()) ? parsed[0] : parsed;
353 }
354 
355 Json::Value Utils::getNetworkInfo() {
356  // get interface with default route
357  std::ifstream path_stream("/proc/net/route");
358  std::string route_content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
359 
360  struct {
361  std::string name;
362  std::string ip;
363  std::string mac;
364  } itf;
365  std::istringstream route_stream(route_content);
366  std::array<char, 200> line{};
367 
368  // skip first line
369  route_stream.getline(&line[0], line.size());
370  while (route_stream.getline(&line[0], line.size())) {
371  std::string itfn = Utils::extractField(&line[0], 0);
372  std::string droute = Utils::extractField(&line[0], 1);
373  if (droute == "00000000") {
374  itf.name = itfn;
375  // take the first routing to 0
376  break;
377  }
378  }
379 
380  if (itf.name != "") {
381  {
382  // get ip address
383  StructGuard<struct ifaddrs> ifaddrs(nullptr, freeifaddrs);
384  {
385  struct ifaddrs *ifa;
386  if (getifaddrs(&ifa) < 0) {
387  LOG_ERROR << "getifaddrs: " << std::strerror(errno);
388  } else {
389  ifaddrs.reset(ifa);
390  }
391  }
392  if (ifaddrs != nullptr) {
393  for (struct ifaddrs *ifa = ifaddrs.get(); ifa != nullptr; ifa = ifa->ifa_next) {
394  if (itf.name == ifa->ifa_name) {
395  if (ifa->ifa_addr == nullptr) {
396  continue;
397  }
398  if (ifa->ifa_addr->sa_family != AF_INET) {
399  continue;
400  }
401  const struct sockaddr_storage *sa = reinterpret_cast<struct sockaddr_storage *>(ifa->ifa_addr);
402 
403  itf.ip = Utils::ipDisplayName(*sa);
404  }
405  }
406  }
407  }
408  {
409  // get mac address
410  std::ifstream mac_stream("/sys/class/net/" + itf.name + "/address");
411  std::string m((std::istreambuf_iterator<char>(mac_stream)), std::istreambuf_iterator<char>());
412  itf.mac = std::move(m);
413  boost::trim_right(itf.mac);
414  }
415  }
416 
417  Json::Value network_info;
418  network_info["local_ipv4"] = itf.ip;
419  network_info["mac"] = itf.mac;
420  network_info["hostname"] = Utils::getHostname();
421 
422  return network_info;
423 }
424 
425 std::string Utils::getHostname() {
426  char hostname[200];
427  if (gethostname(hostname, 200) < 0) {
428  return "";
429  }
430  return hostname;
431 }
432 
433 std::string Utils::randomUuid() {
434  std::random_device urandom;
435  boost::uuids::basic_random_generator<std::random_device> uuid_gen(urandom);
436  return boost::uuids::to_string(uuid_gen());
437 }
438 
439 void Utils::copyDir(const boost::filesystem::path &from, const boost::filesystem::path &to) {
440  boost::filesystem::remove_all(to);
441 
442  boost::filesystem::create_directories(to);
443  boost::filesystem::directory_iterator it(from);
444 
445  for (; it != boost::filesystem::directory_iterator(); it++) {
446  if (boost::filesystem::is_directory(it->path())) {
447  copyDir(it->path(), to / it->path().filename());
448  } else {
449  boost::filesystem::copy_file(it->path(), to / it->path().filename());
450  }
451  }
452 }
453 
454 std::string Utils::readFileFromArchive(std::istream &as, const std::string &filename) {
455  struct archive *a = archive_read_new();
456  if (a == nullptr) {
457  LOG_ERROR << "archive error: could not initialize archive object";
458  throw std::runtime_error("archive error");
459  }
460  archive_read_support_filter_all(a);
461  archive_read_support_format_all(a);
462  archive_state state = {as, {}};
463  int r = archive_read_open(a, reinterpret_cast<void *>(&state), nullptr, read_cb, nullptr);
464  if (r != ARCHIVE_OK) {
465  LOG_ERROR << "archive error: " << archive_error_string(a);
466  archive_read_free(a);
467  throw std::runtime_error("archive error");
468  }
469 
470  bool found = false;
471  std::stringstream out_stream;
472  struct archive_entry *entry;
473  while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
474  if (filename != archive_entry_pathname(entry)) {
475  archive_read_data_skip(a);
476  continue;
477  }
478 
479  const char *buff;
480  size_t size;
481  int64_t offset;
482 
483  for (;;) {
484  r = archive_read_data_block(a, reinterpret_cast<const void **>(&buff), &size, &offset);
485  if (r == ARCHIVE_EOF) {
486  found = true;
487  break;
488  }
489  if (r != ARCHIVE_OK) {
490  LOG_ERROR << "archive error: " << archive_error_string(a);
491  break;
492  }
493  if (size > 0 && buff != nullptr) {
494  out_stream.write(buff, static_cast<ssize_t>(size));
495  }
496  }
497  }
498 
499  r = archive_read_free(a);
500  if (r != ARCHIVE_OK) {
501  LOG_ERROR << "archive error: " << archive_error_string(a);
502  }
503 
504  if (!found) {
505  throw std::runtime_error("could not extract " + filename + " from archive");
506  }
507 
508  return out_stream.str();
509 }
510 
511 static ssize_t write_cb(struct archive *a, void *client_data, const void *buffer, size_t length) {
512  auto s = reinterpret_cast<std::ostream *>(client_data);
513  s->write(reinterpret_cast<const char *>(buffer), static_cast<ssize_t>(length));
514  if (s->fail()) {
515  archive_set_error(a, -1, "unable to write in stream");
516  return -1;
517  }
518 
519  return static_cast<ssize_t>(length);
520 }
521 
522 void Utils::writeArchive(const std::map<std::string, std::string> &entries, std::ostream &as) {
523  struct archive *a = archive_write_new();
524  if (a == nullptr) {
525  LOG_ERROR << "archive error: could not initialize archive object";
526  throw std::runtime_error("archive error");
527  }
528  archive_write_set_format_pax(a);
529  archive_write_add_filter_gzip(a);
530 
531  int r = archive_write_open(a, reinterpret_cast<void *>(&as), nullptr, write_cb, nullptr);
532  if (r != ARCHIVE_OK) {
533  LOG_ERROR << "archive error: " << archive_error_string(a);
534  archive_write_free(a);
535  throw std::runtime_error("archive error");
536  }
537 
538  struct archive_entry *entry = archive_entry_new();
539  for (const auto &el : entries) {
540  archive_entry_clear(entry);
541  archive_entry_set_filetype(entry, AE_IFREG);
542  archive_entry_set_perm(entry, S_IRWXU | S_IRWXG | S_IRWXO);
543  archive_entry_set_size(entry, static_cast<ssize_t>(el.second.size()));
544  archive_entry_set_pathname(entry, el.first.c_str());
545  if (archive_write_header(a, entry) != 0) {
546  LOG_ERROR << "archive error: " << archive_error_string(a);
547  archive_entry_free(entry);
548  archive_write_free(a);
549  throw std::runtime_error("archive error");
550  }
551  if (archive_write_data(a, el.second.c_str(), el.second.size()) < 0) {
552  LOG_ERROR << "archive error: " << archive_error_string(a);
553  archive_entry_free(entry);
554  archive_write_free(a);
555  throw std::runtime_error("archive error");
556  }
557  }
558  archive_entry_free(entry);
559  r = archive_write_free(a);
560  if (r != ARCHIVE_OK) {
561  LOG_ERROR << "archive error: " << archive_error_string(a);
562  }
563 }
564 
565 sockaddr_storage Utils::ipGetSockaddr(int fd) {
566  sockaddr_storage ss{};
567  socklen_t len = sizeof(ss);
568  if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) < 0) {
569  throw std::runtime_error(std::string("Could not get sockaddr: ") + std::strerror(errno));
570  }
571 
572  return ss;
573 }
574 
575 std::string Utils::ipDisplayName(const sockaddr_storage &saddr) {
576  char ipstr[INET6_ADDRSTRLEN];
577 
578  switch (saddr.ss_family) {
579  case AF_INET: {
580  const auto *sa = reinterpret_cast<const sockaddr_in *>(&saddr);
581  inet_ntop(AF_INET, &sa->sin_addr, ipstr, sizeof(ipstr));
582  return std::string(ipstr);
583  }
584  case AF_INET6: {
585  const auto *sa = reinterpret_cast<const sockaddr_in6 *>(&saddr);
586  inet_ntop(AF_INET6, &sa->sin6_addr, ipstr, sizeof(ipstr));
587  return std::string(ipstr);
588  }
589  default:
590  return "unknown";
591  }
592 }
593 
594 int Utils::ipPort(const sockaddr_storage &saddr) {
595  in_port_t p;
596  if (saddr.ss_family == AF_INET) {
597  const auto *sa = reinterpret_cast<const sockaddr_in *>(&saddr);
598  p = sa->sin_port;
599  } else if (saddr.ss_family == AF_INET6) {
600  const auto *sa = reinterpret_cast<const sockaddr_in6 *>(&saddr);
601  p = sa->sin6_port;
602  } else {
603  return -1;
604  }
605 
606  return ntohs(p);
607 }
608 
609 int Utils::shell(const std::string &command, std::string *output, bool include_stderr) {
610  char buffer[128];
611  std::string full_command(command);
612  if (include_stderr) {
613  full_command += " 2>&1";
614  }
615  FILE *pipe = popen(full_command.c_str(), "r");
616  if (pipe == nullptr) {
617  *output = "popen() failed!";
618  return -1;
619  }
620  while (feof(pipe) == 0) {
621  if (fgets(buffer, 128, pipe) != nullptr) {
622  *output += buffer;
623  }
624  }
625  int exitcode = pclose(pipe);
626  return WEXITSTATUS(exitcode);
627 }
628 
629 boost::filesystem::path Utils::absolutePath(const boost::filesystem::path &root, const boost::filesystem::path &file) {
630  if (file.is_absolute() || root.empty()) {
631  return file;
632  }
633  return (root / file);
634 }
635 
636 std::vector<boost::filesystem::path> Utils::glob(const std::string &pat) {
637  glob_t glob_result;
638  ::glob(pat.c_str(), GLOB_TILDE, nullptr, &glob_result);
639  std::vector<boost::filesystem::path> ret;
640  for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
641  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
642  ret.emplace_back(glob_result.gl_pathv[i]);
643  }
644  globfree(&glob_result);
645  std::sort(ret.begin(), ret.end());
646  return ret;
647 }
648 
649 void Utils::createDirectories(const boost::filesystem::path &path, mode_t mode) {
650  boost::filesystem::path parent = path.parent_path();
651  if (!parent.empty() && !boost::filesystem::exists(parent)) {
652  Utils::createDirectories(parent, mode);
653  }
654  if (mkdir(path.c_str(), mode) == -1) {
655  throw std::runtime_error("could not create directory: " + path.native());
656  }
657  std::cout << "created: " << path.native() << "\n";
658 }
659 
661  public:
662  SafeTempRoot(const SafeTempRoot &) = delete;
663  SafeTempRoot operator=(const SafeTempRoot &) = delete;
664  // provide this as a static method so that we can use C++ static destructor
665  // to remove the temp root
666  static boost::filesystem::path &Get() {
667  static SafeTempRoot r;
668 
669  return r.path;
670  }
671 
672  private:
673  SafeTempRoot() {
674  boost::filesystem::path p =
675  boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("aktualizr-%%%%-%%%%-%%%%-%%%%");
676 
677  if (mkdir(p.c_str(), S_IRWXU) == -1) {
678  throw std::runtime_error("could not create temporary directory root: " + p.native());
679  }
680 
681  path = boost::filesystem::path(p);
682  }
683  ~SafeTempRoot() {
684  try {
685  boost::filesystem::remove_all(path);
686  } catch (...) {
687  // ignore this, not critical
688  }
689  }
690 
691  boost::filesystem::path path;
692 };
693 
694 TemporaryFile::TemporaryFile(const std::string &hint)
695  : tmp_name_(SafeTempRoot::Get() / boost::filesystem::unique_path("%%%%-%%%%-" + hint)) {}
696 
697 TemporaryFile::~TemporaryFile() { boost::filesystem::remove(tmp_name_); }
698 
699 void TemporaryFile::PutContents(const std::string &contents) {
700  mode_t mode = S_IRUSR | S_IWUSR;
701  int fd = open(Path().c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
702  ssize_t written = write(fd, contents.c_str(), contents.size());
703  close(fd);
704  if (written < 0 || static_cast<size_t>(written) != contents.size()) {
705  throw std::runtime_error(std::string("Could not write content to file: ") + Path().string());
706  }
707 }
708 
709 boost::filesystem::path TemporaryFile::Path() const { return tmp_name_; }
710 
711 std::string TemporaryFile::PathString() const { return Path().string(); }
712 
713 TemporaryDirectory::TemporaryDirectory(const std::string &hint)
714  : tmp_name_(SafeTempRoot::Get() / boost::filesystem::unique_path("%%%%-%%%%-" + hint)) {
715  Utils::createDirectories(tmp_name_, S_IRWXU);
716 }
717 
718 TemporaryDirectory::~TemporaryDirectory() { boost::filesystem::remove_all(tmp_name_); }
719 
720 boost::filesystem::path TemporaryDirectory::Path() const { return tmp_name_; }
721 
722 boost::filesystem::path TemporaryDirectory::operator/(const boost::filesystem::path &subdir) const {
723  return (tmp_name_ / subdir);
724 }
725 
726 std::string TemporaryDirectory::PathString() const { return Path().string(); }
727 
728 void Utils::setSocketPort(sockaddr_storage *addr, in_port_t port) {
729  if (addr->ss_family == AF_INET) {
730  reinterpret_cast<sockaddr_in *>(addr)->sin_port = port;
731  } else if (addr->ss_family == AF_INET6) {
732  reinterpret_cast<sockaddr_in6 *>(addr)->sin6_port = port;
733  }
734 }
735 
736 bool operator<(const sockaddr_storage &left, const sockaddr_storage &right) {
737  if (left.ss_family == AF_INET) {
738  throw std::runtime_error("IPv4 addresses are not supported");
739  }
740  const unsigned char *left_addr = reinterpret_cast<const sockaddr_in6 *>(&left)->sin6_addr.s6_addr; // NOLINT
741  const unsigned char *right_addr = reinterpret_cast<const sockaddr_in6 *>(&right)->sin6_addr.s6_addr; // NOLINT
742  int res = memcmp(left_addr, right_addr, 16);
743 
744  return (res < 0);
745 }
Definition: common.h:20