2010-01-07 01:03:55 +03:00
# include <stdio.h>
# include <string.h>
# include <simpleconfig.h>
2010-01-14 21:38:37 +03:00
# include <static_map.h>
2010-01-07 01:03:55 +03:00
# include <stdint.h>
# include <sys/types.h>
2017-05-29 05:18:37 +03:00
# include <sys/stat.h>
2010-01-07 01:03:55 +03:00
# include <sys/time.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <net/if.h>
# include <arpa/inet.h>
# include <mcast.h>
# include <xvm.h>
# include "server_plugin.h"
2010-01-13 19:38:04 +03:00
# include <simple_auth.h>
2010-01-07 01:03:55 +03:00
static int
yesno ( const char * prompt , int dfl )
{
char result [ 10 ] ;
printf ( " %s [%c/%c]? " , prompt , dfl ? ' Y ' : ' y ' , dfl ? ' n ' : ' N ' ) ;
fflush ( stdout ) ;
memset ( result , 0 , sizeof ( result ) ) ;
if ( fgets ( result , 9 , stdin ) = = NULL )
return dfl ;
if ( result [ 0 ] = = ' y ' | | result [ 0 ] = = ' Y ' )
return 1 ;
if ( result [ 0 ] = = ' n ' | | result [ 0 ] = = ' N ' )
return 0 ;
return dfl ;
}
static int
text_input ( const char * prompt , char * dfl , char * input , size_t len )
{
printf ( " %s [%s]: " , prompt , dfl ? dfl : " " ) ;
fflush ( stdout ) ;
2011-09-20 19:11:39 +04:00
memset ( input , 0 , len ) ;
2010-01-07 01:03:55 +03:00
if ( fgets ( input , len , stdin ) = = NULL ) {
strncpy ( input , dfl , len ) ;
return 0 ;
}
if ( input [ strlen ( input ) - 1 ] = = ' \n ' )
input [ strlen ( input ) - 1 ] = 0 ;
if ( strlen ( input ) = = 0 ) {
strncpy ( input , dfl , len ) ;
return 0 ;
}
return 0 ;
}
static int
plugin_path_configure ( config_object_t * config )
{
# ifdef _MODULE
char val [ 4096 ] ;
char inp [ 4096 ] ;
int done = 0 ;
if ( sc_get ( config , " fence_virtd/@module_path " , val ,
sizeof ( val ) ) ) {
# ifdef MODULE_PATH
snprintf ( val , sizeof ( val ) , MODULE_PATH ) ;
# else
printf ( " Failed to determine module search path. \n " ) ;
# endif
}
do {
text_input ( " Module search path " , val , inp , sizeof ( inp ) ) ;
2010-01-13 19:38:04 +03:00
printf ( " \n " ) ;
2010-01-07 01:03:55 +03:00
done = plugin_search ( inp ) ;
if ( done > 0 ) {
plugin_dump ( ) ;
done = 1 ;
} else {
done = 0 ;
printf ( " No modules found in %s! \n " , inp ) ;
if ( yesno ( " Use this value anyway " , 0 ) = = 1 )
done = 1 ;
}
} while ( ! done ) ;
sc_set ( config , " fence_virtd/@module_path " , inp ) ;
# endif
return 0 ;
}
static int
backend_config_libvirt ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
printf ( " \n " ) ;
printf ( " The libvirt backend module is designed for single desktops or \n "
" servers. Do not use in environments where virtual machines \n "
" may be migrated between hosts. \n \n " ) ;
/* Default backend plugin */
if ( sc_get ( config , " backends/libvirt/@uri " , val ,
sizeof ( val ) ) ) {
2010-01-15 00:21:16 +03:00
strncpy ( val , DEFAULT_HYPERVISOR_URI , sizeof ( val ) ) ;
2010-01-07 01:03:55 +03:00
}
text_input ( " Libvirt URI " , val , inp , sizeof ( inp ) ) ;
sc_set ( config , " backends/libvirt/@uri " , inp ) ;
return 0 ;
}
static int
2017-05-28 04:19:41 +03:00
backend_config_cpg ( config_object_t * config )
2010-01-07 01:03:55 +03:00
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
int done = 0 ;
printf ( " \n " ) ;
2017-05-28 04:19:41 +03:00
printf ( " The CPG backend module is designed for use in clusters \n "
" running corosync and libvirt. It utilizes the CPG API to \n "
2010-01-07 01:03:55 +03:00
" route fencing requests, finally utilizing libvirt to perform \n "
" fencing actions. \n \n " ) ;
2017-05-28 04:19:41 +03:00
if ( sc_get ( config , " backends/cpg/@uri " , val ,
2010-01-07 01:03:55 +03:00
sizeof ( val ) ) ) {
2010-01-15 00:21:16 +03:00
strncpy ( val , DEFAULT_HYPERVISOR_URI , sizeof ( val ) ) ;
2010-01-07 01:03:55 +03:00
}
text_input ( " Libvirt URI " , val , inp , sizeof ( inp ) ) ;
2017-05-28 04:19:41 +03:00
sc_set ( config , " backends/cpg/@uri " , inp ) ;
2010-01-07 01:03:55 +03:00
printf ( " \n " ) ;
2017-05-28 04:19:41 +03:00
printf ( " The name mode is how the cpg plugin stores and \n "
2010-01-07 01:03:55 +03:00
" references virtual machines. Since virtual machine names \n "
" are not guaranteed to be unique cluster-wide, use of UUIDs \n "
" is strongly recommended. However, for compatibility with \n "
" fence_xvmd, the use of 'name' mode is also supported. \n \n " ) ;
2017-05-28 04:19:41 +03:00
if ( sc_get ( config , " backends/cpg/@name_mode " , val ,
2010-01-07 01:03:55 +03:00
sizeof ( val ) ) ) {
strncpy ( val , " uuid " , sizeof ( val ) ) ;
}
do {
text_input ( " VM naming/tracking mode (name or uuid) " ,
val , inp , sizeof ( inp ) ) ;
if ( ! strcasecmp ( inp , " uuid " ) ) {
done = 1 ;
} else if ( ! strcasecmp ( inp , " name " ) ) {
done = 0 ;
printf ( " This can be dangerous if you do not take care to "
" ensure that \n "
" virtual machine names are unique "
" cluster-wide. \n " ) ;
if ( yesno ( " Use name mode anyway " , 1 ) = = 1 )
done = 1 ;
}
} while ( ! done ) ;
2017-05-28 04:19:41 +03:00
sc_set ( config , " backends/cpg/@name_mode " , inp ) ;
2010-01-07 01:03:55 +03:00
return 0 ;
}
static int
listener_config_multicast ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
2012-02-07 20:14:25 +04:00
const char * family = " ipv4 " ;
2010-01-07 01:03:55 +03:00
struct in_addr sin ;
struct in6_addr sin6 ;
int done = 0 ;
printf ( " \n " ) ;
printf ( " The multicast listener module is designed for use environments \n "
" where the guests and hosts may communicate over a network using \n "
" multicast. \n \n " ) ;
/* MULTICAST IP ADDRESS/FAMILY */
printf ( " The multicast address is the address that a client will use to \n "
" send fencing requests to fence_virtd. \n \n " ) ;
if ( sc_get ( config , " listeners/multicast/@address " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , IPV4_MCAST_DEFAULT , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
text_input ( " Multicast IP Address " , val , inp , sizeof ( inp ) ) ;
if ( inet_pton ( AF_INET , inp , & sin ) = = 1 ) {
printf ( " \n Using ipv4 as family. \n \n " ) ;
family = " ipv4 " ;
2017-05-29 05:18:37 +03:00
done = 1 ;
2010-01-07 01:03:55 +03:00
} else if ( inet_pton ( AF_INET6 , inp , & sin6 ) = = 1 ) {
printf ( " \n Using ipv6 as family. \n \n " ) ;
family = " ipv6 " ;
2017-05-29 05:18:37 +03:00
done = 1 ;
} else
2010-01-07 01:03:55 +03:00
printf ( " '%s' is not a valid IP address! \n " , inp ) ;
2017-05-29 05:18:37 +03:00
} while ( ! done ) ;
2010-01-07 01:03:55 +03:00
sc_set ( config , " listeners/multicast/@family " , family ) ;
sc_set ( config , " listeners/multicast/@address " , inp ) ;
/* MULTICAST IP PORT */
if ( sc_get ( config , " listeners/multicast/@port " ,
val , sizeof ( val ) - 1 ) ) {
snprintf ( val , sizeof ( val ) , " %d " , DEFAULT_MCAST_PORT ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
2017-03-14 00:43:17 +03:00
char * p ;
2017-05-29 05:18:37 +03:00
int ret ;
2010-01-07 01:03:55 +03:00
2017-05-29 05:18:37 +03:00
text_input ( " Multicast IP Port " , val , inp , sizeof ( inp ) ) ;
ret = strtol ( inp , & p , 0 ) ;
if ( * p ! = ' \0 ' | | ret < = 0 | | ret > = 65536 ) {
2010-01-07 01:03:55 +03:00
printf ( " Port value '%s' is out of range \n " , val ) ;
continue ;
2017-05-29 05:18:37 +03:00
} else
done = 1 ;
} while ( ! done ) ;
2010-01-07 01:03:55 +03:00
sc_set ( config , " listeners/multicast/@port " , inp ) ;
/* MULTICAST INTERFACE */
2010-01-13 19:38:04 +03:00
printf ( " \n Setting a preferred interface causes fence_virtd to listen only \n "
2010-01-07 01:03:55 +03:00
" on that interface. Normally, it listens on all interfaces. \n "
" In environments where the virtual machines are using the host \n "
" machine as a gateway, this *must* be set (typically to virbr0). \n "
" Set to 'none' for no interface. \n \n "
) ;
if ( sc_get ( config , " listeners/multicast/@interface " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , " none " , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
text_input ( " Interface " , val , inp , sizeof ( inp ) ) ;
if ( ! strcasecmp ( inp , " none " ) ) {
break ;
}
if ( strlen ( inp ) > 0 ) {
2017-05-29 05:18:37 +03:00
int ret ;
ret = if_nametoindex ( inp ) ;
if ( ret < 0 ) {
2010-01-07 01:03:55 +03:00
printf ( " Invalid interface: %s \n " , inp ) ;
if ( yesno ( " Use anyway " , 1 ) = = 1 )
2017-05-29 05:18:37 +03:00
done = 1 ;
} else
done = 1 ;
} else
printf ( " No interface given \n " ) ;
} while ( ! done ) ;
2010-01-07 01:03:55 +03:00
if ( ! strcasecmp ( inp , " none " ) ) {
sc_set ( config , " listeners/multicast/@interface " , NULL ) ;
} else {
sc_set ( config , " listeners/multicast/@interface " , inp ) ;
}
/* KEY FILE */
2010-01-13 19:38:04 +03:00
printf ( " \n The key file is the shared key information which is used to \n "
2010-01-07 01:03:55 +03:00
" authenticate fencing requests. The contents of this file must \n "
" be distributed to each physical host and virtual machine within \n "
" a cluster. \n \n " ) ;
if ( sc_get ( config , " listeners/multicast/@key_file " ,
val , sizeof ( val ) - 1 ) ) {
2010-01-13 19:38:04 +03:00
strncpy ( val , DEFAULT_KEY_FILE , sizeof ( val ) ) ;
2010-01-07 01:03:55 +03:00
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
text_input ( " Key File " , val , inp , sizeof ( inp ) ) ;
if ( ! strcasecmp ( inp , " none " ) ) {
break ;
}
if ( strlen ( inp ) > 0 ) {
if ( inp [ 0 ] ! = ' / ' ) {
printf ( " Invalid key file: %s \n " , inp ) ;
if ( yesno ( " Use anyway " , 1 ) = = 1 )
2017-05-29 05:18:37 +03:00
done = 1 ;
} else
done = 1 ;
} else
printf ( " No key file given \n " ) ;
} while ( ! done ) ;
2010-01-07 01:03:55 +03:00
if ( ! strcasecmp ( inp , " none " ) ) {
sc_set ( config , " listeners/multicast/@key_file " , NULL ) ;
} else {
sc_set ( config , " listeners/multicast/@key_file " , inp ) ;
}
return 0 ;
}
2012-06-01 23:22:02 +04:00
static int
listener_config_tcp ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
const char * family = " ipv4 " ;
struct in_addr sin ;
struct in6_addr sin6 ;
int done = 0 ;
printf ( " \n " ) ;
printf ( " The TCP listener module is designed for use in environments \n "
" where the guests and hosts communicate over viosproxy. \n \n " ) ;
/* IP ADDRESS/FAMILY */
printf ( " The IP address is the address that a client will use to \n "
" send fencing requests to fence_virtd. \n \n " ) ;
if ( sc_get ( config , " listeners/tcp/@address " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , IPV4_MCAST_DEFAULT , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2012-06-01 23:22:02 +04:00
do {
text_input ( " TCP Listen IP Address " , val , inp , sizeof ( inp ) ) ;
if ( inet_pton ( AF_INET , inp , & sin ) = = 1 ) {
printf ( " \n Using ipv4 as family. \n \n " ) ;
family = " ipv4 " ;
2017-05-29 05:18:37 +03:00
done = 1 ;
2012-06-01 23:22:02 +04:00
} else if ( inet_pton ( AF_INET6 , inp , & sin6 ) = = 1 ) {
printf ( " \n Using ipv6 as family. \n \n " ) ;
family = " ipv6 " ;
2017-05-29 05:18:37 +03:00
done = 1 ;
2012-06-01 23:22:02 +04:00
} else {
printf ( " '%s' is not a valid IP address! \n " , inp ) ;
continue ;
}
2017-05-29 05:18:37 +03:00
} while ( ! done ) ;
2012-06-01 23:22:02 +04:00
sc_set ( config , " listeners/tcp/@family " , family ) ;
sc_set ( config , " listeners/tcp/@address " , inp ) ;
/* MULTICAST IP PORT */
if ( sc_get ( config , " listeners/tcp/@port " ,
val , sizeof ( val ) - 1 ) ) {
snprintf ( val , sizeof ( val ) , " %d " , DEFAULT_MCAST_PORT ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2012-06-01 23:22:02 +04:00
do {
text_input ( " TCP Listen Port " , val , inp , sizeof ( inp ) ) ;
2017-03-14 00:43:17 +03:00
char * p ;
2017-05-29 05:18:37 +03:00
int ret ;
2012-06-01 23:22:02 +04:00
2017-05-29 05:18:37 +03:00
ret = strtol ( inp , & p , 0 ) ;
if ( * p ! = ' \0 ' | | ret < = 0 | | ret > = 65536 ) {
2012-06-01 23:22:02 +04:00
printf ( " Port value '%s' is out of range \n " , val ) ;
continue ;
}
2017-05-29 05:18:37 +03:00
done = 1 ;
} while ( ! done ) ;
2012-06-01 23:22:02 +04:00
sc_set ( config , " listeners/tcp/@port " , inp ) ;
/* KEY FILE */
printf ( " \n The key file is the shared key information which is used to \n "
" authenticate fencing requests. The contents of this file must \n "
" be distributed to each physical host and virtual machine within \n "
" a cluster. \n \n " ) ;
if ( sc_get ( config , " listeners/tcp/@key_file " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , DEFAULT_KEY_FILE , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2012-06-01 23:22:02 +04:00
do {
text_input ( " Key File " , val , inp , sizeof ( inp ) ) ;
if ( ! strcasecmp ( inp , " none " ) ) {
break ;
}
if ( strlen ( inp ) > 0 ) {
if ( inp [ 0 ] ! = ' / ' ) {
printf ( " Invalid key file: %s \n " , inp ) ;
if ( yesno ( " Use anyway " , 1 ) = = 1 )
2017-05-29 05:18:37 +03:00
done = 1 ;
} else
done = 1 ;
} else
printf ( " No key file given \n " ) ;
} while ( ! done ) ;
2012-06-01 23:22:02 +04:00
if ( ! strcasecmp ( inp , " none " ) ) {
sc_set ( config , " listeners/tcp/@key_file " , NULL ) ;
} else {
sc_set ( config , " listeners/tcp/@key_file " , inp ) ;
}
return 0 ;
}
2010-01-07 01:03:55 +03:00
2010-01-15 00:21:16 +03:00
static int
listener_config_serial ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
2017-05-29 05:18:37 +03:00
int done ;
2010-01-15 00:21:16 +03:00
printf ( " \n " ) ;
printf ( " The serial plugin allows fence_virtd to communicate with \n "
" guests using serial or guest-forwarding VMChannel instead \n "
" of using TCP/IP networking. \n \n " ) ;
printf ( " Special configuration of virtual machines is required. See \n "
" fence_virt.conf(5) for more details. \n \n " ) ;
if ( sc_get ( config , " listeners/serial/@uri " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , DEFAULT_HYPERVISOR_URI , sizeof ( val ) ) ;
}
text_input ( " Libvirt URI " , val , inp , sizeof ( inp ) ) ;
printf ( " \n Setting a socket path prevents fence_virtd from taking \n "
" hold of all Unix domain sockets created when the guest \n "
" is started. A value like /var/run/cluster/fence might \n "
" be a good value. Don't forget to create the directory! \n \n " ) ;
if ( sc_get ( config , " listeners/serial/@path " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , " none " , sizeof ( val ) ) ;
}
text_input ( " Socket directory " , val , inp , sizeof ( inp ) ) ;
if ( ! strcasecmp ( inp , " none " ) ) {
sc_set ( config , " listeners/serial/@path " , NULL ) ;
} else {
sc_set ( config , " listeners/serial/@path " , inp ) ;
}
printf ( " \n The serial plugin allows two types of guest to host \n "
" configurations. One is via a serial port; the other is \n "
" utilizing the newer VMChannel. \n \n " ) ;
if ( sc_get ( config , " listeners/serial/@mode " ,
val , sizeof ( val ) - 1 ) ) {
strncpy ( val , " serial " , sizeof ( val ) ) ;
}
if ( ! strcasecmp ( inp , " none " ) ) {
sc_set ( config , " listeners/serial/@path " , NULL ) ;
} else {
sc_set ( config , " listeners/serial/@path " , inp ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-15 00:21:16 +03:00
do {
text_input ( " Mode (serial or vmchannel) " , val , inp ,
sizeof ( inp ) ) ;
2017-05-29 05:18:37 +03:00
if ( strcasecmp ( inp , " serial " ) & & strcasecmp ( inp , " vmchannel " ) ) {
2010-01-15 00:21:16 +03:00
printf ( " Invalid mode: %s \n " , inp ) ;
if ( yesno ( " Use anyway " , 1 ) = = 1 )
2017-05-29 05:18:37 +03:00
done = 1 ;
} else
done = 1 ;
} while ( ! done ) ;
2010-01-15 00:21:16 +03:00
2017-05-29 05:18:37 +03:00
sc_set ( config , " listeners/serial/@mode " , inp ) ;
2010-01-15 00:21:16 +03:00
return 0 ;
}
2010-01-07 01:03:55 +03:00
static int
backend_configure ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
2017-05-29 05:18:37 +03:00
int done ;
2010-01-07 01:03:55 +03:00
printf ( " \n " ) ;
printf ( " Backend modules are responsible for routing requests to \n "
" the appropriate hypervisor or management layer. \n \n " ) ;
/* Default backend plugin */
if ( sc_get ( config , " fence_virtd/@backend " , val ,
sizeof ( val ) ) ) {
strncpy ( val , " libvirt " , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
text_input ( " Backend module " , val , inp , sizeof ( inp ) ) ;
if ( plugin_find_backend ( inp ) = = NULL ) {
printf ( " No backend module named %s found! \n " , inp ) ;
if ( yesno ( " Use this value anyway " , 0 ) = = 1 )
done = 1 ;
2017-05-29 05:18:37 +03:00
} else
2010-01-07 01:03:55 +03:00
done = 1 ;
} while ( ! done ) ;
sc_set ( config , " fence_virtd/@backend " , inp ) ;
if ( ! strcmp ( inp , " libvirt " ) ) {
backend_config_libvirt ( config ) ;
2017-05-28 04:19:41 +03:00
} else if ( ! strcmp ( inp , " cpg " ) ) {
backend_config_cpg ( config ) ;
2010-01-07 01:03:55 +03:00
}
return 0 ;
}
static int
listener_configure ( config_object_t * config )
{
char val [ 4096 ] ;
char inp [ 4096 ] ;
2017-05-29 05:18:37 +03:00
int done ;
2010-01-07 01:03:55 +03:00
printf ( " \n " ) ;
printf ( " Listener modules are responsible for accepting requests \n "
" from fencing clients. \n \n " ) ;
/* Default backend plugin */
if ( sc_get ( config , " fence_virtd/@listener " , val ,
sizeof ( val ) ) ) {
strncpy ( val , " multicast " , sizeof ( val ) ) ;
}
2017-05-29 05:18:37 +03:00
done = 0 ;
2010-01-07 01:03:55 +03:00
do {
text_input ( " Listener module " , val , inp , sizeof ( inp ) ) ;
if ( plugin_find_listener ( inp ) = = NULL ) {
printf ( " No listener module named %s found! \n " , inp ) ;
if ( yesno ( " Use this value anyway " , 0 ) = = 1 )
done = 1 ;
2017-05-29 05:18:37 +03:00
} else
2010-01-07 01:03:55 +03:00
done = 1 ;
} while ( ! done ) ;
sc_set ( config , " fence_virtd/@listener " , inp ) ;
if ( ! strcmp ( inp , " multicast " ) )
listener_config_multicast ( config ) ;
2012-06-01 23:22:02 +04:00
else if ( ! strcmp ( inp , " tcp " ) )
listener_config_tcp ( config ) ;
2010-01-15 00:21:16 +03:00
else if ( ! strcmp ( inp , " serial " ) )
listener_config_serial ( config ) ;
else
2017-05-29 05:18:37 +03:00
printf ( " Unable to configure unknown listner module '%s' \n " , inp ) ;
2010-01-07 01:03:55 +03:00
return 0 ;
}
int
do_configure ( config_object_t * config , const char * config_file )
{
FILE * fp = NULL ;
char message [ 80 ] ;
char tmp_filename [ 4096 ] ;
int tmp_fd = - 1 ;
2017-05-29 05:18:37 +03:00
mode_t old_umask ;
2010-01-07 01:03:55 +03:00
if ( sc_parse ( config , config_file ) ! = 0 ) {
printf ( " Parsing of %s failed. \n " , config_file ) ;
if ( yesno ( " Start from scratch " , 0 ) = = 0 ) {
return 1 ;
}
}
plugin_path_configure ( config ) ;
listener_configure ( config ) ;
backend_configure ( config ) ;
printf ( " \n Configuration complete. \n \n " ) ;
printf ( " === Begin Configuration === \n " ) ;
sc_dump ( config , stdout ) ;
printf ( " === End Configuration === \n " ) ;
snprintf ( message , sizeof ( message ) , " Replace %s with the above " ,
config_file ) ;
if ( yesno ( message , 0 ) = = 0 ) {
return 1 ;
}
snprintf ( tmp_filename , sizeof ( tmp_filename ) ,
" %s.XXXXXX " , config_file ) ;
2017-05-29 05:18:37 +03:00
old_umask = umask ( 077 ) ;
2010-01-07 01:03:55 +03:00
tmp_fd = mkstemp ( tmp_filename ) ;
2017-05-29 05:18:37 +03:00
umask ( old_umask ) ;
2010-01-07 01:03:55 +03:00
if ( tmp_fd < 0 ) {
perror ( " fopen " ) ;
printf ( " Failed to write configuration file! \n " ) ;
return 1 ;
}
fp = fdopen ( tmp_fd , " w+ " ) ;
if ( fp = = NULL )
goto out_fail ;
sc_dump ( config , fp ) ;
if ( rename ( tmp_filename , config_file ) < 0 ) {
perror ( " rename " ) ;
goto out_fail ;
}
fclose ( fp ) ;
close ( tmp_fd ) ;
return 0 ;
out_fail :
if ( fp )
fclose ( fp ) ;
if ( tmp_fd > = 0 )
close ( tmp_fd ) ;
if ( strlen ( tmp_filename ) )
unlink ( tmp_filename ) ;
printf ( " Failed to write configuration file! \n " ) ;
return 1 ;
}