Commit e2e258ae authored by Eric Cano's avatar Eric Cano
Browse files

Catching up with master branch

parents e25badf5 0a091aff
......@@ -29,7 +29,7 @@
#include <gtest/gtest.h>
#include <gmock/gmock-cardinalities.h>
namespace UnitTests {
namespace unitTests {
class Nested {
public:
void f1();
......
/******************************************************************************
* castor/log/LoggerImplementationTest.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/log/LoggerImplementation.hpp"
#include <gtest/gtest.h>
#include <memory>
#include <sys/time.h>
namespace unitTests {
class castor_log_LoggerImplementationTest: public ::testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
}
}; // class LoggerImplementationTest
TEST_F(castor_log_LoggerImplementationTest, testLogMsgWithAllParams) {
using namespace castor::log;
std::auto_ptr<Logger> logger;
ASSERT_NO_THROW(logger.reset(new LoggerImplementation("unitttests")));
const int numParams = 1;
const Param params[1] = {Param("testParam", "valueOfTestParam")};
struct timeval timeStamp;
ASSERT_EQ(0, gettimeofday(&timeStamp, NULL));
ASSERT_NO_THROW(
logger->logMsg(
LOG_INFO,
"Calling logMsg() with all parameters",
numParams,
params,
timeStamp));
}
TEST_F(castor_log_LoggerImplementationTest, testLogMsgWithoutTimeStamp) {
using namespace castor::log;
std::auto_ptr<Logger> logger;
ASSERT_NO_THROW(logger.reset(new LoggerImplementation("unitttests")));
const int numParams = 1;
const Param params[1] = {Param("testParam", "valueOfTestParam")};
ASSERT_NO_THROW(
logger->logMsg(
LOG_INFO,
"Calling logMsg() without time stamp",
numParams,
params));
}
TEST_F(castor_log_LoggerImplementationTest, testLogMsgWithoutParamsOrTimeStamp) {
using namespace castor::log;
std::auto_ptr<Logger> logger;
ASSERT_NO_THROW(logger.reset(new LoggerImplementation("unitttests")));
ASSERT_NO_THROW(
logger->logMsg(
LOG_INFO,
"Calling logMsg() without parameters or time stamp"));
}
} // namespace unitTests
/******************************************************************************
* test/unittest/castor/log/ParamTest.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/log/Param.hpp"
#include <gtest/gtest.h>
#include <memory>
namespace unitTests {
class castor_log_ParamTest: public ::testing::Test {
protected:
void SetUp() {
}
void TearDown() {
}
}; // castor_log_ParamTest
TEST_F(castor_log_ParamTest, testConstructorWithAString) {
using namespace castor::log;
std::auto_ptr<Param> param;
ASSERT_NO_THROW(param.reset(new Param("Name", "Value")));
ASSERT_EQ(std::string("Name"), param->getName());
ASSERT_EQ(std::string("Value"), param->getValue());
}
TEST_F(castor_log_ParamTest, testConstructorWithAnInt) {
using namespace castor::log;
std::auto_ptr<Param> param;
ASSERT_NO_THROW(param.reset(new Param("Name", 1234)));
ASSERT_EQ(std::string("Name"), param->getName());
ASSERT_EQ(std::string("1234"), param->getValue());
}
} // namespace unitTests
......@@ -21,6 +21,8 @@
******************************************************************************/
#include "castor/dlf/Dlf.hpp"
#include "castor/exception/Errnum.hpp"
#include "castor/exception/Internal.hpp"
#include "castor/io/UDPSocket.hpp"
#include "castor/server/Daemon.hpp"
#include "castor/server/ThreadNotification.hpp"
......@@ -29,6 +31,7 @@
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
//------------------------------------------------------------------------------
// constructor
......@@ -190,38 +193,47 @@ void castor::server::Daemon::dlfInit(castor::dlf::Message messages[])
// daemonize
//------------------------------------------------------------------------------
void castor::server::Daemon::daemonize() throw (castor::exception::Exception) {
// Do nothing if already a daemon
if (1 == getppid()) {
return;
}
// If the daemon is to be run in the background
if (!m_foreground) {
m_logger.prepareForFork();
{
pid_t pid = 0;
castor::exception::Errnum::throwOnNegative(pid = fork(),
"Failed to daemonize: Failed to fork");
// If we got a good PID, then we can exit the parent process
if (0 < pid) {
exit(EXIT_SUCCESS);
}
}
// We could set our working directory to '/' here with a call to chdir(2).
// For the time being we don't and leave it to the initd script to change
// to a suitable directory for us!
int pid = fork();
if (pid < 0) {
castor::exception::Internal ex;
ex.getMessage() << "Background daemon initialization failed with result "
<< pid << std::endl;
throw ex;
}
else if (pid > 0) {
// The parent exits normally
exit(EXIT_SUCCESS);
}
// Change the file mode mask
umask(0);
// Run the daemon in a new session
setsid();
// Redirect the standard file descriptors to /dev/null
if ((freopen("/dev/null", "r", stdin) == NULL) ||
(freopen("/dev/null", "w", stdout) == NULL) ||
(freopen("/dev/null", "w", stderr) == NULL)) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to redirect standard file descriptors to "
<< "/dev/null" << std::endl;
throw ex;
}
}
castor::exception::Errnum::throwOnNegative(setsid(),
"Failed to daemonize: Failed to run daemon is a new session");
// Redirect standard files to /dev/null
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "r", stdin),
"Failed to daemonize: Falied to freopen stdin");
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "w", stdout),
"Failed to daemonize: Failed to freopen stdout");
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "w", stderr),
"Failed to daemonize: Failed to freopen stderr");
} // if (!m_foreground)
// Change the user of the daemon process to the Castor superuser if requested
if (m_runAsStagerSuperuser) {
......
......@@ -30,7 +30,7 @@
#include <stdio.h>
#include <string.h>
namespace UnitTests {
namespace unitTests {
class castor_server_DaemonTest : public ::testing::Test {
protected:
......@@ -99,4 +99,4 @@ TEST_F(castor_server_DaemonTest, parseFOnCmdLine) {
ASSERT_EQ(true, daemon.getForeground());
}
} // namespace UnitTests
} // namespace unitTests
......@@ -31,7 +31,7 @@ using ::testing::AtLeast;
using ::testing::Return;
using ::testing::_;
namespace UnitTests {
namespace unitTests {
castor::tape::System::mockWrapper sysWrapper;
TEST(castor_tape_SCSI_DeviceList, TriesToFind) {
......
......@@ -33,7 +33,7 @@ using ::testing::AtLeast;
using ::testing::Return;
using ::testing::_;
namespace UnitTests {
namespace unitTests {
TEST(castor_tape_SCSI_Structures, inquiryData_t_multi_byte_numbers_strings) {
/* Validate the bit field behavior of the struct inquiryData_t,
which represents the standard INQUIRY data format as defined in
......
add_executable(tapeserverd tapeserverd.cpp)
add_executable(tapeserverd TapeDaemon.cpp TapeDaemonMain.cpp)
target_link_libraries(tapeserverd Exception SCSI System Utils File castorcommon
castorclient)
......@@ -10,4 +10,4 @@ add_library(tapeserverdTest
../../tpcp/TpcpCommand.cpp
../../tpcp/StreamOperators.cpp
../../tpcp/Helper.cpp
../../tpcp/TapeFseqRange.cpp)
\ No newline at end of file
../../tpcp/TapeFseqRange.cpp)
/******************************************************************************
* tapeserverd.cpp
* castor/tape/tapeserver/daemon/TapeDaemon.cpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
......@@ -17,192 +17,122 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Castor Dev team, castor-dev@cern.ch
*
* @author Steven.Murray@cern.ch
*****************************************************************************/
#include "tapeserverd.hpp"
#include "castor/log/LoggerImplementation.hpp"
#include "log.h"
#include "castor/io/AbstractSocket.hpp"
#include "castor/PortNumbers.hpp"
#include "castor/exception/Errnum.hpp"
#include "castor/exception/Internal.hpp"
#include "castor/exception/InvalidArgument.hpp"
#include "castor/tape/tapeserver/daemon/TapeDaemon.hpp"
#include "castor/tape/utils/utils.hpp"
#include <iostream>
#include <exception>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sstream>
#include <algorithm>
#include <memory>
#include <signal.h>
//------------------------------------------------------------------------------
// main
// constructor
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
return castor::tape::Server::Daemon::main(argc, argv);
castor::tape::tapeserver::daemon::TapeDaemon::TapeDaemon::TapeDaemon(std::ostream &stdOut,
std::ostream &stdErr, log::Logger &logger)
throw(castor::exception::Exception):
castor::server::Daemon(stdOut, stdErr, logger),
m_programName("tapeserverd") {
}
//------------------------------------------------------------------------------
// main
// destructor
//------------------------------------------------------------------------------
int castor::tape::Server::Daemon::main(int argc, char ** argv) throw() {
try {
/* Before anything, we need a logger: */
castor::log::LoggerImplementation logger("tapeserverd");
try {
/* Setup the object (parse command line, register logger) */
castor::tape::Server::Daemon
daemon(argc, argv, std::cout, std::cerr, logger);
/* ... and run. */
daemon.run();
/* Catch all block for any left over exception which will go to the logger */
} catch (std::exception & e) {
logger.logMsg(LOG_ALERT, std::string("Uncaught standard exception in tapeserverd:\n")+
e.what());
exit(EXIT_FAILURE);
} catch (...) {
logger.logMsg(LOG_ALERT, std::string("Uncaught non-standard exception in tapeserverd."));
exit(EXIT_FAILURE);
}
/* Catch-all block for before logger creation. */
} catch (std::exception & e) {
std::cerr << "Uncaught standard exception in tapeserverd:" << std::endl
<< e.what() << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Uncaught non-standard exception in tapeserverd." << std::endl;
exit(EXIT_FAILURE);
}
return (EXIT_SUCCESS);
castor::tape::tapeserver::daemon::TapeDaemon::~TapeDaemon() throw() {
}
//------------------------------------------------------------------------------
// constructor
// main
//------------------------------------------------------------------------------
castor::tape::Server::Daemon::Daemon(int argc, char** argv,
std::ostream &stdOut, std::ostream &stdErr, castor::log::Logger & logger)
throw (castor::tape::Exception):
castor::server::Daemon(stdOut, stdErr, logger),
m_option_run_directory ("/var/log/castor") {
parseCommandLineOptions(argc, argv);
int castor::tape::tapeserver::daemon::TapeDaemon::main(const int argc,
char **const argv) throw() {
try {
exceptionThrowingMain(argc, argv);
} catch (castor::exception::Exception &ex) {
std::ostringstream msg;
msg << "Caught an unexpected exception: " << ex.getMessage().str();
m_stdErr << std::endl << msg.str() << std::endl << std::endl;
log::Param params[] = {
log::Param("Message", msg.str()),
log::Param("Code" , ex.code())};
logMsg(LOG_INFO, msg.str(), params);
return 1;
}
return 0;
}
//------------------------------------------------------------------------------
// run
// exceptionThrowingMain
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::run() {
/* Block signals, we will handle them synchronously */
int castor::tape::tapeserver::daemon::TapeDaemon::exceptionThrowingMain(
const int argc, char **const argv) throw(castor::exception::Exception) {
logStartOfDaemon(argc, argv);
parseCommandLine(argc, argv);
blockSignals();
/* Daemonize if requested */
if (!getForeground()) daemonize();
/* Setup the the mother forker, which will spawn and handle the tape sessions */
/* TODO */
/* Setup the listening socket for VDQM requests */
/* TODO */
/* Loop on both */
return 0;
}
//------------------------------------------------------------------------------
// parseCommandLineOptions
// logStartOfDaemon
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::parseCommandLineOptions(int argc,
char** argv) throw (castor::tape::Exception) {
bool foreground = false; // Should the daemon run in the foreground?
/* Expect -f or --foreground */
struct ::option opts[] = {
{ "foreground", no_argument, 0, 'f'},
{ 0, 0, 0, 0}
};
int c;
while (-1 != (c = getopt_long(argc, argv, ":f", opts, NULL))) {
switch (c) {
case 'f':
foreground = true;
break;
case ':':
{
castor::tape::exceptions::InvalidArgument ex(std::string("The -") + (char) optopt + " option requires a parameter");
throw ex;
}
case '?':
{
std::stringstream err("Unknown command-line option");
if (optopt) err << std::string(": -") << optopt;
castor::tape::exceptions::InvalidArgument ex(err.str().c_str());
throw ex;
}
default:
{
std::stringstream err;
err << "getopt_long returned the following unknown value: 0x" <<
std::hex << (int) c;
castor::tape::exceptions::InvalidArgument ex(err.str().c_str());
throw ex;
}
}
}
setCommandLineHasBeenParsed(foreground);
void castor::tape::tapeserver::daemon::TapeDaemon::logStartOfDaemon(
const int argc, const char *const *const argv) throw() {
const std::string concatenatedArgs = argvToString(argc, argv);
std::ostringstream msg;
msg << m_programName << " started";
log::Param params[] = {
log::Param("argv", concatenatedArgs)};
logMsg(LOG_INFO, msg.str(), params);
}
//------------------------------------------------------------------------------
// daemonize
// argvToString
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::daemonize()
{
pid_t pid, sid;
/* already a daemon */
if (getppid() == 1) return;
/* Fork off the parent process */
castor::exception::Errnum::throwOnNegative(pid = fork(),
"Failed to fork in castor::tape::Server::Daemon::daemonize");
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
/* Create a new session for the child process */
castor::exception::Errnum::throwOnNegative(sid = setsid(),
"Failed to create new session in castor::tape::Server::Daemon::daemonize");
/* At this point we are executing as the child process, and parent process should be init */
if (getppid() != 1) {
castor::tape::Exception e("Failed to detach from parent process in castor::tape::Server::Daemon::daemonize");
throw e;
std::string castor::tape::tapeserver::daemon::TapeDaemon::argvToString(
const int argc, const char *const *const argv) throw() {
std::string str;
for(int i=0; i < argc; i++) {
if(i != 0) {
str += " ";
}
str += argv[i];
}
/* Change the current working directory. This prevents the current
directory from being locked; hence not being able to remove it. */
castor::exception::Errnum::throwOnNegative(
chdir(m_option_run_directory.c_str()),
std::string("Failed to chdir in castor::tape::Server::Daemon::daemonize"
" ( destination directory: ") + m_option_run_directory + ")");
/* Redirect standard files to /dev/null */
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "r", stdin),
"Failed to freopen stdin in castor::tape::Server::Daemon::daemonize");
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "r", stdout),
"Failed to freopen stdout in castor::tape::Server::Daemon::daemonize");
castor::exception::Errnum::throwOnNull(
freopen("/dev/null", "r", stderr),
"Failed to freopen stderr in castor::tape::Server::Daemon::daemonize");
return str;
}
//------------------------------------------------------------------------------
// blockSignals
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::blockSignals()
{
void castor::tape::tapeserver::daemon::TapeDaemon::blockSignals() const
throw(castor::exception::Exception) {
sigset_t sigs;
sigemptyset(&sigs);
/* The list of signal that should not disturb our daemon. Some of them
* will be dealt with synchronously in the main loop.
* See signal(7) for full list.
*/
// The list of signal that should not disturb our daemon. Some of them
// will be dealt with synchronously in the main loop.
// See signal(7) for full list.
sigaddset(&sigs, SIGHUP);
sigaddset(&sigs, SIGINT);
sigaddset(&sigs, SIGQUIT);
......@@ -218,6 +148,6 @@ void castor::tape::Server::Daemon::blockSignals()
sigaddset(&sigs, SIGURG);
sigaddset(&sigs, SIGVTALRM);
castor::exception::Errnum::throwOnNonZero(
sigprocmask(SIG_BLOCK, &sigs, NULL),
sigprocmask(SIG_BLOCK, &sigs, NULL),
"Failed to sigprocmask in castor::tape::Server::Daemon::blockSignals");
}
/******************************************************************************
* tapeserverd.hpp
* castor/tape/tapeserver/daemon/TapeDaemon.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
......@@ -17,61 +17,103 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
*
* @author Castor Dev team, castor-dev@cern.ch
*
* @author Steven.Murray@cern.ch
*****************************************************************************/
#pragma once
#include "../exception/Exception.hpp"
#ifndef CASTOR_TAPE_TAPESERVER_DAEMON_TAPEDAEMON_HPP
#define CASTOR_TAPE_TAPESERVER_DAEMON_TAPEDAEMON_HPP 1