/*
* Copyright (c) [2004-2011] Novell, Inc.
- * Copyright (c) 2018 SUSE LLC
+ * Copyright (c) [2018-2021] SUSE LLC
*
* All Rights Reserved.
*
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
-#include <ostream>
-#include <fstream>
#include <sys/wait.h>
#include <string>
#include <boost/algorithm/string.hpp>
#include "snapper/Log.h"
#include "snapper/AppUtil.h"
#include "snapper/SystemCmd.h"
+#include "snapper/SnapperDefines.h"
namespace snapper
SystemCmd::SystemCmd(const string& Command_Cv, bool log_output)
- : Combine_b(false), log_output(log_output)
+ : log_output(log_output)
{
y2mil("constructor SystemCmd:\"" << Command_Cv << "\"");
init();
SystemCmd::execute(const string& Cmd_Cv)
{
y2mil("SystemCmd Executing:\"" << Cmd_Cv << "\"");
- Background_b = false;
return doExecute(Cmd_Cv);
}
-int
-SystemCmd::executeBackground( const string& Cmd_Cv )
-{
- y2mil("SystemCmd Executing (Background):\"" << Cmd_Cv << "\"");
- Background_b = true;
- return doExecute(Cmd_Cv);
-}
-
-
-int
-SystemCmd::executeRestricted( const string& Command_Cv,
- long unsigned MaxTimeSec, long unsigned MaxLineOut,
- bool& ExceedTime, bool& ExceedLines )
-{
- y2mil("cmd:" << Command_Cv << " MaxTime:" << MaxTimeSec << " MaxLines:" << MaxLineOut);
- ExceedTime = ExceedLines = false;
- int ret = executeBackground( Command_Cv );
- unsigned long ts = 0;
- unsigned long ls = 0;
- unsigned long start_time = time(NULL);
- while( !ExceedTime && !ExceedLines && !doWait( false, ret ) )
- {
- if( MaxTimeSec>0 )
- {
- ts = time(NULL)-start_time;
- y2mil( "time used:" << ts );
- }
- if( MaxLineOut>0 )
- {
- ls = numLines()+numLines(false,IDX_STDERR);
- y2mil( "lines out:" << ls );
- }
- ExceedTime = MaxTimeSec>0 && ts>MaxTimeSec;
- ExceedLines = MaxLineOut>0 && ls>MaxLineOut;
- sleep( 1 );
- }
- if( ExceedTime || ExceedLines )
- {
- int r = kill( Pid_i, SIGKILL );
- y2mil( "kill pid:" << Pid_i << " ret:" << r );
- unsigned count=0;
- int Status_ii;
- int Wait_ii = -1;
- while( count<5 && Wait_ii<=0 )
- {
- Wait_ii = waitpid( Pid_i, &Status_ii, WNOHANG );
- y2mil( "waitpid:" << Wait_ii );
- count++;
- sleep( 1 );
- }
- /*
- r = kill( Pid_i, SIGKILL );
- y2mil( "kill pid:" << Pid_i << " ret:" << r );
- count=0;
- waitDone = false;
- while( count<8 && !waitDone )
- {
- y2mil( "doWait:" << count );
- waitDone = doWait( false, ret );
- count++;
- sleep( 1 );
- }
- */
- Ret_i = -257;
- }
- else
- Ret_i = ret;
- y2mil("ret:" << ret << " ExceedTime:" << ExceedTime << " ExceedLines:" << ExceedLines);
- return ret;
-}
-
-
-#define PRIMARY_SHELL "/bin/sh"
-#define ALTERNATE_SHELL "/bin/bash"
-
int
SystemCmd::doExecute( const string& Cmd )
{
- string Shell_Ci = PRIMARY_SHELL;
- if( access( Shell_Ci.c_str(), X_OK ) != 0 )
- {
- Shell_Ci = ALTERNATE_SHELL;
- }
-
lastCmd = Cmd;
y2deb("Cmd:" << Cmd);
int sout[2];
int serr[2];
bool ok_bi = true;
- if( !testmode && pipe(sout)<0 )
+ if( pipe(sout)<0 )
{
y2err("pipe stdout creation failed errno:" << errno << " (" << stringerror(errno) << ")");
ok_bi = false;
}
- if( !testmode && !Combine_b && pipe(serr)<0 )
+ if( pipe(serr)<0 )
{
y2err("pipe stderr creation failed errno:" << errno << " (" << stringerror(errno) << ")");
ok_bi = false;
}
- if( !testmode && ok_bi )
+ if( ok_bi )
{
pfds[0].fd = sout[0];
if( fcntl( pfds[0].fd, F_SETFL, O_NONBLOCK )<0 )
{
y2err("fcntl O_NONBLOCK failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- if( !Combine_b )
+ pfds[1].fd = serr[0];
+ if( fcntl( pfds[1].fd, F_SETFL, O_NONBLOCK )<0 )
{
- pfds[1].fd = serr[0];
- if( fcntl( pfds[1].fd, F_SETFL, O_NONBLOCK )<0 )
- {
- y2err("fcntl O_NONBLOCK failed errno:" << errno << " (" << stringerror(errno) << ")");
- }
+ y2err("fcntl O_NONBLOCK failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- y2deb("sout:" << pfds[0].fd << " serr:" << (Combine_b?-1:pfds[1].fd));
+ y2deb("sout:" << pfds[0].fd << " serr:" << pfds[1].fd);
const vector<const char*> env = make_env();
{
y2err("dup2 stdout child failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- if( !Combine_b && dup2( serr[1], STDERR_FILENO )<0 )
- {
- y2err("dup2 stderr child failed errno:" << errno << " (" << stringerror(errno) << ")");
- }
- if( Combine_b && dup2( STDOUT_FILENO, STDERR_FILENO )<0 )
+ if( dup2( serr[1], STDERR_FILENO )<0 )
{
y2err("dup2 stderr child failed errno:" << errno << " (" << stringerror(errno) << ")");
}
{
y2err("close child failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- if( !Combine_b && close( serr[0] )<0 )
+ if( close( serr[0] )<0 )
{
y2err("close child failed errno:" << errno << " (" << stringerror(errno) << ")");
}
closeOpenFds();
- Ret_i = execle(Shell_Ci.c_str(), Shell_Ci.c_str(), "-c", Cmd.c_str(), nullptr, &env[0]);
- y2err("SHOULD NOT HAPPEN \"" << Shell_Ci << "\" Ret:" << Ret_i);
+ Ret_i = execle(SH_BIN, SH_BIN, "-c", Cmd.c_str(), nullptr, &env[0]);
+ y2err("SHOULD NOT HAPPEN \"" SH_BIN "\" Ret:" << Ret_i);
break;
case -1:
Ret_i = -1;
{
y2err("close parent failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- if( !Combine_b && close( serr[1] )<0 )
+ if( close( serr[1] )<0 )
{
y2err("close parent failed errno:" << errno << " (" << stringerror(errno) << ")");
}
{
y2err("fdopen stdout failed errno:" << errno << " (" << stringerror(errno) << ")");
}
- if( !Combine_b )
+ File_aC[IDX_STDERR] = fdopen( serr[0], "r" );
+ if( File_aC[IDX_STDERR] == NULL )
{
- File_aC[IDX_STDERR] = fdopen( serr[0], "r" );
- if( File_aC[IDX_STDERR] == NULL )
- {
y2err("fdopen stderr failed errno:" << errno << " (" << stringerror(errno) << ")");
- }
- }
- if( !Background_b )
- {
- doWait( true, Ret_i );
- y2mil("stopwatch " << stopwatch << " for \"" << cmd() << "\"");
}
+
+ doWait( Ret_i );
+ y2mil("stopwatch " << stopwatch << " for \"" << cmd() << "\"");
+
break;
}
}
- else if( !testmode )
- {
- Ret_i = -1;
- }
else
{
- Ret_i = 0;
- y2mil("TESTMODE would execute \"" << Cmd << "\"");
+ Ret_i = -1;
}
if( Ret_i==-127 || Ret_i==-1 )
{
y2err("system (\"" << Cmd << "\") = " << Ret_i);
}
- if( !testmode )
- checkOutput();
+ checkOutput();
y2mil("system() Returns:" << Ret_i);
if (Ret_i != 0 && log_output)
logOutput();
bool
-SystemCmd::doWait( bool Hang_bv, int& Ret_ir )
+SystemCmd::doWait( int& Ret_ir )
{
int Wait_ii;
int Status_ii;
do
{
- y2deb("[0] id:" << pfds[0].fd << " ev:" << hex << (unsigned)pfds[0].events << dec << " [1] fs:" <<
- (Combine_b?-1:pfds[1].fd) << " ev:" << hex << (Combine_b?0:(unsigned)pfds[1].events));
- int sel = poll( pfds, Combine_b?1:2, 1000 );
+ y2deb("[0] fd:" << pfds[0].fd << " ev:" << hex << (unsigned)(pfds[0].events) << dec << " "
+ "[1] fd:" << pfds[1].fd << " ev:" << hex << (unsigned)(pfds[1].events));
+ int sel = poll( pfds, 2, 1000 );
if (sel < 0)
{
y2err("poll failed errno:" << errno << " (" << stringerror(errno) << ")");
Wait_ii = waitpid( Pid_i, &Status_ii, WNOHANG );
y2deb("Wait ret:" << Wait_ii);
}
- while( Hang_bv && Wait_ii == 0 );
+ while( Wait_ii == 0 );
if( Wait_ii != 0 )
{
checkOutput();
fclose( File_aC[IDX_STDOUT] );
File_aC[IDX_STDOUT] = NULL;
- if( !Combine_b )
- {
- fclose( File_aC[IDX_STDERR] );
- File_aC[IDX_STDERR] = NULL;
- }
+ fclose( File_aC[IDX_STDERR] );
+ File_aC[IDX_STDERR] = NULL;
if (WIFEXITED(Status_ii))
{
Ret_ir = WEXITSTATUS(Status_ii);
}
y2deb("Wait:" << Wait_ii << " pid:" << Pid_i << " stat:" << Status_ii <<
- " Hang:" << Hang_bv << " Ret:" << Ret_ir);
+ " Ret:" << Ret_ir);
return Wait_ii != 0;
}
-void
-SystemCmd::setCombine(bool val)
-{
- Combine_b = val;
-}
-
-
-void
-SystemCmd::setTestmode(bool val)
-{
- testmode = val;
-}
-
-
unsigned
-SystemCmd::numLines( bool Sel_bv, OutputStream Idx_iv ) const
+SystemCmd::numLines( OutputStream Idx_iv ) const
{
unsigned Ret_ii;
{
y2err("invalid index " << Idx_iv);
}
- if( Sel_bv )
- {
- Ret_ii = SelLines_aC[Idx_iv].size();
- }
- else
- {
- Ret_ii = Lines_aC[Idx_iv].size();
- }
+ Ret_ii = Lines_aC[Idx_iv].size();
y2deb("ret:" << Ret_ii);
return Ret_ii;
}
string
-SystemCmd::getLine( unsigned Nr_iv, bool Sel_bv, OutputStream Idx_iv ) const
+SystemCmd::getLine( unsigned Nr_iv, OutputStream Idx_iv ) const
{
string ret;
{
y2err("invalid index " << Idx_iv);
}
- if( Sel_bv )
- {
- if( Nr_iv < SelLines_aC[Idx_iv].capacity() )
- {
- ret = *SelLines_aC[Idx_iv][Nr_iv];
- }
- }
- else
+ if( Nr_iv < Lines_aC[Idx_iv].size() )
{
- if( Nr_iv < Lines_aC[Idx_iv].size() )
- {
- ret = Lines_aC[Idx_iv][Nr_iv];
- }
+ ret = Lines_aC[Idx_iv][Nr_iv];
}
return ret;
}
{
for (int Idx_ii = 0; Idx_ii < 2; Idx_ii++)
{
- SelLines_aC[Idx_ii].resize(0);
Lines_aC[Idx_ii].clear();
NewLineSeen_ab[Idx_ii] = true;
}
void
SystemCmd::logOutput() const
{
- unsigned lines = numLines(false, IDX_STDERR);
+ unsigned lines = numLines(IDX_STDERR);
if (lines <= line_limit)
{
for (unsigned i = 0; i < lines; ++i)
- y2mil("stderr:" << getLine(i, false, IDX_STDERR));
+ y2mil("stderr:" << getLine(i, IDX_STDERR));
}
else
{
for (unsigned i = 0; i < line_limit / 2; ++i)
- y2mil("stderr:" << getLine(i, false, IDX_STDERR));
+ y2mil("stderr:" << getLine(i, IDX_STDERR));
y2mil("stderr omitting lines");
for (unsigned i = lines - line_limit / 2; i < lines; ++i)
- y2mil("stderr:" << getLine(i, false, IDX_STDERR));
+ y2mil("stderr:" << getLine(i, IDX_STDERR));
}
- lines = numLines(false, IDX_STDOUT);
+ lines = numLines(IDX_STDOUT);
if (lines <= line_limit)
{
for (unsigned i = 0; i < lines; ++i)
- y2mil("stdout:" << getLine(i, false, IDX_STDOUT));
+ y2mil("stdout:" << getLine(i, IDX_STDOUT));
}
else
{
for (unsigned i = 0; i < line_limit / 2; ++i)
- y2mil("stdout:" << getLine(i, false, IDX_STDOUT));
+ y2mil("stdout:" << getLine(i, IDX_STDOUT));
y2mil("stdout omitting lines");
for (unsigned i = lines - line_limit / 2; i < lines; ++i)
- y2mil("stdout:" << getLine(i, false, IDX_STDOUT));
+ y2mil("stdout:" << getLine(i, IDX_STDOUT));
}
}
return "'" + boost::replace_all_copy(str, "'", "'\\''") + "'";
}
-
-string
-SystemCmd::quote(const list<string>& strs)
-{
- string ret;
- for (std::list<string>::const_iterator it = strs.begin(); it != strs.end(); it++)
- {
- if (it != strs.begin())
- ret.append(" ");
- ret.append(quote(*it));
- }
- return ret;
-}
-
-
-bool SystemCmd::testmode = false;
-
}
/*
* Copyright (c) [2004-2014] Novell, Inc.
- * Copyright (c) [2018-2020] SUSE LLC
+ * Copyright (c) [2018-2021] SUSE LLC
*
* All Rights Reserved.
*
#include <string>
#include <vector>
-#include <list>
#include <boost/noncopyable.hpp>
{
public:
- enum OutputStream { IDX_STDOUT, IDX_STDERR };
-
SystemCmd(const string& Command_Cv, bool log_output = true);
virtual ~SystemCmd();
- protected:
+ private:
+
+ enum OutputStream { IDX_STDOUT, IDX_STDERR };
int execute(const string& Command_Cv);
- int executeBackground(const string& Command_Cv);
- int executeRestricted(const string& Command_Cv,
- unsigned long MaxTimeSec, unsigned long MaxLineOut,
- bool& ExceedTime, bool& ExceedLines);
public:
string cmd() const { return lastCmd; }
int retcode() const { return Ret_i; }
- protected:
+ private:
- unsigned numLines(bool Selected_bv = false, OutputStream Idx_ii = IDX_STDOUT) const;
- string getLine(unsigned Num_iv, bool Selected_bv = false, OutputStream Idx_ii = IDX_STDOUT) const;
-
- void setCombine(bool combine = true);
-
- static void setTestmode(bool testmode = true);
+ unsigned numLines(OutputStream Idx_ii = IDX_STDOUT) const;
+ string getLine(unsigned Num_iv, OutputStream Idx_ii = IDX_STDOUT) const;
public:
*/
static string quote(const string& str);
- /**
- * Quotes and protects every single string in the list for shell execution.
- */
- static string quote(const std::list<string>& strs);
-
- protected:
+ private:
void invalidate();
void closeOpenFds() const;
int doExecute(const string& Cmd_Cv);
- bool doWait(bool Hang_bv, int& Ret_ir);
+ bool doWait(int& Ret_ir);
void checkOutput();
- void getUntilEOF(FILE* File_Cr, std::vector<string>& Lines_Cr, bool& NewLineSeen_br,
+ void getUntilEOF(FILE* File_Cr, vector<string>& Lines_Cr, bool& NewLineSeen_br,
bool Stderr_bv);
void extractNewline(const string& Buf_ti, int Cnt_ii, bool& NewLineSeen_br,
- string& Text_Cr, std::vector<string>& Lines_Cr);
- void addLine(const string& Text_Cv, std::vector<string>& Lines_Cr);
+ string& Text_Cr, vector<string>& Lines_Cr);
+ void addLine(const string& Text_Cv, vector<string>& Lines_Cr);
void init();
void logOutput() const;
vector<const char*> make_env() const;
FILE* File_aC[2];
- std::vector<string> Lines_aC[2];
- std::vector<string*> SelLines_aC[2];
+ vector<string> Lines_aC[2];
bool NewLineSeen_ab[2];
- bool Combine_b;
bool log_output;
- bool Background_b;
string lastCmd;
int Ret_i;
int Pid_i;
struct pollfd pfds[2];
- static bool testmode;
-
static const unsigned line_limit = 50;
};
return SystemCmd::quote(str);
}
- inline string quote(const std::list<string>& strs)
- {
- return SystemCmd::quote(strs);
- }
-
}
#endif