xref: /aosp_15_r20/external/ltp/lib/safe_file_ops.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker /*
2*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (C) 2012 Cyril Hrubis [email protected]
3*49cdfc7eSAndroid Build Coastguard Worker  *
4*49cdfc7eSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify it
5*49cdfc7eSAndroid Build Coastguard Worker  * under the terms of version 2 of the GNU General Public License as
6*49cdfc7eSAndroid Build Coastguard Worker  * published by the Free Software Foundation.
7*49cdfc7eSAndroid Build Coastguard Worker  *
8*49cdfc7eSAndroid Build Coastguard Worker  * This program is distributed in the hope that it would be useful, but
9*49cdfc7eSAndroid Build Coastguard Worker  * WITHOUT ANY WARRANTY; without even the implied warranty of
10*49cdfc7eSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11*49cdfc7eSAndroid Build Coastguard Worker  *
12*49cdfc7eSAndroid Build Coastguard Worker  * Further, this software is distributed without any warranty that it is
13*49cdfc7eSAndroid Build Coastguard Worker  * free of the rightful claim of any third person regarding infringement
14*49cdfc7eSAndroid Build Coastguard Worker  * or the like.  Any license provided herein, whether implied or
15*49cdfc7eSAndroid Build Coastguard Worker  * otherwise, applies only to this software file.  Patent licenses, if
16*49cdfc7eSAndroid Build Coastguard Worker  * any, provided herein do not apply to combinations of this program with
17*49cdfc7eSAndroid Build Coastguard Worker  * other software, or any other product whatsoever.
18*49cdfc7eSAndroid Build Coastguard Worker  *
19*49cdfc7eSAndroid Build Coastguard Worker  * You should have received a copy of the GNU General Public License along
20*49cdfc7eSAndroid Build Coastguard Worker  * with this program; if not, write the Free Software Foundation, Inc.,
21*49cdfc7eSAndroid Build Coastguard Worker  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22*49cdfc7eSAndroid Build Coastguard Worker  */
23*49cdfc7eSAndroid Build Coastguard Worker 
24*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
25*49cdfc7eSAndroid Build Coastguard Worker #include <stdarg.h>
26*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
27*49cdfc7eSAndroid Build Coastguard Worker #include <sys/time.h>
28*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
29*49cdfc7eSAndroid Build Coastguard Worker #include <sys/stat.h>
30*49cdfc7eSAndroid Build Coastguard Worker #include <fcntl.h>
31*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
32*49cdfc7eSAndroid Build Coastguard Worker #include <utime.h>
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker #include "test.h"
35*49cdfc7eSAndroid Build Coastguard Worker #include "safe_file_ops_fn.h"
36*49cdfc7eSAndroid Build Coastguard Worker 
tst_count_scanf_conversions(const char * fmt)37*49cdfc7eSAndroid Build Coastguard Worker int tst_count_scanf_conversions(const char *fmt)
38*49cdfc7eSAndroid Build Coastguard Worker {
39*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int cnt = 0;
40*49cdfc7eSAndroid Build Coastguard Worker 	int flag = 0;
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker 	while (*fmt) {
43*49cdfc7eSAndroid Build Coastguard Worker 		switch (*fmt) {
44*49cdfc7eSAndroid Build Coastguard Worker 		case '%':
45*49cdfc7eSAndroid Build Coastguard Worker 			if (flag) {
46*49cdfc7eSAndroid Build Coastguard Worker 				cnt--;
47*49cdfc7eSAndroid Build Coastguard Worker 				flag = 0;
48*49cdfc7eSAndroid Build Coastguard Worker 			} else {
49*49cdfc7eSAndroid Build Coastguard Worker 				flag = 1;
50*49cdfc7eSAndroid Build Coastguard Worker 				cnt++;
51*49cdfc7eSAndroid Build Coastguard Worker 			}
52*49cdfc7eSAndroid Build Coastguard Worker 			break;
53*49cdfc7eSAndroid Build Coastguard Worker 		case '*':
54*49cdfc7eSAndroid Build Coastguard Worker 			if (flag) {
55*49cdfc7eSAndroid Build Coastguard Worker 				cnt--;
56*49cdfc7eSAndroid Build Coastguard Worker 				flag = 0;
57*49cdfc7eSAndroid Build Coastguard Worker 			}
58*49cdfc7eSAndroid Build Coastguard Worker 			break;
59*49cdfc7eSAndroid Build Coastguard Worker 		default:
60*49cdfc7eSAndroid Build Coastguard Worker 			flag = 0;
61*49cdfc7eSAndroid Build Coastguard Worker 		}
62*49cdfc7eSAndroid Build Coastguard Worker 
63*49cdfc7eSAndroid Build Coastguard Worker 		fmt++;
64*49cdfc7eSAndroid Build Coastguard Worker 	}
65*49cdfc7eSAndroid Build Coastguard Worker 
66*49cdfc7eSAndroid Build Coastguard Worker 	return cnt;
67*49cdfc7eSAndroid Build Coastguard Worker }
68*49cdfc7eSAndroid Build Coastguard Worker 
file_scanf(const char * file,const int lineno,const char * path,const char * fmt,...)69*49cdfc7eSAndroid Build Coastguard Worker int file_scanf(const char *file, const int lineno,
70*49cdfc7eSAndroid Build Coastguard Worker 		     const char *path, const char *fmt, ...)
71*49cdfc7eSAndroid Build Coastguard Worker {
72*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
73*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f;
74*49cdfc7eSAndroid Build Coastguard Worker 	int exp_convs, ret;
75*49cdfc7eSAndroid Build Coastguard Worker 
76*49cdfc7eSAndroid Build Coastguard Worker 	f = fopen(path, "r");
77*49cdfc7eSAndroid Build Coastguard Worker 
78*49cdfc7eSAndroid Build Coastguard Worker 	if (f == NULL) {
79*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'",
80*49cdfc7eSAndroid Build Coastguard Worker 			path);
81*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
82*49cdfc7eSAndroid Build Coastguard Worker 	}
83*49cdfc7eSAndroid Build Coastguard Worker 
84*49cdfc7eSAndroid Build Coastguard Worker 	exp_convs = tst_count_scanf_conversions(fmt);
85*49cdfc7eSAndroid Build Coastguard Worker 
86*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
87*49cdfc7eSAndroid Build Coastguard Worker 	ret = vfscanf(f, fmt, va);
88*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == EOF) {
91*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO,
92*49cdfc7eSAndroid Build Coastguard Worker 			"The FILE '%s' ended prematurely", path);
93*49cdfc7eSAndroid Build Coastguard Worker 		goto err;
94*49cdfc7eSAndroid Build Coastguard Worker 	}
95*49cdfc7eSAndroid Build Coastguard Worker 
96*49cdfc7eSAndroid Build Coastguard Worker 	if (ret != exp_convs) {
97*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO,
98*49cdfc7eSAndroid Build Coastguard Worker 			"Expected %i conversions got %i FILE '%s'",
99*49cdfc7eSAndroid Build Coastguard Worker 			exp_convs, ret, path);
100*49cdfc7eSAndroid Build Coastguard Worker 		goto err;
101*49cdfc7eSAndroid Build Coastguard Worker 	}
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
104*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'",
105*49cdfc7eSAndroid Build Coastguard Worker 			path);
106*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
107*49cdfc7eSAndroid Build Coastguard Worker 	}
108*49cdfc7eSAndroid Build Coastguard Worker 
109*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
110*49cdfc7eSAndroid Build Coastguard Worker 
111*49cdfc7eSAndroid Build Coastguard Worker err:
112*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
113*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'",
114*49cdfc7eSAndroid Build Coastguard Worker 			path);
115*49cdfc7eSAndroid Build Coastguard Worker 	}
116*49cdfc7eSAndroid Build Coastguard Worker 
117*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
118*49cdfc7eSAndroid Build Coastguard Worker }
119*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_scanf(const char * file,const int lineno,void (* cleanup_fn)(void),const char * path,const char * fmt,...)120*49cdfc7eSAndroid Build Coastguard Worker void safe_file_scanf(const char *file, const int lineno,
121*49cdfc7eSAndroid Build Coastguard Worker 		     void (*cleanup_fn) (void),
122*49cdfc7eSAndroid Build Coastguard Worker 		     const char *path, const char *fmt, ...)
123*49cdfc7eSAndroid Build Coastguard Worker {
124*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
125*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f;
126*49cdfc7eSAndroid Build Coastguard Worker 	int exp_convs, ret;
127*49cdfc7eSAndroid Build Coastguard Worker 
128*49cdfc7eSAndroid Build Coastguard Worker 	f = fopen(path, "r");
129*49cdfc7eSAndroid Build Coastguard Worker 
130*49cdfc7eSAndroid Build Coastguard Worker 	if (f == NULL) {
131*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
132*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to open FILE '%s' for reading", path);
133*49cdfc7eSAndroid Build Coastguard Worker 		return;
134*49cdfc7eSAndroid Build Coastguard Worker 	}
135*49cdfc7eSAndroid Build Coastguard Worker 
136*49cdfc7eSAndroid Build Coastguard Worker 	exp_convs = tst_count_scanf_conversions(fmt);
137*49cdfc7eSAndroid Build Coastguard Worker 
138*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
139*49cdfc7eSAndroid Build Coastguard Worker 	ret = vfscanf(f, fmt, va);
140*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
141*49cdfc7eSAndroid Build Coastguard Worker 
142*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == EOF) {
143*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
144*49cdfc7eSAndroid Build Coastguard Worker 			"The FILE '%s' ended prematurely", path);
145*49cdfc7eSAndroid Build Coastguard Worker 		return;
146*49cdfc7eSAndroid Build Coastguard Worker 	}
147*49cdfc7eSAndroid Build Coastguard Worker 
148*49cdfc7eSAndroid Build Coastguard Worker 	if (ret != exp_convs) {
149*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
150*49cdfc7eSAndroid Build Coastguard Worker 			"Expected %i conversions got %i FILE '%s'",
151*49cdfc7eSAndroid Build Coastguard Worker 			exp_convs, ret, path);
152*49cdfc7eSAndroid Build Coastguard Worker 		return;
153*49cdfc7eSAndroid Build Coastguard Worker 	}
154*49cdfc7eSAndroid Build Coastguard Worker 
155*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
156*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
157*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to close FILE '%s'", path);
158*49cdfc7eSAndroid Build Coastguard Worker 		return;
159*49cdfc7eSAndroid Build Coastguard Worker 	}
160*49cdfc7eSAndroid Build Coastguard Worker }
161*49cdfc7eSAndroid Build Coastguard Worker 
162*49cdfc7eSAndroid Build Coastguard Worker 
163*49cdfc7eSAndroid Build Coastguard Worker /*
164*49cdfc7eSAndroid Build Coastguard Worker  * Try to parse each line from file specified by 'path' according
165*49cdfc7eSAndroid Build Coastguard Worker  * to scanf format 'fmt'. If all fields could be parsed, stop and
166*49cdfc7eSAndroid Build Coastguard Worker  * return 0, otherwise continue or return 1 if EOF is reached.
167*49cdfc7eSAndroid Build Coastguard Worker  */
file_lines_scanf(const char * file,const int lineno,void (* cleanup_fn)(void),int strict,const char * path,const char * fmt,...)168*49cdfc7eSAndroid Build Coastguard Worker int file_lines_scanf(const char *file, const int lineno,
169*49cdfc7eSAndroid Build Coastguard Worker 		     void (*cleanup_fn)(void), int strict,
170*49cdfc7eSAndroid Build Coastguard Worker 		     const char *path, const char *fmt, ...)
171*49cdfc7eSAndroid Build Coastguard Worker {
172*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fp;
173*49cdfc7eSAndroid Build Coastguard Worker 	int ret = 0;
174*49cdfc7eSAndroid Build Coastguard Worker 	int arg_count = 0;
175*49cdfc7eSAndroid Build Coastguard Worker 	char line[BUFSIZ];
176*49cdfc7eSAndroid Build Coastguard Worker 	va_list ap;
177*49cdfc7eSAndroid Build Coastguard Worker 
178*49cdfc7eSAndroid Build Coastguard Worker 	if (!fmt) {
179*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn, "pattern is NULL");
180*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
181*49cdfc7eSAndroid Build Coastguard Worker 	}
182*49cdfc7eSAndroid Build Coastguard Worker 
183*49cdfc7eSAndroid Build Coastguard Worker 	fp = fopen(path, "r");
184*49cdfc7eSAndroid Build Coastguard Worker 	if (fp == NULL) {
185*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
186*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to open FILE '%s' for reading", path);
187*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
188*49cdfc7eSAndroid Build Coastguard Worker 	}
189*49cdfc7eSAndroid Build Coastguard Worker 
190*49cdfc7eSAndroid Build Coastguard Worker 	arg_count = tst_count_scanf_conversions(fmt);
191*49cdfc7eSAndroid Build Coastguard Worker 
192*49cdfc7eSAndroid Build Coastguard Worker 	while (fgets(line, BUFSIZ, fp) != NULL) {
193*49cdfc7eSAndroid Build Coastguard Worker 		va_start(ap, fmt);
194*49cdfc7eSAndroid Build Coastguard Worker 		ret = vsscanf(line, fmt, ap);
195*49cdfc7eSAndroid Build Coastguard Worker 		va_end(ap);
196*49cdfc7eSAndroid Build Coastguard Worker 
197*49cdfc7eSAndroid Build Coastguard Worker 		if (ret == arg_count)
198*49cdfc7eSAndroid Build Coastguard Worker 			break;
199*49cdfc7eSAndroid Build Coastguard Worker 	}
200*49cdfc7eSAndroid Build Coastguard Worker 	fclose(fp);
201*49cdfc7eSAndroid Build Coastguard Worker 
202*49cdfc7eSAndroid Build Coastguard Worker 	if (strict && ret != arg_count) {
203*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
204*49cdfc7eSAndroid Build Coastguard Worker 			"Expected %i conversions got %i FILE '%s'",
205*49cdfc7eSAndroid Build Coastguard Worker 			arg_count, ret, path);
206*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
207*49cdfc7eSAndroid Build Coastguard Worker 	}
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker 	return !(ret == arg_count);
210*49cdfc7eSAndroid Build Coastguard Worker }
211*49cdfc7eSAndroid Build Coastguard Worker 
file_printf(const char * file,const int lineno,const char * path,const char * fmt,...)212*49cdfc7eSAndroid Build Coastguard Worker int file_printf(const char *file, const int lineno,
213*49cdfc7eSAndroid Build Coastguard Worker 		      const char *path, const char *fmt, ...)
214*49cdfc7eSAndroid Build Coastguard Worker {
215*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
216*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f;
217*49cdfc7eSAndroid Build Coastguard Worker 
218*49cdfc7eSAndroid Build Coastguard Worker 	f = fopen(path, "w");
219*49cdfc7eSAndroid Build Coastguard Worker 
220*49cdfc7eSAndroid Build Coastguard Worker 	if (f == NULL) {
221*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'",
222*49cdfc7eSAndroid Build Coastguard Worker 			path);
223*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
224*49cdfc7eSAndroid Build Coastguard Worker 	}
225*49cdfc7eSAndroid Build Coastguard Worker 
226*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
227*49cdfc7eSAndroid Build Coastguard Worker 
228*49cdfc7eSAndroid Build Coastguard Worker 	if (vfprintf(f, fmt, va) < 0) {
229*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to print to FILE '%s'",
230*49cdfc7eSAndroid Build Coastguard Worker 			path);
231*49cdfc7eSAndroid Build Coastguard Worker 		goto err;
232*49cdfc7eSAndroid Build Coastguard Worker 	}
233*49cdfc7eSAndroid Build Coastguard Worker 
234*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
235*49cdfc7eSAndroid Build Coastguard Worker 
236*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
237*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'",
238*49cdfc7eSAndroid Build Coastguard Worker 			path);
239*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
240*49cdfc7eSAndroid Build Coastguard Worker 	}
241*49cdfc7eSAndroid Build Coastguard Worker 
242*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
243*49cdfc7eSAndroid Build Coastguard Worker 
244*49cdfc7eSAndroid Build Coastguard Worker err:
245*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
246*49cdfc7eSAndroid Build Coastguard Worker 		tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'",
247*49cdfc7eSAndroid Build Coastguard Worker 			path);
248*49cdfc7eSAndroid Build Coastguard Worker 	}
249*49cdfc7eSAndroid Build Coastguard Worker 
250*49cdfc7eSAndroid Build Coastguard Worker 	return 1;
251*49cdfc7eSAndroid Build Coastguard Worker }
252*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_vprintf(const char * file,const int lineno,void (* cleanup_fn)(void),const char * path,const char * fmt,va_list va)253*49cdfc7eSAndroid Build Coastguard Worker static void safe_file_vprintf(const char *file, const int lineno,
254*49cdfc7eSAndroid Build Coastguard Worker 	void (*cleanup_fn)(void), const char *path, const char *fmt,
255*49cdfc7eSAndroid Build Coastguard Worker 	va_list va)
256*49cdfc7eSAndroid Build Coastguard Worker {
257*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f;
258*49cdfc7eSAndroid Build Coastguard Worker 
259*49cdfc7eSAndroid Build Coastguard Worker 	f = fopen(path, "w");
260*49cdfc7eSAndroid Build Coastguard Worker 
261*49cdfc7eSAndroid Build Coastguard Worker 	if (f == NULL) {
262*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
263*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to open FILE '%s' for writing", path);
264*49cdfc7eSAndroid Build Coastguard Worker 		return;
265*49cdfc7eSAndroid Build Coastguard Worker 	}
266*49cdfc7eSAndroid Build Coastguard Worker 
267*49cdfc7eSAndroid Build Coastguard Worker 	if (vfprintf(f, fmt, va) < 0) {
268*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
269*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to print to FILE '%s'", path);
270*49cdfc7eSAndroid Build Coastguard Worker 		return;
271*49cdfc7eSAndroid Build Coastguard Worker 	}
272*49cdfc7eSAndroid Build Coastguard Worker 
273*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f)) {
274*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
275*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to close FILE '%s'", path);
276*49cdfc7eSAndroid Build Coastguard Worker 		return;
277*49cdfc7eSAndroid Build Coastguard Worker 	}
278*49cdfc7eSAndroid Build Coastguard Worker }
279*49cdfc7eSAndroid Build Coastguard Worker 
safe_file_printf(const char * file,const int lineno,void (* cleanup_fn)(void),const char * path,const char * fmt,...)280*49cdfc7eSAndroid Build Coastguard Worker void safe_file_printf(const char *file, const int lineno,
281*49cdfc7eSAndroid Build Coastguard Worker 	void (*cleanup_fn)(void), const char *path, const char *fmt, ...)
282*49cdfc7eSAndroid Build Coastguard Worker {
283*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
284*49cdfc7eSAndroid Build Coastguard Worker 
285*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
286*49cdfc7eSAndroid Build Coastguard Worker 	safe_file_vprintf(file, lineno, cleanup_fn, path, fmt, va);
287*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
288*49cdfc7eSAndroid Build Coastguard Worker }
289*49cdfc7eSAndroid Build Coastguard Worker 
safe_try_file_printf(const char * file,const int lineno,void (* cleanup_fn)(void),const char * path,const char * fmt,...)290*49cdfc7eSAndroid Build Coastguard Worker void safe_try_file_printf(const char *file, const int lineno,
291*49cdfc7eSAndroid Build Coastguard Worker 	void (*cleanup_fn)(void), const char *path, const char *fmt, ...)
292*49cdfc7eSAndroid Build Coastguard Worker {
293*49cdfc7eSAndroid Build Coastguard Worker 	va_list va;
294*49cdfc7eSAndroid Build Coastguard Worker 
295*49cdfc7eSAndroid Build Coastguard Worker 	if (access(path, F_OK))
296*49cdfc7eSAndroid Build Coastguard Worker 		return;
297*49cdfc7eSAndroid Build Coastguard Worker 
298*49cdfc7eSAndroid Build Coastguard Worker 	va_start(va, fmt);
299*49cdfc7eSAndroid Build Coastguard Worker 	safe_file_vprintf(file, lineno, cleanup_fn, path, fmt, va);
300*49cdfc7eSAndroid Build Coastguard Worker 	va_end(va);
301*49cdfc7eSAndroid Build Coastguard Worker }
302*49cdfc7eSAndroid Build Coastguard Worker 
303*49cdfc7eSAndroid Build Coastguard Worker //TODO: C implementation? better error condition reporting?
safe_cp(const char * file,const int lineno,void (* cleanup_fn)(void),const char * src,const char * dst)304*49cdfc7eSAndroid Build Coastguard Worker int safe_cp(const char *file, const int lineno,
305*49cdfc7eSAndroid Build Coastguard Worker 	     void (*cleanup_fn) (void), const char *src, const char *dst)
306*49cdfc7eSAndroid Build Coastguard Worker {
307*49cdfc7eSAndroid Build Coastguard Worker 	size_t len = strlen(src) + strlen(dst) + 16;
308*49cdfc7eSAndroid Build Coastguard Worker 	char buf[len];
309*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
310*49cdfc7eSAndroid Build Coastguard Worker 
311*49cdfc7eSAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
312*49cdfc7eSAndroid Build Coastguard Worker 
313*49cdfc7eSAndroid Build Coastguard Worker 	ret = system(buf);
314*49cdfc7eSAndroid Build Coastguard Worker 
315*49cdfc7eSAndroid Build Coastguard Worker 	if (ret) {
316*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
317*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to copy '%s' to '%s'", src, dst);
318*49cdfc7eSAndroid Build Coastguard Worker 		return ret;
319*49cdfc7eSAndroid Build Coastguard Worker 	}
320*49cdfc7eSAndroid Build Coastguard Worker 
321*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
322*49cdfc7eSAndroid Build Coastguard Worker }
323*49cdfc7eSAndroid Build Coastguard Worker 
324*49cdfc7eSAndroid Build Coastguard Worker #ifndef HAVE_UTIMENSAT
325*49cdfc7eSAndroid Build Coastguard Worker 
set_time(struct timeval * res,const struct timespec * src,long cur_tv_sec,long cur_tv_usec)326*49cdfc7eSAndroid Build Coastguard Worker static void set_time(struct timeval *res, const struct timespec *src,
327*49cdfc7eSAndroid Build Coastguard Worker 			long cur_tv_sec, long cur_tv_usec)
328*49cdfc7eSAndroid Build Coastguard Worker {
329*49cdfc7eSAndroid Build Coastguard Worker 	switch (src->tv_nsec) {
330*49cdfc7eSAndroid Build Coastguard Worker 	case UTIME_NOW:
331*49cdfc7eSAndroid Build Coastguard Worker 	break;
332*49cdfc7eSAndroid Build Coastguard Worker 	case UTIME_OMIT:
333*49cdfc7eSAndroid Build Coastguard Worker 		res->tv_sec = cur_tv_sec;
334*49cdfc7eSAndroid Build Coastguard Worker 		res->tv_usec = cur_tv_usec;
335*49cdfc7eSAndroid Build Coastguard Worker 	break;
336*49cdfc7eSAndroid Build Coastguard Worker 	default:
337*49cdfc7eSAndroid Build Coastguard Worker 		res->tv_sec = src->tv_sec;
338*49cdfc7eSAndroid Build Coastguard Worker 		res->tv_usec = src->tv_nsec / 1000;
339*49cdfc7eSAndroid Build Coastguard Worker 	}
340*49cdfc7eSAndroid Build Coastguard Worker }
341*49cdfc7eSAndroid Build Coastguard Worker 
342*49cdfc7eSAndroid Build Coastguard Worker #endif
343*49cdfc7eSAndroid Build Coastguard Worker 
safe_touch(const char * file,const int lineno,void (* cleanup_fn)(void),const char * pathname,mode_t mode,const struct timespec times[2])344*49cdfc7eSAndroid Build Coastguard Worker int safe_touch(const char *file, const int lineno,
345*49cdfc7eSAndroid Build Coastguard Worker 		void (*cleanup_fn)(void),
346*49cdfc7eSAndroid Build Coastguard Worker 		const char *pathname,
347*49cdfc7eSAndroid Build Coastguard Worker 		mode_t mode, const struct timespec times[2])
348*49cdfc7eSAndroid Build Coastguard Worker {
349*49cdfc7eSAndroid Build Coastguard Worker 	int ret;
350*49cdfc7eSAndroid Build Coastguard Worker 	mode_t defmode;
351*49cdfc7eSAndroid Build Coastguard Worker 
352*49cdfc7eSAndroid Build Coastguard Worker 	defmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
353*49cdfc7eSAndroid Build Coastguard Worker 
354*49cdfc7eSAndroid Build Coastguard Worker 	ret = open(pathname, O_CREAT | O_WRONLY, defmode);
355*49cdfc7eSAndroid Build Coastguard Worker 
356*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == -1) {
357*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
358*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to open file '%s'", pathname);
359*49cdfc7eSAndroid Build Coastguard Worker 		return ret;
360*49cdfc7eSAndroid Build Coastguard Worker 	} else if (ret < 0) {
361*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
362*49cdfc7eSAndroid Build Coastguard Worker 			"Invalid open(%s) return value %d", pathname, ret);
363*49cdfc7eSAndroid Build Coastguard Worker 		return ret;
364*49cdfc7eSAndroid Build Coastguard Worker 	}
365*49cdfc7eSAndroid Build Coastguard Worker 
366*49cdfc7eSAndroid Build Coastguard Worker 	ret = close(ret);
367*49cdfc7eSAndroid Build Coastguard Worker 
368*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == -1) {
369*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
370*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to close file '%s'", pathname);
371*49cdfc7eSAndroid Build Coastguard Worker 		return ret;
372*49cdfc7eSAndroid Build Coastguard Worker 	} else if (ret) {
373*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
374*49cdfc7eSAndroid Build Coastguard Worker 			"Invalid close('%s') return value %d", pathname, ret);
375*49cdfc7eSAndroid Build Coastguard Worker 		return ret;
376*49cdfc7eSAndroid Build Coastguard Worker 	}
377*49cdfc7eSAndroid Build Coastguard Worker 
378*49cdfc7eSAndroid Build Coastguard Worker 	if (mode != 0) {
379*49cdfc7eSAndroid Build Coastguard Worker 		ret = chmod(pathname, mode);
380*49cdfc7eSAndroid Build Coastguard Worker 
381*49cdfc7eSAndroid Build Coastguard Worker 		if (ret == -1) {
382*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
383*49cdfc7eSAndroid Build Coastguard Worker 				"Failed to chmod file '%s'", pathname);
384*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
385*49cdfc7eSAndroid Build Coastguard Worker 		} else if (ret) {
386*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
387*49cdfc7eSAndroid Build Coastguard Worker 				"Invalid chmod('%s') return value %d",
388*49cdfc7eSAndroid Build Coastguard Worker 				pathname, ret);
389*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
390*49cdfc7eSAndroid Build Coastguard Worker 		}
391*49cdfc7eSAndroid Build Coastguard Worker 	}
392*49cdfc7eSAndroid Build Coastguard Worker 
393*49cdfc7eSAndroid Build Coastguard Worker 
394*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_UTIMENSAT
395*49cdfc7eSAndroid Build Coastguard Worker 	ret = utimensat(AT_FDCWD, pathname, times, 0);
396*49cdfc7eSAndroid Build Coastguard Worker #else
397*49cdfc7eSAndroid Build Coastguard Worker 	if (times == NULL) {
398*49cdfc7eSAndroid Build Coastguard Worker 		ret = utimes(pathname, NULL);
399*49cdfc7eSAndroid Build Coastguard Worker 	} else {
400*49cdfc7eSAndroid Build Coastguard Worker 		struct stat sb;
401*49cdfc7eSAndroid Build Coastguard Worker 		struct timeval cotimes[2];
402*49cdfc7eSAndroid Build Coastguard Worker 
403*49cdfc7eSAndroid Build Coastguard Worker 		ret = stat(pathname, &sb);
404*49cdfc7eSAndroid Build Coastguard Worker 
405*49cdfc7eSAndroid Build Coastguard Worker 		if (ret == -1) {
406*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
407*49cdfc7eSAndroid Build Coastguard Worker 				"Failed to stat file '%s'", pathname);
408*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
409*49cdfc7eSAndroid Build Coastguard Worker 		} else if (ret) {
410*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
411*49cdfc7eSAndroid Build Coastguard Worker 				"Invalid stat('%s') return value %d",
412*49cdfc7eSAndroid Build Coastguard Worker 				pathname, ret);
413*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
414*49cdfc7eSAndroid Build Coastguard Worker 		}
415*49cdfc7eSAndroid Build Coastguard Worker 
416*49cdfc7eSAndroid Build Coastguard Worker 		ret = gettimeofday(cotimes, NULL);
417*49cdfc7eSAndroid Build Coastguard Worker 
418*49cdfc7eSAndroid Build Coastguard Worker 		if (ret == -1) {
419*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
420*49cdfc7eSAndroid Build Coastguard Worker 				"Failed to gettimeofday()");
421*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
422*49cdfc7eSAndroid Build Coastguard Worker 		} else if (ret) {
423*49cdfc7eSAndroid Build Coastguard Worker 			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
424*49cdfc7eSAndroid Build Coastguard Worker 				"Invalid gettimeofday() return value %d", ret);
425*49cdfc7eSAndroid Build Coastguard Worker 			return ret;
426*49cdfc7eSAndroid Build Coastguard Worker 		}
427*49cdfc7eSAndroid Build Coastguard Worker 
428*49cdfc7eSAndroid Build Coastguard Worker 		cotimes[1] = cotimes[0];
429*49cdfc7eSAndroid Build Coastguard Worker 
430*49cdfc7eSAndroid Build Coastguard Worker 		set_time(cotimes, times,
431*49cdfc7eSAndroid Build Coastguard Worker 			sb.st_atime, sb.st_atim.tv_nsec / 1000);
432*49cdfc7eSAndroid Build Coastguard Worker 		set_time(cotimes + 1, times + 1,
433*49cdfc7eSAndroid Build Coastguard Worker 			sb.st_mtime, sb.st_mtim.tv_nsec / 1000);
434*49cdfc7eSAndroid Build Coastguard Worker 
435*49cdfc7eSAndroid Build Coastguard Worker 		ret = utimes(pathname, cotimes);
436*49cdfc7eSAndroid Build Coastguard Worker 	}
437*49cdfc7eSAndroid Build Coastguard Worker #endif
438*49cdfc7eSAndroid Build Coastguard Worker 	if (ret == -1) {
439*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
440*49cdfc7eSAndroid Build Coastguard Worker 			"Failed to update the access/modification time on file '%s'",
441*49cdfc7eSAndroid Build Coastguard Worker 			pathname);
442*49cdfc7eSAndroid Build Coastguard Worker 	} else if (ret) {
443*49cdfc7eSAndroid Build Coastguard Worker 		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
444*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_UTIMENSAT
445*49cdfc7eSAndroid Build Coastguard Worker 			"Invalid utimensat('%s') return value %d",
446*49cdfc7eSAndroid Build Coastguard Worker #else
447*49cdfc7eSAndroid Build Coastguard Worker 			"Invalid utimes('%s') return value %d",
448*49cdfc7eSAndroid Build Coastguard Worker #endif
449*49cdfc7eSAndroid Build Coastguard Worker 			pathname, ret);
450*49cdfc7eSAndroid Build Coastguard Worker 	}
451*49cdfc7eSAndroid Build Coastguard Worker 
452*49cdfc7eSAndroid Build Coastguard Worker 	return ret;
453*49cdfc7eSAndroid Build Coastguard Worker }
454