2006-03-23 02:49:09 +03:00
/*
Unix SMB / CIFS implementation .
DMAPI Support routines
Copyright ( C ) James Peach 2006
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-03-23 02:49:09 +03:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-03-23 02:49:09 +03:00
*/
# include "includes.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2006-03-23 02:49:09 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_DMAPI
# ifndef USE_DMAPI
2015-05-03 07:01:14 +03:00
uint32_t dmapi_file_flags ( const char * const path ) { return 0 ; }
2007-10-19 04:40:25 +04:00
bool dmapi_have_session ( void ) { return False ; }
2008-01-18 17:34:21 +03:00
const void * dmapi_get_current_session ( void ) { return NULL ; }
2006-03-23 02:49:09 +03:00
# else /* USE_DMAPI */
# ifdef HAVE_XFS_DMAPI_H
# include <xfs/dmapi.h>
2006-03-24 21:40:28 +03:00
# elif defined(HAVE_SYS_DMI_H)
2006-03-23 02:49:09 +03:00
# include <sys/dmi.h>
2006-03-24 21:40:28 +03:00
# elif defined(HAVE_SYS_JFSDMAPI_H)
# include <sys/jfsdmapi.h>
# elif defined(HAVE_SYS_DMAPI_H)
# include <sys/dmapi.h>
2007-02-20 18:55:12 +03:00
# elif defined(HAVE_DMAPI_H)
# include <dmapi.h>
2006-03-23 02:49:09 +03:00
# endif
# define DMAPI_SESSION_NAME "samba"
# define DMAPI_TRACE 10
2009-01-08 13:37:06 +03:00
struct smbd_dmapi_context {
dm_sessid_t session ;
unsigned session_num ;
} ;
2008-01-18 17:34:21 +03:00
/*
Initialise DMAPI session . The session is persistant kernel state ,
so it might already exist , in which case we merely want to
reconnect to it . This function should be called as root .
*/
2009-01-08 13:37:06 +03:00
static int dmapi_init_session ( struct smbd_dmapi_context * ctx )
2006-03-23 02:49:09 +03:00
{
char buf [ DM_SESSION_INFO_LEN ] ;
size_t buflen ;
2008-01-18 17:34:21 +03:00
uint nsessions = 5 ;
2006-03-23 02:49:09 +03:00
dm_sessid_t * sessions = NULL ;
2008-01-18 17:34:21 +03:00
char * version ;
2008-01-29 17:43:49 +03:00
char * session_name ;
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
2006-03-23 02:49:09 +03:00
int i , err ;
2009-01-08 13:37:06 +03:00
if ( ctx - > session_num = = 0 ) {
session_name = talloc_strdup ( tmp_ctx , DMAPI_SESSION_NAME ) ;
2008-01-29 17:43:49 +03:00
} else {
session_name = talloc_asprintf ( tmp_ctx , " %s%u " , DMAPI_SESSION_NAME ,
2009-01-08 13:37:06 +03:00
ctx - > session_num ) ;
2008-01-29 17:43:49 +03:00
}
if ( session_name = = NULL ) {
DEBUG ( 0 , ( " Out of memory in dmapi_init_session \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2008-01-18 17:34:21 +03:00
if ( dm_init_service ( & version ) < 0 ) {
DEBUG ( 0 , ( " dm_init_service failed - disabling DMAPI \n " ) ) ;
2008-01-29 17:43:49 +03:00
talloc_free ( tmp_ctx ) ;
2006-03-23 02:49:09 +03:00
return - 1 ;
}
2008-01-18 17:34:21 +03:00
ZERO_STRUCT ( buf ) ;
2006-03-23 02:49:09 +03:00
2008-01-29 17:43:49 +03:00
/* Fetch kernel DMAPI sessions until we get any of them */
2008-01-18 17:34:21 +03:00
do {
dm_sessid_t * new_sessions ;
nsessions * = 2 ;
2011-06-07 05:10:15 +04:00
new_sessions = talloc_realloc ( tmp_ctx , sessions ,
2008-01-18 17:34:21 +03:00
dm_sessid_t , nsessions ) ;
if ( new_sessions = = NULL ) {
2008-01-29 17:43:49 +03:00
talloc_free ( tmp_ctx ) ;
2008-01-18 17:34:21 +03:00
return - 1 ;
2006-03-23 02:49:09 +03:00
}
2008-01-18 17:34:21 +03:00
sessions = new_sessions ;
err = dm_getall_sessions ( nsessions , sessions , & nsessions ) ;
} while ( err = = - 1 & & errno = = E2BIG ) ;
if ( err = = - 1 ) {
2006-03-23 02:49:09 +03:00
DEBUGADD ( DMAPI_TRACE ,
( " failed to retrieve DMAPI sessions: %s \n " ,
strerror ( errno ) ) ) ;
2008-01-29 17:43:49 +03:00
talloc_free ( tmp_ctx ) ;
2006-03-23 02:49:09 +03:00
return - 1 ;
}
2008-01-29 17:43:49 +03:00
/* Look through existing kernel DMAPI sessions to find out ours */
2006-03-23 02:49:09 +03:00
for ( i = 0 ; i < nsessions ; + + i ) {
err = dm_query_session ( sessions [ i ] , sizeof ( buf ) , buf , & buflen ) ;
buf [ sizeof ( buf ) - 1 ] = ' \0 ' ;
2008-01-29 17:43:49 +03:00
if ( err = = 0 & & strcmp ( session_name , buf ) = = 0 ) {
2009-01-08 13:37:06 +03:00
ctx - > session = sessions [ i ] ;
2006-03-23 02:49:09 +03:00
DEBUGADD ( DMAPI_TRACE ,
( " attached to existing DMAPI session "
" named '%s' \n " , buf ) ) ;
break ;
}
}
/* No session already defined. */
2009-01-08 13:37:06 +03:00
if ( ctx - > session = = DM_NO_SESSION ) {
2008-01-16 12:17:03 +03:00
err = dm_create_session ( DM_NO_SESSION ,
2008-01-29 17:43:49 +03:00
session_name ,
2009-01-08 13:37:06 +03:00
& ctx - > session ) ;
2006-03-23 02:49:09 +03:00
if ( err < 0 ) {
DEBUGADD ( DMAPI_TRACE ,
( " failed to create new DMAPI session: %s \n " ,
strerror ( errno ) ) ) ;
2009-01-08 13:37:06 +03:00
ctx - > session = DM_NO_SESSION ;
2008-01-29 17:43:49 +03:00
talloc_free ( tmp_ctx ) ;
2006-03-23 02:49:09 +03:00
return - 1 ;
}
2008-01-18 17:34:21 +03:00
DEBUG ( 0 , ( " created new DMAPI session named '%s' for %s \n " ,
2008-01-29 17:43:49 +03:00
session_name , version ) ) ;
2008-01-18 17:34:21 +03:00
}
2009-01-08 13:37:06 +03:00
if ( ctx - > session ! = DM_NO_SESSION ) {
2008-01-18 17:34:21 +03:00
set_effective_capability ( DMAPI_ACCESS_CAPABILITY ) ;
2006-03-23 02:49:09 +03:00
}
2008-01-18 17:34:21 +03:00
/*
Note that we never end the DMAPI session . It gets re - used if possiblie .
DMAPI session is a kernel resource that is usually lives until server reboot
and doesn ' t get destroed when an application finishes .
2008-01-29 17:43:49 +03:00
However , we free list of references to DMAPI sessions we ' ve got from the kernel
as it is not needed anymore once we have found ( or created ) our session .
2006-03-23 02:49:09 +03:00
*/
2008-01-29 17:43:49 +03:00
talloc_free ( tmp_ctx ) ;
2006-03-23 02:49:09 +03:00
return 0 ;
}
2008-01-18 17:34:21 +03:00
/*
Return a pointer to our DMAPI session , if available .
This assumes that you have called dmapi_have_session ( ) first .
*/
const void * dmapi_get_current_session ( void )
2006-03-23 02:49:09 +03:00
{
2009-01-08 13:37:06 +03:00
if ( ! dmapi_ctx ) {
return NULL ;
}
if ( dmapi_ctx - > session = = DM_NO_SESSION ) {
2008-01-18 17:34:21 +03:00
return NULL ;
2006-03-23 02:49:09 +03:00
}
2009-01-08 13:37:06 +03:00
return ( void * ) & dmapi_ctx - > session ;
2006-03-23 02:49:09 +03:00
}
2008-01-18 17:34:21 +03:00
/*
dmapi_have_session ( ) must be the first DMAPI call you make in Samba . It will
initialize DMAPI , if available , and tell you if you can get a DMAPI session .
This should be called in the client - specific child process .
*/
2006-03-23 02:49:09 +03:00
2008-01-18 17:34:21 +03:00
bool dmapi_have_session ( void )
2006-03-23 02:49:09 +03:00
{
2009-01-08 13:37:06 +03:00
if ( ! dmapi_ctx ) {
2010-10-03 15:21:21 +04:00
dmapi_ctx = talloc ( NULL , struct smbd_dmapi_context ) ;
2009-01-08 13:37:06 +03:00
if ( ! dmapi_ctx ) {
exit_server ( " unable to allocate smbd_dmapi_context " ) ;
}
dmapi_ctx - > session = DM_NO_SESSION ;
dmapi_ctx - > session_num = 0 ;
2008-01-18 17:34:21 +03:00
become_root ( ) ;
2009-01-08 13:37:06 +03:00
dmapi_init_session ( dmapi_ctx ) ;
2008-01-18 17:34:21 +03:00
unbecome_root ( ) ;
2008-01-16 12:17:03 +03:00
}
2008-01-18 17:34:21 +03:00
2009-01-08 13:37:06 +03:00
return dmapi_ctx - > session ! = DM_NO_SESSION ;
2008-01-16 12:17:03 +03:00
}
2006-03-23 02:49:09 +03:00
2008-01-29 17:43:49 +03:00
/*
only call this when you get back an EINVAL error indicating that the
session you are using is invalid . This destroys the existing session
and creates a new one .
*/
2008-01-29 18:01:23 +03:00
bool dmapi_new_session ( void )
2008-01-29 17:43:49 +03:00
{
if ( dmapi_have_session ( ) ) {
/* try to destroy the old one - this may not succeed */
2009-01-08 13:37:06 +03:00
dm_destroy_session ( dmapi_ctx - > session ) ;
2008-01-29 17:43:49 +03:00
}
2009-01-08 13:37:06 +03:00
dmapi_ctx - > session = DM_NO_SESSION ;
2008-01-29 17:43:49 +03:00
become_root ( ) ;
2009-01-08 13:37:06 +03:00
dmapi_ctx - > session_num + + ;
dmapi_init_session ( dmapi_ctx ) ;
2008-01-29 17:43:49 +03:00
unbecome_root ( ) ;
2009-01-08 13:37:06 +03:00
return dmapi_ctx - > session ! = DM_NO_SESSION ;
2008-01-29 17:43:49 +03:00
}
2008-04-08 15:19:01 +04:00
/*
only call this when exiting from master smbd process . DMAPI sessions
are long - lived kernel resources we ought to share across smbd processes .
However , we must free them when all smbd processes are finished to
allow other subsystems clean up properly . Not freeing DMAPI session
blocks certain HSM implementations from proper shutdown .
*/
bool dmapi_destroy_session ( void )
{
2009-01-08 13:37:06 +03:00
if ( ! dmapi_ctx ) {
return true ;
}
if ( dmapi_ctx - > session ! = DM_NO_SESSION ) {
2008-04-08 15:19:01 +04:00
become_root ( ) ;
2009-01-08 13:37:06 +03:00
if ( 0 = = dm_destroy_session ( dmapi_ctx - > session ) ) {
dmapi_ctx - > session_num - - ;
dmapi_ctx - > session = DM_NO_SESSION ;
2008-04-08 15:19:01 +04:00
} else {
DEBUG ( 0 , ( " Couldn't destroy DMAPI session: %s \n " ,
strerror ( errno ) ) ) ;
}
unbecome_root ( ) ;
}
2009-01-08 13:37:06 +03:00
return dmapi_ctx - > session = = DM_NO_SESSION ;
2008-04-08 15:19:01 +04:00
}
2008-01-18 17:34:21 +03:00
/*
This is default implementation of dmapi_file_flags ( ) that is
called from VFS is_offline ( ) call to know whether file is offline .
For GPFS - specific version see modules / vfs_tsmsm . c . It might be
that approach on quering existence of a specific attribute that
is used in vfs_tsmsm . c will work with other DMAPI - based HSM
implementations as well .
*/
2015-05-03 07:01:14 +03:00
uint32_t dmapi_file_flags ( const char * const path )
2008-01-16 12:17:03 +03:00
{
2006-03-23 02:49:09 +03:00
int err ;
dm_eventset_t events = { 0 } ;
uint nevents ;
2008-01-29 17:43:49 +03:00
dm_sessid_t dmapi_session ;
2014-02-26 23:16:26 +04:00
dm_sessid_t * dmapi_session_ptr ;
const void * _dmapi_session_ptr ;
2008-01-29 17:43:49 +03:00
void * dm_handle = NULL ;
size_t dm_handle_len = 0 ;
2006-03-23 02:49:09 +03:00
2015-05-03 07:01:14 +03:00
uint32_t flags = 0 ;
2006-03-23 02:49:09 +03:00
2014-02-26 23:16:26 +04:00
_dmapi_session_ptr = dmapi_get_current_session ( ) ;
if ( _dmapi_session_ptr = = NULL ) {
2008-01-18 17:34:21 +03:00
return 0 ;
}
2014-02-26 23:16:26 +04:00
dmapi_session_ptr = discard_const_p ( dm_sessid_t , _dmapi_session_ptr ) ;
dmapi_session = * dmapi_session_ptr ;
2008-01-16 12:17:03 +03:00
if ( dmapi_session = = DM_NO_SESSION ) {
return 0 ;
2006-03-23 02:49:09 +03:00
}
2006-11-24 08:35:05 +03:00
/* AIX has DMAPI but no POSIX capablities support. In this case,
* we need to be root to do DMAPI manipulations .
*/
# ifndef HAVE_POSIX_CAPABILITIES
become_root ( ) ;
# endif
2011-05-06 03:19:49 +04:00
err = dm_path_to_handle ( discard_const_p ( char , path ) ,
2006-03-23 02:49:09 +03:00
& dm_handle , & dm_handle_len ) ;
if ( err < 0 ) {
DEBUG ( DMAPI_TRACE , ( " dm_path_to_handle(%s): %s \n " ,
path , strerror ( errno ) ) ) ;
if ( errno ! = EPERM ) {
2006-11-24 08:35:05 +03:00
goto done ;
2006-03-23 02:49:09 +03:00
}
/* Linux capabilities are broken in that changing our
* user ID will clobber out effective capabilities irrespective
* of whether we have set PR_SET_KEEPCAPS . Fortunately , the
* capabilities are not removed from our permitted set , so we
* can re - acquire them if necessary .
*/
set_effective_capability ( DMAPI_ACCESS_CAPABILITY ) ;
2011-05-06 03:19:49 +04:00
err = dm_path_to_handle ( discard_const_p ( char , path ) ,
2006-03-23 02:49:09 +03:00
& dm_handle , & dm_handle_len ) ;
if ( err < 0 ) {
DEBUG ( DMAPI_TRACE ,
( " retrying dm_path_to_handle(%s): %s \n " ,
path , strerror ( errno ) ) ) ;
2006-11-24 08:35:05 +03:00
goto done ;
2006-03-23 02:49:09 +03:00
}
}
err = dm_get_eventlist ( dmapi_session , dm_handle , dm_handle_len ,
DM_NO_TOKEN , DM_EVENT_MAX , & events , & nevents ) ;
if ( err < 0 ) {
DEBUG ( DMAPI_TRACE , ( " dm_get_eventlist(%s): %s \n " ,
path , strerror ( errno ) ) ) ;
dm_handle_free ( dm_handle , dm_handle_len ) ;
2006-11-24 08:35:05 +03:00
goto done ;
2006-03-23 02:49:09 +03:00
}
/* We figure that the only reason a DMAPI application would be
* interested in trapping read events is that part of the file is
* offline .
*/
2008-01-29 17:43:49 +03:00
DEBUG ( DMAPI_TRACE , ( " DMAPI event list for %s \n " , path ) ) ;
2006-03-23 02:49:09 +03:00
if ( DMEV_ISSET ( DM_EVENT_READ , events ) ) {
flags = FILE_ATTRIBUTE_OFFLINE ;
}
dm_handle_free ( dm_handle , dm_handle_len ) ;
if ( flags & FILE_ATTRIBUTE_OFFLINE ) {
DEBUG ( DMAPI_TRACE , ( " %s is OFFLINE \n " , path ) ) ;
}
2006-11-24 08:35:05 +03:00
done :
# ifndef HAVE_POSIX_CAPABILITIES
unbecome_root ( ) ;
# endif
2006-03-23 02:49:09 +03:00
return flags ;
}
2008-01-16 12:17:03 +03:00
2006-03-23 02:49:09 +03:00
# endif /* USE_DMAPI */