xref: /third_party/ltp/lib/tst_sys_conf.c (revision f08c3bdf)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2018 Jan Stancek <jstancek@redhat.com>
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
15struct tst_sys_conf {
16	char path[PATH_MAX];
17	char value[PATH_MAX];
18	struct tst_sys_conf *next;
19};
20
21static struct tst_sys_conf *save_restore_data;
22
23static 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
32void 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
40void 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
54int 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
135void 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