tmp += " " + extensions;
tmp += " " + quote(f1) + " " + quote(f2);
- SystemCmd cmd(tmp);
+ SystemCmd cmd({ SH_BIN, "-c", tmp });
for (const string& line : cmd.get_stdout())
cout << line << endl;
Fri Oct 13 08:56:18 CEST 2023 - aschnell@suse.com
- fix diff for lvm based configs (bsc#1216191)
+- make SystemCmd take vector of strings
-------------------------------------------------------------------
Thu Sep 14 15:45:53 CEST 2023 - aschnell@suse.com
int r1 = mkdir((subvolume + "/.snapshots").c_str(), 0700);
if (r1 == 0)
{
- SystemCmd cmd1(CHATTRBIN " +x " + quote(subvolume + "/.snapshots"));
+ SystemCmd cmd1({ CHATTRBIN, "+x", subvolume + "/.snapshots" });
if (cmd1.retcode() != 0)
throw CreateConfigFailedException("chattr failed");
}
int r2 = mkdir((subvolume + "/.snapshots/.info").c_str(), 0700);
if (r2 == 0)
{
- SystemCmd cmd2(CHATTRBIN " -x " + quote(subvolume + "/.snapshots/.info"));
+ SystemCmd cmd2({ CHATTRBIN, "-x", subvolume + "/.snapshots/.info" });
if (cmd2.retcode() != 0)
throw CreateConfigFailedException("chattr failed");
}
if (num_parent != 0 || !read_only)
throw std::logic_error("not implemented");
- SystemCmd cmd1(TOUCHBIN " " + quote(snapshotFile(num)));
+ SystemCmd cmd1({ TOUCHBIN, snapshotFile(num) });
if (cmd1.retcode() != 0)
throw CreateSnapshotFailedException();
- SystemCmd cmd2(CHSNAPBIN " +S " + quote(snapshotFile(num)));
+ SystemCmd cmd2({ CHSNAPBIN, "+S", snapshotFile(num) });
if (cmd2.retcode() != 0)
throw CreateSnapshotFailedException();
}
void
Ext4::deleteSnapshot(unsigned int num) const
{
- SystemCmd cmd(CHSNAPBIN " -S " + quote(snapshotFile(num)));
+ SystemCmd cmd({ CHSNAPBIN, "-S", snapshotFile(num) });
if (cmd.retcode() != 0)
throw DeleteSnapshotFailedException();
}
if (isSnapshotMounted(num))
return;
- SystemCmd cmd1(CHSNAPBIN " +n " + quote(snapshotFile(num)));
+ SystemCmd cmd1({ CHSNAPBIN, "+n", snapshotFile(num) });
if (cmd1.retcode() != 0)
throw MountSnapshotFailedException();
// if (!umount(snapshotDir(num)))
// throw UmountSnapshotFailedException();
- SystemCmd cmd1(CHSNAPBIN " -n " + quote(snapshotFile(num)));
+ SystemCmd cmd1({ CHSNAPBIN, "-n", snapshotFile(num) });
if (cmd1.retcode() != 0)
throw UmountSnapshotFailedException();
/*
* Copyright (c) [2011-2015] Novell, Inc.
- * Copyright (c) 2022 SUSE LLC
+ * Copyright (c) [2022-2023] SUSE LLC
*
* All Rights Reserved.
*
std::sort(scripts.begin(), scripts.end());
for (const string& script : scripts)
{
- string cmd_line = dir.fullname(script);
- for (const string& arg : args)
- cmd_line += " " + quote(arg);
- SystemCmd cmd(cmd_line);
+ SystemCmd::Args cmd_args = { dir.fullname(script) };
+ cmd_args << args;
+ SystemCmd cmd(cmd_args);
}
}
catch (const Exception& e)
if (subvolume == "/" && filesystem->fstype() == "btrfs" && access(GRUB_SCRIPT, X_OK) == 0)
{
- SystemCmd cmd(string(GRUB_SCRIPT) + " " + option);
+ SystemCmd cmd({ GRUB_SCRIPT, option });
}
#endif
}
// Fate#319108
if (access(ROLLBACK_SCRIPT, X_OK) == 0)
{
- SystemCmd cmd(string(ROLLBACK_SCRIPT) + " " + old_root + " " + new_root);
+ SystemCmd cmd({ ROLLBACK_SCRIPT, old_root, new_root });
}
#endif
}
LvmCapabilities::LvmCapabilities()
{
- SystemCmd cmd(string(LVMBIN " version"));
+ SystemCmd cmd({ LVMBIN, "version" });
if (cmd.retcode() != 0 || cmd.get_stdout().empty())
{
lvm_version version(maj, min, rev);
if (version >= lvm_version(2, 2, 99))
- ignoreactivationskip = " -K";
+ ignoreactivationskip = "--ignoreactivationskip";
}
}
}
LvmCapabilities();
- // empty or " -K" if lvm supports ignore activation skip flag
+ // empty or "--ignoreactivationskip" if lvm supports ignore activation skip flag
string ignoreactivationskip;
};
{
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upg_lock);
- SystemCmd cmd(LVCHANGEBIN + caps->get_ignoreactivationskip() + " -ay " + quote(full_name()));
+ SystemCmd::Args cmd_args = { LVCHANGEBIN };
+ if (!caps->get_ignoreactivationskip().empty())
+ cmd_args << caps->get_ignoreactivationskip();
+ cmd_args << "--activate" << "y" << full_name();
+
+ SystemCmd cmd(cmd_args);
if (cmd.retcode() != 0)
{
y2err("lvm cache: " << full_name() << " activation failed!");
{
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upg_lock);
- SystemCmd cmd(LVCHANGEBIN " -an " + quote(full_name()));
+ SystemCmd cmd({ LVCHANGEBIN, "--activate", "n", full_name() });
if (cmd.retcode() != 0)
{
y2err("lvm cache: " << full_name() << " deactivation failed!");
{
boost::unique_lock<boost::shared_mutex> unique_lock(lv_mutex);
- SystemCmd cmd(LVSBIN " --noheadings -o lv_attr,segtype " + quote(full_name()));
+ SystemCmd cmd({ LVSBIN, "--noheadings", "--options", "lv_attr,segtype", full_name() });
if (cmd.retcode() != 0 || cmd.get_stdout().empty())
{
y2err("lvm cache: failed to get info about " << full_name());
{
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upg_lock);
- SystemCmd cmd(LVCHANGEBIN " --permission " + string(read_only ? "r" : "rw") + " " +
- quote(full_name()));
+ SystemCmd cmd({ LVCHANGEBIN, "--permission", read_only ? "r" : "rw", full_name() });
if (cmd.retcode() != 0)
{
y2err("lvm cache: " << full_name() << " setting permission failed!");
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upg_lock);
- SystemCmd cmd(LVCREATEBIN " --permission " + string(read_only ? "r" : "rw") + " --snapshot "
- "--name " + quote(lv_snapshot_name) + " " + quote(full_name(lv_origin_name)));
+ SystemCmd cmd({ LVCREATEBIN, "--permission", read_only ? "r" : "rw", "--snapshot",
+ "--name", lv_snapshot_name, full_name(lv_origin_name) });
if (cmd.retcode() != 0)
throw LvmCacheException();
}
else
{
- SystemCmd cmd(LVSBIN " --noheadings -o lv_attr,segtype " + quote(full_name(lv_name)));
+ SystemCmd cmd({ LVSBIN, "--noheadings", "--options", "lv_attr,segtype", full_name(lv_name) });
if (cmd.retcode() != 0 || cmd.get_stdout().empty())
{
y2err("lvm cache: failed to get info about " << full_name(lv_name));
// wait for all invidual lv cache operations under shared vg lock to finish
boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upg_lock);
- SystemCmd cmd(LVREMOVEBIN " --force " + quote(full_name(lv_name)));
+ SystemCmd cmd({ LVREMOVEBIN, "--force", full_name(lv_name) });
if (cmd.retcode() != 0)
throw LvmCacheException();
void
LvmCache::add_vg(const string& vg_name, const string& include_lv_name)
{
- SystemCmd cmd(LVSBIN " --noheadings -o lv_name,lv_attr,segtype " + quote(vg_name));
+ SystemCmd cmd({ LVSBIN, "--noheadings", "--options", "lv_name,lv_attr,segtype", vg_name });
if (cmd.retcode() != 0)
{
y2err("lvm cache: failed to get info about VG " << vg_name);
sysconfig.save();
- SystemCmd cmd(RMBIN " " + quote(CONFIGS_DIR "/" + config_name));
+ SystemCmd cmd({ RMBIN, "--", CONFIGS_DIR "/" + config_name });
SN_RETHROW(e);
}
SN_THROW(DeleteConfigFailedException("deleting snapshot failed"));
}
- SystemCmd cmd1(RMBIN " " + quote(CONFIGS_DIR "/" + config_name));
+ SystemCmd cmd1({ RMBIN, "--", CONFIGS_DIR "/" + config_name });
if (cmd1.retcode() != 0)
{
SN_THROW(DeleteConfigFailedException("deleting config-file failed"));
/*
* Copyright (c) [2004-2011] Novell, Inc.
- * Copyright (c) [2018-2021] SUSE LLC
+ * Copyright (c) [2018-2023] SUSE LLC
*
* All Rights Reserved.
*
*/
-#include <stdlib.h>
+#include <cstdlib>
#include <unistd.h>
-#include <errno.h>
+#include <cerrno>
#include <fcntl.h>
#include <sys/wait.h>
-#include <string>
#include <boost/algorithm/string.hpp>
extern char **environ;
#include "snapper/AppUtil.h"
#include "snapper/SystemCmd.h"
#include "snapper/SnapperDefines.h"
+#include "snapper/Exception.h"
namespace snapper
using namespace std;
- SystemCmd::SystemCmd(const string& Command_Cv, bool log_output)
- : log_output(log_output)
-{
- y2mil("constructor SystemCmd:\"" << Command_Cv << "\"");
- init();
- execute( Command_Cv );
-}
+ SystemCmd::SystemCmd(const Args& args, bool log_output)
+ : args(args), log_output(log_output)
+ {
+ y2mil("constructor SystemCmd: " << cmd());
+
+ if (args.get_values().empty())
+ SN_THROW(Exception("args empty"));
+
+ init();
+ execute();
+ }
+
+
+ string
+ SystemCmd::cmd() const
+ {
+ return boost::join(args.get_values(), " ");
+ }
void SystemCmd::init()
}
-int
-SystemCmd::execute(const string& Cmd_Cv)
-{
- y2mil("SystemCmd Executing:\"" << Cmd_Cv << "\"");
- return doExecute(Cmd_Cv);
-}
-
-
-int
-SystemCmd::doExecute( const string& Cmd )
+ void
+ SystemCmd::execute()
{
- lastCmd = Cmd;
- y2deb("Cmd:" << Cmd);
-
StopWatch stopwatch;
File_aC[IDX_STDERR] = File_aC[IDX_STDOUT] = NULL;
}
y2deb("sout:" << pfds[0].fd << " serr:" << pfds[1].fd);
- const vector<const char*> env = make_env();
+ const TmpForExec args_p(make_args());
+ const TmpForExec env_p(make_env());
switch( (Pid_i=fork()) )
{
{
y2err("close child failed errno:" << errno << " (" << stringerror(errno) << ")");
}
+
closeOpenFds();
- Ret_i = execle(SH_BIN, SH_BIN, "-c", Cmd.c_str(), nullptr, &env[0]);
- y2err("SHOULD NOT HAPPEN \"" SH_BIN "\" Ret:" << Ret_i);
+
+ Ret_i = execvpe(args.get_values()[0].c_str(), args_p.get(), env_p.get());
+ y2err("SHOULD NOT HAPPEN execvpe returned ret=" << Ret_i << " errno=" << errno);
break;
case -1:
Ret_i = -1;
}
if( Ret_i==-127 || Ret_i==-1 )
{
- y2err("system (\"" << Cmd << "\") = " << Ret_i);
+ y2err("system (\"" << cmd() << "\") = " << Ret_i);
}
checkOutput();
y2mil("system() Returns:" << Ret_i);
if (Ret_i != 0 && log_output)
logOutput();
- return Ret_i;
}
{
Ret_ir = WEXITSTATUS(Status_ii);
if (Ret_ir == 126)
- y2err("command \"" << lastCmd << "\" not executable");
+ y2err("command \"" << cmd() << "\" not executable");
else if (Ret_ir == 127)
- y2err("command \"" << lastCmd << "\" not found");
+ y2err("command \"" << cmd() << "\" not found");
}
else
{
Ret_ir = -127;
- y2err("command \"" << lastCmd << "\" failed");
+ y2err("command \"" << cmd() << "\" failed");
}
}
}
- vector<const char*>
+ SystemCmd::TmpForExec::~TmpForExec()
+ {
+ for (char* v : values)
+ free(v);
+ }
+
+
+ SystemCmd::TmpForExec
+ SystemCmd::make_args() const
+ {
+ vector<char*> ret;
+
+ for (const string& v : args.get_values())
+ {
+ ret.push_back(strdup(v.c_str()));
+ }
+
+ ret.push_back(nullptr);
+
+ return ret;
+ }
+
+
+ SystemCmd::TmpForExec
SystemCmd::make_env() const
{
- vector<const char*> env;
+ vector<char*> ret;
for (char** v = environ; *v != NULL; ++v)
{
if (strncmp(*v, "LC_ALL=", strlen("LC_ALL=")) != 0 &&
strncmp(*v, "LANGUAGE=", strlen("LANGUAGE=")) != 0)
- env.push_back(*v);
+ ret.push_back(strdup(*v));
}
- env.push_back("LC_ALL=C");
- env.push_back("LANGUAGE=C");
+ ret.push_back(strdup("LC_ALL=C"));
+ ret.push_back(strdup("LANGUAGE=C"));
- env.push_back(nullptr);
+ ret.push_back(nullptr);
- return env;
+ return ret;
}
/*
* Copyright (c) [2004-2014] Novell, Inc.
- * Copyright (c) [2018-2021] SUSE LLC
+ * Copyright (c) [2018-2023] SUSE LLC
*
* All Rights Reserved.
*
#define SNAPPER_SYSTEM_CMD_H
#include <poll.h>
-#include <stdio.h>
-
+#include <cstdio>
#include <string>
#include <vector>
+#include <initializer_list>
#include <boost/noncopyable.hpp>
using std::vector;
- class SystemCmd : private boost::noncopyable
+ class SystemCmd final : private boost::noncopyable
{
public:
- SystemCmd(const string& Command_Cv, bool log_output = true);
- virtual ~SystemCmd();
+ /**
+ * Class holding command with arguments.
+ */
+ class Args
+ {
+ public:
+
+ Args(std::initializer_list<string> init)
+ : values(init) {}
+
+ const vector<string>& get_values() const { return values; }
+
+ Args& operator<<(const char* arg) { values.push_back(arg); return *this; }
+ Args& operator<<(const string& arg) { values.push_back(arg); return *this; }
+
+ Args& operator<<(const vector<string>& args)
+ { values.insert(values.end(), args.begin(), args.end()); return *this; }
+
+ private:
+
+ vector<string> values;
+
+ };
+
+
+ SystemCmd(const Args& args, bool log_output = true);
+
+ ~SystemCmd();
private:
enum OutputStream { IDX_STDOUT, IDX_STDERR };
- int execute(const string& Command_Cv);
-
public:
const vector<string>& get_stdout() const { return Lines_aC[IDX_STDOUT]; }
const vector<string>& get_stderr() const { return Lines_aC[IDX_STDERR]; }
- string cmd() const { return lastCmd; }
+ /**
+ * Command as a simple string (without quoting of args - so only for display and
+ * logging).
+ */
+ string cmd() const;
+
int retcode() const { return Ret_i; }
private:
void invalidate();
void closeOpenFds() const;
- int doExecute(const string& Cmd_Cv);
+ void execute();
bool doWait(int& Ret_ir);
void checkOutput();
void getUntilEOF(FILE* File_Cr, vector<string>& Lines_Cr, bool& NewLineSeen_br,
void logOutput() const;
+
/**
- * Constructs the environment for the child process.
+ * Class to tempararily hold copies for execle() and execvpe().
+ */
+ class TmpForExec
+ {
+ public:
+
+ TmpForExec(const vector<char*>& values) : values(values) {}
+ ~TmpForExec();
+
+ char* const * get() const { return &values[0]; }
+
+ private:
+
+ vector<char*> values;
+
+ };
+
+
+ /**
+ * Constructs the args for the child process.
*
* Must not be called after exec since allocating the memory
* for the vector is not allowed then (in a multithreaded
* program), see fork(2) and signal-safety(7). So simply call
* it right before fork.
*/
- vector<const char*> make_env() const;
+ TmpForExec make_args() const;
+
+ /**
+ * Constructs the environment for the child process.
+ *
+ * Same not as for make_args().
+ */
+ TmpForExec make_env() const;
+
+
+ const Args args;
+ const bool log_output;
FILE* File_aC[2];
vector<string> Lines_aC[2];
bool NewLineSeen_ab[2];
- bool log_output;
- string lastCmd;
- int Ret_i;
- int Pid_i;
+ int Ret_i = 0;
+ int Pid_i = 0;
struct pollfd pfds[2];
static const unsigned line_limit = 50;
+
};
// When run in a chroot system the enable command works but the start command
// fails (which is likely what we want).
- SystemCmd cmd(SYSTEMCTL_BIN " " + string(enable ? "enable " : "disable ") +
- string(now ? "--now " : "") + name);
+ SystemCmd::Args cmd_args = { SYSTEMCTL_BIN, enable ? "enable" : "disable" };
+ if (now)
+ cmd_args << "--now";
+ cmd_args << name;
+
+ SystemCmd cmd(cmd_args);
}