mirror of
https://github.com/openSUSE/snapper.git
synced 2026-02-06 00:45:39 +01:00
221 lines
4.7 KiB
C++
221 lines
4.7 KiB
C++
/*
|
|
* Copyright (c) [2011-2014] Novell, Inc.
|
|
* Copyright (c) [2020-2023] SUSE LLC
|
|
*
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as published
|
|
* by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, contact Novell, Inc.
|
|
*
|
|
* To contact Novell about this file by physical or electronic mail, you may
|
|
* find current contact information at www.novell.com.
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include <snapper/AppUtil.h>
|
|
#include <snapper/SystemCmd.h>
|
|
#include <snapper/SnapperDefines.h>
|
|
#include <snapper/Filesystem.h>
|
|
|
|
#include "utils/text.h"
|
|
#include "misc.h"
|
|
|
|
|
|
namespace snapper
|
|
{
|
|
|
|
unsigned int
|
|
read_num(const string& str)
|
|
{
|
|
istringstream s(str);
|
|
unsigned int num = 0;
|
|
s >> num;
|
|
|
|
if (s.fail() || !s.eof())
|
|
{
|
|
cerr << sformat(_("Invalid snapshot '%s'."), str.c_str()) << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
|
|
map<string, string>
|
|
read_userdata(const string& s, const map<string, string>& old)
|
|
{
|
|
if (s.empty())
|
|
{
|
|
cerr << _("Empty userdata.") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
list<string> tmp;
|
|
boost::split(tmp, s, boost::is_any_of(","), boost::token_compress_on);
|
|
if (tmp.empty())
|
|
{
|
|
cerr << _("Empty userdata.") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
map<string, string> userdata = old;
|
|
|
|
for (list<string>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
|
|
{
|
|
string::size_type pos = it->find("=");
|
|
if (pos == string::npos)
|
|
{
|
|
cerr << sformat(_("Userdata '%s' does not include '=' sign."), it->c_str()) << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
string key = boost::trim_copy(it->substr(0, pos));
|
|
string value = boost::trim_copy(it->substr(pos + 1));
|
|
|
|
if (key.empty())
|
|
{
|
|
cerr << sformat(_("Userdata '%s' has empty key."), it->c_str()) << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (value.empty())
|
|
userdata.erase(key);
|
|
else
|
|
userdata[key] = value;
|
|
}
|
|
|
|
return userdata;
|
|
}
|
|
|
|
|
|
string
|
|
show_userdata(const map<string, string>& userdata)
|
|
{
|
|
string s;
|
|
|
|
for (map<string, string>::const_iterator it = userdata.begin(); it != userdata.end(); ++it)
|
|
{
|
|
if (!s.empty())
|
|
s += ", ";
|
|
s += it->first + "=" + it->second;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
map<string, string>
|
|
read_configdata(const vector<string>& v, const map<string, string>& old)
|
|
{
|
|
if (v.empty())
|
|
{
|
|
cerr << _("Empty configdata.") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
map<string, string> configdata = old;
|
|
|
|
for (vector<string>::const_iterator it = v.begin(); it != v.end(); ++it)
|
|
{
|
|
string::size_type pos = it->find("=");
|
|
if (pos == string::npos)
|
|
{
|
|
cerr << sformat(_("Configdata '%s' does not include '=' sign."), it->c_str()) << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
string key = boost::trim_copy(it->substr(0, pos));
|
|
string value = boost::trim_copy(it->substr(pos + 1));
|
|
|
|
if (key.empty())
|
|
{
|
|
cerr << sformat(_("Configdata '%s' has empty key."), it->c_str()) << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
configdata[key] = value;
|
|
}
|
|
|
|
return configdata;
|
|
}
|
|
|
|
|
|
string
|
|
username(uid_t uid)
|
|
{
|
|
string username;
|
|
gid_t gid;
|
|
|
|
if (!get_uid_username_gid(uid, username, gid))
|
|
return sformat("unknown (%d)", uid);
|
|
|
|
return username;
|
|
}
|
|
|
|
|
|
unique_ptr<const Filesystem>
|
|
get_filesystem(const ProxyConfig& config, const string& target_root)
|
|
{
|
|
const map<string, string>& raw = config.getAllValues();
|
|
|
|
map<string, string>::const_iterator pos1 = raw.find(KEY_FSTYPE);
|
|
map<string, string>::const_iterator pos2 = raw.find(KEY_SUBVOLUME);
|
|
if (pos1 == raw.end() || pos2 == raw.end())
|
|
{
|
|
cerr << _("Failed to initialize filesystem handler.") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
try
|
|
{
|
|
return Filesystem::create(pos1->second, pos2->second, target_root);
|
|
}
|
|
catch (const InvalidConfigException& e)
|
|
{
|
|
SN_CAUGHT(e);
|
|
cerr << _("Failed to initialize filesystem handler.") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
|
|
Differ::Differ()
|
|
: command(DIFF_BIN " --new-file --unified")
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
Differ::run(const string& f1, const string& f2) const
|
|
{
|
|
string tmp = command;
|
|
if (!extensions.empty())
|
|
tmp += " " + extensions;
|
|
tmp += " " + quote(f1) + " " + quote(f2);
|
|
|
|
SystemCmd cmd({ SH_BIN, "-c", tmp });
|
|
|
|
for (const string& line : cmd.get_stdout())
|
|
cout << line << endl;
|
|
|
|
for (const string& line : cmd.get_stderr())
|
|
cerr << line << endl;
|
|
}
|
|
|
|
}
|