Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dCache
cta
Commits
07e7ab5d
Commit
07e7ab5d
authored
Feb 11, 2016
by
Eric Cano
Browse files
Created the embryo of the new cta-taped daemon, importing many daemon utilities
from castor in the exercise.
parent
35d0282d
Changes
82
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
07e7ab5d
...
...
@@ -11,6 +11,12 @@ set(CMAKE_C_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter")
#
# ClientSimulator.hpp:65: error: ISO C++ prohibits anonymous structs
set
(
CMAKE_CXX_FLAGS
"-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-long-long -std=c++0x -fms-extensions -fstack-protector-all"
)
#
# A maximalist error checking parameter combo has been suggested by S. Ponce and D. Come:
# to be tested once we have a stable compilation on CC7:
#-Wno-unused-parameter -Wlogical-op -Wfloat-equal -Wdeclaration-after- statement -Wundef -Wno-endif-labels -Wshadow -Wunsafe-loop- optimizations -Wpointer-arith -Wbad-function-cast -Wcast-align -Wwrite- strings -Wconversion -Wmissing-field-initializers -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Wvariadic-macros -Wtraditional -Wmissing-prototypes -Wmissing-declarations -Wold-style- definition -Wc++-compat -Wstrict-prototypes -Wpadded -Wcast-qual -Wnon-virtual-dtor -Wlogical-op -Wmissing-declarations -Wsign-conversion -Wredundant-decls -Wold-style-cast -Wshadow
# Explicitly setting the C and C++ compiler flags for the RelWithDebInfo build
...
...
@@ -77,6 +83,10 @@ ELSE(DEFINED PackageOnly)
add_subdirectory
(
tapeserver
)
add_subdirectory
(
tests
)
add_subdirectory
(
xroot_plugins
)
#Generate version information
configure_file
(
${
PROJECT_SOURCE_DIR
}
/version.hpp.in
${
CMAKE_BINARY_DIR
}
/version.h
)
ENDIF
(
DEFINED PackageOnly
)
################################################################################
...
...
common/CMakeLists.txt
View file @
07e7ab5d
...
...
@@ -45,30 +45,41 @@ set (COMMON_LIB_SRC_FILES
archiveNS/StorageClass.cpp
archiveNS/Tape.cpp
archiveNS/TapeFileLocation.cpp
ArchiveRequest.cpp
CreationLog.cpp
checksum/Checksum.cpp
exception/Backtrace.cpp
exception/DiskException.hpp
exception/Errnum.cpp
exception/Exception.cpp
exception/Serrnum.cpp
exception/TapeException.cpp
log/DummyLogger.cpp
log/LogContext.cpp
log/Logger.cpp
log/Message.cpp
log/Param.cpp
log/StringLogger.cpp
log/SyslogLogger.cpp
priorities/DriveQuota.cpp
priorities/MountCriteria.cpp
priorities/UserGroup.cpp
processCap/ProcessCap.cpp
processCap/SmartCap.cpp
remoteFS/RemoteFileStatus.cpp
remoteFS/RemotePath.cpp
remoteFS/RemotePathAndStatus.cpp
SecurityIdentity.cpp
strerror_r_wrapper.cpp
TapePool.cpp
Timer.cpp
threading/ChildProcess.cpp
threading/Daemon.cpp
threading/Mutex.cpp
threading/System.cpp
threading/Threading.cpp
utils/Utils.cpp
utils/strerror_r_wrapper.cpp
ArchiveRequest.cpp
CreationLog.cpp
Configuration.cpp
SecurityIdentity.cpp
TapePool.cpp
Timer.cpp
UserIdentity.cpp
Utils.cpp
VO.cpp
)
add_library
(
ctacommon SHARED
...
...
@@ -81,13 +92,18 @@ target_link_libraries (ctacommon
${
SQLITE3_LIBRARY_RELEASE
}
uuid
z
Utils
)
Utils
cap
)
set
(
COMMON_UNIT_TESTS_LIB_SRC_FILES
checksum/ChecksumTest.cpp
log/LogContextTest.cpp
log/ParamTest.cpp
log/SyslogLoggerTest.cpp
remoteFS/RemotePathTest.cpp
UserIdentityTest.cpp
UtilsTest.cpp
)
threading/DaemonTest.cpp
utils/UtilsTest.cpp
UserIdentityTest.cpp
)
add_library
(
ctacommonunittests SHARED
${
COMMON_UNIT_TESTS_LIB_SRC_FILES
}
)
common/Configuration.cpp
0 → 100644
View file @
07e7ab5d
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include
"Configuration.hpp"
#include
"common/exception/Errnum.hpp"
#include
<algorithm>
#include
<fstream>
#include
<errno.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta
::
common
::
Configuration
::
Configuration
(
std
::
string
fileName
)
:
m_fileName
(
fileName
),
m_lastUpdateTime
(
0
)
{
// create internal r/w lock
int
rc
=
pthread_rwlock_init
(
&
m_lock
,
NULL
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"CastorConfiguration constructor Failed"
": Failed to create internal r/w lock"
;
throw
e
;
}
}
//------------------------------------------------------------------------------
// copy constructor
//------------------------------------------------------------------------------
cta
::
common
::
Configuration
::
Configuration
(
const
Configuration
&
other
)
:
m_fileName
(
other
.
m_fileName
),
m_lastUpdateTime
(
other
.
m_lastUpdateTime
),
m_config
(
other
.
m_config
)
{
// create a new internal r/w lock
int
rc
=
pthread_rwlock_init
(
&
m_lock
,
NULL
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"CastorConfiguration copy constructor failed"
": Failed to create a new internal r/w lock"
;
throw
e
;
}
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
cta
::
common
::
Configuration
::~
Configuration
()
{
// relase read write lock
pthread_rwlock_destroy
(
&
m_lock
);
}
//------------------------------------------------------------------------------
// assignment operator
//------------------------------------------------------------------------------
cta
::
common
::
Configuration
&
cta
::
common
::
Configuration
::
operator
=
(
const
cta
::
common
::
Configuration
&
other
)
{
m_fileName
=
other
.
m_fileName
;
m_lastUpdateTime
=
other
.
m_lastUpdateTime
;
m_config
=
other
.
m_config
;
// create a new internal r/w lock
int
rc
=
pthread_rwlock_init
(
&
m_lock
,
NULL
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"Assignment operator of CastorConfiguration object failed"
": Failed to create a new internal r/w lock"
;
throw
e
;
}
return
*
this
;
}
//------------------------------------------------------------------------------
// getConfEntString
//------------------------------------------------------------------------------
const
std
::
string
&
cta
::
common
::
Configuration
::
getConfEntString
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
const
std
::
string
&
defaultValue
,
log
::
Logger
*
const
log
)
{
try
{
if
(
isStale
())
{
tryToRenewConfig
();
}
// get read lock
int
rc
=
pthread_rwlock_rdlock
(
&
m_lock
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Failed to get read lock"
;
throw
e
;
}
// get the entry
std
::
map
<
std
::
string
,
ConfCategory
>::
const_iterator
catIt
=
m_config
.
find
(
category
);
if
(
m_config
.
end
()
!=
catIt
)
{
// get the entry
ConfCategory
::
const_iterator
entIt
=
catIt
->
second
.
find
(
key
);
if
(
catIt
->
second
.
end
()
!=
entIt
)
{
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
entIt
->
second
),
log
::
Param
(
"source"
,
m_fileName
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
return
entIt
->
second
;
}
}
// no entry found
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
defaultValue
),
log
::
Param
(
"source"
,
"DEFAULT"
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
// Unlock and return default
pthread_rwlock_unlock
(
&
m_lock
);
}
catch
(
cta
::
exception
::
Exception
ex
)
{
// exception caught : Unlock and return default
pthread_rwlock_unlock
(
&
m_lock
);
// log the exception
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
defaultValue
),
log
::
Param
(
"source"
,
"DEFAULT"
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
}
catch
(...)
{
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
throw
;
}
return
defaultValue
;
}
//------------------------------------------------------------------------------
// getConfEntString
//------------------------------------------------------------------------------
const
std
::
string
&
cta
::
common
::
Configuration
::
getConfEntString
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
log
::
Logger
*
const
log
)
{
// check whether we need to reload the configuration
if
(
isStale
())
{
tryToRenewConfig
();
}
// get read lock
int
rc
=
pthread_rwlock_rdlock
(
&
m_lock
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Failed to get read lock"
;
throw
e
;
}
// get the entry
try
{
std
::
map
<
std
::
string
,
ConfCategory
>::
const_iterator
catIt
=
m_config
.
find
(
category
);
if
(
m_config
.
end
()
==
catIt
)
{
NoEntry
e
;
e
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Failed to find "
<<
category
<<
" category"
;
throw
e
;
}
// get the entry
ConfCategory
::
const_iterator
entIt
=
catIt
->
second
.
find
(
key
);
if
(
catIt
->
second
.
end
()
==
entIt
)
{
NoEntry
e
;
e
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Failed to find "
<<
key
<<
" key"
;
throw
e
;
}
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
entIt
->
second
),
log
::
Param
(
"source"
,
m_fileName
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
return
entIt
->
second
;
}
catch
(...)
{
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
throw
;
}
}
//------------------------------------------------------------------------------
// isStale
//------------------------------------------------------------------------------
bool
cta
::
common
::
Configuration
::
isStale
()
{
// get read lock
int
rc
=
pthread_rwlock_rdlock
(
&
m_lock
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"Failed to determine if CASTOR configuration is stale"
": Failed to get read lock"
;
throw
e
;
}
try
{
// get the timeout
int
timeout
=
getTimeoutNolock
();
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
// return whether we should renew
return
time
(
0
)
>
m_lastUpdateTime
+
timeout
;
}
catch
(...)
{
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
throw
;
}
}
//------------------------------------------------------------------------------
// tryToRenewConfig
//------------------------------------------------------------------------------
void
cta
::
common
::
Configuration
::
tryToRenewConfig
()
{
// we should probably renew. First take the write lock.
int
rc
=
pthread_rwlock_wrlock
(
&
m_lock
);
if
(
0
!=
rc
)
{
cta
::
exception
::
Errnum
e
(
rc
);
e
.
getMessage
()
<<
"Failed to renew configuration cache"
": Failed to take write lock"
;
throw
e
;
}
// now check that we should really renew, because someone may have done it
// while we waited for the lock
try
{
if
(
time
(
0
)
>
m_lastUpdateTime
+
getTimeoutNolock
())
{
// now we should really renew
renewConfigNolock
();
}
}
catch
(...)
{
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
throw
;
}
// release the lock
pthread_rwlock_unlock
(
&
m_lock
);
return
;
}
//------------------------------------------------------------------------------
// getTimeoutNolock
//------------------------------------------------------------------------------
int
cta
::
common
::
Configuration
::
getTimeoutNolock
()
{
// start with the default (300s = 5mn)
int
timeout
=
300
;
// get value from config
std
::
map
<
std
::
string
,
ConfCategory
>::
const_iterator
catIt
=
m_config
.
find
(
"Config"
);
if
(
m_config
.
end
()
!=
catIt
)
{
ConfCategory
::
const_iterator
entIt
=
catIt
->
second
.
find
(
"ExpirationDelay"
);
if
(
catIt
->
second
.
end
()
!=
entIt
)
{
// parse the timeout into an integer
timeout
=
atoi
(
entIt
->
second
.
c_str
());
}
}
// return timeout
return
timeout
;
}
//------------------------------------------------------------------------------
// renewConfigNolock
//------------------------------------------------------------------------------
void
cta
::
common
::
Configuration
::
renewConfigNolock
()
{
// reset the config
m_config
.
clear
();
// try to open the configuration file, throwing an exception if there is a
// failure
std
::
ifstream
file
(
m_fileName
.
c_str
());
if
(
file
.
fail
())
{
cta
::
exception
::
Errnum
ex
(
EIO
);
ex
.
getMessage
()
<<
__FUNCTION__
<<
" failed"
": Failed to open file"
": m_fileName="
<<
m_fileName
;
throw
ex
;
}
std
::
string
line
;
while
(
std
::
getline
(
file
,
line
))
{
// get rid of potential tabs
std
::
replace
(
line
.
begin
(),
line
.
end
(),
'\t'
,
' '
);
// get the category
std
::
istringstream
sline
(
line
);
std
::
string
category
;
if
(
!
(
sline
>>
category
))
continue
;
// empty line
if
(
category
[
0
]
==
'#'
)
continue
;
// comment
// get the key
std
::
string
key
;
if
(
!
(
sline
>>
key
))
continue
;
// no key on line
if
(
key
[
0
]
==
'#'
)
continue
;
// key commented
// get and store value
while
(
sline
.
get
()
==
' '
){};
sline
.
unget
();
// skip spaces
std
::
string
value
;
std
::
getline
(
sline
,
value
,
'#'
);
value
.
erase
(
value
.
find_last_not_of
(
"
\n\r\t
"
)
+
1
);
// right trim
m_config
[
category
][
key
]
=
value
;
}
m_lastUpdateTime
=
time
(
0
);
}
common/Configuration.hpp
0 → 100644
View file @
07e7ab5d
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include
"common/exception/Exception.hpp"
#include
"common/log/Logger.hpp"
#include
"common/utils/Utils.hpp"
#include
<string>
#include
<map>
namespace
cta
{
namespace
common
{
/**
* represents a category from the CTA configuration file
*/
typedef
std
::
map
<
std
::
string
,
std
::
string
>
ConfCategory
;
/**
* a class representing the configuration of castor.
* This configurations is obtained from the local file given in the
* constructor and will be updated regularly. The time between two
* updates is taken from the Config/ExpirationDelay entry of the
* configuration itself and defaults to 5mn if no such entry is found
*/
class
Configuration
{
public:
/**
* Private exceptions for this
*/
CTA_GENERATE_EXCEPTION_CLASS
(
InvalidConfigEntry
);
CTA_GENERATE_EXCEPTION_CLASS
(
NoEntry
);
public:
/**
* constructor
* @param fileName the file that should be used to build the configuration
*/
Configuration
(
std
::
string
fileName
=
"/etc/cta/cta.conf"
);
/**
* copy constructor
* @param other instance of CastorConfiguration class
*/
Configuration
(
const
Configuration
&
other
);
/**
* destructor
*/
virtual
~
Configuration
();
/**
* assignment operator
* @param other instance of CastorConfiguration class
*/
Configuration
&
operator
=
(
const
Configuration
&
other
);
/**
* Retrieves a configuration entry.
*
* If this method is passed a logger object then it will log the value
* of the configuration entry together with an indication of whether the
* value was found in the castor configuration file or whether the
* specified default value was used instead.
*
* @param category the category of the entry
* @param key the key of the entry
* @param defaultValue the value to be returned if the configuration entry
* is not in the configuration file
* @param log pointer to NULL or an optional logger object
*/
const
std
::
string
&
getConfEntString
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
const
std
::
string
&
defaultValue
,
log
::
Logger
*
const
log
=
NULL
);
/**
* Retrieves a configuration entry.
*
* Besides other possible exceptions, this method throws a
* castor::exception::NoEntry exception if the specified configuration
* entry is not in the configuration file.
*
* If this method is passed a logger object then this method will log the
* the value of the configuration entry.
*
* @param category the category of the entry
* @param key the key of the entry
* @param log pointer to NULL or an optional logger object
*/
const
std
::
string
&
getConfEntString
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
log
::
Logger
*
const
log
=
NULL
);
/**
* Retrieves a configuration entry as an integer.
*
* If this method is passed a logger object then it will log the value
* of the configuration entry together with an indication of whether the
* value was found in the castor configuration file or whether the
* specified default value was used instead.
*
* @param category category of the configuration parameter
* @param name category of the configuration parameter
* @param defaultValue the value to be returned if the configuration entry
* is not in the configuration file
* @param log pointer to NULL or an optional logger object
* @return the integer value
*/
template
<
typename
T
>
T
getConfEntInt
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
const
T
defaultValue
,
log
::
Logger
*
const
log
=
NULL
)
{
std
::
string
strValue
;
try
{
strValue
=
getConfEntString
(
category
,
key
);
}
catch
(
cta
::
exception
::
Exception
&
ex
)
{
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
defaultValue
),
log
::
Param
(
"source"
,
"DEFAULT"
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
return
defaultValue
;
}
if
(
!
Utils
::
isValidUInt
(
strValue
.
c_str
()))
{
InvalidConfigEntry
ex
(
category
.
c_str
(),
key
.
c_str
(),
strValue
.
c_str
());
ex
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Value is not a valid unsigned integer: value="
<<
strValue
;
throw
ex
;
}
T
value
;
std
::
stringstream
ss
;
ss
<<
strValue
.
c_str
();
ss
>>
value
;
if
(
NULL
!=
log
)
{
log
::
Param
params
[]
=
{
log
::
Param
(
"category"
,
category
),
log
::
Param
(
"key"
,
key
),
log
::
Param
(
"value"
,
value
),
log
::
Param
(
"source"
,
m_fileName
)};
(
*
log
)(
LOG_INFO
,
"Configuration entry"
,
params
);
}
return
value
;
}
/**
* Retrieves a configuration entry as an integer.
*
* Besides other possible exceptions, this method throws a
* castor::exception::NoEntry exception if the specified configuration
* entry is not in the configuration file.
*
* @param category category of the configuration parameter
* @param name category of the configuration parameter
* @param log pointer to NULL or an optional logger object
* @return the integer value
*/
template
<
typename
T
>
T
getConfEntInt
(
const
std
::
string
&
category
,
const
std
::
string
&
key
,
log
::
Logger
*
const
log
=
NULL
)
{
const
std
::
string
strValue
=
getConfEntString
(
category
,
key
);
if
(
!
Utils
::
isValidUInt
(
strValue
.
c_str
()))
{
InvalidConfigEntry
ex
(
category
.
c_str
(),
key
.
c_str
(),
strValue
.
c_str
());
ex
.
getMessage
()
<<
"Failed to get configuration entry "
<<
category
<<
":"
<<
key
<<
": Value is not a valid unsigned integer: value="
<<
strValue
;
throw
ex
;