xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/ctime.c (revision 716fd348e01c5f2ba125f878a634a753436c2994)
1*716fd348SMartin Matuska /*
2*716fd348SMartin Matuska  * CDDL HEADER START
3*716fd348SMartin Matuska  *
4*716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5*716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6*716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7*716fd348SMartin Matuska  *
8*716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*716fd348SMartin Matuska  * or http://www.opensolaris.org/os/licensing.
10*716fd348SMartin Matuska  * See the License for the specific language governing permissions
11*716fd348SMartin Matuska  * and limitations under the License.
12*716fd348SMartin Matuska  *
13*716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14*716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16*716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17*716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18*716fd348SMartin Matuska  *
19*716fd348SMartin Matuska  * CDDL HEADER END
20*716fd348SMartin Matuska  */
21*716fd348SMartin Matuska 
22*716fd348SMartin Matuska /*
23*716fd348SMartin Matuska  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*716fd348SMartin Matuska  * Use is subject to license terms.
25*716fd348SMartin Matuska  */
26*716fd348SMartin Matuska 
27*716fd348SMartin Matuska /*
28*716fd348SMartin Matuska  * Copyright (c) 2013 by Delphix. All rights reserved.
29*716fd348SMartin Matuska  */
30*716fd348SMartin Matuska 
31*716fd348SMartin Matuska 
32*716fd348SMartin Matuska #include <sys/types.h>
33*716fd348SMartin Matuska #include <sys/stat.h>
34*716fd348SMartin Matuska #ifndef __FreeBSD__
35*716fd348SMartin Matuska #include <sys/xattr.h>
36*716fd348SMartin Matuska #endif
37*716fd348SMartin Matuska #include <utime.h>
38*716fd348SMartin Matuska #include <stdio.h>
39*716fd348SMartin Matuska #include <stdlib.h>
40*716fd348SMartin Matuska #include <unistd.h>
41*716fd348SMartin Matuska #include <errno.h>
42*716fd348SMartin Matuska #include <fcntl.h>
43*716fd348SMartin Matuska #include <libgen.h>
44*716fd348SMartin Matuska #include <string.h>
45*716fd348SMartin Matuska 
46*716fd348SMartin Matuska #define	ST_ATIME 0
47*716fd348SMartin Matuska #define	ST_CTIME 1
48*716fd348SMartin Matuska #define	ST_MTIME 2
49*716fd348SMartin Matuska 
50*716fd348SMartin Matuska #define	ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
51*716fd348SMartin Matuska 
52*716fd348SMartin Matuska typedef struct timetest {
53*716fd348SMartin Matuska 	int	type;
54*716fd348SMartin Matuska 	char	*name;
55*716fd348SMartin Matuska 	int	(*func)(const char *pfile);
56*716fd348SMartin Matuska } timetest_t;
57*716fd348SMartin Matuska 
58*716fd348SMartin Matuska static char tfile[BUFSIZ] = { 0 };
59*716fd348SMartin Matuska 
60*716fd348SMartin Matuska /*
61*716fd348SMartin Matuska  * DESCRIPTION:
62*716fd348SMartin Matuska  * 	Verify time will be changed correctly after each operation.
63*716fd348SMartin Matuska  *
64*716fd348SMartin Matuska  * STRATEGY:
65*716fd348SMartin Matuska  *	1. Define time test array.
66*716fd348SMartin Matuska  *	2. Loop through each item in this array.
67*716fd348SMartin Matuska  *	3. Verify the time is changed after each operation.
68*716fd348SMartin Matuska  *
69*716fd348SMartin Matuska  */
70*716fd348SMartin Matuska 
71*716fd348SMartin Matuska static int
72*716fd348SMartin Matuska get_file_time(const char *pfile, int what, time_t *ptr)
73*716fd348SMartin Matuska {
74*716fd348SMartin Matuska 	struct stat stat_buf;
75*716fd348SMartin Matuska 
76*716fd348SMartin Matuska 	if (pfile == NULL || ptr == NULL) {
77*716fd348SMartin Matuska 		return (-1);
78*716fd348SMartin Matuska 	}
79*716fd348SMartin Matuska 
80*716fd348SMartin Matuska 	if (stat(pfile, &stat_buf) == -1) {
81*716fd348SMartin Matuska 		return (-1);
82*716fd348SMartin Matuska 	}
83*716fd348SMartin Matuska 
84*716fd348SMartin Matuska 	switch (what) {
85*716fd348SMartin Matuska 		case ST_ATIME:
86*716fd348SMartin Matuska 			*ptr = stat_buf.st_atime;
87*716fd348SMartin Matuska 			return (0);
88*716fd348SMartin Matuska 		case ST_CTIME:
89*716fd348SMartin Matuska 			*ptr = stat_buf.st_ctime;
90*716fd348SMartin Matuska 			return (0);
91*716fd348SMartin Matuska 		case ST_MTIME:
92*716fd348SMartin Matuska 			*ptr = stat_buf.st_mtime;
93*716fd348SMartin Matuska 			return (0);
94*716fd348SMartin Matuska 		default:
95*716fd348SMartin Matuska 			return (-1);
96*716fd348SMartin Matuska 	}
97*716fd348SMartin Matuska }
98*716fd348SMartin Matuska 
99*716fd348SMartin Matuska static ssize_t
100*716fd348SMartin Matuska get_dirnamelen(const char *path)
101*716fd348SMartin Matuska {
102*716fd348SMartin Matuska 	const char *end = strrchr(path, '/');
103*716fd348SMartin Matuska 	return (end ? end - path : -1);
104*716fd348SMartin Matuska }
105*716fd348SMartin Matuska 
106*716fd348SMartin Matuska static int
107*716fd348SMartin Matuska do_read(const char *pfile)
108*716fd348SMartin Matuska {
109*716fd348SMartin Matuska 	int fd, ret = 0;
110*716fd348SMartin Matuska 	char buf[BUFSIZ] = { 0 };
111*716fd348SMartin Matuska 
112*716fd348SMartin Matuska 	if (pfile == NULL) {
113*716fd348SMartin Matuska 		return (-1);
114*716fd348SMartin Matuska 	}
115*716fd348SMartin Matuska 
116*716fd348SMartin Matuska 	if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
117*716fd348SMartin Matuska 		return (-1);
118*716fd348SMartin Matuska 	}
119*716fd348SMartin Matuska 	if (read(fd, buf, sizeof (buf)) == -1) {
120*716fd348SMartin Matuska 		(void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
121*716fd348SMartin Matuska 		    "%d\n", fd, sizeof (buf), errno);
122*716fd348SMartin Matuska 		(void) close(fd);
123*716fd348SMartin Matuska 		return (1);
124*716fd348SMartin Matuska 	}
125*716fd348SMartin Matuska 	(void) close(fd);
126*716fd348SMartin Matuska 
127*716fd348SMartin Matuska 	return (ret);
128*716fd348SMartin Matuska }
129*716fd348SMartin Matuska 
130*716fd348SMartin Matuska static int
131*716fd348SMartin Matuska do_write(const char *pfile)
132*716fd348SMartin Matuska {
133*716fd348SMartin Matuska 	int fd, ret = 0;
134*716fd348SMartin Matuska 	char buf[BUFSIZ] = "call function do_write()";
135*716fd348SMartin Matuska 
136*716fd348SMartin Matuska 	if (pfile == NULL) {
137*716fd348SMartin Matuska 		return (-1);
138*716fd348SMartin Matuska 	}
139*716fd348SMartin Matuska 
140*716fd348SMartin Matuska 	if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
141*716fd348SMartin Matuska 		return (-1);
142*716fd348SMartin Matuska 	}
143*716fd348SMartin Matuska 	if (write(fd, buf, strlen(buf)) == -1) {
144*716fd348SMartin Matuska 		(void) fprintf(stderr, "write(%d, buf, %d) failed with errno "
145*716fd348SMartin Matuska 		    "%d\n", fd, (int)strlen(buf), errno);
146*716fd348SMartin Matuska 		(void) close(fd);
147*716fd348SMartin Matuska 		return (1);
148*716fd348SMartin Matuska 	}
149*716fd348SMartin Matuska 	(void) close(fd);
150*716fd348SMartin Matuska 
151*716fd348SMartin Matuska 	return (ret);
152*716fd348SMartin Matuska }
153*716fd348SMartin Matuska 
154*716fd348SMartin Matuska static int
155*716fd348SMartin Matuska do_link(const char *pfile)
156*716fd348SMartin Matuska {
157*716fd348SMartin Matuska 	int ret = 0;
158*716fd348SMartin Matuska 	char link_file[BUFSIZ + 16] = { 0 };
159*716fd348SMartin Matuska 
160*716fd348SMartin Matuska 	if (pfile == NULL) {
161*716fd348SMartin Matuska 		return (-1);
162*716fd348SMartin Matuska 	}
163*716fd348SMartin Matuska 
164*716fd348SMartin Matuska 	/*
165*716fd348SMartin Matuska 	 * Figure out source file directory name, and create
166*716fd348SMartin Matuska 	 * the link file in the same directory.
167*716fd348SMartin Matuska 	 */
168*716fd348SMartin Matuska 	(void) snprintf(link_file, sizeof (link_file),
169*716fd348SMartin Matuska 	    "%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file");
170*716fd348SMartin Matuska 
171*716fd348SMartin Matuska 	if (link(pfile, link_file) == -1) {
172*716fd348SMartin Matuska 		(void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
173*716fd348SMartin Matuska 		    pfile, link_file, errno);
174*716fd348SMartin Matuska 		return (1);
175*716fd348SMartin Matuska 	}
176*716fd348SMartin Matuska 
177*716fd348SMartin Matuska 	(void) unlink(link_file);
178*716fd348SMartin Matuska 
179*716fd348SMartin Matuska 	return (ret);
180*716fd348SMartin Matuska }
181*716fd348SMartin Matuska 
182*716fd348SMartin Matuska static int
183*716fd348SMartin Matuska do_creat(const char *pfile)
184*716fd348SMartin Matuska {
185*716fd348SMartin Matuska 	int fd, ret = 0;
186*716fd348SMartin Matuska 
187*716fd348SMartin Matuska 	if (pfile == NULL) {
188*716fd348SMartin Matuska 		return (-1);
189*716fd348SMartin Matuska 	}
190*716fd348SMartin Matuska 
191*716fd348SMartin Matuska 	if ((fd = creat(pfile, ALL_MODE)) == -1) {
192*716fd348SMartin Matuska 		(void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
193*716fd348SMartin Matuska 		    "%d\n", pfile, errno);
194*716fd348SMartin Matuska 		return (1);
195*716fd348SMartin Matuska 	}
196*716fd348SMartin Matuska 	(void) close(fd);
197*716fd348SMartin Matuska 
198*716fd348SMartin Matuska 	return (ret);
199*716fd348SMartin Matuska }
200*716fd348SMartin Matuska 
201*716fd348SMartin Matuska static int
202*716fd348SMartin Matuska do_utime(const char *pfile)
203*716fd348SMartin Matuska {
204*716fd348SMartin Matuska 	int ret = 0;
205*716fd348SMartin Matuska 
206*716fd348SMartin Matuska 	if (pfile == NULL) {
207*716fd348SMartin Matuska 		return (-1);
208*716fd348SMartin Matuska 	}
209*716fd348SMartin Matuska 
210*716fd348SMartin Matuska 	/*
211*716fd348SMartin Matuska 	 * Times of the file are set to the current time
212*716fd348SMartin Matuska 	 */
213*716fd348SMartin Matuska 	if (utime(pfile, NULL) == -1) {
214*716fd348SMartin Matuska 		(void) fprintf(stderr, "utime(%s, NULL) failed with errno "
215*716fd348SMartin Matuska 		    "%d\n", pfile, errno);
216*716fd348SMartin Matuska 		return (1);
217*716fd348SMartin Matuska 	}
218*716fd348SMartin Matuska 
219*716fd348SMartin Matuska 	return (ret);
220*716fd348SMartin Matuska }
221*716fd348SMartin Matuska 
222*716fd348SMartin Matuska static int
223*716fd348SMartin Matuska do_chmod(const char *pfile)
224*716fd348SMartin Matuska {
225*716fd348SMartin Matuska 	int ret = 0;
226*716fd348SMartin Matuska 
227*716fd348SMartin Matuska 	if (pfile == NULL) {
228*716fd348SMartin Matuska 		return (-1);
229*716fd348SMartin Matuska 	}
230*716fd348SMartin Matuska 
231*716fd348SMartin Matuska 	if (chmod(pfile, ALL_MODE) == -1) {
232*716fd348SMartin Matuska 		(void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
233*716fd348SMartin Matuska 		    "errno %d\n", pfile, errno);
234*716fd348SMartin Matuska 		return (1);
235*716fd348SMartin Matuska 	}
236*716fd348SMartin Matuska 
237*716fd348SMartin Matuska 	return (ret);
238*716fd348SMartin Matuska }
239*716fd348SMartin Matuska 
240*716fd348SMartin Matuska static int
241*716fd348SMartin Matuska do_chown(const char *pfile)
242*716fd348SMartin Matuska {
243*716fd348SMartin Matuska 	int ret = 0;
244*716fd348SMartin Matuska 
245*716fd348SMartin Matuska 	if (pfile == NULL) {
246*716fd348SMartin Matuska 		return (-1);
247*716fd348SMartin Matuska 	}
248*716fd348SMartin Matuska 
249*716fd348SMartin Matuska 	if (chown(pfile, getuid(), getgid()) == -1) {
250*716fd348SMartin Matuska 		(void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
251*716fd348SMartin Matuska 		    "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
252*716fd348SMartin Matuska 		return (1);
253*716fd348SMartin Matuska 	}
254*716fd348SMartin Matuska 
255*716fd348SMartin Matuska 	return (ret);
256*716fd348SMartin Matuska }
257*716fd348SMartin Matuska 
258*716fd348SMartin Matuska #ifndef __FreeBSD__
259*716fd348SMartin Matuska static int
260*716fd348SMartin Matuska do_xattr(const char *pfile)
261*716fd348SMartin Matuska {
262*716fd348SMartin Matuska 	int ret = 0;
263*716fd348SMartin Matuska 	char *value = "user.value";
264*716fd348SMartin Matuska 
265*716fd348SMartin Matuska 	if (pfile == NULL) {
266*716fd348SMartin Matuska 		return (-1);
267*716fd348SMartin Matuska 	}
268*716fd348SMartin Matuska 
269*716fd348SMartin Matuska 	if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {
270*716fd348SMartin Matuska 		(void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "
271*716fd348SMartin Matuska 		    "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
272*716fd348SMartin Matuska 		return (1);
273*716fd348SMartin Matuska 	}
274*716fd348SMartin Matuska 	return (ret);
275*716fd348SMartin Matuska }
276*716fd348SMartin Matuska #endif
277*716fd348SMartin Matuska 
278*716fd348SMartin Matuska static void
279*716fd348SMartin Matuska cleanup(void)
280*716fd348SMartin Matuska {
281*716fd348SMartin Matuska 	if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
282*716fd348SMartin Matuska 		(void) unlink(tfile);
283*716fd348SMartin Matuska 	}
284*716fd348SMartin Matuska }
285*716fd348SMartin Matuska 
286*716fd348SMartin Matuska static timetest_t timetest_table[] = {
287*716fd348SMartin Matuska 	{ ST_ATIME,	"st_atime",	do_read		},
288*716fd348SMartin Matuska 	{ ST_ATIME,	"st_atime",	do_utime	},
289*716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_creat	},
290*716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_write	},
291*716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_utime	},
292*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_creat	},
293*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_write	},
294*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_chmod	},
295*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_chown 	},
296*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_link		},
297*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_utime	},
298*716fd348SMartin Matuska #ifndef __FreeBSD__
299*716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_xattr	},
300*716fd348SMartin Matuska #endif
301*716fd348SMartin Matuska };
302*716fd348SMartin Matuska 
303*716fd348SMartin Matuska #define	NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
304*716fd348SMartin Matuska 
305*716fd348SMartin Matuska int
306*716fd348SMartin Matuska main(void)
307*716fd348SMartin Matuska {
308*716fd348SMartin Matuska 	int i, ret, fd;
309*716fd348SMartin Matuska 	char *penv[] = {"TESTDIR", "TESTFILE0"};
310*716fd348SMartin Matuska 
311*716fd348SMartin Matuska 	(void) atexit(cleanup);
312*716fd348SMartin Matuska 
313*716fd348SMartin Matuska 	/*
314*716fd348SMartin Matuska 	 * Get the environment variable values.
315*716fd348SMartin Matuska 	 */
316*716fd348SMartin Matuska 	for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
317*716fd348SMartin Matuska 		if ((penv[i] = getenv(penv[i])) == NULL) {
318*716fd348SMartin Matuska 			(void) fprintf(stderr, "getenv(penv[%d])\n", i);
319*716fd348SMartin Matuska 			return (1);
320*716fd348SMartin Matuska 		}
321*716fd348SMartin Matuska 	}
322*716fd348SMartin Matuska 	(void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
323*716fd348SMartin Matuska 
324*716fd348SMartin Matuska 	/*
325*716fd348SMartin Matuska 	 * If the test file exists, remove it first.
326*716fd348SMartin Matuska 	 */
327*716fd348SMartin Matuska 	if (access(tfile, F_OK) == 0) {
328*716fd348SMartin Matuska 		(void) unlink(tfile);
329*716fd348SMartin Matuska 	}
330*716fd348SMartin Matuska 	ret = 0;
331*716fd348SMartin Matuska 	if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
332*716fd348SMartin Matuska 		(void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
333*716fd348SMartin Matuska 		return (1);
334*716fd348SMartin Matuska 	}
335*716fd348SMartin Matuska 	(void) close(fd);
336*716fd348SMartin Matuska 
337*716fd348SMartin Matuska 	for (i = 0; i < NCOMMAND; i++) {
338*716fd348SMartin Matuska 		time_t t1, t2;
339*716fd348SMartin Matuska 
340*716fd348SMartin Matuska 		/*
341*716fd348SMartin Matuska 		 * Get original time before operating.
342*716fd348SMartin Matuska 		 */
343*716fd348SMartin Matuska 		ret = get_file_time(tfile, timetest_table[i].type, &t1);
344*716fd348SMartin Matuska 		if (ret != 0) {
345*716fd348SMartin Matuska 			(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
346*716fd348SMartin Matuska 			    tfile, timetest_table[i].type, ret);
347*716fd348SMartin Matuska 			return (1);
348*716fd348SMartin Matuska 		}
349*716fd348SMartin Matuska 
350*716fd348SMartin Matuska 		/*
351*716fd348SMartin Matuska 		 * Sleep 2 seconds, then invoke command on given file
352*716fd348SMartin Matuska 		 */
353*716fd348SMartin Matuska 		(void) sleep(2);
354*716fd348SMartin Matuska 		timetest_table[i].func(tfile);
355*716fd348SMartin Matuska 
356*716fd348SMartin Matuska 		/*
357*716fd348SMartin Matuska 		 * Get time after operating.
358*716fd348SMartin Matuska 		 */
359*716fd348SMartin Matuska 		ret = get_file_time(tfile, timetest_table[i].type, &t2);
360*716fd348SMartin Matuska 		if (ret != 0) {
361*716fd348SMartin Matuska 			(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
362*716fd348SMartin Matuska 			    tfile, timetest_table[i].type, ret);
363*716fd348SMartin Matuska 			return (1);
364*716fd348SMartin Matuska 		}
365*716fd348SMartin Matuska 
366*716fd348SMartin Matuska 		if (t1 == t2) {
367*716fd348SMartin Matuska 			(void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
368*716fd348SMartin Matuska 			    timetest_table[i].name, (long)t1, (long)t2);
369*716fd348SMartin Matuska 			return (1);
370*716fd348SMartin Matuska 		} else {
371*716fd348SMartin Matuska 			(void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n",
372*716fd348SMartin Matuska 			    timetest_table[i].name, (long)t1, (long)t2);
373*716fd348SMartin Matuska 		}
374*716fd348SMartin Matuska 	}
375*716fd348SMartin Matuska 
376*716fd348SMartin Matuska 	return (0);
377*716fd348SMartin Matuska }
378