blob: b1b11f3b1917022decd0f12b9eedb434609d4e8d [file] [log] [blame]
Cyril Hrubis42748952012-11-27 19:26:45 +01001/*
2 * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#include <stdarg.h>
25#include <stdio.h>
26
27#include "safe_file_ops.h"
28
29/*
30 * Count number of expected assigned conversions. Any conversion starts with '%'.
31 * The '%%' matches % and no assigment is done. The %*x matches as x would do but
32 * the assigment is supressed.
33 *
34 * NOTE: This is not 100% correct for complex scanf strings, but will do for
35 * all of our intended usage.
36 */
37static int count_scanf_conversions(const char *fmt)
38{
39 unsigned int cnt = 0;
40 int flag = 0;
41
42 while (*fmt) {
43 switch (*fmt) {
44 case '%':
45 if (flag) {
46 cnt--;
47 flag = 0;
48 } else {
49 flag = 1;
50 cnt++;
51 }
52 break;
53 case '*':
54 if (flag) {
55 cnt--;
56 flag = 0;
57 }
58 break;
59 default:
60 flag = 0;
61 }
62
63 fmt++;
64 }
65
66 return cnt;
67}
68
69void safe_file_scanf(const char *file, const int lineno,
70 void (*cleanup_fn)(void),
71 const char *path, const char *fmt, ...)
72{
73 va_list va;
74 FILE *f;
75 int exp_convs, ret;
76
77 f = fopen(path, "r");
78
79 if (f == NULL) {
80 tst_brkm(TBROK | TERRNO, cleanup_fn,
81 "Failed to open FILE '%s' for reading at %s:%d",
82 path, file, lineno);
83 }
84
85 exp_convs = count_scanf_conversions(fmt);
86
87 va_start(va, fmt);
88 ret = vfscanf(f, fmt, va);
89 va_end(va);
90
91 if (ret == EOF) {
92 tst_brkm(TBROK, cleanup_fn,
93 "The FILE '%s' ended prematurely at %s:%d",
94 path, file, lineno);
95 }
96
97 if (ret != exp_convs) {
98 tst_brkm(TBROK, cleanup_fn,
99 "Expected %i conversions got %i FILE '%s' at %s:%d",
100 exp_convs, ret, path, file, lineno);
101 }
102
103}
104
105
106void safe_file_printf(const char *file, const int lineno,
107 void (*cleanup_fn)(void),
108 const char *path, const char *fmt, ...)
109{
110 va_list va;
111 FILE *f;
112
113 f = fopen(path, "w");
114
115 if (f == NULL) {
116 tst_brkm(TBROK | TERRNO, cleanup_fn,
117 "Failed to open FILE '%s' for writing at %s:%d",
118 path, file, lineno);
119 }
120
121 va_start(va, fmt);
122
123 if (vfprintf(f, fmt, va) < 0) {
124 tst_brkm(TBROK, cleanup_fn,
125 "Failed to print to FILE '%s' at %s:%d",
126 path, file, lineno);
127 }
128
129 va_end(va);
130
131 if (fclose(f)) {
132 tst_brkm(TBROK | TERRNO, cleanup_fn,
133 "Failed to close FILE '%s' at %s:%d",
134 path, file, lineno);
135 }
136}
137
138//TODO: C implementation? better error condition reporting?
139void safe_cp(const char *file, const int lineno,
140 void (*cleanup_fn)(void),
141 const char *src, const char *dst)
142{
143 size_t len = strlen(src) + strlen(dst) + 16;
144 char buf[len];
145 int ret;
146
147 snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
148
149 ret = system(buf);
150
151 if (ret) {
152 tst_brkm(TBROK, cleanup_fn,
153 "Failed to copy '%s' to '%s' at %s:%d",
154 src, dst, file, lineno);
155 }
156}