xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/ctime.c (revision a0b956f5ac5e0941f9e74e24c1c53e05ad061a38)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * CDDL HEADER START
3716fd348SMartin Matuska  *
4716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9716fd348SMartin Matuska  * or http://www.opensolaris.org/os/licensing.
10716fd348SMartin Matuska  * See the License for the specific language governing permissions
11716fd348SMartin Matuska  * and limitations under the License.
12716fd348SMartin Matuska  *
13716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska  *
19716fd348SMartin Matuska  * CDDL HEADER END
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska /*
23716fd348SMartin Matuska  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24716fd348SMartin Matuska  * Use is subject to license terms.
25716fd348SMartin Matuska  */
26716fd348SMartin Matuska 
27716fd348SMartin Matuska /*
28716fd348SMartin Matuska  * Copyright (c) 2013 by Delphix. All rights reserved.
29716fd348SMartin Matuska  */
30716fd348SMartin Matuska 
31716fd348SMartin Matuska 
32716fd348SMartin Matuska #include <sys/types.h>
33716fd348SMartin Matuska #include <sys/stat.h>
34716fd348SMartin Matuska #ifndef __FreeBSD__
35716fd348SMartin Matuska #include <sys/xattr.h>
36716fd348SMartin Matuska #endif
37716fd348SMartin Matuska #include <utime.h>
38716fd348SMartin Matuska #include <stdio.h>
39716fd348SMartin Matuska #include <stdlib.h>
40716fd348SMartin Matuska #include <unistd.h>
41716fd348SMartin Matuska #include <errno.h>
42716fd348SMartin Matuska #include <fcntl.h>
43716fd348SMartin Matuska #include <libgen.h>
44716fd348SMartin Matuska #include <string.h>
45716fd348SMartin Matuska 
46716fd348SMartin Matuska #define	ST_ATIME 0
47716fd348SMartin Matuska #define	ST_CTIME 1
48716fd348SMartin Matuska #define	ST_MTIME 2
49716fd348SMartin Matuska 
50716fd348SMartin Matuska #define	ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
51716fd348SMartin Matuska 
52716fd348SMartin Matuska typedef struct timetest {
53716fd348SMartin Matuska 	int	type;
54*a0b956f5SMartin Matuska 	const char	*name;
55716fd348SMartin Matuska 	int	(*func)(const char *pfile);
56716fd348SMartin Matuska } timetest_t;
57716fd348SMartin Matuska 
58716fd348SMartin Matuska static char tfile[BUFSIZ] = { 0 };
59716fd348SMartin Matuska 
60716fd348SMartin Matuska /*
61716fd348SMartin Matuska  * DESCRIPTION:
62716fd348SMartin Matuska  * 	Verify time will be changed correctly after each operation.
63716fd348SMartin Matuska  *
64716fd348SMartin Matuska  * STRATEGY:
65716fd348SMartin Matuska  *	1. Define time test array.
66716fd348SMartin Matuska  *	2. Loop through each item in this array.
67716fd348SMartin Matuska  *	3. Verify the time is changed after each operation.
68716fd348SMartin Matuska  *
69716fd348SMartin Matuska  */
70716fd348SMartin Matuska 
71716fd348SMartin Matuska static int
72716fd348SMartin Matuska get_file_time(const char *pfile, int what, time_t *ptr)
73716fd348SMartin Matuska {
74716fd348SMartin Matuska 	struct stat stat_buf;
75716fd348SMartin Matuska 
76716fd348SMartin Matuska 	if (pfile == NULL || ptr == NULL) {
77716fd348SMartin Matuska 		return (-1);
78716fd348SMartin Matuska 	}
79716fd348SMartin Matuska 
80716fd348SMartin Matuska 	if (stat(pfile, &stat_buf) == -1) {
81716fd348SMartin Matuska 		return (-1);
82716fd348SMartin Matuska 	}
83716fd348SMartin Matuska 
84716fd348SMartin Matuska 	switch (what) {
85716fd348SMartin Matuska 		case ST_ATIME:
86716fd348SMartin Matuska 			*ptr = stat_buf.st_atime;
87716fd348SMartin Matuska 			return (0);
88716fd348SMartin Matuska 		case ST_CTIME:
89716fd348SMartin Matuska 			*ptr = stat_buf.st_ctime;
90716fd348SMartin Matuska 			return (0);
91716fd348SMartin Matuska 		case ST_MTIME:
92716fd348SMartin Matuska 			*ptr = stat_buf.st_mtime;
93716fd348SMartin Matuska 			return (0);
94716fd348SMartin Matuska 		default:
95716fd348SMartin Matuska 			return (-1);
96716fd348SMartin Matuska 	}
97716fd348SMartin Matuska }
98716fd348SMartin Matuska 
99716fd348SMartin Matuska static ssize_t
100716fd348SMartin Matuska get_dirnamelen(const char *path)
101716fd348SMartin Matuska {
102716fd348SMartin Matuska 	const char *end = strrchr(path, '/');
103716fd348SMartin Matuska 	return (end ? end - path : -1);
104716fd348SMartin Matuska }
105716fd348SMartin Matuska 
106716fd348SMartin Matuska static int
107716fd348SMartin Matuska do_read(const char *pfile)
108716fd348SMartin Matuska {
109716fd348SMartin Matuska 	int fd, ret = 0;
110716fd348SMartin Matuska 	char buf[BUFSIZ] = { 0 };
111716fd348SMartin Matuska 
112716fd348SMartin Matuska 	if (pfile == NULL) {
113716fd348SMartin Matuska 		return (-1);
114716fd348SMartin Matuska 	}
115716fd348SMartin Matuska 
116716fd348SMartin Matuska 	if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
117716fd348SMartin Matuska 		return (-1);
118716fd348SMartin Matuska 	}
119716fd348SMartin Matuska 	if (read(fd, buf, sizeof (buf)) == -1) {
120716fd348SMartin Matuska 		(void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
121716fd348SMartin Matuska 		    "%d\n", fd, sizeof (buf), errno);
122716fd348SMartin Matuska 		(void) close(fd);
123716fd348SMartin Matuska 		return (1);
124716fd348SMartin Matuska 	}
125716fd348SMartin Matuska 	(void) close(fd);
126716fd348SMartin Matuska 
127716fd348SMartin Matuska 	return (ret);
128716fd348SMartin Matuska }
129716fd348SMartin Matuska 
130716fd348SMartin Matuska static int
131716fd348SMartin Matuska do_write(const char *pfile)
132716fd348SMartin Matuska {
133716fd348SMartin Matuska 	int fd, ret = 0;
134716fd348SMartin Matuska 	char buf[BUFSIZ] = "call function do_write()";
135716fd348SMartin Matuska 
136716fd348SMartin Matuska 	if (pfile == NULL) {
137716fd348SMartin Matuska 		return (-1);
138716fd348SMartin Matuska 	}
139716fd348SMartin Matuska 
140716fd348SMartin Matuska 	if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
141716fd348SMartin Matuska 		return (-1);
142716fd348SMartin Matuska 	}
143716fd348SMartin Matuska 	if (write(fd, buf, strlen(buf)) == -1) {
144716fd348SMartin Matuska 		(void) fprintf(stderr, "write(%d, buf, %d) failed with errno "
145716fd348SMartin Matuska 		    "%d\n", fd, (int)strlen(buf), errno);
146716fd348SMartin Matuska 		(void) close(fd);
147716fd348SMartin Matuska 		return (1);
148716fd348SMartin Matuska 	}
149716fd348SMartin Matuska 	(void) close(fd);
150716fd348SMartin Matuska 
151716fd348SMartin Matuska 	return (ret);
152716fd348SMartin Matuska }
153716fd348SMartin Matuska 
154716fd348SMartin Matuska static int
155716fd348SMartin Matuska do_link(const char *pfile)
156716fd348SMartin Matuska {
157716fd348SMartin Matuska 	int ret = 0;
158716fd348SMartin Matuska 	char link_file[BUFSIZ + 16] = { 0 };
159716fd348SMartin Matuska 
160716fd348SMartin Matuska 	if (pfile == NULL) {
161716fd348SMartin Matuska 		return (-1);
162716fd348SMartin Matuska 	}
163716fd348SMartin Matuska 
164716fd348SMartin Matuska 	/*
165716fd348SMartin Matuska 	 * Figure out source file directory name, and create
166716fd348SMartin Matuska 	 * the link file in the same directory.
167716fd348SMartin Matuska 	 */
168716fd348SMartin Matuska 	(void) snprintf(link_file, sizeof (link_file),
169716fd348SMartin Matuska 	    "%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file");
170716fd348SMartin Matuska 
171716fd348SMartin Matuska 	if (link(pfile, link_file) == -1) {
172716fd348SMartin Matuska 		(void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
173716fd348SMartin Matuska 		    pfile, link_file, errno);
174716fd348SMartin Matuska 		return (1);
175716fd348SMartin Matuska 	}
176716fd348SMartin Matuska 
177716fd348SMartin Matuska 	(void) unlink(link_file);
178716fd348SMartin Matuska 
179716fd348SMartin Matuska 	return (ret);
180716fd348SMartin Matuska }
181716fd348SMartin Matuska 
182716fd348SMartin Matuska static int
183716fd348SMartin Matuska do_creat(const char *pfile)
184716fd348SMartin Matuska {
185716fd348SMartin Matuska 	int fd, ret = 0;
186716fd348SMartin Matuska 
187716fd348SMartin Matuska 	if (pfile == NULL) {
188716fd348SMartin Matuska 		return (-1);
189716fd348SMartin Matuska 	}
190716fd348SMartin Matuska 
191716fd348SMartin Matuska 	if ((fd = creat(pfile, ALL_MODE)) == -1) {
192716fd348SMartin Matuska 		(void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
193716fd348SMartin Matuska 		    "%d\n", pfile, errno);
194716fd348SMartin Matuska 		return (1);
195716fd348SMartin Matuska 	}
196716fd348SMartin Matuska 	(void) close(fd);
197716fd348SMartin Matuska 
198716fd348SMartin Matuska 	return (ret);
199716fd348SMartin Matuska }
200716fd348SMartin Matuska 
201716fd348SMartin Matuska static int
202716fd348SMartin Matuska do_utime(const char *pfile)
203716fd348SMartin Matuska {
204716fd348SMartin Matuska 	int ret = 0;
205716fd348SMartin Matuska 
206716fd348SMartin Matuska 	if (pfile == NULL) {
207716fd348SMartin Matuska 		return (-1);
208716fd348SMartin Matuska 	}
209716fd348SMartin Matuska 
210716fd348SMartin Matuska 	/*
211716fd348SMartin Matuska 	 * Times of the file are set to the current time
212716fd348SMartin Matuska 	 */
213716fd348SMartin Matuska 	if (utime(pfile, NULL) == -1) {
214716fd348SMartin Matuska 		(void) fprintf(stderr, "utime(%s, NULL) failed with errno "
215716fd348SMartin Matuska 		    "%d\n", pfile, errno);
216716fd348SMartin Matuska 		return (1);
217716fd348SMartin Matuska 	}
218716fd348SMartin Matuska 
219716fd348SMartin Matuska 	return (ret);
220716fd348SMartin Matuska }
221716fd348SMartin Matuska 
222716fd348SMartin Matuska static int
223716fd348SMartin Matuska do_chmod(const char *pfile)
224716fd348SMartin Matuska {
225716fd348SMartin Matuska 	int ret = 0;
226716fd348SMartin Matuska 
227716fd348SMartin Matuska 	if (pfile == NULL) {
228716fd348SMartin Matuska 		return (-1);
229716fd348SMartin Matuska 	}
230716fd348SMartin Matuska 
231716fd348SMartin Matuska 	if (chmod(pfile, ALL_MODE) == -1) {
232716fd348SMartin Matuska 		(void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
233716fd348SMartin Matuska 		    "errno %d\n", pfile, errno);
234716fd348SMartin Matuska 		return (1);
235716fd348SMartin Matuska 	}
236716fd348SMartin Matuska 
237716fd348SMartin Matuska 	return (ret);
238716fd348SMartin Matuska }
239716fd348SMartin Matuska 
240716fd348SMartin Matuska static int
241716fd348SMartin Matuska do_chown(const char *pfile)
242716fd348SMartin Matuska {
243716fd348SMartin Matuska 	int ret = 0;
244716fd348SMartin Matuska 
245716fd348SMartin Matuska 	if (pfile == NULL) {
246716fd348SMartin Matuska 		return (-1);
247716fd348SMartin Matuska 	}
248716fd348SMartin Matuska 
249716fd348SMartin Matuska 	if (chown(pfile, getuid(), getgid()) == -1) {
250716fd348SMartin Matuska 		(void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
251716fd348SMartin Matuska 		    "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
252716fd348SMartin Matuska 		return (1);
253716fd348SMartin Matuska 	}
254716fd348SMartin Matuska 
255716fd348SMartin Matuska 	return (ret);
256716fd348SMartin Matuska }
257716fd348SMartin Matuska 
258716fd348SMartin Matuska #ifndef __FreeBSD__
259716fd348SMartin Matuska static int
260716fd348SMartin Matuska do_xattr(const char *pfile)
261716fd348SMartin Matuska {
262716fd348SMartin Matuska 	int ret = 0;
263*a0b956f5SMartin Matuska 	const char *value = "user.value";
264716fd348SMartin Matuska 
265716fd348SMartin Matuska 	if (pfile == NULL) {
266716fd348SMartin Matuska 		return (-1);
267716fd348SMartin Matuska 	}
268716fd348SMartin Matuska 
269716fd348SMartin Matuska 	if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {
270716fd348SMartin Matuska 		(void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "
271716fd348SMartin Matuska 		    "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
272716fd348SMartin Matuska 		return (1);
273716fd348SMartin Matuska 	}
274716fd348SMartin Matuska 	return (ret);
275716fd348SMartin Matuska }
276716fd348SMartin Matuska #endif
277716fd348SMartin Matuska 
278716fd348SMartin Matuska static void
279716fd348SMartin Matuska cleanup(void)
280716fd348SMartin Matuska {
281716fd348SMartin Matuska 	if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
282716fd348SMartin Matuska 		(void) unlink(tfile);
283716fd348SMartin Matuska 	}
284716fd348SMartin Matuska }
285716fd348SMartin Matuska 
286716fd348SMartin Matuska static timetest_t timetest_table[] = {
287716fd348SMartin Matuska 	{ ST_ATIME,	"st_atime",	do_read		},
288716fd348SMartin Matuska 	{ ST_ATIME,	"st_atime",	do_utime	},
289716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_creat	},
290716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_write	},
291716fd348SMartin Matuska 	{ ST_MTIME,	"st_mtime",	do_utime	},
292716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_creat	},
293716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_write	},
294716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_chmod	},
295716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_chown 	},
296716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_link		},
297716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_utime	},
298716fd348SMartin Matuska #ifndef __FreeBSD__
299716fd348SMartin Matuska 	{ ST_CTIME,	"st_ctime",	do_xattr	},
300716fd348SMartin Matuska #endif
301716fd348SMartin Matuska };
302716fd348SMartin Matuska 
303716fd348SMartin Matuska #define	NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
304716fd348SMartin Matuska 
305716fd348SMartin Matuska int
306716fd348SMartin Matuska main(void)
307716fd348SMartin Matuska {
308716fd348SMartin Matuska 	int i, ret, fd;
309*a0b956f5SMartin Matuska 	const char *penv[] = {"TESTDIR", "TESTFILE0"};
310716fd348SMartin Matuska 
311716fd348SMartin Matuska 	(void) atexit(cleanup);
312716fd348SMartin Matuska 
313716fd348SMartin Matuska 	/*
314716fd348SMartin Matuska 	 * Get the environment variable values.
315716fd348SMartin Matuska 	 */
316716fd348SMartin Matuska 	for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
317716fd348SMartin Matuska 		if ((penv[i] = getenv(penv[i])) == NULL) {
318716fd348SMartin Matuska 			(void) fprintf(stderr, "getenv(penv[%d])\n", i);
319716fd348SMartin Matuska 			return (1);
320716fd348SMartin Matuska 		}
321716fd348SMartin Matuska 	}
322716fd348SMartin Matuska 	(void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
323716fd348SMartin Matuska 
324716fd348SMartin Matuska 	/*
325716fd348SMartin Matuska 	 * If the test file exists, remove it first.
326716fd348SMartin Matuska 	 */
327716fd348SMartin Matuska 	if (access(tfile, F_OK) == 0) {
328716fd348SMartin Matuska 		(void) unlink(tfile);
329716fd348SMartin Matuska 	}
330716fd348SMartin Matuska 	ret = 0;
331716fd348SMartin Matuska 	if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
332716fd348SMartin Matuska 		(void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
333716fd348SMartin Matuska 		return (1);
334716fd348SMartin Matuska 	}
335716fd348SMartin Matuska 	(void) close(fd);
336716fd348SMartin Matuska 
337716fd348SMartin Matuska 	for (i = 0; i < NCOMMAND; i++) {
338716fd348SMartin Matuska 		time_t t1, t2;
339716fd348SMartin Matuska 
340716fd348SMartin Matuska 		/*
341716fd348SMartin Matuska 		 * Get original time before operating.
342716fd348SMartin Matuska 		 */
343716fd348SMartin Matuska 		ret = get_file_time(tfile, timetest_table[i].type, &t1);
344716fd348SMartin Matuska 		if (ret != 0) {
345716fd348SMartin Matuska 			(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
346716fd348SMartin Matuska 			    tfile, timetest_table[i].type, ret);
347716fd348SMartin Matuska 			return (1);
348716fd348SMartin Matuska 		}
349716fd348SMartin Matuska 
350716fd348SMartin Matuska 		/*
351716fd348SMartin Matuska 		 * Sleep 2 seconds, then invoke command on given file
352716fd348SMartin Matuska 		 */
353716fd348SMartin Matuska 		(void) sleep(2);
354716fd348SMartin Matuska 		timetest_table[i].func(tfile);
355716fd348SMartin Matuska 
356716fd348SMartin Matuska 		/*
357716fd348SMartin Matuska 		 * Get time after operating.
358716fd348SMartin Matuska 		 */
359716fd348SMartin Matuska 		ret = get_file_time(tfile, timetest_table[i].type, &t2);
360716fd348SMartin Matuska 		if (ret != 0) {
361716fd348SMartin Matuska 			(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
362716fd348SMartin Matuska 			    tfile, timetest_table[i].type, ret);
363716fd348SMartin Matuska 			return (1);
364716fd348SMartin Matuska 		}
365716fd348SMartin Matuska 
366716fd348SMartin Matuska 		if (t1 == t2) {
367716fd348SMartin Matuska 			(void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
368716fd348SMartin Matuska 			    timetest_table[i].name, (long)t1, (long)t2);
369716fd348SMartin Matuska 			return (1);
370716fd348SMartin Matuska 		} else {
371716fd348SMartin Matuska 			(void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n",
372716fd348SMartin Matuska 			    timetest_table[i].name, (long)t1, (long)t2);
373716fd348SMartin Matuska 		}
374716fd348SMartin Matuska 	}
375716fd348SMartin Matuska 
376716fd348SMartin Matuska 	return (0);
377716fd348SMartin Matuska }
378