lib: new tst_test field to save and restore proc|sys
PATCH v3 1/1 lib: new tst_test field to save and restore proc|sys
To avoid adding specially crafted functions for every feature where we need to save/restore some proc/sys config, this patch introduces a new field to tst_test struct where user specifies NULL terminated array of strings whose values should be saved before test and restored after.
---
Changes in v3:
- make list single linked
- drop list parameter, all functions use one single list
doc/test-writing-guidelines.txt | 37 +++++++++++++++ include/tst_sys_conf.h | 21 +++++++++ include/tst_test.h | 7 +++ lib/newlib_tests/.gitignore | 1 + lib/newlib_tests/test19.c | 48 +++++++++++++++++++ lib/tst_sys_conf.c | 100 ++++++++++++++++++++++++++++++++++++++++ lib/tst_test.c | 13 ++++++ 7 files changed, 227 insertions(+) create mode 100644 include/tst_sys_conf.h create mode 100644 lib/newlib_tests/test19.c create mode 100644 lib/tst_sys_conf.c
doc/test-writing-guidelines.txt +37 -0
@@ -1468,6 +1468,43 @@ first missing driver. Since it relies on modprobe command, the check will be skipped if the command itself is not available on the system. +2.2.27 Saving & restoring /proc|sys values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LTP library can be instructed to save and restore value of specified +(/proc|sys) files. This is achieved by initialized tst_test struct +field 'save_restore'. It is a NULL terminated array of strings where +each string represents a file, whose value is saved at the beginning +and restored at the end of the test. Only first line of a specified +file is saved and restored. + +Pathnames can be optionally prefixed to specify how strictly (during +'store') are handled files that don't exist: + (no prefix) - test ends with TCONF + '?' - test prints info message and continues + '!' - test ends with TBROK + +'restore' is always strict and will TWARN if it encounters any error. + +Example: + +static const char *save_restore[] = { + "/proc/sys/kernel/core_pattern", + NULL, +}; + +static void setup(void) +{ + FILE_PRINTF("/proc/sys/kernel/core_pattern", "/mypath"); +} + +static struct tst_test test = { + ... + .setup = setup, + .save_restore = save_restore, +}; + + 2.3 Writing a testcase in shell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/tst_sys_conf.h new file +21 -0
@@ -0,0 +1,21 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* Copyright (c) 2018 Jan Stancek <[email protected]> +*/ + +#ifndef TST_SYS_CONF_H__ +#define TST_SYS_CONF_H__ + +struct tst_sys_conf { +char path[PATH_MAX ]; +char value[PATH_MAX ]; +struct tst_sys_conf *next; +}; + +int tst_sys_conf_save_str (const char *path,const char *value); +int tst_sys_conf_save (const char *path); +void tst_sys_conf_restore (int verbose); +void tst_sys_conf_dump (void ); + +#endif
include/tst_test.h +7 -0
@@ -42,6 +42,7 @@#include "tst_minmax.h" #include "tst_get_bad_addr.h" #include "tst_path_has_mnt_flags.h" +#include "tst_sys_conf.h" /* * Reports testcase result.
@@ -175,6 +176,12 @@ struct tst_test {/* NULL terminated array of needed kernel drivers */ const char *const *needs_drivers; + +/* +* NULL terminated array of (/proc, /sys) files to save +* before setup and restore after cleanup +*/ +const char *const *save_restore; };/*
lib/newlib_tests/.gitignore +1 -0
@@ -20,6 +20,7 @@ tst_res_hexd tst_strstatus test17 test18 +test19 tst_expiration_timer test_exec test_exec_child
lib/newlib_tests/test19.c new file +48 -0
48 lines not on this page · raw message
lib/tst_sys_conf.c new file +100 -0
100 lines not on this page · raw message
lib/tst_test.c +13 -0
@@ -35,6 +35,7 @@#include "tst_timer_test.h" #include "tst_clocks.h" #include "tst_timer.h" +#include "tst_sys_conf.h" #include "old_resource.h" #include "old_device.h"
@@ -809,6 +810,15 @@ static void do_setup(int argc, char *argv[])if (needs_tmpdir () && !tst_tmpdir_created ())tst_tmpdir (); +if (tst_test->save_restore) { +const char *const *name = tst_test->save_restore; + +while (*name) { +tst_sys_conf_save (*name); + name++; + } + } +if (tst_test->mntpoint)SAFE_MKDIR (tst_test->mntpoint,0777 );
@@ -885,6 +895,9 @@ static void do_cleanup(void)tst_rmdir (); } +if (tst_test->save_restore) +tst_sys_conf_restore (0 ); +cleanup_ipc (); }
Signature · 1 line
1.8.3.1
PATCH v3 1/1 lib: new tst_test field to save and restore proc|sys
Quoted 168 lines · Jan Stancek
To avoid adding specially crafted functions for every feature where we need to save/restore some proc/sys config, this patch introduces a new field to
tst_teststruct where user specifies NULL terminated array of strings whose values should be saved before test and restored after.Signed-off-by Jan Stancek<[email protected]>---
Changes in v3:
- make list single linked
- drop list parameter, all functions use one single listdoc/test-writing-guidelines.txt | 37 +++++++++++++++ include/tst_sys_conf.h | 21 +++++++++ include/tst_test.h | 7 +++ lib/newlib_tests/.gitignore | 1 + lib/newlib_tests/test19.c | 48 +++++++++++++++++++ lib/tst_sys_conf.c | 100 ++++++++++++++++++++++++++++++++++++++++ lib/tst_test.c | 13 ++++++ 7 files changed, 227 insertions(+)create mode 100644
include/tst_sys_conf.h
create mode 100644lib/newlib_tests/test19.c
create mode 100644lib/tst_sys_conf.cdoc/test-writing-guidelines.txt +37
-0@@ -1468,6 +1468,43 @@ first missing driver. Since it relies on modprobe command, the check will be skipped if the command itself is not available on the system. +2.2.27 Saving& restoring /proc|sys values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LTP library can be instructed to save and restore value of specified +(/proc|sys) files. This is achieved by initialized tst_test struct +field 'save_restore'. It is a NULL terminated array of strings where +each string represents a file, whose value is saved at the beginning +and restored at the end of the test. Only first line of a specified +file is saved and restored. + +Pathnames can be optionally prefixed to specify how strictly (during +'store') are handled files that don't exist: + (no prefix) - test ends with TCONF + '?' - test prints info message and continues + '!' - test ends with TBROK + +'restore' is always strict and will TWARN if it encounters any error. + +Example: + +static const char *save_restore[] = { + "/proc/sys/kernel/core_pattern", + NULL, +}; + +static void setup(void) +{ + FILE_PRINTF("/proc/sys/kernel/core_pattern", "/mypath"); +} + +static struct tst_test test = { + ... + .setup = setup, + .save_restore = save_restore, +}; + + 2.3 Writing a testcase in shell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~include/tst_sys_conf.h new file +21
-0@@ -0,0 +1,21 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* Copyright (c) 2018 Jan Stancek<[email protected]> +*/ + +#ifndef TST_SYS_CONF_H__ +#define TST_SYS_CONF_H__ + +struct tst_sys_conf { +char path[PATH_MAX ]; +char value[PATH_MAX ]; +struct tst_sys_conf *next; +}; + +int tst_sys_conf_save_str (const char *path,const char *value); +int tst_sys_conf_save (const char *path); +void tst_sys_conf_restore (int verbose); +void tst_sys_conf_dump (void ); + +#endif include/tst_test.h +7
-0@@ -42,6 +42,7 @@#include "tst_minmax.h" #include "tst_get_bad_addr.h" #include "tst_path_has_mnt_flags.h" +#include "tst_sys_conf.h" /* * Reports testcase result. @@ -175,6 +176,12 @@ struct tst_test {/* NULL terminated array of needed kernel drivers */ const char *const *needs_drivers; + +/* +* NULL terminated array of (/proc, /sys) files to save +* before setup and restore after cleanup +*/ +const char *const *save_restore; };/* lib/newlib_tests/.gitignore +1
-0@@ -20,6 +20,7 @@ tst_res_hexd tst_strstatus test17 test18 +test19 tst_expiration_timer test_exec test_exec_childlib/newlib_tests/test19.c new file +26
-0@@ -0,0 +1,48 @@ +/* +* Copyright (c) 2018, Linux Test Project +* +* 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 2 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 <stdlib.h> +#include <unistd.h> +#include "tst_test.h" +#include "tst_sys_conf.h" + +static char orig[1024 ]; + +static const char *const save_restore[] = { +"?/proc/nonexistent" ,
lib/newlib_tests/test19.c line 36
Quoted 10 lines
lib/newlib_tests/test19.c new file +10
-0+"!/proc/sys/kernel/numa_balancing" , +"/proc/sys/kernel/core_pattern" , + NULL, +}; + +static void setup (void ) +{ +SAFE_FILE_SCANF ("/proc/sys/kernel/core_pattern" ,"%s" , orig); +SAFE_FILE_PRINTF ("/proc/sys/kernel/core_pattern" ,"changed" ); +}
Hi Jan,
Why do you save the value of core_pattern by SAFE_FILE_SCANF() ? It seems that the .save_restore flag has done it.
Quoted 42 lines
lib/newlib_tests/test19.c new file +12
-0+ +static void run (void ) +{ +tst_res (TPASS ,"OK" ); +} + +static struct tst_test test = { + .needs_root =1 , + .test_all = run, + .setup = setup, + .save_restore = save_restore, +};lib/tst_sys_conf.c new file +24
-0@@ -0,0 +1,100 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* Copyright (c) 2018 Jan Stancek<[email protected]> +*/ + +#include <limits.h> +#include <stdio.h> +#include <unistd.h> + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_sys_conf.h" + +static struct tst_sys_conf save_restore_data; + +void tst_sys_conf_dump (void ) +{ +struct tst_sys_conf *i = save_restore_data.next; + +while (i) { +tst_res (TINFO ,"%s -> %s" , i->path, i->value); + i = i->next; + }
lib/tst_sys_conf.c line 34
Quoted 10 lines
lib/tst_sys_conf.c new file +10
-0+} + +int tst_sys_conf_save_str (const char *path,const char *value) +{ +struct tst_sys_conf *n =SAFE_MALLOC (sizeof (*n)); + +strncpy (n->path, path,sizeof (n->path)); +strncpy (n->value, value,sizeof (n->value)); + +/* add new entry at the beginning, right after 'c' */
Does this comment need to be updated?
Best Regards,
Xiao Yang
Quoted 104 lines
lib/tst_sys_conf.c new file +66
-0+ n->next = save_restore_data.next; + save_restore_data.next = n; + +return 0 ; +} + +int tst_sys_conf_save (const char *path) +{ +char line[PATH_MAX ]; +FILE *fp; +void *ret; +char flag; + +if (!path) +tst_brk (TBROK ,"path is empty" ); + + flag = path[0 ]; +if (flag =='?' || flag =='!' ) + path++; + +if (access (path,F_OK ) !=0 ) { +switch (flag) { +case '?' : +tst_res (TINFO ,"Path not found: '%s'" , path); +break ; +case '!' : +tst_brk (TBROK |TERRNO ,"Path not found: '%s'" , path); +break ; +default : +tst_brk (TCONF |TERRNO ,"Path not found: '%s'" , path); + } +return 1 ; + } + + fp =fopen (path,"r" ); +if (fp ==NULL ) { +tst_brk (TBROK |TERRNO ,"Failed to open FILE '%s' for reading" , + path); +return 1 ; + } + + ret =fgets (line,sizeof (line), fp); +fclose (fp); + +if (ret ==NULL ) { +tst_brk (TBROK |TERRNO ,"Failed to read anything from '%s'" , + path); + } + +return tst_sys_conf_save_str (path, line); +} + +void tst_sys_conf_restore (int verbose) +{ +struct tst_sys_conf *i = save_restore_data.next; + +while (i) { +if (verbose) { +tst_res (TINFO ,"Restoring conf.: %s -> %s\n" , + i->path, i->value); + } +FILE_PRINTF (i->path,"%s" , i->value); + i = i->next; + } +} +lib/tst_test.c +13
-0@@ -35,6 +35,7 @@#include "tst_timer_test.h" #include "tst_clocks.h" #include "tst_timer.h" +#include "tst_sys_conf.h" #include "old_resource.h" #include "old_device.h" @@ -809,6 +810,15 @@ static void do_setup(int argc, char *argv[])if (needs_tmpdir ()&& !tst_tmpdir_created ())tst_tmpdir (); +if (tst_test->save_restore) { +const char *const *name = tst_test->save_restore; + +while (*name) { +tst_sys_conf_save (*name); + name++; + } + } +if (tst_test->mntpoint)SAFE_MKDIR (tst_test->mntpoint,0777 );@@ -885,6 +895,9 @@ static void do_cleanup(void)tst_rmdir (); } +if (tst_test->save_restore) +tst_sys_conf_restore (0 ); +cleanup_ipc (); }
PATCH v3 1/1 lib: new tst_test field to save and restore proc|sys
----- Original Message -----
Quoted 184 lines · Jan Stancek
Quoted 171 lines
To avoid adding specially crafted functions for every feature where we need to save/restore some proc/sys config, this patch introduces a new field to
tst_teststruct where user specifies NULL terminated array of strings whose values should be saved before test and restored after.Signed-off-by Jan Stancek<[email protected]>---
Changes in v3:
- make list single linked
- drop list parameter, all functions use one single listdoc/test-writing-guidelines.txt | 37 +++++++++++++++ include/tst_sys_conf.h | 21 +++++++++ include/tst_test.h | 7 +++ lib/newlib_tests/.gitignore | 1 + lib/newlib_tests/test19.c | 48 +++++++++++++++++++ lib/tst_sys_conf.c | 100 ++++++++++++++++++++++++++++++++++++++++ lib/tst_test.c | 13 ++++++ 7 files changed, 227 insertions(+)create mode 100644
include/tst_sys_conf.h
create mode 100644lib/newlib_tests/test19.c
create mode 100644lib/tst_sys_conf.cdoc/test-writing-guidelines.txt +37
-0@@ -1468,6 +1468,43 @@ first missing driver. Since it relies on modprobe command, the check will be skipped if the command itself is not available on the system. +2.2.27 Saving& restoring /proc|sys values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LTP library can be instructed to save and restore value of specified +(/proc|sys) files. This is achieved by initialized tst_test struct +field 'save_restore'. It is a NULL terminated array of strings where +each string represents a file, whose value is saved at the beginning +and restored at the end of the test. Only first line of a specified +file is saved and restored. + +Pathnames can be optionally prefixed to specify how strictly (during +'store') are handled files that don't exist: + (no prefix) - test ends with TCONF + '?' - test prints info message and continues + '!' - test ends with TBROK + +'restore' is always strict and will TWARN if it encounters any error. + +Example: + +static const char *save_restore[] = { + "/proc/sys/kernel/core_pattern", + NULL, +}; + +static void setup(void) +{ + FILE_PRINTF("/proc/sys/kernel/core_pattern", "/mypath"); +} + +static struct tst_test test = { + ... + .setup = setup, + .save_restore = save_restore, +}; + + 2.3 Writing a testcase in shell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~include/tst_sys_conf.h new file +21
-0@@ -0,0 +1,21 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* Copyright (c) 2018 Jan Stancek<[email protected]> +*/ + +#ifndef TST_SYS_CONF_H__ +#define TST_SYS_CONF_H__ + +struct tst_sys_conf { +char path[PATH_MAX ]; +char value[PATH_MAX ]; +struct tst_sys_conf *next; +}; + +int tst_sys_conf_save_str (const char *path,const char *value); +int tst_sys_conf_save (const char *path); +void tst_sys_conf_restore (int verbose); +void tst_sys_conf_dump (void ); + +#endif include/tst_test.h +7
-0@@ -42,6 +42,7 @@#include "tst_minmax.h" #include "tst_get_bad_addr.h" #include "tst_path_has_mnt_flags.h" +#include "tst_sys_conf.h" /* * Reports testcase result. @@ -175,6 +176,12 @@ struct tst_test {/* NULL terminated array of needed kernel drivers */ const char *const *needs_drivers; + +/* +* NULL terminated array of (/proc, /sys) files to save +* before setup and restore after cleanup +*/ +const char *const *save_restore; };/* lib/newlib_tests/.gitignore +1
-0@@ -20,6 +20,7 @@ tst_res_hexd tst_strstatus test17 test18 +test19 tst_expiration_timer test_exec test_exec_childlib/newlib_tests/test19.c new file +26
-0@@ -0,0 +1,48 @@ +/* +* Copyright (c) 2018, Linux Test Project +* +* 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 2 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 <stdlib.h> +#include <unistd.h> +#include "tst_test.h" +#include "tst_sys_conf.h" + +static char orig[1024 ]; + +static const char *const save_restore[] = { +"?/proc/nonexistent" ,lib/newlib_tests/test19.c line 36
Quoted 10 lines
lib/newlib_tests/test19.c new file +10
-0+"!/proc/sys/kernel/numa_balancing" , +"/proc/sys/kernel/core_pattern" , + NULL, +}; + +static void setup (void ) +{ +SAFE_FILE_SCANF ("/proc/sys/kernel/core_pattern" ,"%s" , orig); +SAFE_FILE_PRINTF ("/proc/sys/kernel/core_pattern" ,"changed" ); +}Hi Jan,
Quoted 2 lines
Why do you save the value of
core_patternbySAFE_FILE_SCANF()? It seems that the .save_restore flag has done it.
Old code was checking that value has been restored properly, but that was before save/restore moved to lib.
You're right to point out, that it's useless now.
Quoted 45 lines
Quoted 45 lines
lib/newlib_tests/test19.c new file +12
-0+ +static void run (void ) +{ +tst_res (TPASS ,"OK" ); +} + +static struct tst_test test = { + .needs_root =1 , + .test_all = run, + .setup = setup, + .save_restore = save_restore, +};lib/tst_sys_conf.c new file +27
-0@@ -0,0 +1,100 @@ +/* +* SPDX-License-Identifier: GPL-2.0-or-later +* +* Copyright (c) 2018 Jan Stancek<[email protected]> +*/ + +#include <limits.h> +#include <stdio.h> +#include <unistd.h> + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_sys_conf.h" + +static struct tst_sys_conf save_restore_data; + +void tst_sys_conf_dump (void ) +{ +struct tst_sys_conf *i = save_restore_data.next; + +while (i) { +tst_res (TINFO ,"%s -> %s" , i->path, i->value); + i = i->next; + } +} + +int tst_sys_conf_save_str (const char *path,const char *value)
Quoted 8 lines
lib/tst_sys_conf.c line 34
Quoted 7 lines
lib/tst_sys_conf.c new file +7
-0+{ +struct tst_sys_conf *n =SAFE_MALLOC (sizeof (*n)); + +strncpy (n->path, path,sizeof (n->path)); +strncpy (n->value, value,sizeof (n->value)); + +/* add new entry at the beginning, right after 'c' */ Does this comment need to be updated?
I'll drop this too, v3 is easier to follow with single linked list.
Regards,
Jan
Quoted 111 lines
Best Regards,
Xiao YangQuoted 104 lines
lib/tst_sys_conf.c new file +66
-0+ n->next = save_restore_data.next; + save_restore_data.next = n; + +return 0 ; +} + +int tst_sys_conf_save (const char *path) +{ +char line[PATH_MAX ]; +FILE *fp; +void *ret; +char flag; + +if (!path) +tst_brk (TBROK ,"path is empty" ); + + flag = path[0 ]; +if (flag =='?' || flag =='!' ) + path++; + +if (access (path,F_OK ) !=0 ) { +switch (flag) { +case '?' : +tst_res (TINFO ,"Path not found: '%s'" , path); +break ; +case '!' : +tst_brk (TBROK |TERRNO ,"Path not found: '%s'" , path); +break ; +default : +tst_brk (TCONF |TERRNO ,"Path not found: '%s'" , path); + } +return 1 ; + } + + fp =fopen (path,"r" ); +if (fp ==NULL ) { +tst_brk (TBROK |TERRNO ,"Failed to open FILE '%s' for reading" , + path); +return 1 ; + } + + ret =fgets (line,sizeof (line), fp); +fclose (fp); + +if (ret ==NULL ) { +tst_brk (TBROK |TERRNO ,"Failed to read anything from '%s'" , + path); + } + +return tst_sys_conf_save_str (path, line); +} + +void tst_sys_conf_restore (int verbose) +{ +struct tst_sys_conf *i = save_restore_data.next; + +while (i) { +if (verbose) { +tst_res (TINFO ,"Restoring conf.: %s -> %s\n" , + i->path, i->value); + } +FILE_PRINTF (i->path,"%s" , i->value); + i = i->next; + } +} +lib/tst_test.c +13
-0@@ -35,6 +35,7 @@#include "tst_timer_test.h" #include "tst_clocks.h" #include "tst_timer.h" +#include "tst_sys_conf.h" #include "old_resource.h" #include "old_device.h" @@ -809,6 +810,15 @@ static void do_setup(int argc, char *argv[])if (needs_tmpdir ()&& !tst_tmpdir_created ())tst_tmpdir (); +if (tst_test->save_restore) { +const char *const *name = tst_test->save_restore; + +while (*name) { +tst_sys_conf_save (*name); + name++; + } + } +if (tst_test->mntpoint)SAFE_MKDIR (tst_test->mntpoint,0777 );@@ -885,6 +895,9 @@ static void do_cleanup(void)tst_rmdir (); } +if (tst_test->save_restore) +tst_sys_conf_restore (0 ); +cleanup_ipc (); }