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 using base64_text = boost::archive::iterators::base64_from_binary<
186 boost::archive::iterators::transform_width<std::string::const_iterator, 6, 8> >;
188 using base64_to_bin = boost::archive::iterators::transform_width<
189 boost::archive::iterators::binary_from_base64<
190 boost::archive::iterators::remove_whitespace<std::string::const_iterator> >,
193 std::string Utils::fromBase64(std::string base64_string) {
194 int64_t paddingChars = std::count(base64_string.begin(), base64_string.end(),
'=');
195 std::replace(base64_string.begin(), base64_string.end(),
'=',
'A');
196 std::string
result(base64_to_bin(base64_string.begin()), base64_to_bin(base64_string.end()));
201 std::string Utils::toBase64(
const std::string &tob64) {
202 std::string b64sig(base64_text(tob64.begin()), base64_text(tob64.end()));
203 b64sig.append((3 - tob64.length() % 3) % 3,
'=');
208 std::string Utils::stripQuotes(
const std::string &value) {
209 std::string res = value;
210 res.erase(std::remove(res.begin(), res.end(),
'\"'), res.end());
215 std::string Utils::addQuotes(
const std::string &value) {
return "\"" + value +
"\""; }
217 std::string Utils::extractField(
const std::string &in,
unsigned int field_id) {
219 auto it = in.begin();
222 for (; it != in.end() && (isspace(*it) != 0); it++) {
225 for (
unsigned int k = 0; k < field_id; k++) {
227 for (; it != in.end() && (isspace(*it) == 0); it++) {
231 throw std::runtime_error(std::string(
"No such field ").append(std::to_string(field_id)));
233 for (; it != in.end() && (isspace(*it) != 0); it++) {
238 for (; it != in.end() && (isspace(*it) == 0); it++) {
244 Json::Value Utils::parseJSON(
const std::string &json_str) {
245 std::istringstream strs(json_str);
246 Json::Value json_value;
247 parseFromStream(Json::CharReaderBuilder(), strs, &json_value,
nullptr);
251 Json::Value Utils::parseJSONFile(
const boost::filesystem::path &filename) {
252 std::ifstream path_stream(filename.c_str());
253 std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
254 return Utils::parseJSON(content);
257 std::string Utils::genPrettyName() {
258 std::random_device urandom;
260 std::uniform_int_distribution<size_t> adverbs_dist(0, adverbs.size() - 1);
261 std::uniform_int_distribution<size_t> nouns_dist(0, names.size() - 1);
262 std::uniform_int_distribution<size_t> digits(0, 999);
263 std::stringstream pretty_name;
264 pretty_name << adverbs.at(adverbs_dist(urandom));
266 pretty_name << names.at(nouns_dist(urandom));
268 pretty_name << digits(urandom);
269 std::string res = pretty_name.str();
270 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
274 std::string Utils::readFile(
const boost::filesystem::path &filename,
const bool trim) {
275 boost::filesystem::path tmpFilename = filename;
276 tmpFilename +=
".new";
278 if (boost::filesystem::exists(tmpFilename)) {
279 LOG_WARNING << tmpFilename <<
" was found on FS, removing";
280 boost::filesystem::remove(tmpFilename);
282 std::ifstream path_stream(filename.c_str());
283 std::string content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
286 boost::trim_if(content, boost::is_any_of(
" \t\r\n"));
291 static constexpr
size_t BSIZE = 20 * 512;
297 std::array<char, BSIZE> buf{};
300 static ssize_t read_cb(
struct archive *a,
void *client_data,
const void **buffer) {
303 archive_set_error(a, -1,
"unable to read from stream");
309 s->is.read(s->buf.data(), BSIZE);
310 if (!s->is.eof() && s->is.fail()) {
311 archive_set_error(a, -1,
"unable to read from stream");
314 *buffer = s->buf.data();
316 return s->is.gcount();
319 void Utils::writeFile(
const boost::filesystem::path &filename,
const std::string &content,
bool create_directories) {
320 if (create_directories) {
321 boost::filesystem::create_directories(filename.parent_path());
323 Utils::writeFile(filename, content.c_str(), content.size());
326 void Utils::writeFile(
const boost::filesystem::path &filename,
const char *content,
size_t size) {
329 boost::filesystem::path tmpFilename = filename;
330 tmpFilename +=
".new";
332 std::ofstream file(tmpFilename.c_str());
334 throw std::runtime_error(std::string(
"Error opening file ") + tmpFilename.string());
336 file.write(content,
static_cast<std::streamsize
>(size));
339 boost::filesystem::rename(tmpFilename, filename);
342 void Utils::writeFile(
const boost::filesystem::path &filename,
const Json::Value &content,
bool create_directories) {
343 Utils::writeFile(filename, jsonToStr(content), create_directories);
346 std::string Utils::jsonToStr(
const Json::Value &json) {
347 std::stringstream ss;
352 std::string Utils::jsonToCanonicalStr(
const Json::Value &json) {
353 static Json::StreamWriterBuilder wbuilder = []() {
354 Json::StreamWriterBuilder w;
355 wbuilder[
"indentation"] =
"";
358 return Json::writeString(wbuilder, json);
361 Json::Value Utils::getHardwareInfo() {
363 const int exit_code = shell(
"lshw -json", &
result);
365 if (exit_code != 0) {
366 LOG_WARNING <<
"Could not execute lshw (is it installed?).";
367 return Json::Value();
369 const Json::Value parsed = Utils::parseJSON(
result);
370 return (parsed.isArray()) ? parsed[0] : parsed;
373 Json::Value Utils::getNetworkInfo() {
375 std::ifstream path_stream(
"/proc/net/route");
376 std::string route_content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
379 std::string name = std::string();
380 std::string ip = std::string();
381 std::string mac = std::string();
383 std::istringstream route_stream(route_content);
384 std::array<char, 200> line{};
387 route_stream.getline(&line[0], line.size());
388 while (route_stream.getline(&line[0], line.size())) {
389 std::string itfn = Utils::extractField(&line[0], 0);
390 std::string droute = Utils::extractField(&line[0], 1);
391 if (droute ==
"00000000") {
398 if (!itf.name.empty()) {
401 StructGuard<struct ifaddrs> ifaddrs(
nullptr, freeifaddrs);
404 if (getifaddrs(&ifa) < 0) {
405 LOG_ERROR <<
"getifaddrs: " << std::strerror(errno);
410 if (ifaddrs !=
nullptr) {
411 for (
struct ifaddrs *ifa = ifaddrs.get(); ifa !=
nullptr; ifa = ifa->ifa_next) {
412 if (itf.name == ifa->ifa_name) {
413 if (ifa->ifa_addr ==
nullptr) {
416 if (ifa->ifa_addr->sa_family != AF_INET) {
419 const struct sockaddr_storage *sa =
reinterpret_cast<struct sockaddr_storage *
>(ifa->ifa_addr);
421 itf.ip = Utils::ipDisplayName(*sa);
428 std::ifstream mac_stream(
"/sys/class/net/" + itf.name +
"/address");
429 std::string m((std::istreambuf_iterator<char>(mac_stream)), std::istreambuf_iterator<char>());
430 itf.mac = std::move(m);
431 boost::trim_right(itf.mac);
435 Json::Value network_info;
436 network_info[
"local_ipv4"] = itf.ip;
437 network_info[
"mac"] = itf.mac;
438 network_info[
"hostname"] = Utils::getHostname();
443 std::string Utils::getHostname() {
444 std::array<char, 200> hostname{};
445 if (gethostname(hostname.data(), hostname.size()) < 0) {
448 return std::string(hostname.data());
451 std::string Utils::randomUuid() {
452 std::random_device urandom;
453 boost::uuids::basic_random_generator<std::random_device> uuid_gen(urandom);
454 return boost::uuids::to_string(uuid_gen());
458 void Utils::copyDir(
const boost::filesystem::path &from,
const boost::filesystem::path &to) {
459 boost::filesystem::remove_all(to);
461 boost::filesystem::create_directories(to);
462 boost::filesystem::directory_iterator it(from);
464 for (; it != boost::filesystem::directory_iterator(); it++) {
465 if (boost::filesystem::is_directory(it->path())) {
466 copyDir(it->path(), to / it->path().filename());
468 boost::filesystem::copy_file(it->path(), to / it->path().filename());
473 std::string Utils::readFileFromArchive(std::istream &as,
const std::string &filename,
const bool trim) {
474 StructGuardInt<struct archive> a(archive_read_new(), archive_read_free);
476 LOG_ERROR <<
"archive error: could not initialize archive object";
477 throw std::runtime_error(
"archive error");
479 archive_read_support_filter_all(a.get());
480 archive_read_support_format_all(a.get());
481 auto state = std_::make_unique<archive_state>(std::ref(as));
482 int r = archive_read_open(a.get(),
reinterpret_cast<void *
>(state.get()),
nullptr, read_cb,
nullptr);
483 if (r != ARCHIVE_OK) {
484 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
485 throw std::runtime_error(
"archive error");
489 std::stringstream out_stream;
490 struct archive_entry *entry;
491 while (archive_read_next_header(a.get(), &entry) == ARCHIVE_OK) {
492 if (filename != archive_entry_pathname(entry)) {
493 archive_read_data_skip(a.get());
502 r = archive_read_data_block(a.get(),
reinterpret_cast<const void **
>(&buff), &size, &offset);
503 if (r == ARCHIVE_EOF) {
506 }
else if (r != ARCHIVE_OK) {
507 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
510 if (size > 0 && buff !=
nullptr) {
511 out_stream.write(buff,
static_cast<ssize_t
>(size));
516 r = archive_read_close(a.get());
517 if (r != ARCHIVE_OK) {
518 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
522 throw std::runtime_error(
"could not extract " + filename +
" from archive");
525 std::string
result = out_stream.str();
527 boost::trim_if(
result, boost::is_any_of(
" \t\r\n"));
532 static ssize_t write_cb(
struct archive *a,
void *client_data,
const void *buffer,
size_t length) {
533 auto *s =
reinterpret_cast<std::ostream *
>(client_data);
534 s->write(
reinterpret_cast<const char *
>(buffer),
static_cast<ssize_t
>(length));
536 archive_set_error(a, -1,
"unable to write in stream");
540 return static_cast<ssize_t
>(length);
543 void Utils::writeArchive(
const std::map<std::string, std::string> &entries, std::ostream &as) {
544 StructGuardInt<struct archive> a(archive_write_new(), archive_write_free);
546 LOG_ERROR <<
"archive error: could not initialize archive object";
547 throw std::runtime_error(
"archive error");
549 archive_write_set_format_pax(a.get());
550 archive_write_add_filter_gzip(a.get());
552 int r = archive_write_open(a.get(),
reinterpret_cast<void *
>(&as),
nullptr, write_cb,
nullptr);
553 if (r != ARCHIVE_OK) {
554 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
555 throw std::runtime_error(
"archive error");
558 StructGuard<struct archive_entry> entry(archive_entry_new(), archive_entry_free);
559 for (
const auto &el : entries) {
560 archive_entry_clear(entry.get());
561 archive_entry_set_filetype(entry.get(), AE_IFREG);
562 archive_entry_set_perm(entry.get(), S_IRWXU | S_IRWXG | S_IRWXO);
563 archive_entry_set_size(entry.get(),
static_cast<ssize_t
>(el.second.size()));
564 archive_entry_set_pathname(entry.get(), el.first.c_str());
565 if (archive_write_header(a.get(), entry.get()) != 0) {
566 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
567 throw std::runtime_error(
"archive error");
569 if (archive_write_data(a.get(), el.second.c_str(), el.second.size()) < 0) {
570 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
571 throw std::runtime_error(
"archive error");
574 r = archive_write_close(a.get());
575 if (r != ARCHIVE_OK) {
576 LOG_ERROR <<
"archive error: " << archive_error_string(a.get());
584 void Utils::removeFileFromArchive(
const boost::filesystem::path &archive_path,
const std::string &filename) {
585 std::ifstream as_in(archive_path.c_str(), std::ios::in | std::ios::binary);
587 LOG_ERROR <<
"Unable to open provided provisioning archive " << archive_path <<
": " << std::strerror(errno);
588 throw std::runtime_error(
"Unable to parse provisioning credentials");
590 const boost::filesystem::path outfile = archive_path.string() +
"-" + boost::filesystem::unique_path().string();
591 std::ofstream as_out(outfile.c_str(), std::ios::out | std::ios::binary);
593 LOG_ERROR <<
"Unable to create file " << outfile <<
": " << std::strerror(errno);
594 throw std::runtime_error(
"Unable to parse provisioning credentials");
597 StructGuardInt<struct archive> a_in(archive_read_new(), archive_read_free);
598 if (a_in ==
nullptr) {
599 LOG_ERROR <<
"archive error: could not initialize archive object";
600 throw std::runtime_error(
"archive error");
602 archive_read_support_filter_all(a_in.get());
603 archive_read_support_format_all(a_in.get());
604 auto state = std_::make_unique<archive_state>(std::ref(as_in));
605 int r = archive_read_open(a_in.get(),
reinterpret_cast<void *
>(state.get()),
nullptr, read_cb,
nullptr);
606 if (r != ARCHIVE_OK) {
607 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
608 throw std::runtime_error(
"archive error");
611 StructGuardInt<struct archive> a_out(archive_write_new(), archive_write_free);
612 if (a_out ==
nullptr) {
613 LOG_ERROR <<
"archive error: could not initialize archive object";
614 throw std::runtime_error(
"archive error");
616 archive_write_set_format_zip(a_out.get());
617 r = archive_write_open(a_out.get(),
reinterpret_cast<void *
>(&as_out),
nullptr, write_cb,
nullptr);
618 if (r != ARCHIVE_OK) {
619 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
620 throw std::runtime_error(
"archive error");
624 struct archive_entry *entry_in;
625 while (archive_read_next_header(a_in.get(), &entry_in) == ARCHIVE_OK) {
626 const char *entry_name = archive_entry_pathname(entry_in);
627 if (filename == entry_name) {
628 archive_read_data_skip(a_in.get());
633 StructGuard<struct archive_entry> entry_out(archive_entry_new(), archive_entry_free);
634 const struct stat *entry_stat = archive_entry_stat(entry_in);
635 archive_entry_copy_stat(entry_out.get(), entry_stat);
636 archive_entry_set_pathname(entry_out.get(), entry_name);
637 if (archive_write_header(a_out.get(), entry_out.get()) != 0) {
638 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
639 throw std::runtime_error(
"archive error");
647 r = archive_read_data_block(a_in.get(),
reinterpret_cast<const void **
>(&buff), &size, &offset);
648 if (r == ARCHIVE_EOF) {
650 }
else if (r != ARCHIVE_OK) {
651 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
654 if (size > 0 && buff !=
nullptr) {
655 if (archive_write_data(a_out.get(), buff, size) < 0) {
656 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
657 throw std::runtime_error(
"archive error");
663 r = archive_read_close(a_in.get());
664 if (r != ARCHIVE_OK) {
665 LOG_ERROR <<
"archive error: " << archive_error_string(a_in.get());
668 r = archive_write_close(a_out.get());
669 if (r != ARCHIVE_OK) {
670 LOG_ERROR <<
"archive error: " << archive_error_string(a_out.get());
674 boost::filesystem::rename(outfile, archive_path);
676 boost::filesystem::remove(outfile);
677 throw std::runtime_error(
"Requested file not found in archive!");
681 sockaddr_storage Utils::ipGetSockaddr(
int fd) {
682 sockaddr_storage ss{};
683 socklen_t len =
sizeof(ss);
684 if (getsockname(fd,
reinterpret_cast<sockaddr *
>(&ss), &len) < 0) {
685 throw std::runtime_error(std::string(
"Could not get sockaddr: ") + std::strerror(errno));
691 std::string Utils::ipDisplayName(
const sockaddr_storage &saddr) {
692 std::array<char, INET6_ADDRSTRLEN> ipstr{};
694 switch (saddr.ss_family) {
696 const auto *sa =
reinterpret_cast<const sockaddr_in *
>(&saddr);
697 inet_ntop(AF_INET, &sa->sin_addr, ipstr.data(), ipstr.size());
698 return std::string(ipstr.data());
701 const auto *sa =
reinterpret_cast<const sockaddr_in6 *
>(&saddr);
702 inet_ntop(AF_INET6, &sa->sin6_addr, ipstr.data(), ipstr.size());
703 return std::string(ipstr.data());
710 int Utils::ipPort(
const sockaddr_storage &saddr) {
712 if (saddr.ss_family == AF_INET) {
713 const auto *sa =
reinterpret_cast<const sockaddr_in *
>(&saddr);
715 }
else if (saddr.ss_family == AF_INET6) {
716 const auto *sa =
reinterpret_cast<const sockaddr_in6 *
>(&saddr);
725 int Utils::shell(
const std::string &command, std::string *output,
bool include_stderr) {
726 std::array<char, 128> buffer{};
727 std::string full_command(command);
728 if (include_stderr) {
729 full_command +=
" 2>&1";
731 FILE *pipe = popen(full_command.c_str(),
"r");
732 if (pipe ==
nullptr) {
733 *output =
"popen() failed!";
736 while (feof(pipe) == 0) {
737 if (fgets(buffer.data(), buffer.size(), pipe) !=
nullptr) {
738 *output += buffer.data();
741 int exitcode = pclose(pipe);
742 return WEXITSTATUS(exitcode);
745 boost::filesystem::path Utils::absolutePath(
const boost::filesystem::path &root,
const boost::filesystem::path &file) {
746 if (file.is_absolute() || root.empty()) {
749 return (root / file);
754 std::vector<boost::filesystem::path> Utils::getDirEntriesByExt(
const boost::filesystem::path &dir_path,
755 const std::string &ext) {
756 std::vector<boost::filesystem::path> entries;
757 boost::filesystem::directory_iterator entryItEnd;
758 boost::filesystem::directory_iterator entryIt(dir_path);
759 for (; entryIt != entryItEnd; ++entryIt) {
760 const auto &entry_path = entryIt->path();
761 if (!boost::filesystem::is_directory(*entryIt) && entry_path.extension().string() == ext) {
762 entries.push_back(entry_path);
765 std::sort(entries.begin(), entries.end());
769 void Utils::createDirectories(
const boost::filesystem::path &path, mode_t mode) {
770 boost::filesystem::path parent = path.parent_path();
771 if (!parent.empty() && !boost::filesystem::exists(parent)) {
772 Utils::createDirectories(parent, mode);
774 if (mkdir(path.c_str(), mode) == -1) {
775 throw std::runtime_error(std::string(
"could not create directory: ").append(path.native()));
777 std::cout <<
"created: " << path.native() <<
"\n";
780 bool Utils::createSecureDirectory(
const boost::filesystem::path &path) {
781 if (mkdir(path.c_str(), S_IRWXU) == 0) {
788 int ret = stat(path.c_str(), &st);
793 return (ret >= 0 && ((st.st_mode & S_IFDIR) == S_IFDIR) && (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == S_IRWXU &&
794 (st.st_uid == getuid()));
797 std::string Utils::urlEncode(
const std::string &input) {
800 for (
char c : input) {
801 if ((c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' ||
802 c ==
'_' || c ==
'~' || c ==
'/') {
806 auto nib =
static_cast<char>(((c >> 4) & 0x0F));
807 res.push_back(
static_cast<char>((nib < 10) ? nib +
'0' : nib - 10 +
'A'));
808 nib =
static_cast<char>(c & 0x0F);
809 res.push_back(
static_cast<char>((nib < 10) ? nib +
'0' : nib - 10 +
'A'));
815 CURL *Utils::curlDupHandleWrapper(CURL *
const curl_in,
const bool using_pkcs11) {
816 CURL *curl = curl_easy_duphandle(curl_in);
823 curlEasySetoptWrapper(curl, CURLOPT_SSLENGINE,
"pkcs11");
836 static boost::filesystem::path &Get() {
844 boost::filesystem::path prefix = Utils::getStorageRootPath();
845 if (prefix.empty()) {
846 prefix = boost::filesystem::temp_directory_path();
848 boost::filesystem::path p = prefix / boost::filesystem::unique_path(
"aktualizr-%%%%-%%%%-%%%%-%%%%");
849 if (mkdir(p.c_str(), S_IRWXU) == -1) {
850 throw std::runtime_error(std::string(
"Could not create temporary directory root: ").append(p.native()));
853 path = boost::filesystem::path(p);
857 boost::filesystem::remove_all(path);
863 boost::filesystem::path path;
866 std::string Utils::storage_root_path_;
868 void Utils::setStorageRootPath(
const std::string &storage_root_path) { storage_root_path_ = storage_root_path; }
870 boost::filesystem::path Utils::getStorageRootPath() {
return storage_root_path_; }
872 void Utils::setUserAgent(std::string user_agent) { user_agent_ = std::move(user_agent); }
874 const char *Utils::getUserAgent() {
875 if (user_agent_.empty()) {
876 user_agent_ = (std::string(
"Aktualizr/") + aktualizr_version());
878 return user_agent_.c_str();
881 std::string Utils::user_agent_;
883 void Utils::setCaPath(boost::filesystem::path path) { ca_path_ = std::move(path); }
885 const char *Utils::getCaPath() {
return ca_path_.c_str(); }
887 boost::filesystem::path Utils::ca_path_{
"/etc/ssl/certs"};
889 TemporaryFile::TemporaryFile(
const std::string &hint)
890 : tmp_name_(
SafeTempRoot::Get() / boost::filesystem::unique_path(std::string(
"%%%%-%%%%-").append(hint))) {}
892 TemporaryFile::~TemporaryFile() { boost::filesystem::remove(tmp_name_); }
894 void TemporaryFile::PutContents(
const std::string &contents)
const {
895 mode_t mode = S_IRUSR | S_IWUSR;
896 int fd = open(Path().c_str(), O_WRONLY | O_CREAT | O_TRUNC, mode);
898 throw std::runtime_error(std::string(
"Could not write content to file: ") + Path().
string() +
": " +
899 std::strerror(errno));
901 ssize_t written = write(fd, contents.c_str(), contents.size());
903 if (written < 0 ||
static_cast<size_t>(written) != contents.size()) {
904 throw std::runtime_error(std::string(
"Could not write content to file: ") + Path().
string());
908 boost::filesystem::path TemporaryFile::Path()
const {
return tmp_name_; }
910 std::string TemporaryFile::PathString()
const {
return Path().string(); }
912 TemporaryDirectory::TemporaryDirectory(
const std::string &hint)
913 : tmp_name_(
SafeTempRoot::Get() / boost::filesystem::unique_path(std::string(
"%%%%-%%%%-").append(hint))) {
914 Utils::createDirectories(tmp_name_, S_IRWXU);
917 TemporaryDirectory::~TemporaryDirectory() { boost::filesystem::remove_all(tmp_name_); }
919 boost::filesystem::path TemporaryDirectory::Path()
const {
return tmp_name_; }
921 boost::filesystem::path TemporaryDirectory::operator/(
const boost::filesystem::path &subdir)
const {
922 return (tmp_name_ / subdir);
925 std::string TemporaryDirectory::PathString()
const {
return Path().string(); }
928 socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
929 if (-1 == socket_fd_) {
930 throw std::system_error(errno, std::system_category(),
"socket");
934 Socket::~Socket() { ::close(socket_fd_); }
936 std::string Socket::toString()
const {
937 auto saddr = Utils::ipGetSockaddr(socket_fd_);
938 return Utils::ipDisplayName(saddr) +
":" + std::to_string(Utils::ipPort(saddr));
941 void Socket::bind(in_port_t port,
bool reuse)
const {
943 memset(&sa, 0,
sizeof(sa));
944 sa.sin_family = AF_INET;
945 sa.sin_port = htons(port);
946 sa.sin_addr.s_addr = htonl(INADDR_ANY);
948 int reuseaddr = reuse ? 1 : 0;
949 if (-1 == setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(reuseaddr))) {
950 throw std::system_error(errno, std::system_category(),
"socket");
953 if (-1 == ::bind(socket_fd_,
reinterpret_cast<const sockaddr *
>(&sa),
sizeof(sa))) {
954 throw std::system_error(errno, std::system_category(),
"socket");
958 ListenSocket::ListenSocket(in_port_t port) : _port(port) {
962 auto ephemeral_port = Utils::ipPort(Utils::ipGetSockaddr(socket_fd_));
963 if (-1 != ephemeral_port) {
964 _port =
static_cast<in_port_t
>(ephemeral_port);
969 ConnectionSocket::ConnectionSocket(
const std::string &ip, in_port_t port, in_port_t bind_port)
970 : remote_sock_address_{} {
971 memset(&remote_sock_address_, 0,
sizeof(remote_sock_address_));
972 remote_sock_address_.sin_family = AF_INET;
973 if (-1 == inet_pton(AF_INET, ip.c_str(), &(remote_sock_address_.sin_addr))) {
974 throw std::system_error(errno, std::system_category(),
"socket");
976 remote_sock_address_.sin_port = htons(port);
983 ConnectionSocket::~ConnectionSocket() { ::shutdown(socket_fd_, SHUT_RDWR); }
985 int ConnectionSocket::connect() {
986 return ::connect(socket_fd_,
reinterpret_cast<const struct sockaddr *
>(&remote_sock_address_),
987 sizeof(remote_sock_address_));
990 CurlEasyWrapper::CurlEasyWrapper() {
991 handle = curl_easy_init();
992 if (handle ==
nullptr) {
993 throw std::runtime_error(
"Could not initialize curl handle");
995 curlEasySetoptWrapper(handle, CURLOPT_USERAGENT, Utils::getUserAgent());
998 CurlEasyWrapper::~CurlEasyWrapper() {
999 if (handle !=
nullptr) {
1000 curl_easy_cleanup(handle);