2010-11-18 23:52:26 +03:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-11-18 23:52:26 +03:00
( at your option ) any later version .
systemd 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-11-18 23:52:26 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-11-18 23:52:26 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <stdlib.h>
# include <stdbool.h>
# include <errno.h>
# include <string.h>
# include <stdio.h>
# include <limits.h>
2011-07-12 05:36:17 +04:00
# include <getopt.h>
2010-11-18 23:52:26 +03:00
# include "log.h"
2011-04-25 22:41:47 +04:00
# include "strv.h"
2010-11-18 23:52:26 +03:00
# include "util.h"
2011-07-15 04:01:31 +04:00
# include "strv.h"
2012-05-07 20:55:45 +04:00
# include "conf-files.h"
2010-11-18 23:52:26 +03:00
# define PROC_SYS_PREFIX " / proc / sys / "
2011-07-15 04:01:31 +04:00
static char * * arg_prefixes = NULL ;
2011-07-12 05:36:17 +04:00
2011-03-04 00:17:09 +03:00
static int apply_sysctl ( const char * property , const char * value ) {
2010-11-18 23:52:26 +03:00
char * p , * n ;
2011-03-04 00:17:09 +03:00
int r = 0 , k ;
2010-11-18 23:52:26 +03:00
log_debug ( " Setting '%s' to '%s' " , property , value ) ;
2011-07-12 05:36:17 +04:00
p = new ( char , sizeof ( PROC_SYS_PREFIX ) + strlen ( property ) ) ;
if ( ! p ) {
2010-11-18 23:52:26 +03:00
log_error ( " Out of memory " ) ;
2011-03-04 00:17:09 +03:00
return - ENOMEM ;
2010-11-18 23:52:26 +03:00
}
n = stpcpy ( p , PROC_SYS_PREFIX ) ;
strcpy ( n , property ) ;
for ( ; * n ; n + + )
if ( * n = = ' . ' )
* n = ' / ' ;
2011-07-15 04:01:31 +04:00
if ( ! strv_isempty ( arg_prefixes ) ) {
char * * i ;
bool good = false ;
STRV_FOREACH ( i , arg_prefixes )
if ( path_startswith ( p , * i ) ) {
good = true ;
break ;
}
if ( ! good ) {
log_debug ( " Skipping %s " , p ) ;
free ( p ) ;
return 0 ;
}
2011-07-12 05:36:17 +04:00
}
k = write_one_line_file ( p , value ) ;
if ( k < 0 ) {
2011-01-05 02:05:53 +03:00
2011-03-04 00:17:09 +03:00
log_full ( k = = - ENOENT ? LOG_DEBUG : LOG_WARNING ,
" Failed to write '%s' to '%s': %s " , value , p , strerror ( - k ) ) ;
2010-11-19 01:03:42 +03:00
2011-03-04 00:17:09 +03:00
if ( k ! = - ENOENT & & r = = 0 )
r = k ;
2010-11-18 23:52:26 +03:00
}
free ( p ) ;
2011-03-04 00:17:09 +03:00
return r ;
2010-11-18 23:52:26 +03:00
}
2011-03-04 00:17:09 +03:00
static int apply_file ( const char * path , bool ignore_enoent ) {
2010-11-18 23:52:26 +03:00
FILE * f ;
2011-03-04 00:17:09 +03:00
int r = 0 ;
2010-11-18 23:52:26 +03:00
assert ( path ) ;
if ( ! ( f = fopen ( path , " re " ) ) ) {
2011-03-04 00:17:09 +03:00
if ( ignore_enoent & & errno = = ENOENT )
return 0 ;
2010-11-18 23:52:26 +03:00
log_error ( " Failed to open file '%s', ignoring: %m " , path ) ;
2011-03-04 00:17:09 +03:00
return - errno ;
2010-11-18 23:52:26 +03:00
}
2011-04-25 22:41:47 +04:00
log_debug ( " apply: %s \n " , path ) ;
2010-11-18 23:52:26 +03:00
while ( ! feof ( f ) ) {
char l [ LINE_MAX ] , * p , * value ;
2011-03-04 00:17:09 +03:00
int k ;
2010-11-18 23:52:26 +03:00
if ( ! fgets ( l , sizeof ( l ) , f ) ) {
if ( feof ( f ) )
break ;
log_error ( " Failed to read file '%s', ignoring: %m " , path ) ;
2011-03-04 00:17:09 +03:00
r = - errno ;
2010-11-18 23:52:26 +03:00
goto finish ;
}
p = strstrip ( l ) ;
if ( ! * p )
continue ;
if ( strchr ( COMMENTS , * p ) )
continue ;
if ( ! ( value = strchr ( p , ' = ' ) ) ) {
log_error ( " Line is not an assignment in file '%s': %s " , path , value ) ;
2011-03-04 00:17:09 +03:00
if ( r = = 0 )
r = - EINVAL ;
2010-11-18 23:52:26 +03:00
continue ;
}
* value = 0 ;
value + + ;
2011-03-04 00:17:09 +03:00
if ( ( k = apply_sysctl ( strstrip ( p ) , strstrip ( value ) ) ) < 0 & & r = = 0 )
r = k ;
2010-11-18 23:52:26 +03:00
}
finish :
fclose ( f ) ;
2011-03-04 00:17:09 +03:00
return r ;
2010-11-18 23:52:26 +03:00
}
2011-07-12 05:36:17 +04:00
static int help ( void ) {
printf ( " %s [OPTIONS...] [CONFIGURATION FILE...] \n \n "
" Applies kernel sysctl settings. \n \n "
" -h --help Show this help \n "
" --prefix=PATH Only apply rules that apply to paths with the specified prefix \n " ,
program_invocation_short_name ) ;
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_PREFIX
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " prefix " , required_argument , NULL , ARG_PREFIX } ,
{ NULL , 0 , NULL , 0 }
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " h " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ;
case ARG_PREFIX : {
char * p ;
2011-07-15 04:01:31 +04:00
char * * l ;
2011-07-12 05:36:17 +04:00
for ( p = optarg ; * p ; p + + )
if ( * p = = ' . ' )
* p = ' / ' ;
2011-07-15 04:01:31 +04:00
l = strv_append ( arg_prefixes , optarg ) ;
if ( ! l ) {
log_error ( " Out of memory " ) ;
return - ENOMEM ;
}
strv_free ( arg_prefixes ) ;
arg_prefixes = l ;
2011-07-12 05:36:17 +04:00
break ;
}
case ' ? ' :
return - EINVAL ;
default :
log_error ( " Unknown option code %c " , c ) ;
return - EINVAL ;
}
}
return 1 ;
}
2010-11-18 23:52:26 +03:00
int main ( int argc , char * argv [ ] ) {
2011-03-04 00:17:09 +03:00
int r = 0 ;
2010-11-18 23:52:26 +03:00
2011-07-12 05:36:17 +04:00
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2010-11-18 23:52:26 +03:00
log_set_target ( LOG_TARGET_AUTO ) ;
log_parse_environment ( ) ;
log_open ( ) ;
2011-08-01 22:52:18 +04:00
umask ( 0022 ) ;
2012-03-20 18:31:09 +04:00
if ( argc > optind ) {
int i ;
for ( i = optind ; i < argc ; i + + ) {
int k ;
k = apply_file ( argv [ i ] , false ) ;
if ( k < 0 & & r = = 0 )
r = k ;
}
} else {
2011-04-25 22:41:47 +04:00
char * * files , * * f ;
2012-03-20 18:31:09 +04:00
int k ;
2011-03-04 00:17:09 +03:00
2011-04-29 01:51:24 +04:00
r = conf_files_list ( & files , " .conf " ,
" /etc/sysctl.d " ,
2012-03-14 17:25:05 +04:00
" /run/sysctl.d " ,
2011-05-01 16:49:33 +04:00
" /usr/local/lib/sysctl.d " ,
2011-04-29 01:51:24 +04:00
" /usr/lib/sysctl.d " ,
2012-03-20 18:31:09 +04:00
# ifdef HAVE_SPLIT_USR
2011-04-30 22:31:33 +04:00
" /lib/sysctl.d " ,
2012-03-20 18:31:09 +04:00
# endif
2011-04-29 01:51:24 +04:00
NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to enumerate sysctl.d files: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-04-25 22:41:47 +04:00
STRV_FOREACH ( f , files ) {
k = apply_file ( * f , true ) ;
if ( k < 0 & & r = = 0 )
r = k ;
}
2012-03-20 18:31:09 +04:00
k = apply_file ( " /etc/sysctl.conf " , true ) ;
if ( k < 0 & & r = = 0 )
r = k ;
2011-05-16 13:11:52 +04:00
2011-04-25 22:41:47 +04:00
strv_free ( files ) ;
2010-11-18 23:52:26 +03:00
}
2011-04-29 01:51:24 +04:00
finish :
2011-07-15 04:01:31 +04:00
strv_free ( arg_prefixes ) ;
2011-03-04 00:17:09 +03:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2010-11-18 23:52:26 +03:00
}