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