2022-10-03 19:58:49 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
2017-07-13 00:33:43 +03:00
/*
* proc sysctl test driver
*
* Copyright ( C ) 2017 Luis R . Rodriguez < mcgrof @ kernel . org >
*/
/*
2020-10-16 06:11:10 +03:00
* This module provides an interface to the proc sysctl interfaces . This
2017-07-13 00:33:43 +03:00
* driver requires CONFIG_PROC_SYSCTL . It will not normally be loaded by the
* system unless explicitly requested by name . You can also build this driver
* into your kernel .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/init.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/printk.h>
# include <linux/fs.h>
# include <linux/miscdevice.h>
# include <linux/slab.h>
# include <linux/uaccess.h>
# include <linux/async.h>
# include <linux/delay.h>
# include <linux/vmalloc.h>
static int i_zero ;
static int i_one_hundred = 100 ;
2022-05-01 06:55:24 +03:00
static int match_int_ok = 1 ;
2017-07-13 00:33:43 +03:00
2023-06-16 11:59:20 +03:00
static struct {
struct ctl_table_header * test_h_setup_node ;
struct ctl_table_header * test_h_mnt ;
struct ctl_table_header * test_h_mnterror ;
2023-11-21 14:02:19 +03:00
struct ctl_table_header * empty_add ;
struct ctl_table_header * empty ;
2023-06-16 11:59:20 +03:00
} sysctl_test_headers ;
2017-07-13 00:33:43 +03:00
struct test_sysctl_data {
int int_0001 ;
2017-07-13 00:33:52 +03:00
int int_0002 ;
2017-07-13 00:33:58 +03:00
int int_0003 [ 4 ] ;
2017-07-13 00:33:52 +03:00
2020-06-08 07:40:38 +03:00
int boot_int ;
2017-07-13 00:33:55 +03:00
unsigned int uint_0001 ;
2017-07-13 00:33:43 +03:00
char string_0001 [ 65 ] ;
2019-05-15 01:45:10 +03:00
# define SYSCTL_TEST_BITMAP_SIZE 65536
unsigned long * bitmap_0001 ;
2017-07-13 00:33:43 +03:00
} ;
static struct test_sysctl_data test_data = {
. int_0001 = 60 ,
2017-07-13 00:33:52 +03:00
. int_0002 = 1 ,
2017-07-13 00:33:58 +03:00
. int_0003 [ 0 ] = 0 ,
. int_0003 [ 1 ] = 1 ,
. int_0003 [ 2 ] = 2 ,
. int_0003 [ 3 ] = 3 ,
2020-06-08 07:40:38 +03:00
. boot_int = 0 ,
2017-07-13 00:33:55 +03:00
. uint_0001 = 314 ,
2017-07-13 00:33:43 +03:00
. string_0001 = " (none) " ,
} ;
/* These are all under /proc/sys/debug/test_sysctl/ */
static struct ctl_table test_table [ ] = {
{
. procname = " int_0001 " ,
. data = & test_data . int_0001 ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec_minmax ,
. extra1 = & i_zero ,
. extra2 = & i_one_hundred ,
} ,
2017-07-13 00:33:52 +03:00
{
. procname = " int_0002 " ,
. data = & test_data . int_0002 ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec ,
} ,
2017-07-13 00:33:58 +03:00
{
. procname = " int_0003 " ,
. data = & test_data . int_0003 ,
. maxlen = sizeof ( test_data . int_0003 ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec ,
} ,
2022-05-01 06:55:24 +03:00
{
. procname = " match_int " ,
. data = & match_int_ok ,
. maxlen = sizeof ( match_int_ok ) ,
. mode = 0444 ,
. proc_handler = proc_dointvec ,
} ,
2020-06-08 07:40:38 +03:00
{
. procname = " boot_int " ,
. data = & test_data . boot_int ,
. maxlen = sizeof ( test_data . boot_int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE ,
} ,
2017-07-13 00:33:55 +03:00
{
. procname = " uint_0001 " ,
. data = & test_data . uint_0001 ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = proc_douintvec ,
} ,
2017-07-13 00:33:43 +03:00
{
. procname = " string_0001 " ,
. data = & test_data . string_0001 ,
. maxlen = sizeof ( test_data . string_0001 ) ,
. mode = 0644 ,
. proc_handler = proc_dostring ,
} ,
2019-05-15 01:45:10 +03:00
{
. procname = " bitmap_0001 " ,
. data = & test_data . bitmap_0001 ,
. maxlen = SYSCTL_TEST_BITMAP_SIZE ,
. mode = 0644 ,
. proc_handler = proc_do_large_bitmap ,
} ,
2017-07-13 00:33:43 +03:00
} ;
2023-06-16 11:59:17 +03:00
static void test_sysctl_calc_match_int_ok ( void )
2017-07-13 00:33:43 +03:00
{
2022-05-01 06:55:24 +03:00
int i ;
struct {
int defined ;
int wanted ;
} match_int [ ] = {
{ . defined = * ( int * ) SYSCTL_ZERO , . wanted = 0 } ,
{ . defined = * ( int * ) SYSCTL_ONE , . wanted = 1 } ,
{ . defined = * ( int * ) SYSCTL_TWO , . wanted = 2 } ,
{ . defined = * ( int * ) SYSCTL_THREE , . wanted = 3 } ,
{ . defined = * ( int * ) SYSCTL_FOUR , . wanted = 4 } ,
{ . defined = * ( int * ) SYSCTL_ONE_HUNDRED , . wanted = 100 } ,
{ . defined = * ( int * ) SYSCTL_TWO_HUNDRED , . wanted = 200 } ,
{ . defined = * ( int * ) SYSCTL_ONE_THOUSAND , . wanted = 1000 } ,
{ . defined = * ( int * ) SYSCTL_THREE_THOUSAND , . wanted = 3000 } ,
{ . defined = * ( int * ) SYSCTL_INT_MAX , . wanted = INT_MAX } ,
{ . defined = * ( int * ) SYSCTL_MAXOLDUID , . wanted = 65535 } ,
{ . defined = * ( int * ) SYSCTL_NEG_ONE , . wanted = - 1 } ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( match_int ) ; i + + )
if ( match_int [ i ] . defined ! = match_int [ i ] . wanted )
match_int_ok = 0 ;
2023-06-16 11:59:17 +03:00
}
2022-05-01 06:55:24 +03:00
2023-06-16 11:59:17 +03:00
static int test_sysctl_setup_node_tests ( void )
{
test_sysctl_calc_match_int_ok ( ) ;
2019-05-15 01:45:10 +03:00
test_data . bitmap_0001 = kzalloc ( SYSCTL_TEST_BITMAP_SIZE / 8 , GFP_KERNEL ) ;
if ( ! test_data . bitmap_0001 )
return - ENOMEM ;
2023-06-16 11:59:20 +03:00
sysctl_test_headers . test_h_setup_node = register_sysctl ( " debug/test_sysctl " , test_table ) ;
if ( ! sysctl_test_headers . test_h_setup_node ) {
2019-05-15 01:45:10 +03:00
kfree ( test_data . bitmap_0001 ) ;
2017-07-13 00:33:43 +03:00
return - ENOMEM ;
2019-05-15 01:45:10 +03:00
}
2023-06-16 11:59:17 +03:00
2017-07-13 00:33:43 +03:00
return 0 ;
}
2023-06-16 11:59:17 +03:00
2023-06-16 11:59:18 +03:00
/* Used to test that unregister actually removes the directory */
static struct ctl_table test_table_unregister [ ] = {
{
. procname = " unregister_error " ,
. data = & test_data . int_0001 ,
. maxlen = sizeof ( int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec_minmax ,
} ,
} ;
static int test_sysctl_run_unregister_nested ( void )
{
struct ctl_table_header * unregister ;
unregister = register_sysctl ( " debug/test_sysctl/unregister_error " ,
test_table_unregister ) ;
if ( ! unregister )
return - ENOMEM ;
unregister_sysctl_table ( unregister ) ;
return 0 ;
}
2023-06-16 11:59:20 +03:00
static int test_sysctl_run_register_mount_point ( void )
{
sysctl_test_headers . test_h_mnt
= register_sysctl_mount_point ( " debug/test_sysctl/mnt " ) ;
if ( ! sysctl_test_headers . test_h_mnt )
return - ENOMEM ;
sysctl_test_headers . test_h_mnterror
= register_sysctl ( " debug/test_sysctl/mnt/mnt_error " ,
test_table_unregister ) ;
/*
* Don ' t check the result . :
* If it fails ( expected behavior ) , return 0.
* If successful ( missbehavior of register mount point ) , we want to see
* mnt_error when we run the sysctl test script
*/
return 0 ;
}
2023-11-21 14:02:19 +03:00
static struct ctl_table test_table_empty [ ] = { } ;
static int test_sysctl_run_register_empty ( void )
{
/* Tets that an empty dir can be created */
sysctl_test_headers . empty_add
= register_sysctl ( " debug/test_sysctl/empty_add " , test_table_empty ) ;
if ( ! sysctl_test_headers . empty_add )
return - ENOMEM ;
/* Test that register on top of an empty dir works */
sysctl_test_headers . empty
= register_sysctl ( " debug/test_sysctl/empty_add/empty " , test_table_empty ) ;
if ( ! sysctl_test_headers . empty )
return - ENOMEM ;
return 0 ;
}
2023-06-16 11:59:17 +03:00
static int __init test_sysctl_init ( void )
{
int err ;
err = test_sysctl_setup_node_tests ( ) ;
2023-06-16 11:59:18 +03:00
if ( err )
goto out ;
err = test_sysctl_run_unregister_nested ( ) ;
2023-06-16 11:59:20 +03:00
if ( err )
goto out ;
err = test_sysctl_run_register_mount_point ( ) ;
2023-11-21 14:02:19 +03:00
if ( err )
goto out ;
err = test_sysctl_run_register_empty ( ) ;
2023-06-16 11:59:17 +03:00
2023-06-16 11:59:18 +03:00
out :
2023-06-16 11:59:17 +03:00
return err ;
}
2020-05-28 17:52:16 +03:00
module_init ( test_sysctl_init ) ;
2017-07-13 00:33:43 +03:00
static void __exit test_sysctl_exit ( void )
{
2019-05-15 01:45:10 +03:00
kfree ( test_data . bitmap_0001 ) ;
2023-06-16 11:59:20 +03:00
if ( sysctl_test_headers . test_h_setup_node )
unregister_sysctl_table ( sysctl_test_headers . test_h_setup_node ) ;
if ( sysctl_test_headers . test_h_mnt )
unregister_sysctl_table ( sysctl_test_headers . test_h_mnt ) ;
if ( sysctl_test_headers . test_h_mnterror )
unregister_sysctl_table ( sysctl_test_headers . test_h_mnterror ) ;
2023-11-21 14:02:19 +03:00
if ( sysctl_test_headers . empty )
unregister_sysctl_table ( sysctl_test_headers . empty ) ;
if ( sysctl_test_headers . empty_add )
unregister_sysctl_table ( sysctl_test_headers . empty_add ) ;
2017-07-13 00:33:43 +03:00
}
module_exit ( test_sysctl_exit ) ;
MODULE_AUTHOR ( " Luis R. Rodriguez <mcgrof@kernel.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;