File indexing completed on 2024-05-05 05:45:56

0001 /*
0002     Copyright Hannah von Reth <vonreth@kde.org>
0003 
0004     Redistribution and use in source and binary forms, with or without
0005     modification, are permitted provided that the following conditions
0006     are met:
0007     1. Redistributions of source code must retain the above copyright
0008        notice, this list of conditions and the following disclaimer.
0009     2. Redistributions in binary form must reproduce the above copyright
0010        notice, this list of conditions and the following disclaimer in the
0011        documentation and/or other materials provided with the distribution.
0012 
0013     THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0014     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0016     ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0017     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0018     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0019     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0020     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0021     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0022     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0023     SUCH DAMAGE.
0024 */
0025 
0026 #include "kshimdata.h"
0027 #include "kshim.h"
0028 
0029 #include "../3dparty/nlohmann/json.hpp"
0030 
0031 #include <cstring>
0032 #include <iostream>
0033 #include <iomanip>
0034 #include <fstream>
0035 #include <sstream>
0036 
0037 using namespace nlohmann;
0038 
0039 namespace {
0040 enum class Format { Json, Ubjson };
0041 Format KSHIM_DATA_FORMAT()
0042 {
0043     static Format format = [] {
0044         const auto var = KShimLib::getenv(KSTRING("KSHIM_FORMAT"), KSTRING("ubjson"));
0045         kLog << "DataFormat: " << var;
0046         if (var == KSTRING("ubjson")) {
0047             return Format::Ubjson;
0048         }
0049         return Format::Json;
0050     }();
0051     return format;
0052 }
0053 }
0054 
0055 KShimData::KShimData(const std::filesystem::path &app) : m_app(app) { }
0056 
0057 KShimData::KShimData(const std::vector<uint8_t> &payLoad)
0058 {
0059     kLog << "PayLoad Size: " << payLoad.size();
0060     json data;
0061     switch (KSHIM_DATA_FORMAT()) {
0062     case Format::Json:
0063         data = json::parse(payLoad.cbegin(), payLoad.cend());
0064         break;
0065     case Format::Ubjson:
0066         data = json::from_ubjson(payLoad.cbegin(), payLoad.cend());
0067         break;
0068     }
0069     kLog << "Json Data: " << data.dump(4);
0070     m_app = std::filesystem::path(data["app"].get<KShimLib::string>());
0071     m_args = data["args"].get<std::vector<KShimLib::string>>();
0072     m_env = data["env"].get<std::vector<std::pair<KShimLib::string, KShimLib::string>>>();
0073     m_envOverrideEnabled = data["envOverrideEnabled"].get<bool>();
0074     m_keepArgv0Enabled = data["keepArgv0Enabled"].get<bool>();
0075 }
0076 
0077 std::filesystem::path KShimData::app() const
0078 {
0079     return m_app;
0080 }
0081 
0082 std::filesystem::path KShimData::appAbs() const
0083 {
0084     return makeAbsouteCommand(app());
0085 }
0086 
0087 void KShimData::setApp(const std::filesystem::path &app)
0088 {
0089     m_app = app;
0090 }
0091 
0092 const std::vector<KShimLib::string> &KShimData::args() const
0093 {
0094     return m_args;
0095 }
0096 
0097 void KShimData::setArgs(const std::vector<KShimLib::string_view> &args)
0098 {
0099     m_args = { args.cbegin(), args.cend() };
0100 }
0101 
0102 void KShimData::addArg(const KShimLib::string_view &arg)
0103 {
0104     m_args.push_back(KShimLib::string(arg));
0105 }
0106 
0107 KShimLib::string KShimData::formatArgs(const std::vector<KShimLib::string_view> &arguments) const
0108 {
0109     KShimLib::stringstream cmd;
0110     cmd << KShimLib::quoteArgs({ args().cbegin(), args().cend() })
0111         << KShimLib::quoteArgs(arguments);
0112     return cmd.str();
0113 }
0114 
0115 std::vector<uint8_t> KShimData::toJson() const
0116 {
0117     const auto jsonData = json { { "app", app().native() },
0118                                  { "args", args() },
0119                                  { "env", env() },
0120                                  { "envOverrideEnabled", isEnvOverrideEnabled() },
0121                                  { "keepArgv0Enabled", isKeepArgv0Enabled() } };
0122     std::vector<uint8_t> out;
0123     switch (KSHIM_DATA_FORMAT()) {
0124     case Format::Json: {
0125         const auto dump = jsonData.dump();
0126         out = std::vector<uint8_t>(dump.cbegin(), dump.cend());
0127         break;
0128     }
0129     case Format::Ubjson:
0130         out = json::to_ubjson(jsonData);
0131     }
0132 
0133     kLog << "toJson:" << out.size();
0134     return out;
0135 }
0136 
0137 std::filesystem::path KShimData::makeAbsouteCommand(const std::filesystem::path &path) const
0138 {
0139     if (path.is_absolute()) {
0140         return path;
0141     } else {
0142         auto tmp = KShimLib::binaryName().parent_path() / path;
0143         if (tmp != KShimLib::binaryName() && KShimLib::exists(tmp)) {
0144             return tmp;
0145         }
0146     }
0147     return KShimLib::findInPath(path);
0148 }
0149 
0150 const std::vector<std::pair<KShimLib::string, KShimLib::string>> &KShimData::env() const
0151 {
0152     return m_env;
0153 }
0154 
0155 void KShimData::setEnv(
0156         const std::vector<std::pair<KShimLib::string_view, KShimLib::string_view>> &env)
0157 {
0158     m_env = { env.cbegin(), env.cend() };
0159 }
0160 
0161 void KShimData::addEnvVar(const std::pair<KShimLib::string_view, KShimLib::string_view> &var)
0162 {
0163     m_env.push_back({ KShimLib::string(var.first), KShimLib::string(var.second) });
0164 }
0165 
0166 bool KShimData::isEnvOverrideEnabled() const
0167 {
0168     return m_envOverrideEnabled;
0169 }
0170 
0171 void KShimData::setEnvOverrideEnabled(bool envOverrideEnabled)
0172 {
0173     m_envOverrideEnabled = envOverrideEnabled;
0174 }
0175 
0176 std::filesystem::path KShimData::appAbsWithOverride() const
0177 {
0178     if (m_envOverrideEnabled) {
0179         KShimLib::stringstream stream;
0180         stream << "KSHIM_" << KShimLib::string(KShimLib::binaryName().filename());
0181         const auto overrideApp =
0182                 std::filesystem::path(KShimLib::getenv(stream.str(), KShimLib::string(appAbs())));
0183         if (overrideApp.is_absolute()) {
0184             return overrideApp;
0185         }
0186         kLog2(KLog::Type::Error) << stream.str()
0187                                  << " must be absolute, current value: " << overrideApp
0188                                  << " falling back to internal value " << appAbs();
0189     }
0190     return appAbs();
0191 }
0192 
0193 bool KShimData::isKeepArgv0Enabled() const
0194 {
0195     return m_keepArgv0Enabled;
0196 }
0197 
0198 void KShimData::setKeepArgv0Enabled(bool keepArgv0Enabled)
0199 {
0200     m_keepArgv0Enabled = keepArgv0Enabled;
0201 }