blob: 8cfd264e0ae860239eb92ed7f29bedc2adfd39e9 [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>
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +040026#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
Cyril Hrubis42748952012-11-27 19:26:45 +010029
30#include "safe_file_ops.h"
31
32/*
33 * Count number of expected assigned conversions. Any conversion starts with '%'.
34 * The '%%' matches % and no assigment is done. The %*x matches as x would do but
35 * the assigment is supressed.
36 *
37 * NOTE: This is not 100% correct for complex scanf strings, but will do for
38 * all of our intended usage.
39 */
40static int count_scanf_conversions(const char *fmt)
41{
42 unsigned int cnt = 0;
43 int flag = 0;
44
45 while (*fmt) {
46 switch (*fmt) {
47 case '%':
48 if (flag) {
49 cnt--;
50 flag = 0;
51 } else {
52 flag = 1;
53 cnt++;
54 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080055 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010056 case '*':
57 if (flag) {
58 cnt--;
59 flag = 0;
60 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080061 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010062 default:
63 flag = 0;
64 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080065
Cyril Hrubis42748952012-11-27 19:26:45 +010066 fmt++;
67 }
68
69 return cnt;
70}
71
72void safe_file_scanf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +080073 void (*cleanup_fn) (void),
Cyril Hrubis42748952012-11-27 19:26:45 +010074 const char *path, const char *fmt, ...)
75{
76 va_list va;
77 FILE *f;
78 int exp_convs, ret;
79
80 f = fopen(path, "r");
81
82 if (f == NULL) {
83 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +080084 "Failed to open FILE '%s' for reading at %s:%d",
85 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +010086 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080087
Cyril Hrubis42748952012-11-27 19:26:45 +010088 exp_convs = count_scanf_conversions(fmt);
89
90 va_start(va, fmt);
91 ret = vfscanf(f, fmt, va);
92 va_end(va);
Wanlong Gao354ebb42012-12-07 10:10:04 +080093
Cyril Hrubis42748952012-11-27 19:26:45 +010094 if (ret == EOF) {
95 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +080096 "The FILE '%s' ended prematurely at %s:%d",
97 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +010098 }
99
100 if (ret != exp_convs) {
101 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800102 "Expected %i conversions got %i FILE '%s' at %s:%d",
103 exp_convs, ret, path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100104 }
105
106}
107
Cyril Hrubis42748952012-11-27 19:26:45 +0100108void safe_file_printf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800109 void (*cleanup_fn) (void),
110 const char *path, const char *fmt, ...)
Cyril Hrubis42748952012-11-27 19:26:45 +0100111{
112 va_list va;
113 FILE *f;
114
115 f = fopen(path, "w");
116
117 if (f == NULL) {
118 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800119 "Failed to open FILE '%s' for writing at %s:%d",
120 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100121 }
122
123 va_start(va, fmt);
124
125 if (vfprintf(f, fmt, va) < 0) {
126 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800127 "Failed to print to FILE '%s' at %s:%d",
128 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100129 }
130
131 va_end(va);
132
133 if (fclose(f)) {
134 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800135 "Failed to close FILE '%s' at %s:%d",
136 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100137 }
138}
139
140//TODO: C implementation? better error condition reporting?
141void safe_cp(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800142 void (*cleanup_fn) (void), const char *src, const char *dst)
Cyril Hrubis42748952012-11-27 19:26:45 +0100143{
144 size_t len = strlen(src) + strlen(dst) + 16;
145 char buf[len];
146 int ret;
147
148 snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
149
150 ret = system(buf);
151
152 if (ret) {
153 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800154 "Failed to copy '%s' to '%s' at %s:%d",
155 src, dst, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100156 }
157}
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +0400158
159void safe_touch(const char *file, const int lineno,
160 void (*cleanup_fn)(void),
161 const char *pathname,
162 mode_t mode, const struct timespec times[2])
163{
164 int ret;
165 mode_t defmode;
166
167 defmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
168
169 ret = open(pathname, O_CREAT | O_WRONLY, defmode);
170 if (ret == -1)
171 tst_brkm(TBROK | TERRNO, cleanup_fn,
172 "Failed to open file '%s' at %s:%d",
173 pathname, file, lineno);
174
175 ret = close(ret);
176 if (ret == -1)
177 tst_brkm(TBROK | TERRNO, cleanup_fn,
178 "Failed to close file '%s' at %s:%d",
179 pathname, file, lineno);
180
181 if (mode != 0) {
182 ret = chmod(pathname, mode);
183 if (ret == -1)
184 tst_brkm(TBROK | TERRNO, cleanup_fn,
185 "Failed to chmod file '%s' at %s:%d",
186 pathname, file, lineno);
187 }
188
189 ret = utimensat(AT_FDCWD, pathname, times, 0);
190 if (ret == -1)
191 tst_brkm(TBROK | TERRNO, cleanup_fn,
192 "Failed to do utimensat() on file '%s' at %s:%d",
193 pathname, file, lineno);
194}
195