2005-01-06 21:22:44 +03:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 20:26:07 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2005-01-06 21:22:44 +03:00
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 20:26:07 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2005-01-06 21:22:44 +03:00
*
2007-08-21 20:26:07 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-01-06 21:22:44 +03:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-01-06 21:22:44 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "libdm/misc/dmlib.h"
2005-01-06 21:22:44 +03:00
# include <sys/file.h>
# include <fcntl.h>
# include <dirent.h>
2005-01-27 19:16:54 +03:00
2015-09-17 15:29:51 +03:00
static int _is_dir ( const char * path )
{
struct stat st ;
if ( stat ( path , & st ) < 0 ) {
log_sys_error ( " stat " , path ) ;
return 0 ;
}
if ( ! S_ISDIR ( st . st_mode ) ) {
log_error ( " Existing path %s is not "
" a directory. " , path ) ;
return 0 ;
}
return 1 ;
}
2005-01-06 21:22:44 +03:00
static int _create_dir_recursive ( const char * dir )
{
char * orig , * s ;
2006-05-10 20:23:41 +04:00
int rc , r = 0 ;
2005-01-06 21:22:44 +03:00
log_verbose ( " Creating directory \" %s \" " , dir ) ;
/* Create parent directories */
2006-01-31 17:50:38 +03:00
orig = s = dm_strdup ( dir ) ;
2011-08-04 21:56:11 +04:00
if ( ! s ) {
log_error ( " Failed to duplicate directory name. " ) ;
return 0 ;
}
2005-01-06 21:22:44 +03:00
while ( ( s = strchr ( s , ' / ' ) ) ! = NULL ) {
* s = ' \0 ' ;
if ( * orig ) {
rc = mkdir ( orig , 0777 ) ;
2015-09-17 15:29:51 +03:00
if ( rc < 0 ) {
if ( errno = = EEXIST ) {
if ( ! _is_dir ( orig ) )
goto_out ;
} else {
if ( errno ! = EROFS )
log_sys_error ( " mkdir " , orig ) ;
goto out ;
}
2005-01-06 21:22:44 +03:00
}
}
* s + + = ' / ' ;
}
/* Create final directory */
rc = mkdir ( dir , 0777 ) ;
2015-09-17 15:29:51 +03:00
if ( rc < 0 ) {
if ( errno = = EEXIST ) {
if ( ! _is_dir ( dir ) )
goto_out ;
} else {
if ( errno ! = EROFS )
log_sys_error ( " mkdir " , orig ) ;
goto out ;
}
2005-01-06 21:22:44 +03:00
}
2006-05-10 20:23:41 +04:00
r = 1 ;
out :
dm_free ( orig ) ;
return r ;
2005-01-06 21:22:44 +03:00
}
2007-07-28 14:48:36 +04:00
int dm_create_dir ( const char * dir )
2005-01-06 21:22:44 +03:00
{
struct stat info ;
if ( ! * dir )
return 1 ;
2015-09-17 15:29:51 +03:00
if ( stat ( dir , & info ) = = 0 & & S_ISDIR ( info . st_mode ) )
2005-01-06 21:22:44 +03:00
return 1 ;
2016-06-29 16:58:14 +03:00
if ( ! _create_dir_recursive ( dir ) )
return_0 ;
2015-09-17 15:29:51 +03:00
return 1 ;
2005-01-06 21:22:44 +03:00
}
2011-09-22 21:23:35 +04:00
int dm_is_empty_dir ( const char * dir )
{
struct dirent * dirent ;
DIR * d ;
if ( ! ( d = opendir ( dir ) ) ) {
log_sys_error ( " opendir " , dir ) ;
return 0 ;
}
while ( ( dirent = readdir ( d ) ) )
if ( strcmp ( dirent - > d_name , " . " ) & & strcmp ( dirent - > d_name , " .. " ) )
break ;
if ( closedir ( d ) )
log_sys_error ( " closedir " , dir ) ;
return dirent ? 0 : 1 ;
}
2007-07-24 18:15:45 +04:00
int dm_fclose ( FILE * stream )
{
int prev_fail = ferror ( stream ) ;
int fclose_fail = fclose ( stream ) ;
/* If there was a previous failure, but fclose succeeded,
clear errno , since ferror does not set it , and its value
may be unrelated to the ferror - reported failure . */
if ( prev_fail & & ! fclose_fail )
errno = 0 ;
return prev_fail | | fclose_fail ? EOF : 0 ;
}
2010-07-13 17:51:01 +04:00
int dm_create_lockfile ( const char * lockfile )
{
int fd , value ;
size_t bufferlen ;
ssize_t write_out ;
struct flock lock ;
char buffer [ 50 ] ;
2010-10-20 19:12:12 +04:00
int retries = 0 ;
2010-07-13 17:51:01 +04:00
2015-09-06 01:56:30 +03:00
if ( ( fd = open ( lockfile , O_CREAT | O_WRONLY ,
( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) ) ) < 0 ) {
2010-07-13 17:51:01 +04:00
log_error ( " Cannot open lockfile [%s], error was [%s] " ,
lockfile , strerror ( errno ) ) ;
return 0 ;
}
lock . l_type = F_WRLCK ;
lock . l_start = 0 ;
lock . l_whence = SEEK_SET ;
lock . l_len = 0 ;
2010-07-28 01:56:14 +04:00
retry_fcntl :
2010-07-13 17:51:01 +04:00
if ( fcntl ( fd , F_SETLK , & lock ) < 0 ) {
2010-07-28 01:56:14 +04:00
switch ( errno ) {
case EINTR :
goto retry_fcntl ;
case EACCES :
case EAGAIN :
2010-10-20 19:12:12 +04:00
if ( retries = = 20 ) {
log_error ( " Cannot lock lockfile [%s], error was [%s] " ,
lockfile , strerror ( errno ) ) ;
break ;
} else {
+ + retries ;
usleep ( 1000 ) ;
goto retry_fcntl ;
}
2010-07-28 01:56:14 +04:00
default :
2010-07-13 17:51:01 +04:00
log_error ( " process is already running " ) ;
2010-07-28 01:56:14 +04:00
}
2010-07-13 17:51:01 +04:00
2010-07-28 01:56:14 +04:00
goto fail_close ;
2010-07-13 17:51:01 +04:00
}
if ( ftruncate ( fd , 0 ) < 0 ) {
log_error ( " Cannot truncate pidfile [%s], error was [%s] " ,
lockfile , strerror ( errno ) ) ;
2010-07-28 01:56:14 +04:00
goto fail_close_unlink ;
2010-07-13 17:51:01 +04:00
}
2018-02-12 23:50:07 +03:00
snprintf ( buffer , sizeof ( buffer ) , " %u \n " , getpid ( ) ) ;
2010-07-13 17:51:01 +04:00
bufferlen = strlen ( buffer ) ;
write_out = write ( fd , buffer , bufferlen ) ;
if ( ( write_out < 0 ) | | ( write_out = = 0 & & errno ) ) {
log_error ( " Cannot write pid to pidfile [%s], error was [%s] " ,
lockfile , strerror ( errno ) ) ;
2010-07-28 01:56:14 +04:00
goto fail_close_unlink ;
2010-07-13 17:51:01 +04:00
}
2011-04-08 18:40:18 +04:00
if ( ( write_out = = 0 ) | | ( ( size_t ) write_out < bufferlen ) ) {
2010-07-13 17:51:01 +04:00
log_error ( " Cannot write pid to pidfile [%s], shortwrite of "
" [% " PRIsize_t " ] bytes, expected [% " PRIsize_t " ] \n " ,
lockfile , write_out , bufferlen ) ;
2010-07-28 01:56:14 +04:00
goto fail_close_unlink ;
2010-07-13 17:51:01 +04:00
}
if ( ( value = fcntl ( fd , F_GETFD , 0 ) ) < 0 ) {
log_error ( " Cannot get close-on-exec flag from pidfile [%s], "
" error was [%s] " , lockfile , strerror ( errno ) ) ;
2010-07-28 01:56:14 +04:00
goto fail_close_unlink ;
2010-07-13 17:51:01 +04:00
}
value | = FD_CLOEXEC ;
if ( fcntl ( fd , F_SETFD , value ) < 0 ) {
log_error ( " Cannot set close-on-exec flag from pidfile [%s], "
" error was [%s] " , lockfile , strerror ( errno ) ) ;
2010-07-28 01:56:14 +04:00
goto fail_close_unlink ;
2010-07-13 17:51:01 +04:00
}
2018-11-01 17:44:13 +03:00
/* coverity[leaked_handle] intentional leak of fd handle here */
2010-07-13 17:51:01 +04:00
return 1 ;
2010-07-28 01:56:14 +04:00
fail_close_unlink :
2010-07-13 17:51:01 +04:00
if ( unlink ( lockfile ) )
2015-05-07 12:38:43 +03:00
log_sys_debug ( " unlink " , lockfile ) ;
2010-07-28 01:56:14 +04:00
fail_close :
if ( close ( fd ) )
2015-05-07 12:38:43 +03:00
log_sys_debug ( " close " , lockfile ) ;
2010-07-13 17:51:01 +04:00
return 0 ;
}
2010-07-21 17:40:21 +04:00
int dm_daemon_is_running ( const char * lockfile )
{
int fd ;
struct flock lock ;
if ( ( fd = open ( lockfile , O_RDONLY ) ) < 0 )
return 0 ;
lock . l_type = F_WRLCK ;
lock . l_start = 0 ;
lock . l_whence = SEEK_SET ;
lock . l_len = 0 ;
if ( fcntl ( fd , F_GETLK , & lock ) < 0 ) {
log_error ( " Cannot check lock status of lockfile [%s], error was [%s] " ,
lockfile , strerror ( errno ) ) ;
if ( close ( fd ) )
stack ;
return 0 ;
}
if ( close ( fd ) )
stack ;
return ( lock . l_type = = F_UNLCK ) ? 0 : 1 ;
}