Commit 78032a7b authored by Victor Kotlyar's avatar Victor Kotlyar
Browse files

Removed tapeserver/castor/server completely

parent 93cae3ad
......@@ -223,7 +223,6 @@ Unit tests and system tests with virtual tape drives
%attr(0755,root,root) %{_libdir}/libctardbmsunittests.so
%attr(0755,root,root) %{_libdir}/libctaremotensunittests.so
%attr(0755,root,root) %{_libdir}/libctaschedulerunittests.so
%attr(0755,root,root) %{_libdir}/libctaserverunittests.so
%attr(0755,root,root) %{_libdir}/libctatapereactorunittests.so
%attr(0755,root,root) %{_libdir}/libctatapeserverdaemonunittests.so
%attr(0755,root,root) %{_libdir}/libctatapeserverdriveunittests.so
......
......@@ -22,6 +22,5 @@ add_subdirectory (io)
add_subdirectory (legacymsg)
add_subdirectory (mediachanger)
add_subdirectory (messages)
add_subdirectory (server)
add_subdirectory (tape)
add_subdirectory (utils)
/******************************************************************************
*
* 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.
*
* @(#)BaseClient.cpp,v 1.37 $Release$ 2006/02/16 15:56:58 sponcec3
*
* A class with static methods for system level utilities.
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
// Include Files
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
// Local includes
#include "System.hpp"
#include "common/exception/OutOfMemory.hpp"
#define STAGERSUPERGROUP "st"
#define STAGERSUPERUSER "stage"
//------------------------------------------------------------------------------
// getHostName
//------------------------------------------------------------------------------
std::string castor::System::getHostName()
{
// All this to get the hostname, thanks to C !
int len = 64;
char* hostname;
hostname = (char*) calloc(len, 1);
if (0 == hostname) {
cta::exception::OutOfMemory ex;
ex.getMessage() << "Could not allocate hostname with length " << len;
throw ex;
}
if (gethostname(hostname, len) < 0) {
// Test whether error is due to a name too long
// The errno depends on the glibc version
if (EINVAL != errno &&
ENAMETOOLONG != errno) {
free(hostname);
cta::exception::Exception e;
e.getMessage() << "gethostname error";
throw e;
}
// So the name was too long
while (hostname[len - 1] != 0) {
len *= 2;
char *hostnameLonger = (char*) realloc(hostname, len);
if (0 == hostnameLonger) {
free(hostname);
cta::exception::Exception e;
e.getMessage() << "Could not allocate memory for hostname";
throw e;
}
hostname = hostnameLonger;
memset(hostname, 0, len);
if (gethostname(hostname, len) < 0) {
// Test whether error is due to a name too long
// The errno depends on the glibc version
if (EINVAL != errno &&
ENAMETOOLONG != errno) {
free(hostname);
cta::exception::Exception e;
e.getMessage() << "Could not get hostname"
<< strerror(errno);
throw e;
}
}
}
}
std::string res(hostname); // copy the string
free(hostname);
return res;
}
//------------------------------------------------------------------------------
// porttoi
//------------------------------------------------------------------------------
int castor::System::porttoi(char* str)
{
char* dp = str;
errno = 0;
int iport = strtoul(str, &dp, 0);
if (*dp != 0) {
cta::exception::Exception e;
e.getMessage() << "Bad port value." << std::endl;
throw e;
}
if ((iport > 65535) || (iport < 0)) {
cta::exception::Exception e;
e.getMessage()
<< "Invalid port value : " << iport
<< ". Must be < 65535 and > 0." << std::endl;
throw e;
}
return iport;
}
//------------------------------------------------------------------------------
// switchToCastorSuperuser
//------------------------------------------------------------------------------
void castor::System::switchToCastorSuperuser()
{
struct passwd *stage_passwd; // password structure pointer
struct group *stage_group; // group structure pointer
uid_t ruid, euid; // Original uid/euid
gid_t rgid, egid; // Original gid/egid
// Save original values
ruid = getuid();
euid = geteuid();
rgid = getgid();
egid = getegid();
// Get information on generic stage account from password file
if ((stage_passwd = getpwnam(STAGERSUPERUSER)) == NULL) {
cta::exception::Exception e;
e.getMessage() << "Castor super user " << STAGERSUPERUSER
<< " not found in password file";
throw e;
}
// verify existence of its primary group id
if (getgrgid(stage_passwd->pw_gid) == NULL) {
cta::exception::Exception e;
e.getMessage() << "Castor super user group does not exist";
throw e;
}
// Get information on generic stage account from group file
if ((stage_group = getgrnam(STAGERSUPERGROUP)) == NULL) {
cta::exception::Exception e;
e.getMessage() << "Castor super user group " << STAGERSUPERGROUP
<< " not found in group file";
throw e;
}
// Verify consistency
if (stage_group->gr_gid != stage_passwd->pw_gid) {
cta::exception::Exception e;
e.getMessage() << "Inconsistent password file. The group of the "
<< "castor superuser " << STAGERSUPERUSER
<< " should be " << stage_group->gr_gid
<< "(" << STAGERSUPERGROUP << "), but is "
<< stage_passwd->pw_gid;
throw e;
}
// Undo group privilege
if (setregid (egid, rgid) < 0) {
cta::exception::Exception e;
e.getMessage() << "Unable to undo group privilege";
throw e;
}
// Undo user privilege
if (setreuid (euid, ruid) < 0) {
cta::exception::Exception e;
e.getMessage() << "Unable to undo user privilege";
throw e;
}
// set the effective privileges to superuser
if (setegid(stage_passwd->pw_gid) < 0) {
cta::exception::Exception e;
e.getMessage() << "Unable to set group privileges of Castor Superuser. "
<< "You may want to check that the suid bit is set properly";
throw e;
}
if (seteuid(stage_passwd->pw_uid) < 0) {
cta::exception::Exception e;
e.getMessage() << "Unable to set privileges of Castor Superuser.";
throw e;
}
}
/******************************************************************************
*
* 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.
*
*
* A class with static methods for system level utilities.
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
// Include Files
#include <string>
#include "common/exception/Exception.hpp"
namespace castor {
class System {
public:
/**
* Gets the host name. Handles all errors that may occur with
* the gethostname() API.
* @exception in case of an error
*/
static std::string getHostName() ;
/**
* Converts a string into a port number, checking
* that the value is in range [0-65535]
* @param str the string giving the port number
* @return the port as an int
* @exception in case of invalid value
*/
static int porttoi(char* str) ;
/**
* Switches the current process to use the Castor superuser
* (typically stage:st).
* @exception in case of an error
*/
static void switchToCastorSuperuser() ;
};
} // end of namespace castor
cmake_minimum_required (VERSION 2.6)
include_directories(${PROJECT_SOURCE_DIR}/tapeserver)
include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h)
#add_library (ctaserverutils
# ProcessCapDummy.cpp
# Semaphores.cpp
# Mutex.cpp
# Threading.cpp
# ProcessCap.cpp
# SmartCap.cpp
# Daemon.cpp)
#
#target_link_libraries(ctaserverutils cap ctautils)
add_library (ctaserverunittests SHARED
DaemonTest.cpp)
target_link_libraries (ctaserverunittests ctautils)
install(TARGETS ctaserverunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
/*******************************************************************************
*
* 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 Castor Dev team, castor-dev@cern.ch
******************************************************************************/
#include "common/exception/Errnum.hpp"
#include "castor/server/Daemon.hpp"
#include "castor/System.hpp"
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::server::Daemon::Daemon(std::ostream &stdOut, std::ostream &stdErr,
cta::log::Logger &log) throw():
m_stdOut(stdOut),
m_stdErr(stdErr),
m_log(log),
m_foreground(false),
m_commandLineHasBeenParsed(false) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
castor::server::Daemon::~Daemon() throw() {
}
//------------------------------------------------------------------------------
// parseCommandLine
//------------------------------------------------------------------------------
void castor::server::Daemon::parseCommandLine(int argc,
char *argv[]) {
struct ::option longopts[4];
longopts[0].name = "foreground";
longopts[0].has_arg = no_argument;
longopts[0].flag = NULL;
longopts[0].val = 'f';
longopts[1].name = "config";
longopts[1].has_arg = required_argument;
longopts[1].flag = NULL;
longopts[1].val = 'c';
longopts[2].name = "help";
longopts[2].has_arg = no_argument;
longopts[2].flag = NULL;
longopts[2].val = 'h';
memset(&longopts[3], 0, sizeof(struct ::option));
char c;
// Reset getopt's global variables to make sure we start fresh
optind=0;
// Prevent getopt from printing out errors on stdout
opterr=0;
// We ask getopt to not reshuffle argv ('+')
while ((c = getopt_long(argc, argv, "+fc:h", longopts, NULL)) != -1) {
switch (c) {
case 'f':
m_foreground = true;
break;
case 'c':
setenv("PATH_CONFIG", optarg, 1);
m_stdOut << "Using configuration file " << optarg << std::endl;
break;
case 'h':
help(argv[0]);
exit(0);
break;
default:
break;
}
}
m_commandLineHasBeenParsed = true;
}
//------------------------------------------------------------------------------
// help
//------------------------------------------------------------------------------
void castor::server::Daemon::help(const std::string &programName)
throw() {
m_stdOut << "Usage: " << programName << " [options]\n"
"\n"
"where options can be:\n"
"\n"
"\t--foreground or -f \tRemain in the Foreground\n"
"\t--config <config-file> or -c \tConfiguration file\n"
"\t--help or -h \tPrint this help and exit\n"
"\n"
"Comments to: Castor.Support@cern.ch\n";
}
//------------------------------------------------------------------------------
// getServerName
//------------------------------------------------------------------------------
const std::string &castor::server::Daemon::getServerName() const throw() {
return m_log.getProgramName();
}
//------------------------------------------------------------------------------
// getForeground
//------------------------------------------------------------------------------
bool castor::server::Daemon::getForeground() const
{
if(!m_commandLineHasBeenParsed) {
cta::exception::CommandLineNotParsed ex;
ex.getMessage() <<
"Failed to determine whether or not the daemon should run in the"
" foreground because the command-line has not yet been parsed";
throw ex;
}
return m_foreground;
}
//-----------------------------------------------------------------------------
// setCommandLineParsed
//-----------------------------------------------------------------------------
void castor::server::Daemon::setCommandLineHasBeenParsed(const bool foreground)
throw() {
m_foreground = foreground;
m_commandLineHasBeenParsed = true;
}
//------------------------------------------------------------------------------
// daemonizeIfNotRunInForeground
//------------------------------------------------------------------------------
void castor::server::Daemon::daemonizeIfNotRunInForeground(
const bool runAsStagerSuperuser) {
// Do nothing if already a daemon
if (1 == getppid()) {
return;
}
// If the daemon is to be run in the background
if (!m_foreground) {
m_log.prepareForFork();
{
pid_t pid = 0;
cta::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!
// Change the file mode mask
umask(0);
// Run the daemon in a new session
cta::exception::Errnum::throwOnNegative(setsid(),
"Failed to daemonize: Failed to run daemon is a new session");
// Redirect standard files to /dev/null
cta::exception::Errnum::throwOnNull(
freopen("/dev/null", "r", stdin),
"Failed to daemonize: Falied to freopen stdin");
cta::exception::Errnum::throwOnNull(
freopen("/dev/null", "w", stdout),
"Failed to daemonize: Failed to freopen stdout");
cta::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 (runAsStagerSuperuser) {
castor::System::switchToCastorSuperuser();
}
// Ignore SIGPIPE (connection lost with client)
// and SIGXFSZ (a file is too big)
signal(SIGPIPE, SIG_IGN);
signal(SIGXFSZ, SIG_IGN);
}
/*******************************************************************************
*
* 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 Castor Dev team, castor-dev@cern.ch
******************************************************************************/
#pragma once
#include "common/exception/CommandLineNotParsed.hpp"
#include "common/log/Logger.hpp"
#include "common/exception/Exception.hpp"
#include <ostream>
namespace castor {
namespace server {
/**
* This class contains the code common to all daemon classes.
*
* The code common to all daemon classes includes daemonization and logging.
*/
class Daemon {
public:
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param log Object representing the API of the CASTOR logging system.
*/
Daemon(std::ostream &stdOut, std::ostream &stdErr, cta::log::Logger &log)
throw();
/**
* Destructor.
*/
virtual ~Daemon() throw();
/**
* Parses a command line to set the server options.
*
* @param argc The size of the command-line vector.
* @param argv The command-line vector.
*/
virtual void parseCommandLine(int argc, char *argv[])
;
/**
* Prints out the online help
*/
virtual void help(const std::string &programName) throw();
/**
* Returns this server's name as used by the CASTOR logging system.
*/
const std::string &getServerName() const throw();
/**
* Returns true if the daemon is configured to run in the foreground.
*/
bool getForeground() const ;
protected:
/**
* Tells the daemon object that the command-line has been parsed. This
* method allows subclasses to implement their own command-line parsing logic,
* whilst enforcing the fact that they must provide values for the options and
* arguments this class requires.
*
* @param foreground Set to true if the daemon should run in the foreground.
*/
void setCommandLineHasBeenParsed(const bool foreground) throw();
/**
* Daemonizes the daemon if it has not been configured to run in the
* foreground.
*
* Please make sure that the setForeground() method has been called as
* appropriate before this method is called.
*
* This method takes into account whether or not the dameon should run in
* foregreound or background mode (m_foreground).
*
* @param runAsStagerSuperuser Set to true if the user ID and group ID of the
* daemon should be set to those of the stager superuser.
*/
void daemonizeIfNotRunInForeground(const bool runAsStagerSuperuser);
/**
* Stream representing standard out.
*/
std::ostream &m_stdOut;
/**
* Stream representing standard in.