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