xref: /aosp_15_r20/external/ltp/lib/tst_sys_conf.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 Jan Stancek <[email protected]>
4  */
5 
6 #include <limits.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <string.h>
10 
11 #define TST_NO_DEFAULT_MAIN
12 #include "tst_test.h"
13 #include "tst_sys_conf.h"
14 
15 struct tst_sys_conf {
16 	char path[PATH_MAX];
17 	char value[PATH_MAX];
18 	struct tst_sys_conf *next;
19 };
20 
21 static struct tst_sys_conf *save_restore_data;
22 
print_error(const int lineno,int info_only,const char * err,const char * path)23 static void print_error(const int lineno, int info_only, const char *err,
24 	const char *path)
25 {
26 	if (info_only)
27 		tst_res_(__FILE__, lineno, TINFO | TERRNO, err, path);
28 	else
29 		tst_brk_(__FILE__, lineno, TBROK | TERRNO, err, path);
30 }
31 
tst_sys_conf_dump(void)32 void tst_sys_conf_dump(void)
33 {
34 	struct tst_sys_conf *i;
35 
36 	for (i = save_restore_data; i; i = i->next)
37 		tst_res(TINFO, "%s = %s", i->path, i->value);
38 }
39 
tst_sys_conf_save_str(const char * path,const char * value)40 void tst_sys_conf_save_str(const char *path, const char *value)
41 {
42 	struct tst_sys_conf *n = SAFE_MALLOC(sizeof(*n));
43 
44 	strncpy(n->path, path, sizeof(n->path)-1);
45 	strncpy(n->value, value, sizeof(n->value)-1);
46 
47 	n->path[sizeof(n->path) - 1] = 0;
48 	n->value[sizeof(n->value) - 1] = 0;
49 
50 	n->next = save_restore_data;
51 	save_restore_data = n;
52 }
53 
tst_sys_conf_save(const struct tst_path_val * conf)54 int tst_sys_conf_save(const struct tst_path_val *conf)
55 {
56 	char line[PATH_MAX];
57 	int ttype, iret;
58 	FILE *fp;
59 	void *ret;
60 
61 	if (!conf || !conf->path)
62 		tst_brk(TBROK, "path is empty");
63 
64 	if (access(conf->path, F_OK) != 0) {
65 		if (conf->flags & TST_SR_SKIP_MISSING) {
66 			tst_res(TINFO | TERRNO, "Path not found: %s",
67 				conf->path);
68 			return 1;
69 		}
70 
71 		ttype = (conf->flags & TST_SR_TBROK_MISSING) ? TBROK : TCONF;
72 		tst_brk(ttype | TERRNO, "Path not found: %s", conf->path);
73 	}
74 
75 	if (access(conf->path, W_OK) != 0) {
76 		if (conf->flags & TST_SR_SKIP_RO) {
77 			tst_res(TINFO | TERRNO, "Path is not writable: %s",
78 				conf->path);
79 			return 1;
80 		}
81 
82 		ttype = (conf->flags & TST_SR_TBROK_RO) ? TBROK : TCONF;
83 		tst_brk(ttype | TERRNO, "Path is not writable: %s", conf->path);
84 	}
85 
86 	fp = fopen(conf->path, "r");
87 
88 	if (fp == NULL) {
89 		print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR,
90 			"Failed to open '%s' for reading", conf->path);
91 		return 1;
92 	}
93 
94 	ret = fgets(line, sizeof(line), fp);
95 	fclose(fp);
96 
97 	if (ret == NULL) {
98 		if (conf->flags & TST_SR_IGNORE_ERR)
99 			return 1;
100 
101 		tst_brk(TBROK | TERRNO, "Failed to read anything from '%s'",
102 			conf->path);
103 	}
104 
105 	tst_sys_conf_save_str(conf->path, line);
106 
107 	if (!conf->val)
108 		return 0;
109 
110 	fp = fopen(conf->path, "w");
111 
112 	if (fp == NULL) {
113 		print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR,
114 			"Failed to open '%s' for writing", conf->path);
115 		return 0;
116 	}
117 
118 	iret = fputs(conf->val, fp);
119 
120 	if (iret < 0) {
121 		print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR,
122 			"Failed to write into '%s'", conf->path);
123 	}
124 
125 	iret = fclose(fp);
126 
127 	if (iret < 0) {
128 		print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR,
129 			"Failed to close '%s'", conf->path);
130 	}
131 
132 	return 0;
133 }
134 
tst_sys_conf_restore(int verbose)135 void tst_sys_conf_restore(int verbose)
136 {
137 	struct tst_sys_conf *i;
138 
139 	for (i = save_restore_data; i; i = i->next) {
140 		if (verbose) {
141 			tst_res(TINFO, "Restoring conf.: %s -> %s\n",
142 				i->path, i->value);
143 		}
144 		FILE_PRINTF(i->path, "%s", i->value);
145 	}
146 }
147 
148