2015-12-08 08:23:50 +03:00
/*
CTDB mutex fcntl lock file helper
Copyright ( C ) Martin Schwenke 2015
2019-06-27 06:45:01 +03:00
wait_for_parent ( ) code from ctdb_lock_helper . c :
Copyright ( C ) Amitay Isaacs 2013
2015-12-08 08:23:50 +03:00
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 "replace.h"
# include "system/filesys.h"
# include "system/network.h"
2022-01-21 05:37:17 +03:00
# include "system/wait.h"
2023-01-18 10:59:17 +03:00
# include "system/dir.h"
2015-12-08 08:23:50 +03:00
2019-06-27 06:45:01 +03:00
# include <tevent.h>
2016-11-29 04:55:06 +03:00
# include "lib/util/sys_rw.h"
2019-06-27 06:45:01 +03:00
# include "lib/util/tevent_unix.h"
2019-06-27 09:14:26 +03:00
# include "lib/util/util.h"
2020-07-03 09:11:20 +03:00
# include "lib/util/smb_strtox.h"
2016-11-29 04:55:06 +03:00
2015-12-08 08:23:50 +03:00
/* protocol.h is just needed for ctdb_sock_addr, which is used in system.h */
# include "protocol/protocol.h"
# include "common/system.h"
2022-01-21 05:37:17 +03:00
# include "common/tmon.h"
2015-12-08 08:23:50 +03:00
2022-03-01 01:58:22 +03:00
static char progpath [ PATH_MAX ] ;
2015-12-08 08:23:50 +03:00
static char * progname = NULL ;
2022-02-08 03:56:46 +03:00
static int fcntl_lock_fd ( int fd , bool block , off_t start )
{
static struct flock lock = {
. l_type = F_WRLCK ,
. l_whence = SEEK_SET ,
. l_len = 1 ,
. l_pid = 0 ,
} ;
int cmd = block ? F_SETLKW : F_SETLK ;
lock . l_start = start ;
if ( fcntl ( fd , cmd , & lock ) ! = 0 ) {
return errno ;
}
return 0 ;
}
2016-07-28 07:04:23 +03:00
static char fcntl_lock ( const char * file , int * outfd )
2015-12-08 08:23:50 +03:00
{
int fd ;
2022-02-08 03:56:46 +03:00
int ret ;
2015-12-08 08:23:50 +03:00
fd = open ( file , O_RDWR | O_CREAT , 0600 ) ;
if ( fd = = - 1 ) {
fprintf ( stderr , " %s: Unable to open %s - (%s) \n " ,
progname , file , strerror ( errno ) ) ;
return ' 3 ' ;
}
2022-02-08 03:56:46 +03:00
ret = fcntl_lock_fd ( fd , false , 0 ) ;
if ( ret ! = 0 ) {
2015-12-08 08:23:50 +03:00
close ( fd ) ;
2022-02-08 03:56:46 +03:00
if ( ret = = EACCES | | ret = = EAGAIN ) {
2015-12-08 08:23:50 +03:00
/* Lock contention, fail silently */
return ' 1 ' ;
}
/* Log an error for any other failure */
fprintf ( stderr ,
" %s: Failed to get lock on '%s' - (%s) \n " ,
2022-02-08 03:56:46 +03:00
progname ,
file ,
strerror ( ret ) ) ;
2015-12-08 08:23:50 +03:00
return ' 3 ' ;
}
2016-07-28 07:04:23 +03:00
* outfd = fd ;
2015-12-08 08:23:50 +03:00
return ' 0 ' ;
}
2019-06-27 06:45:01 +03:00
/*
* Wait and see if the parent exits
*/
struct wait_for_parent_state {
struct tevent_context * ev ;
pid_t ppid ;
} ;
static void wait_for_parent_check ( struct tevent_req * subreq ) ;
static struct tevent_req * wait_for_parent_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
pid_t ppid )
{
struct tevent_req * req , * subreq ;
struct wait_for_parent_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct wait_for_parent_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > ppid = ppid ;
if ( ppid = = 1 ) {
fprintf ( stderr , " parent == 1 \n " ) ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
subreq = tevent_wakeup_send ( state , ev ,
tevent_timeval_current_ofs ( 5 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , wait_for_parent_check , req ) ;
return req ;
}
static void wait_for_parent_check ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wait_for_parent_state * state = tevent_req_data (
req , struct wait_for_parent_state ) ;
bool status ;
status = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
/* Ignore error */
2022-03-01 01:58:22 +03:00
fprintf ( stderr , " %s: tevent_wakeup_recv() failed \n " , progname ) ;
2019-06-27 06:45:01 +03:00
}
if ( kill ( state - > ppid , 0 ) = = - 1 & & errno = = ESRCH ) {
fprintf ( stderr , " parent gone \n " ) ;
tevent_req_done ( req ) ;
return ;
}
subreq = tevent_wakeup_send ( state , state - > ev ,
tevent_timeval_current_ofs ( 5 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wait_for_parent_check , req ) ;
}
2022-01-21 04:09:45 +03:00
static bool wait_for_parent_recv ( struct tevent_req * req , int * perr )
2019-06-27 06:45:01 +03:00
{
2022-01-21 04:09:45 +03:00
if ( tevent_req_is_unix_error ( req , perr ) ) {
2019-06-27 06:45:01 +03:00
return false ;
}
return true ;
}
2019-06-27 09:14:26 +03:00
/*
2022-02-08 01:35:17 +03:00
* Perform I / O on lock in a loop - complete when file removed or replaced
2019-06-27 09:14:26 +03:00
*/
2022-02-08 01:35:17 +03:00
struct lock_io_check_state {
2019-06-27 09:14:26 +03:00
struct tevent_context * ev ;
const char * lock_file ;
ino_t inode ;
2022-01-19 04:09:07 +03:00
unsigned long recheck_interval ;
2019-06-27 09:14:26 +03:00
} ;
2022-02-08 01:35:17 +03:00
static void lock_io_check_loop ( struct tevent_req * subreq ) ;
2019-06-27 09:14:26 +03:00
2022-02-08 01:35:17 +03:00
static struct tevent_req * lock_io_check_send ( TALLOC_CTX * mem_ctx ,
2019-06-27 09:14:26 +03:00
struct tevent_context * ev ,
const char * lock_file ,
2022-01-21 05:37:17 +03:00
ino_t inode ,
2022-01-19 04:09:07 +03:00
unsigned long recheck_interval )
2019-06-27 09:14:26 +03:00
{
struct tevent_req * req , * subreq ;
2022-02-08 01:35:17 +03:00
struct lock_io_check_state * state ;
2019-06-27 09:14:26 +03:00
2022-02-08 01:35:17 +03:00
req = tevent_req_create ( mem_ctx , & state , struct lock_io_check_state ) ;
2019-06-27 09:14:26 +03:00
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > lock_file = lock_file ;
2022-01-21 05:37:17 +03:00
state - > inode = inode ;
2022-01-19 04:09:07 +03:00
state - > recheck_interval = recheck_interval ;
2019-06-27 09:14:26 +03:00
subreq = tevent_wakeup_send (
state ,
ev ,
2022-01-19 04:09:07 +03:00
tevent_timeval_current_ofs ( state - > recheck_interval , 0 ) ) ;
2019-06-27 09:14:26 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2022-02-08 01:35:17 +03:00
tevent_req_set_callback ( subreq , lock_io_check_loop , req ) ;
2019-06-27 09:14:26 +03:00
return req ;
}
2022-02-08 01:35:17 +03:00
static void lock_io_check_loop ( struct tevent_req * subreq )
2019-06-27 09:14:26 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2022-02-08 01:35:17 +03:00
struct lock_io_check_state * state = tevent_req_data (
req , struct lock_io_check_state ) ;
2019-06-27 09:14:26 +03:00
bool status ;
struct stat sb ;
2022-02-08 04:15:26 +03:00
int fd = - 1 ;
2019-06-27 09:14:26 +03:00
int ret ;
status = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
/* Ignore error */
2022-03-01 01:58:22 +03:00
fprintf ( stderr , " %s: tevent_wakeup_recv() failed \n " , progname ) ;
2019-06-27 09:14:26 +03:00
}
2022-02-08 04:15:26 +03:00
fd = open ( state - > lock_file , O_RDWR ) ;
if ( fd = = - 1 ) {
fprintf ( stderr ,
" %s: "
" lock lost - lock file \" %s \" open failed (ret=%d) \n " ,
progname ,
state - > lock_file ,
errno ) ;
goto done ;
}
ret = fstat ( fd , & sb ) ;
2019-06-27 09:14:26 +03:00
if ( ret ! = 0 ) {
fprintf ( stderr ,
2022-03-01 01:58:22 +03:00
" %s: "
2019-06-27 09:14:26 +03:00
" lock lost - lock file \" %s \" check failed (ret=%d) \n " ,
2022-03-01 01:58:22 +03:00
progname ,
2019-06-27 09:14:26 +03:00
state - > lock_file ,
errno ) ;
2022-02-08 04:15:26 +03:00
goto done ;
2019-06-27 09:14:26 +03:00
}
if ( sb . st_ino ! = state - > inode ) {
fprintf ( stderr ,
2022-03-01 01:58:22 +03:00
" %s: lock lost - lock file \" %s \" inode changed \n " ,
progname ,
2019-06-27 09:14:26 +03:00
state - > lock_file ) ;
2022-02-08 04:15:26 +03:00
goto done ;
2019-06-27 09:14:26 +03:00
}
2022-02-08 04:23:42 +03:00
/*
* Attempt to lock a 2 nd byte range . Using a blocking lock
* encourages ping timeouts if the cluster filesystem is in a
* bad state . It also makes testing easier .
*/
ret = fcntl_lock_fd ( fd , true , 1 ) ;
if ( ret ! = 0 ) {
fprintf ( stderr ,
" %s: "
" lock fail - lock file \" %s \" test lock error (%d) \n " ,
progname ,
state - > lock_file ,
ret ) ;
goto done ;
}
/* Unlock occurs on close */
2022-02-08 04:15:26 +03:00
close ( fd ) ;
2019-06-27 09:14:26 +03:00
subreq = tevent_wakeup_send (
state ,
state - > ev ,
2022-01-19 04:09:07 +03:00
tevent_timeval_current_ofs ( state - > recheck_interval , 0 ) ) ;
2019-06-27 09:14:26 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2022-02-08 01:35:17 +03:00
tevent_req_set_callback ( subreq , lock_io_check_loop , req ) ;
2022-02-08 04:15:26 +03:00
return ;
done :
if ( fd ! = - 1 ) {
close ( fd ) ;
}
tevent_req_done ( req ) ;
2019-06-27 09:14:26 +03:00
}
2022-02-08 01:35:17 +03:00
static bool lock_io_check_recv ( struct tevent_req * req , int * perr )
2019-06-27 09:14:26 +03:00
{
2022-01-21 04:09:45 +03:00
if ( tevent_req_is_unix_error ( req , perr ) ) {
2019-06-27 09:14:26 +03:00
return false ;
}
return true ;
}
2022-01-21 05:37:17 +03:00
struct lock_test_child_state {
} ;
static void lock_test_child_ping_done ( struct tevent_req * subreq ) ;
static void lock_test_child_io_check_done ( struct tevent_req * subreq ) ;
static struct tevent_req * lock_test_child_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * lock_file ,
int fd ,
ino_t inode ,
2022-01-28 05:49:48 +03:00
unsigned long recheck_interval ,
bool send_pings )
2022-01-21 05:37:17 +03:00
{
struct tevent_req * req , * subreq ;
struct lock_test_child_state * state ;
2022-01-28 05:49:48 +03:00
unsigned int interval = send_pings ? 1 : 0 ;
2022-01-21 05:37:17 +03:00
req = tevent_req_create ( mem_ctx , & state , struct lock_test_child_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2022-01-28 05:49:48 +03:00
subreq = tmon_ping_send ( state , ev , fd , TMON_FD_BOTH , 0 , interval ) ;
2022-01-21 05:37:17 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , lock_test_child_ping_done , req ) ;
subreq = lock_io_check_send ( state ,
ev ,
lock_file ,
inode ,
recheck_interval ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , lock_test_child_io_check_done , req ) ;
return req ;
}
static void lock_test_child_ping_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
bool status ;
int err ;
status = tmon_ping_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
tevent_req_error ( req , err ) ;
return ;
}
tevent_req_done ( req ) ;
}
static void lock_test_child_io_check_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
bool status ;
int err ;
status = lock_io_check_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
tevent_req_error ( req , err ) ;
return ;
}
tevent_req_done ( req ) ;
}
static bool lock_test_child_recv ( struct tevent_req * req , int * perr )
{
if ( tevent_req_is_unix_error ( req , perr ) ) {
/* Parent exit is expected */
if ( * perr = = EPIPE ) {
return true ;
}
return false ;
}
return true ;
}
static void lock_test_child ( const char * lock_file ,
int lock_fd ,
int pipe_fd ,
2022-01-28 05:49:48 +03:00
unsigned long recheck_interval ,
bool send_pings )
2022-01-21 05:37:17 +03:00
{
struct tevent_context * ev ;
struct tevent_req * req ;
struct stat sb ;
ino_t inode ;
bool status ;
int ret ;
ret = fstat ( lock_fd , & sb ) ;
if ( ret ! = 0 ) {
fprintf ( stderr ,
" %s: lock lost - "
" lock file \" %s \" stat failed (ret=%d) \n " ,
progname ,
lock_file ,
errno ) ;
_exit ( 1 ) ;
}
inode = sb . st_ino ;
close ( lock_fd ) ;
ev = tevent_context_init ( NULL ) ;
if ( ev = = NULL ) {
fprintf ( stderr , " %s: tevent_context_init() failed \n " , progname ) ;
_exit ( 1 ) ;
}
req = lock_test_child_send ( ev ,
ev ,
lock_file ,
pipe_fd ,
inode ,
2022-01-28 05:49:48 +03:00
recheck_interval ,
send_pings ) ;
2022-01-21 05:37:17 +03:00
if ( req = = NULL ) {
fprintf ( stderr ,
" %s: lock_test_child_send() failed \n " ,
progname ) ;
_exit ( 1 ) ;
}
tevent_req_poll ( req , ev ) ;
status = lock_test_child_recv ( req , & ret ) ;
if ( ! status ) {
fprintf ( stderr ,
" %s: lock_test_child_recv() failed (%d) \n " ,
progname ,
ret ) ;
_exit ( 1 ) ;
}
_exit ( 0 ) ;
}
struct lock_test_state {
int * lock_fdp ;
int pipe_fd ;
pid_t child_pid ;
} ;
static void lock_test_ping_done ( struct tevent_req * subreq ) ;
static struct tevent_req * lock_test_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * lock_file ,
int * fdp ,
2022-01-28 05:49:48 +03:00
unsigned long recheck_interval ,
unsigned long ping_timeout )
2022-01-21 05:37:17 +03:00
{
struct tevent_req * req , * subreq ;
struct lock_test_state * state ;
pid_t pid ;
int sv [ 2 ] ;
int ret ;
req = tevent_req_create ( mem_ctx , & state , struct lock_test_state ) ;
if ( req = = NULL ) {
return NULL ;
}
ret = socketpair ( AF_UNIX , SOCK_STREAM , 0 , sv ) ;
if ( ret ! = 0 ) {
fprintf ( stderr ,
" %s: socketpair() failed (errno=%d) \n " ,
progname ,
errno ) ;
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
}
pid = fork ( ) ;
if ( pid = = - 1 ) {
int err = errno ;
fprintf ( stderr , " %s: fork() failed (errno=%d) \n " , progname , err ) ;
close ( sv [ 0 ] ) ;
close ( sv [ 1 ] ) ;
tevent_req_error ( req , err ) ;
return tevent_req_post ( req , ev ) ;
}
if ( pid = = 0 ) {
/* Child */
close ( sv [ 0 ] ) ;
TALLOC_FREE ( ev ) ;
2022-01-28 05:49:48 +03:00
lock_test_child ( lock_file ,
* fdp ,
sv [ 1 ] ,
recheck_interval ,
ping_timeout ! = 0 ) ;
2022-01-21 05:37:17 +03:00
/* Above does not return */
}
/* Parent */
close ( sv [ 1 ] ) ;
state - > lock_fdp = fdp ;
state - > pipe_fd = sv [ 0 ] ;
state - > child_pid = pid ;
2022-01-28 05:49:48 +03:00
subreq = tmon_ping_send ( state , ev , sv [ 0 ] , TMON_FD_BOTH , ping_timeout , 0 ) ;
2022-01-21 05:37:17 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
close ( sv [ 0 ] ) ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , lock_test_ping_done , req ) ;
return req ;
}
static void lock_test_ping_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct lock_test_state * state = tevent_req_data (
req , struct lock_test_state ) ;
int wstatus ;
bool status ;
int err ;
status = tmon_ping_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
switch ( err ) {
case EPIPE :
/* Child exit, child already printed message */
break ;
case ETIMEDOUT :
fprintf ( stderr ,
" %s: ping timeout from lock test child \n " ,
progname ) ;
break ;
default :
fprintf ( stderr ,
" %s: tmon_ping_recv() failed (%d) \n " ,
progname ,
err ) ;
}
/* Ignore error */
}
/*
* Lock checking child is gone or not sending pings . Release
* the lock , close this end of pipe , send SIGKILL to the child
* process and wait for the child to exit .
*/
close ( * state - > lock_fdp ) ;
* state - > lock_fdp = - 1 ;
close ( state - > pipe_fd ) ;
kill ( state - > child_pid , SIGKILL ) ;
waitpid ( state - > child_pid , & wstatus , 0 ) ;
tevent_req_done ( req ) ;
}
static bool lock_test_recv ( struct tevent_req * req , int * perr )
{
if ( tevent_req_is_unix_error ( req , perr ) ) {
return false ;
}
return true ;
}
2019-06-27 07:13:50 +03:00
/*
2022-02-08 01:35:17 +03:00
* Wait for a reason to exit , indicating that parent has exited or I / O
* on lock failed
2019-06-27 07:13:50 +03:00
*/
struct wait_for_exit_state {
} ;
static void wait_for_exit_parent_done ( struct tevent_req * subreq ) ;
2022-01-21 05:37:17 +03:00
static void wait_for_exit_lock_test_done ( struct tevent_req * subreq ) ;
2019-06-27 07:13:50 +03:00
static struct tevent_req * wait_for_exit_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2019-06-27 09:14:26 +03:00
pid_t ppid ,
const char * lock_file ,
2022-01-21 05:37:17 +03:00
int * fdp ,
2022-01-28 05:49:48 +03:00
unsigned long recheck_interval ,
unsigned long ping_timeout )
2019-06-27 07:13:50 +03:00
{
struct tevent_req * req , * subreq ;
struct wait_for_exit_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct wait_for_exit_state ) ;
if ( req = = NULL ) {
return NULL ;
}
subreq = wait_for_parent_send ( state , ev , ppid ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , wait_for_exit_parent_done , req ) ;
2022-01-19 04:09:07 +03:00
if ( recheck_interval > 0 ) {
2022-01-21 05:37:17 +03:00
subreq = lock_test_send ( state ,
ev ,
lock_file ,
fdp ,
2022-01-28 05:49:48 +03:00
recheck_interval ,
ping_timeout ) ;
2019-06-27 09:14:26 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2022-02-08 01:35:17 +03:00
tevent_req_set_callback ( subreq ,
2022-01-21 05:37:17 +03:00
wait_for_exit_lock_test_done ,
2022-02-08 01:35:17 +03:00
req ) ;
2019-06-27 09:14:26 +03:00
}
2019-06-27 07:13:50 +03:00
return req ;
}
static void wait_for_exit_parent_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
bool status ;
2022-01-21 04:09:45 +03:00
int err ;
2019-06-27 07:13:50 +03:00
2022-01-21 04:09:45 +03:00
status = wait_for_parent_recv ( subreq , & err ) ;
2019-06-27 07:13:50 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
/* Ignore error */
fprintf ( stderr ,
2022-03-01 01:58:22 +03:00
" %s: "
2022-01-21 04:09:45 +03:00
" wait_for_parent_recv() failed (%d) \n " ,
2022-03-01 01:58:22 +03:00
progname ,
2022-01-21 04:09:45 +03:00
err ) ;
2019-06-27 07:13:50 +03:00
}
tevent_req_done ( req ) ;
}
2022-01-21 05:37:17 +03:00
static void wait_for_exit_lock_test_done ( struct tevent_req * subreq )
2019-06-27 09:14:26 +03:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
bool status ;
2022-01-21 04:09:45 +03:00
int err ;
2019-06-27 09:14:26 +03:00
2022-01-21 05:37:17 +03:00
status = lock_test_recv ( subreq , & err ) ;
2019-06-27 09:14:26 +03:00
TALLOC_FREE ( subreq ) ;
if ( ! status ) {
fprintf ( stderr ,
2022-03-01 01:58:22 +03:00
" %s: "
2022-01-21 05:37:17 +03:00
" lock_test_recv() failed (%d) \n " ,
2022-03-01 01:58:22 +03:00
progname ,
2022-01-21 04:09:45 +03:00
err ) ;
2022-01-21 05:37:17 +03:00
/* Ignore error, fall through to done */
2019-06-27 09:14:26 +03:00
}
tevent_req_done ( req ) ;
}
2022-01-21 04:09:45 +03:00
static bool wait_for_exit_recv ( struct tevent_req * req , int * perr )
2019-06-27 07:13:50 +03:00
{
2022-01-21 04:09:45 +03:00
if ( tevent_req_is_unix_error ( req , perr ) ) {
2019-06-27 07:13:50 +03:00
return false ;
}
return true ;
}
2019-06-27 09:14:26 +03:00
static void usage ( void )
{
2022-01-28 05:49:48 +03:00
fprintf ( stderr ,
" Usage: %s <file> [recheck_interval [ping_timeout]] \n " ,
progname ) ;
2019-06-27 09:14:26 +03:00
}
2015-12-08 08:23:50 +03:00
int main ( int argc , char * argv [ ] )
{
2019-06-27 06:45:01 +03:00
struct tevent_context * ev ;
2015-12-08 08:23:50 +03:00
char result ;
int ppid ;
const char * file = NULL ;
2022-01-19 04:09:07 +03:00
unsigned long recheck_interval ;
2022-01-28 05:49:48 +03:00
unsigned long ping_timeout ;
2019-06-27 09:14:26 +03:00
int ret ;
2016-07-28 07:04:23 +03:00
int fd = - 1 ;
2019-06-27 06:45:01 +03:00
struct tevent_req * req ;
bool status ;
2015-12-08 08:23:50 +03:00
2022-03-01 01:58:22 +03:00
strlcpy ( progpath , argv [ 0 ] , sizeof ( progpath ) ) ;
progname = basename ( progpath ) ;
2015-12-08 08:23:50 +03:00
2022-01-28 05:49:48 +03:00
if ( argc < 2 | | argc > 4 ) {
2019-06-27 09:14:26 +03:00
usage ( ) ;
2015-12-08 08:23:50 +03:00
exit ( 1 ) ;
}
2019-06-27 06:45:01 +03:00
ev = tevent_context_init ( NULL ) ;
if ( ev = = NULL ) {
fprintf ( stderr , " locking: tevent_context_init() failed \n " ) ;
2016-08-05 07:17:01 +03:00
exit ( 1 ) ;
}
2019-06-27 06:45:01 +03:00
ppid = getppid ( ) ;
2015-12-08 08:23:50 +03:00
file = argv [ 1 ] ;
2022-01-19 04:09:07 +03:00
recheck_interval = 5 ;
2022-01-28 05:49:48 +03:00
ping_timeout = 0 ;
if ( argc > = 3 ) {
2022-01-19 04:09:07 +03:00
recheck_interval = smb_strtoul ( argv [ 2 ] ,
NULL ,
10 ,
& ret ,
SMB_STR_STANDARD ) ;
2019-06-27 09:14:26 +03:00
if ( ret ! = 0 ) {
usage ( ) ;
exit ( 1 ) ;
}
}
2022-01-28 05:49:48 +03:00
if ( argc > = 4 ) {
ping_timeout = smb_strtoul ( argv [ 3 ] ,
NULL ,
10 ,
& ret ,
SMB_STR_STANDARD ) ;
if ( ret ! = 0 ) {
usage ( ) ;
exit ( 1 ) ;
}
}
2019-06-27 09:14:26 +03:00
2016-07-28 07:04:23 +03:00
result = fcntl_lock ( file , & fd ) ;
2015-12-08 08:23:50 +03:00
sys_write ( STDOUT_FILENO , & result , 1 ) ;
2019-07-05 08:39:23 +03:00
if ( result ! = ' 0 ' ) {
return 0 ;
}
2022-01-28 05:49:48 +03:00
req = wait_for_exit_send ( ev ,
ev ,
ppid ,
file ,
& fd ,
recheck_interval ,
ping_timeout ) ;
2019-06-27 06:45:01 +03:00
if ( req = = NULL ) {
fprintf ( stderr ,
2019-06-27 07:13:50 +03:00
" %s: wait_for_exit_send() failed \n " ,
2019-06-27 06:45:01 +03:00
progname ) ;
exit ( 1 ) ;
}
tevent_req_poll ( req , ev ) ;
2022-01-21 04:09:45 +03:00
status = wait_for_exit_recv ( req , & ret ) ;
2019-06-27 06:45:01 +03:00
if ( ! status ) {
fprintf ( stderr ,
2022-01-21 04:09:45 +03:00
" %s: wait_for_exit_recv() failed (%d) \n " ,
progname ,
ret ) ;
2019-06-27 06:45:01 +03:00
}
2015-12-08 08:23:50 +03:00
2016-07-28 07:04:23 +03:00
if ( fd ! = - 1 ) {
close ( fd ) ;
}
2015-12-08 08:23:50 +03:00
return 0 ;
}