blob: b602345473ee453b1d3e846cb5552455c2320786 [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 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080052 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010053 case '*':
54 if (flag) {
55 cnt--;
56 flag = 0;
57 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080058 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010059 default:
60 flag = 0;
61 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080062
Cyril Hrubis42748952012-11-27 19:26:45 +010063 fmt++;
64 }
65
66 return cnt;
67}
68
69void safe_file_scanf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +080070 void (*cleanup_fn) (void),
Cyril Hrubis42748952012-11-27 19:26:45 +010071 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,
Wanlong Gao354ebb42012-12-07 10:10:04 +080081 "Failed to open FILE '%s' for reading at %s:%d",
82 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +010083 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080084
Cyril Hrubis42748952012-11-27 19:26:45 +010085 exp_convs = count_scanf_conversions(fmt);
86
87 va_start(va, fmt);
88 ret = vfscanf(f, fmt, va);
89 va_end(va);
Wanlong Gao354ebb42012-12-07 10:10:04 +080090
Cyril Hrubis42748952012-11-27 19:26:45 +010091 if (ret == EOF) {
92 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +080093 "The FILE '%s' ended prematurely at %s:%d",
94 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +010095 }
96
97 if (ret != exp_convs) {
98 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +080099 "Expected %i conversions got %i FILE '%s' at %s:%d",
100 exp_convs, ret, path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100101 }
102
103}
104
Cyril Hrubis42748952012-11-27 19:26:45 +0100105void safe_file_printf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800106 void (*cleanup_fn) (void),
107 const char *path, const char *fmt, ...)
Cyril Hrubis42748952012-11-27 19:26:45 +0100108{
109 va_list va;
110 FILE *f;
111
112 f = fopen(path, "w");
113
114 if (f == NULL) {
115 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800116 "Failed to open FILE '%s' for writing at %s:%d",
117 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100118 }
119
120 va_start(va, fmt);
121
122 if (vfprintf(f, fmt, va) < 0) {
123 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800124 "Failed to print to FILE '%s' at %s:%d",
125 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100126 }
127
128 va_end(va);
129
130 if (fclose(f)) {
131 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800132 "Failed to close FILE '%s' at %s:%d",
133 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100134 }
135}
136
137//TODO: C implementation? better error condition reporting?
138void safe_cp(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800139 void (*cleanup_fn) (void), const char *src, const char *dst)
Cyril Hrubis42748952012-11-27 19:26:45 +0100140{
141 size_t len = strlen(src) + strlen(dst) + 16;
142 char buf[len];
143 int ret;
144
145 snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
146
147 ret = system(buf);
148
149 if (ret) {
150 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800151 "Failed to copy '%s' to '%s' at %s:%d",
152 src, dst, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100153 }
154}