Commit 7359e4ad authored by Steven Murray's avatar Steven Murray
Browse files

Replaced:

    tapeserverd.cpp and tapeserverd.hpp

with:

    TapeDaemon.cpp, tapeDaemon.hpp  and TapeDaemonMain.cpp
parent c8214013
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
#include "castor/exception/Exception.hpp"
#include "castor/exception/InvalidConfigEntry.hpp"
#include "castor/server/Daemon.hpp"
namespace castor {
namespace tape {
namespace Server {
#include <stdint.h>
#include <iostream>
#include <list>
#include <map>
#include <string>
class Daemon: public castor::server::Daemon {
public:
/** Wrapper for main */
static int main (int argc, char ** argv) throw ();
namespace castor {
namespace tape {
namespace tapeserver {
namespace daemon {
/**
* Daemon responsible for reading and writing data from and to one or more tape
* drives drives connected to a tape server.
*/
class TapeDaemon : public castor::server::Daemon {
public:
/**
* Constructor: parse the command line
* Constructor.
*
* @param argc The number of command-line arguments.
* @param argv The array of command-line arguments.
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
* @param log The object representing the API of the CASTOR logging system.
*/
Daemon (int argc, char ** argv, std::ostream &stdOut, std::ostream &stdErr,
castor::log::Logger & logger) throw (castor::tape::Exception);
TapeDaemon(std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger)
throw(castor::exception::Exception);
/** Run the daemon: daemonize if needed, and run the main loop. */
/**
* Destructor.
*/
~TapeDaemon() throw();
void run();
~Daemon() throw () {}
/**
* The main entry function of the daemon.
*
* @param argc The number of command-line arguments.
* @param argv The array of command-line arguments.
* @return The return code of the process.
*/
int main(const int argc, char **const argv) throw();
private:
void parseCommandLineOptions(int argc, char ** argv) throw (castor::tape::Exception);
/**
* Exception throwing main() function.
*/
int exceptionThrowingMain(const int argc, char **const argv)
throw(castor::exception::Exception);
/**
* Logs the start of the daemon.
*/
void logStartOfDaemon(const int argc, const char *const *const argv) throw();
/** This daemonize() version has to be merged into castor::server::Daemon::daemonize
* which has a few things to check (error cases for fork are not handled correctly,
* error cases for setsid are not looked at, there is a forced switch to stager
* user, while taped (and children) and rtcpd (but not its children) run
* as root. There is some calls to signal in daemonize for just 2 signals */
void daemonize();
/**
* Creates a string that contains the specified command-line arguments
* separated by single spaces.
*
* @param argc The number of command-line arguments.
* @param argv The array of command-line arguments.
*/
std::string argvToString(const int argc, const char *const *const argv)
throw();
/** We block all signals, so that they can be handled synchronously with
* a sigtimedwait in the main loop (alternately with a poll using a
* non-zero timeout. */
void blockSignals();
/**
* We block all signals, so that they can be handled synchronously with
* a sigtimedwait in the main loop (alternatively with a call to poll using a
* non-zero timeout).
*/
void blockSignals() const throw(castor::exception::Exception);
std::string m_option_run_directory;
}; // class Daemon
/**
* The program name of the tape daemon.
*/
const std::string m_programName;
} // namespace castor
}; // class TapeDaemon
} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace Server
} // namespace castor
#endif // CASTOR_TAPE_TAPESERVER_DAEMON_TAPEDAEMON_HPP
/******************************************************************************
* castor/tape/tapeserver/TapeDaemonMain.cpp
*
* 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 "castor/tape/tapeserver/daemon/TapeDaemon.hpp"
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(const int argc, char **const argv) {
castor::log::LoggerImplementation logger("tapeserverd");
castor::tape::tapeserver::daemon::TapeDaemon
daemon(std::cout, std::cerr, logger);
return daemon.main(argc, argv);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment