blob: dff85cd83fec521a113aa1e9568e8f62298a3b84 [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
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +040024#include "config.h"
Cyril Hrubis42748952012-11-27 19:26:45 +010025#include <stdarg.h>
26#include <stdio.h>
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +040027#include <sys/time.h>
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +040028#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +040031#include <unistd.h>
32#include <utime.h>
Cyril Hrubis42748952012-11-27 19:26:45 +010033
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010034#include "test.h"
35#include "safe_file_ops_fn.h"
Cyril Hrubis42748952012-11-27 19:26:45 +010036
37/*
38 * Count number of expected assigned conversions. Any conversion starts with '%'.
Wei,Jiangang62d6e8b2015-05-13 19:19:42 +080039 * The '%%' matches % and no assignment is done. The %*x matches as x would do but
40 * the assignment is suppressed.
Cyril Hrubis42748952012-11-27 19:26:45 +010041 *
42 * NOTE: This is not 100% correct for complex scanf strings, but will do for
43 * all of our intended usage.
44 */
45static int count_scanf_conversions(const char *fmt)
46{
47 unsigned int cnt = 0;
48 int flag = 0;
49
50 while (*fmt) {
51 switch (*fmt) {
52 case '%':
53 if (flag) {
54 cnt--;
55 flag = 0;
56 } else {
57 flag = 1;
58 cnt++;
59 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080060 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010061 case '*':
62 if (flag) {
63 cnt--;
64 flag = 0;
65 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080066 break;
Cyril Hrubis42748952012-11-27 19:26:45 +010067 default:
68 flag = 0;
69 }
Wanlong Gao354ebb42012-12-07 10:10:04 +080070
Cyril Hrubis42748952012-11-27 19:26:45 +010071 fmt++;
72 }
73
74 return cnt;
75}
76
Li Wang8bfd7c12014-12-03 08:11:36 -050077int file_scanf(const char *file, const int lineno,
78 const char *path, const char *fmt, ...)
79{
80 va_list va;
81 FILE *f;
82 int exp_convs, ret;
83
84 f = fopen(path, "r");
85
86 if (f == NULL) {
87 tst_resm(TWARN,
88 "Failed to open FILE '%s' at %s:%d",
89 path, file, lineno);
90 return 1;
91 }
92
93 exp_convs = count_scanf_conversions(fmt);
94
95 va_start(va, fmt);
96 ret = vfscanf(f, fmt, va);
97 va_end(va);
98
99 if (ret == EOF) {
100 tst_resm(TWARN,
101 "The FILE '%s' ended prematurely at %s:%d",
102 path, file, lineno);
103 goto err;
104 }
105
106 if (ret != exp_convs) {
107 tst_resm(TWARN,
108 "Expected %i conversions got %i FILE '%s' at %s:%d",
109 exp_convs, ret, path, file, lineno);
110 goto err;
111 }
112
113 if (fclose(f)) {
114 tst_resm(TWARN,
115 "Failed to close FILE '%s' at %s:%d",
116 path, file, lineno);
117 return 1;
118 }
119
120 return 0;
121
122err:
123 if (fclose(f)) {
124 tst_resm(TWARN,
125 "Failed to close FILE '%s' at %s:%d",
126 path, file, lineno);
127 }
128 return 1;
129}
130
Cyril Hrubis42748952012-11-27 19:26:45 +0100131void safe_file_scanf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800132 void (*cleanup_fn) (void),
Cyril Hrubis42748952012-11-27 19:26:45 +0100133 const char *path, const char *fmt, ...)
134{
135 va_list va;
136 FILE *f;
137 int exp_convs, ret;
138
139 f = fopen(path, "r");
140
141 if (f == NULL) {
142 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800143 "Failed to open FILE '%s' for reading at %s:%d",
144 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100145 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800146
Cyril Hrubis42748952012-11-27 19:26:45 +0100147 exp_convs = count_scanf_conversions(fmt);
148
149 va_start(va, fmt);
150 ret = vfscanf(f, fmt, va);
151 va_end(va);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800152
Cyril Hrubis42748952012-11-27 19:26:45 +0100153 if (ret == EOF) {
154 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800155 "The FILE '%s' ended prematurely at %s:%d",
156 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100157 }
158
159 if (ret != exp_convs) {
160 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800161 "Expected %i conversions got %i FILE '%s' at %s:%d",
162 exp_convs, ret, path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100163 }
164
Li Wang8bfd7c12014-12-03 08:11:36 -0500165 if (fclose(f)) {
166 tst_brkm(TBROK | TERRNO, cleanup_fn,
167 "Failed to close FILE '%s' at %s:%d",
168 path, file, lineno);
169 }
170}
171
172int file_printf(const char *file, const int lineno,
173 const char *path, const char *fmt, ...)
174{
175 va_list va;
176 FILE *f;
177
178 f = fopen(path, "w");
179
180 if (f == NULL) {
181 tst_resm(TWARN,
182 "Failed to open FILE '%s' at %s:%d",
183 path, file, lineno);
184 return 1;
185 }
186
187 va_start(va, fmt);
188
189 if (vfprintf(f, fmt, va) < 0) {
190 tst_resm(TWARN,
191 "Failed to print to FILE '%s' at %s:%d",
192 path, file, lineno);
193 goto err;
194 }
195
196 va_end(va);
197
198 if (fclose(f)) {
199 tst_resm(TWARN,
200 "Failed to close FILE '%s' at %s:%d",
201 path, file, lineno);
202 return 1;
203 }
204
205 return 0;
206
207err:
208 if (fclose(f)) {
209 tst_resm(TWARN,
210 "Failed to close FILE '%s' at %s:%d",
211 path, file, lineno);
212 }
213 return 1;
Cyril Hrubis42748952012-11-27 19:26:45 +0100214}
215
Cyril Hrubis42748952012-11-27 19:26:45 +0100216void safe_file_printf(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800217 void (*cleanup_fn) (void),
218 const char *path, const char *fmt, ...)
Cyril Hrubis42748952012-11-27 19:26:45 +0100219{
220 va_list va;
221 FILE *f;
222
223 f = fopen(path, "w");
224
225 if (f == NULL) {
226 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800227 "Failed to open FILE '%s' for writing at %s:%d",
228 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100229 }
230
231 va_start(va, fmt);
232
233 if (vfprintf(f, fmt, va) < 0) {
234 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800235 "Failed to print to FILE '%s' at %s:%d",
236 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100237 }
238
239 va_end(va);
240
241 if (fclose(f)) {
242 tst_brkm(TBROK | TERRNO, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800243 "Failed to close FILE '%s' at %s:%d",
244 path, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100245 }
246}
247
248//TODO: C implementation? better error condition reporting?
249void safe_cp(const char *file, const int lineno,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800250 void (*cleanup_fn) (void), const char *src, const char *dst)
Cyril Hrubis42748952012-11-27 19:26:45 +0100251{
252 size_t len = strlen(src) + strlen(dst) + 16;
253 char buf[len];
254 int ret;
255
256 snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
257
258 ret = system(buf);
259
260 if (ret) {
261 tst_brkm(TBROK, cleanup_fn,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800262 "Failed to copy '%s' to '%s' at %s:%d",
263 src, dst, file, lineno);
Cyril Hrubis42748952012-11-27 19:26:45 +0100264 }
265}
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +0400266
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +0400267#ifndef HAVE_UTIMENSAT
268
Mike Frysinger4fd26382014-01-13 18:02:29 -0500269static void set_time(struct timeval *res, const struct timespec *src,
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +0400270 long cur_tv_sec, long cur_tv_usec)
271{
272 switch (src->tv_nsec) {
273 case UTIME_NOW:
274 break;
275 case UTIME_OMIT:
276 res->tv_sec = cur_tv_sec;
277 res->tv_usec = cur_tv_usec;
278 break;
279 default:
280 res->tv_sec = src->tv_sec;
281 res->tv_usec = src->tv_nsec / 1000;
282 }
283}
284
285#endif
286
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +0400287void safe_touch(const char *file, const int lineno,
288 void (*cleanup_fn)(void),
289 const char *pathname,
290 mode_t mode, const struct timespec times[2])
291{
292 int ret;
293 mode_t defmode;
294
295 defmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
296
297 ret = open(pathname, O_CREAT | O_WRONLY, defmode);
298 if (ret == -1)
299 tst_brkm(TBROK | TERRNO, cleanup_fn,
300 "Failed to open file '%s' at %s:%d",
301 pathname, file, lineno);
302
303 ret = close(ret);
304 if (ret == -1)
305 tst_brkm(TBROK | TERRNO, cleanup_fn,
306 "Failed to close file '%s' at %s:%d",
307 pathname, file, lineno);
308
309 if (mode != 0) {
310 ret = chmod(pathname, mode);
311 if (ret == -1)
312 tst_brkm(TBROK | TERRNO, cleanup_fn,
313 "Failed to chmod file '%s' at %s:%d",
314 pathname, file, lineno);
315 }
316
Stanislav Kholmanskikhabf28b22013-11-06 12:23:06 +0400317
Mike Frysinger4fd26382014-01-13 18:02:29 -0500318#ifdef HAVE_UTIMENSAT
Stanislav Kholmanskikh19b69d52013-12-04 16:16:28 +0400319 ret = utimensat(AT_FDCWD, pathname, times, 0);
320#else
321 if (times == NULL) {
322 ret = utimes(pathname, NULL);
323 } else {
324 struct stat sb;
325 struct timeval cotimes[2];
326
327 ret = stat(pathname, &sb);
328 if (ret == -1)
329 tst_brkm(TBROK | TERRNO, cleanup_fn,
330 "Failed to stat file '%s' at %s:%d",
331 pathname, file, lineno);
332
333 ret = gettimeofday(cotimes, NULL);
334 if (ret == -1)
335 tst_brkm(TBROK | TERRNO, cleanup_fn,
336 "Failed to gettimeofday() at %s:%d",
337 file, lineno);
338 cotimes[1] = cotimes[0];
339
340 set_time(cotimes, times,
341 sb.st_atime, sb.st_atim.tv_nsec / 1000);
342 set_time(cotimes + 1, times + 1,
343 sb.st_mtime, sb.st_mtim.tv_nsec / 1000);
344
345 ret = utimes(pathname, cotimes);
346 }
347#endif
348 if (ret == -1) {
349 tst_brkm(TBROK | TERRNO, cleanup_fn,
350 "Failed to update the access/modification time on file"
351 " '%s' at %s:%d", pathname, file, lineno);
352 }
353}