1 #include "utilities/utils.h" 16 #include <archive_entry.h> 17 #include <arpa/inet.h> 21 #include <netinet/in.h> 23 #include <sys/types.h> 25 #include <boost/algorithm/string.hpp> 26 #include <boost/archive/iterators/base64_from_binary.hpp> 27 #include <boost/archive/iterators/binary_from_base64.hpp> 28 #include <boost/archive/iterators/remove_whitespace.hpp> 29 #include <boost/archive/iterators/transform_width.hpp> 30 #include <boost/filesystem.hpp> 31 #include <boost/uuid/random_generator.hpp> 32 #include <boost/uuid/uuid_io.hpp> 34 #include "aktualizr_version.h" 35 #include "logging/logging.h" 37 static const std::array<const char *, 132> adverbs = {
38 "adorable",
"acidic",
"ample",
"aromatic",
"artistic",
"attractive",
"basic",
"beautiful",
39 "best",
"blissful",
"bubbly",
"celebrated",
"cheap",
"chilly",
"cloudy",
"colorful",
40 "colossal",
"complete",
"conventional",
"costly",
"creamy",
"crisp",
"dense",
"double",
41 "dry",
"easy",
"every",
"exotic",
"expert",
"fake",
"fabulous",
"fast",
42 "fine",
"firm",
"first",
"flaky",
"flat",
"fluffy",
"frozen",
"generous",
43 "giant",
"glass",
"glorious",
"golden",
"good",
"grand",
"great",
"half",
44 "happy",
"hard",
"healthy",
"heavy",
"hot",
"huge",
"humble",
"ideal",
45 "icy",
"incredible",
"interesting",
"joyous",
"juicy",
"jumbo",
"large",
"late",
46 "lavish",
"leafy",
"lean",
"light",
"lovely",
"marvelous",
"mature",
"modern",
47 "modest",
"neat",
"new",
"nice",
"nifty",
"nutty",
"oily",
"ornate",
48 "perfect",
"plain",
"posh",
"pretty",
"prime",
"proper",
"pure",
"quick",
49 "raw",
"real",
"rich",
"ripe",
"safe",
"salty",
"several",
"short",
50 "simple",
"slim",
"slow",
"smooth",
"soft",
"solid",
"speedy",
"spotless",
51 "strong",
"stylish",
"subtle",
"super",
"sweet",
"tasty",
"tempting",
"tender",
52 "terrific",
"thick",
"thin",
"tidy",
"tiny",
"twin",
"ultimate",
"unique",
53 "uniform",
"unusual",
"valuable",
"vast",
"warm",
"wavy",
"wet",
"whole",
54 "wide",
"wild",
"wooden",
"young"};
56 static const std::array<const char *, 128> names = {
"Allerlei",
142 "Prinzregententorte",
164 "Sonnenblumenkernbrot",
185 typedef boost::archive::iterators::base64_from_binary<
186 boost::archive::iterators::transform_width<std::string::const_iterator, 6, 8> >
189 typedef boost::archive::iterators::transform_width<
190 boost::archive::iterators::binary_from_base64<
191 boost::archive::iterators::remove_whitespace<std::string::const_iterator> >,
195 std::string Utils::fromBase64(std::string base64_string) {
196 int64_t paddingChars = std::count(base64_string.begin(), base64_string.end(),
'=');
197 std::replace(base64_string.begin(), base64_string.end(),
'=',
'A');
198 std::string
result(base64_to_bin(base64_string.begin()), base64_to_bin(base64_string.end()));
203 std::string Utils::toBase64(
const std::string &tob64) {
204 std::string b64sig(base64_text(tob64.begin()), base64_text(tob64.end()));
205 b64sig.append((3 - tob64.length() % 3) % 3,
'=');
210 std::string Utils::stripQuotes(
const std::string &value) {
211 std::string res = value;
212 res.erase(std::remove(res.begin(), res.end(),
'\"'), res.end());
217 std::string Utils::addQuotes(
const std::string &value) {
return "\"" + value +
"\""; }
219 std::string Utils::extractField(
const std::string &in,
unsigned int field_id) {
221 auto it = in.begin();
224 for (; it != in.end() && (isspace(*it) != 0); it++) {
227 for (
unsigned int k = 0; k < field_id; k++) {
229 for (; it != in.end() && (isspace(*it) == 0); it++) {
233 throw std::runtime_error(std::string(
"No such field ").append(std::to_string(field_id)));
235 for (; it != in.end() && (isspace(*it) != 0); it++) {
240 for (; it != in.end() && (isspace(*it) == 0); it++) {
246 Json::Value Utils::parseJSON(
const std::string &json_str) {
247 std::istringstream strs(json_str);
248 Json::Value json_value;
249 parseFromStream(Json::CharReaderBuilder(), strs, &json_value,
nullptr);
253 Json::Value Utils::parseJSONFile(
const boost::filesystem::path &filename) {
254 std::ifstream path_stream(filename.c_str());
255 std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
256 return Utils::parseJSON(content);
259 std::string Utils::genPrettyName() {
260 std::random_device urandom;
262 std::uniform_int_distribution<size_t> adverbs_dist(0, adverbs.size() - 1);
263 std::uniform_int_distribution<size_t> nouns_dist(0, names.size() - 1);
264 std::uniform_int_distribution<size_t> digits(0, 999);
265 std::stringstream pretty_name;
266 pretty_name << adverbs[adverbs_dist(urandom)];
268 pretty_name << names[nouns_dist(urandom)];
270 pretty_name << digits(urandom);
271 std::string res = pretty_name.str();
272 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
276 std::string Utils::readFile(
const boost::filesystem::path &filename,
const bool trim) {
277 boost::filesystem::path tmpFilename = filename;
278 tmpFilename +=
".new";
283 if (boost::filesystem::exists(tmpFilename)) {
284 LOG_WARNING << tmpFilename <<
" was found on FS, removing";
285 boost::filesystem::remove(tmpFilename);
287 std::ifstream path_stream(filename.c_str());
288 std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
291 boost::trim_if(content, boost::is_any_of(
" \t\r\n"));
296 static constexpr
size_t BSIZE = 20 * 512;
301 std::array<char, BSIZE> buf{};
304 static ssize_t read_cb(
struct archive *a,
void *client_data,
const void **buffer) {
307 archive_set_error(a, -1,
"unable to read from stream");
313 s->is.read(s->buf.data(), BSIZE);
314 if (!s->is.eof() && s->is.fail()) {
315 archive_set_error(a, -1,
"unable to read from stream");
318 *buffer = s->buf.data();
320 return s->is.gcount();
323 void Utils::writeFile(
const boost::filesystem::path &filename,
const std::string &content,
bool create_directories) {
324 if (create_directories) {
325 boost::filesystem::create_directories(filename.parent_path());
327 Utils::writeFile(filename, content.c_str(), content.size());
330 void Utils::writeFile(
const boost::filesystem::path &filename,
const char *content,
size_t size) {
333 boost::filesystem::path tmpFilename = filename;
334 tmpFilename +=
".new";
336 std::ofstream file(tmpFilename.c_str());
338 throw std::runtime_error(std::string(
"Error opening file ") + tmpFilename.string());
340 file.write(content, static_cast<std::streamsize>(size));
343 boost::filesystem::rename(tmpFilename, filename);
346 void Utils::writeFile(
const boost::filesystem::path &filename,
const Json::Value &content,
bool create_directories) {
347 Utils::writeFile(filename, jsonToStr(content), create_directories);
350 std::string Utils::jsonToStr(
const Json::Value &json) {
351 std::stringstream ss;
356 std::string Utils::jsonToCanonicalStr(
const Json::Value &json) {
357 static Json::StreamWriterBuilder wbuilder = []() {
358 Json::StreamWriterBuilder w;
359 wbuilder[
"indentation"] =
"";
362 return Json::writeString(wbuilder, json);
365 Json::Value Utils::getHardwareInfo() {
367 const int exit_code = shell(
"lshw -json", &result);
369 if (exit_code != 0) {
370 LOG_WARNING <<
"Could not execute lshw (is it installed?).";
371 return Json::Value();
373 const Json::Value parsed = Utils::parseJSON(result);
374 return (parsed.isArray()) ? parsed[0] : parsed;
377 Json::Value Utils::getNetworkInfo() {
379 std::ifstream path_stream(
"/proc/net/route");
380 std::string route_content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
383 std::string name = std::string();
384 std::string ip = std::string();
385 std::string mac = std::string();
387 std::istringstream route_stream(route_content);
388 std::array<char, 200> line{};
391 route_stream.getline(&line[0], line.size());
392 while (route_stream.getline(&line[0], line.size())) {
393 std::string itfn = Utils::extractField(&line[0], 0);
394 std::string droute = Utils::extractField(&line[0], 1);
395 if (droute ==
"00000000") {
402 if (itf.name !=
"") {
405 StructGuard<struct ifaddrs> ifaddrs(
nullptr, freeifaddrs);
408 if (getifaddrs(&ifa) < 0) {
409 LOG_ERROR <<
"getifaddrs: " << std::strerror(errno);
414 if (ifaddrs !=
nullptr) {
415 for (
struct ifaddrs *ifa = ifaddrs.get(); ifa !=
nullptr; ifa = ifa->ifa_next) {
416 if (itf.name == ifa->ifa_name) {
417 if (ifa->ifa_addr ==
nullptr) {
420 if (ifa->ifa_addr->sa_family != AF_INET) {
423 const struct sockaddr_storage *sa =
reinterpret_cast<struct sockaddr_storage *
>(ifa->ifa_addr);
425 itf.ip = Utils::ipDisplayName(*sa);
432 std::ifstream mac_stream(
"/sys/class/net/" + itf.name +
"/address");
433 std::string m((std::istreambuf_iterator<char>(mac_stream)), std::istreambuf_iterator<char>());
434 itf.mac = std::move(m);
435 boost::trim_right(itf.mac);
439 Json::Value network_info;
440 network_info[
"local_ipv4"] = itf.ip;
441 network_info[
"mac"] = itf.mac;
442 network_info[
"hostname"] = Utils::getHostname();
447 std::string Utils::getHostname() {
448 std::array<char, 200> hostname{};
449 if (gethostname(hostname.data(), hostname.size()) < 0) {
452 return std::string(hostname.data());
455 std::string Utils::randomUuid() {
456 std::random_device urandom;
457 boost::uuids::basic_random_generator<std::random_device> uuid_gen(urandom);
458 return boost::uuids::to_string(uuid_gen());
462 void Utils::copyDir(
const boost::filesystem::path &from,
const boost::filesystem::path &to) {
463 boost::filesystem::remove_all(to);
465 boost::filesystem::create_directories(to);
466 boost::filesystem::directory_iterator it(from);
468 for (; it != boost::filesystem::directory_iterator(); it++) {
469 if (boost::filesystem::is_directory(it->path())) {
470 copyDir(it->path(), to / it->path().filename());
472 boost::filesystem::copy_file(it->path(), to / it->path().filename());
477 std::string Utils::readFileFromArchive(std::istream &as,
const std::string &filename,
const bool trim) {
478 StructGuardInt<struct archive> a(archive_read_new(), archive_read_free);
480 LOG_ERROR <<
"archive error: could not initialize archive object";
481 throw std::runtime_error(
"archive error");
483 archive_read_support_filter_all(a.get());
484 archive_read_support_format_all(a.get());
485 auto state = std_::make_unique<archive_state>(std::ref(as));
486 int r = archive_read_open(a.get(),
reinterpret_cast<void *
>(state.get()),
nullptr, read_cb,
nullptr);
487 if (r != ARCHIVE_OK) {
488 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
489 throw std::runtime_error(
"archive error");
493 std::stringstream out_stream;
494 struct archive_entry *entry;
495 while (archive_read_next_header(a.get(), &entry) == ARCHIVE_OK) {
496 if (filename != archive_entry_pathname(entry)) {
497 archive_read_data_skip(a.get());
506 r = archive_read_data_block(a.get(),
reinterpret_cast<const void **
>(&buff), &size, &offset);
507 if (r == ARCHIVE_EOF) {
510 }
else if (r != ARCHIVE_OK) {
511 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
514 if (size > 0 && buff !=
nullptr) {
515 out_stream.write(buff, static_cast<ssize_t>(size));
520 r = archive_read_close(a.get());
521 if (r != ARCHIVE_OK) {
522 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
526 throw std::runtime_error(
"could not extract " + filename +
" from archive");
529 std::string
result = out_stream.str();
531 boost::trim_if(result, boost::is_any_of(
" \t\r\n"));
536 static ssize_t write_cb(
struct archive *a,
void *client_data,
const void *buffer,
size_t length) {
537 auto *s =
reinterpret_cast<std::ostream *
>(client_data);
538 s->write(reinterpret_cast<const char *>(buffer), static_cast<ssize_t>(length));
540 archive_set_error(a, -1,
"unable to write in stream");
544 return static_cast<ssize_t
>(length);
547 void Utils::writeArchive(
const std::map<std::string, std::string> &entries, std::ostream &as) {
548 StructGuardInt<struct archive> a(archive_write_new(), archive_write_free);
550 LOG_ERROR <<
"archive error: could not initialize archive object";
551 throw std::runtime_error(
"archive error");
553 archive_write_set_format_pax(a.get());
554 archive_write_add_filter_gzip(a.get());
556 int r = archive_write_open(a.get(),
reinterpret_cast<void *
>(&as),
nullptr, write_cb,
nullptr);
557 if (r != ARCHIVE_OK) {
558 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
559 throw std::runtime_error(
"archive error");
562 StructGuard<struct archive_entry> entry(archive_entry_new(), archive_entry_free);
563 for (
const auto &el : entries) {
564 archive_entry_clear(entry.get());
565 archive_entry_set_filetype(entry.get(), AE_IFREG);
566 archive_entry_set_perm(entry.get(), S_IRWXU | S_IRWXG | S_IRWXO);
567 archive_entry_set_size(entry.get(),
static_cast<ssize_t
>(el.second.size()));
568 archive_entry_set_pathname(entry.get(), el.first.c_str());
569 if (archive_write_header(a.get(), entry.get()) != 0) {
570 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
571 throw std::runtime_error(
"archive error");
573 if (archive_write_data(a.get(), el.second.c_str(), el.second.size()) < 0) {
574 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
575 throw std::runtime_error(
"archive error");
578 r = archive_write_close(a.get());
579 if (r != ARCHIVE_OK) {
580 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
588 void Utils::removeFileFromArchive(
const boost::filesystem::path &archive_path,
const std::string &filename) {
589 std::ifstream as_in(archive_path.c_str(), std::ios::in | std::ios::binary);
591 LOG_ERROR <<
"Unable to open provided provisioning archive " << archive_path <<
": " << std::strerror(errno);
592 throw std::runtime_error(
"Unable to parse provisioning credentials");
594 const boost::filesystem::path outfile = archive_path.string() +
"-" + boost::filesystem::unique_path().string();
595 std::ofstream as_out(outfile.c_str(), std::ios::out | std::ios::binary);
597 LOG_ERROR <<
"Unable to create file " << outfile <<
": " << std::strerror(errno);
598 throw std::runtime_error(
"Unable to parse provisioning credentials");
601 StructGuardInt<struct archive> a_in(archive_read_new(), archive_read_free);
602 if (a_in ==
nullptr) {
603 LOG_ERROR <<
"archive error: could not initialize archive object";
604 throw std::runtime_error(
"archive error");
606 archive_read_support_filter_all(a_in.get());
607 archive_read_support_format_all(a_in.get());
608 auto state = std_::make_unique<archive_state>(std::ref(as_in));
609 int r = archive_read_open(a_in.get(),
reinterpret_cast<void *
>(state.get()),
nullptr, read_cb,
nullptr);
610 if (r != ARCHIVE_OK) {
611 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
612 throw std::runtime_error(
"archive error");
615 StructGuardInt<struct archive> a_out(archive_write_new(), archive_write_free);
616 if (a_out ==
nullptr) {
617 LOG_ERROR <<
"archive error: could not initialize archive object";
618 throw std::runtime_error(
"archive error");
620 archive_write_set_format_zip(a_out.get());
621 r = archive_write_open(a_out.get(),
reinterpret_cast<void *
>(&as_out),
nullptr, write_cb,
nullptr);
622 if (r != ARCHIVE_OK) {
623 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
624 throw std::runtime_error(
"archive error");
628 struct archive_entry *entry_in;
629 while (archive_read_next_header(a_in.get(), &entry_in) == ARCHIVE_OK) {
630 const char *entry_name = archive_entry_pathname(entry_in);
631 if (filename == entry_name) {
632 archive_read_data_skip(a_in.get());
637 StructGuard<struct archive_entry> entry_out(archive_entry_new(), archive_entry_free);
638 const struct stat *entry_stat = archive_entry_stat(entry_in);
639 archive_entry_copy_stat(entry_out.get(), entry_stat);
640 archive_entry_set_pathname(entry_out.get(), entry_name);
641 if (archive_write_header(a_out.get(), entry_out.get()) != 0) {
642 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
643 throw std::runtime_error(
"archive error");
651 r = archive_read_data_block(a_in.get(),
reinterpret_cast<const void **
>(&buff), &size, &offset);
652 if (r == ARCHIVE_EOF) {
654 }
else if (r != ARCHIVE_OK) {
655 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
658 if (size > 0 && buff !=
nullptr) {
659 if (archive_write_data(a_out.get(), buff, size) < 0) {
660 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
661 throw std::runtime_error(
"archive error");
667 r = archive_read_close(a_in.get());
668 if (r != ARCHIVE_OK) {
669 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
672 r = archive_write_close(a_out.get());
673 if (r != ARCHIVE_OK) {
674 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
678 boost::filesystem::rename(outfile, archive_path);
680 boost::filesystem::remove(outfile);
681 throw std::runtime_error(
"Requested file not found in archive!");
685 sockaddr_storage Utils::ipGetSockaddr(
int fd) {
686 sockaddr_storage ss{};
687 socklen_t len =
sizeof(ss);
688 if (getsockname(fd, reinterpret_cast<sockaddr *>(&ss), &len) < 0) {
689 throw std::runtime_error(std::string(
"Could not get sockaddr: ") + std::strerror(errno));
695 std::string Utils::ipDisplayName(
const sockaddr_storage &saddr) {
696 std::array<char, INET6_ADDRSTRLEN> ipstr{};
698 switch (saddr.ss_family) {
700 const auto *sa =
reinterpret_cast<const sockaddr_in *
>(&saddr);
701 inet_ntop(AF_INET, &sa->sin_addr, ipstr.data(), ipstr.size());
702 return std::string(ipstr.data());
705 const auto *sa =
reinterpret_cast<const sockaddr_in6 *
>(&saddr);
706 inet_ntop(AF_INET6, &sa->sin6_addr, ipstr.data(), ipstr.size());
707 return std::string(ipstr.data());
714 int Utils::ipPort(
const sockaddr_storage &saddr) {
716 if (saddr.ss_family == AF_INET) {
717 const auto *sa =
reinterpret_cast<const sockaddr_in *
>(&saddr);
719 }
else if (saddr.ss_family == AF_INET6) {
720 const auto *sa =
reinterpret_cast<const sockaddr_in6 *
>(&saddr);
729 int Utils::shell(
const std::string &command, std::string *output,
bool include_stderr) {
730 std::array<char, 128> buffer{};
731 std::string full_command(command);
732 if (include_stderr) {
733 full_command +=
" 2>&1";
735 FILE *pipe = popen(full_command.c_str(),
"r");
736 if (pipe ==
nullptr) {
737 *output =
"popen() failed!";
740 while (feof(pipe) == 0) {
741 if (fgets(buffer.data(), buffer.size(), pipe) !=
nullptr) {
742 *output += buffer.data();
745 int exitcode = pclose(pipe);
746 return WEXITSTATUS(exitcode);
749 boost::filesystem::path Utils::absolutePath(
const boost::filesystem::path &root,
const boost::filesystem::path &file) {
750 if (file.is_absolute() || root.empty()) {
753 return (root / file);
758 std::vector<boost::filesystem::path> Utils::getDirEntriesByExt(
const boost::filesystem::path &dir_path,
759 const std::string &ext) {
760 std::vector<boost::filesystem::path> entries;
761 boost::filesystem::directory_iterator entryItEnd;
762 boost::filesystem::directory_iterator entryIt(dir_path);
763 for (; entryIt != entryItEnd; ++entryIt) {
764 const auto &entry_path = entryIt->path();
765 if (!boost::filesystem::is_directory(*entryIt) && entry_path.extension().string() == ext) {
766 entries.push_back(entry_path);
769 std::sort(entries.begin(), entries.end());
773 void Utils::createDirectories(
const boost::filesystem::path &path, mode_t mode) {
774 boost::filesystem::path parent = path.parent_path();
775 if (!parent.empty() && !boost::filesystem::exists(parent)) {
776 Utils::createDirectories(parent, mode);
778 if (mkdir(path.c_str(), mode) == -1) {
779 throw std::runtime_error(std::string(
"could not create directory: ").append(path.native()));
781 std::cout <<
"created: " << path.native() <<
"\n";
784 bool Utils::createSecureDirectory(
const boost::filesystem::path &path) {
785 if (mkdir(path.c_str(), S_IRWXU) == 0) {
792 int ret = stat(path.c_str(), &st);
797 return (ret >= 0 && ((st.st_mode & S_IFDIR) == S_IFDIR) && (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == S_IRWXU &&
798 (st.st_uid == getuid()));
801 std::string Utils::urlEncode(
const std::string &input) {
804 for (
char c : input) {
805 if ((c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' ||
806 c ==
'_' || c ==
'~' || c ==
'/') {
810 auto nib =
static_cast<char>(((c >> 4) & 0x0F));
811 res.push_back(static_cast<char>((nib < 10) ? nib +
'0' : nib - 10 +
'A'));
812 nib =
static_cast<char>(c & 0x0F);
813 res.push_back(static_cast<char>((nib < 10) ? nib +
'0' : nib - 10 +
'A'));
819 CURL *Utils::curlDupHandleWrapper(CURL *
const curl_in,
const bool using_pkcs11) {
820 CURL *curl = curl_easy_duphandle(curl_in);
827 curlEasySetoptWrapper(curl, CURLOPT_SSLENGINE,
"pkcs11");
838 static boost::filesystem::path &Get() {
846 boost::filesystem::path prefix = Utils::getStorageRootPath();
847 if (prefix.empty()) {
848 prefix = boost::filesystem::temp_directory_path();
850 boost::filesystem::path p = prefix / boost::filesystem::unique_path(
"aktualizr-%%%%-%%%%-%%%%-%%%%");
851 if (mkdir(p.c_str(), S_IRWXU) == -1) {
852 throw std::runtime_error(std::string(
"could not create temporary directory root: ").append(p.native()));
855 path = boost::filesystem::path(p);
859 boost::filesystem::remove_all(path);
865 boost::filesystem::path path;
868 std::string Utils::storage_root_path_;
870 void Utils::setStorageRootPath(
const std::string &storage_root_path) { storage_root_path_ = storage_root_path; }
872 boost::filesystem::path Utils::getStorageRootPath() {
return storage_root_path_; }
874 void Utils::setUserAgent(std::string user_agent) { user_agent_ = std::move(user_agent); }
876 const char *Utils::getUserAgent() {
877 if (user_agent_.empty()) {
878 user_agent_ = (std::string(
"Aktualizr/") + aktualizr_version());
880 return user_agent_.c_str();
883 std::string Utils::user_agent_;
885 void Utils::setCaPath(boost::filesystem::path path) { ca_path_ = std::move(path); }
887 const char *Utils::getCaPath() {
return ca_path_.c_str(); }
889 boost::filesystem::path Utils::ca_path_{
"/etc/ssl/certs"};
891 TemporaryFile::TemporaryFile(
const std::string &hint)
892 : tmp_name_(SafeTempRoot::Get() / boost::filesystem::unique_path(std::string(
"%%%%-%%%%-").append(hint))) {}
894 TemporaryFile::~TemporaryFile() { boost::filesystem::remove(tmp_name_); }
896 void TemporaryFile::PutContents(
const std::string &contents)
const {
897 mode_t mode = S_IRUSR | S_IWUSR;
898 int fd = open(Path().c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
900 throw std::runtime_error(std::string(
"Could not write content to file: ") + Path().
string() +
": " +
901 std::strerror(errno));
903 ssize_t written = write(fd, contents.c_str(), contents.size());
905 if (written < 0 || static_cast<size_t>(written) != contents.size()) {
906 throw std::runtime_error(std::string(
"Could not write content to file: ") + Path().
string());
910 boost::filesystem::path TemporaryFile::Path()
const {
return tmp_name_; }
912 std::string TemporaryFile::PathString()
const {
return Path().string(); }
914 TemporaryDirectory::TemporaryDirectory(
const std::string &hint)
915 : tmp_name_(SafeTempRoot::Get() / boost::filesystem::unique_path(std::string(
"%%%%-%%%%-").append(hint))) {
916 Utils::createDirectories(tmp_name_, S_IRWXU);
919 TemporaryDirectory::~TemporaryDirectory() { boost::filesystem::remove_all(tmp_name_); }
921 boost::filesystem::path TemporaryDirectory::Path()
const {
return tmp_name_; }
923 boost::filesystem::path TemporaryDirectory::operator/(
const boost::filesystem::path &subdir)
const {
924 return (tmp_name_ / subdir);
927 std::string TemporaryDirectory::PathString()
const {
return Path().string(); }
930 socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
931 if (-1 == socket_fd_) {
932 throw std::system_error(errno, std::system_category(),
"socket");
936 Socket::~Socket() { ::close(socket_fd_); }
938 std::string Socket::toString()
const {
939 auto saddr = Utils::ipGetSockaddr(socket_fd_);
940 return Utils::ipDisplayName(saddr) +
":" + std::to_string(Utils::ipPort(saddr));
943 void Socket::bind(in_port_t port,
bool reuse)
const {
945 memset(&sa, 0,
sizeof(sa));
946 sa.sin_family = AF_INET;
947 sa.sin_port = htons(port);
948 sa.sin_addr.s_addr = htonl(INADDR_ANY);
950 int reuseaddr = reuse ? 1 : 0;
951 if (-1 == setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(reuseaddr))) {
952 throw std::system_error(errno, std::system_category(),
"socket");
955 if (-1 == ::bind(socket_fd_, reinterpret_cast<const sockaddr *>(&sa),
sizeof(sa))) {
956 throw std::system_error(errno, std::system_category(),
"socket");
960 ListenSocket::ListenSocket(in_port_t port) : _port(port) {
964 auto ephemeral_port = Utils::ipPort(Utils::ipGetSockaddr(socket_fd_));
965 if (-1 != ephemeral_port) {
966 _port =
static_cast<in_port_t
>(ephemeral_port);
971 ConnectionSocket::ConnectionSocket(
const std::string &ip, in_port_t port, in_port_t bind_port)
972 : remote_sock_address_{} {
973 memset(&remote_sock_address_, 0,
sizeof(remote_sock_address_));
974 remote_sock_address_.sin_family = AF_INET;
975 if (-1 == inet_pton(AF_INET, ip.c_str(), &(remote_sock_address_.sin_addr))) {
976 throw std::system_error(errno, std::system_category(),
"socket");
978 remote_sock_address_.sin_port = htons(port);
985 ConnectionSocket::~ConnectionSocket() { ::shutdown(socket_fd_, SHUT_RDWR); }
987 int ConnectionSocket::connect() {
988 return ::connect(socket_fd_, reinterpret_cast<const struct sockaddr *>(&remote_sock_address_),
989 sizeof(remote_sock_address_));
992 CurlEasyWrapper::CurlEasyWrapper() {
993 handle = curl_easy_init();
994 if (handle ==
nullptr) {
995 throw std::runtime_error(
"Could not initialize curl handle");
997 curlEasySetoptWrapper(handle, CURLOPT_USERAGENT, Utils::getUserAgent());
1000 CurlEasyWrapper::~CurlEasyWrapper() {
1001 if (handle !=
nullptr) {
1002 curl_easy_cleanup(handle);
Results of libaktualizr API calls.