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
get_file_time(const char * pfile,int what,time_t * ptr)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
do_read(const char * pfile)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
do_write(const char * pfile)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
do_link(const char * pfile)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
do_creat(const char * pfile)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
do_utime(const char * pfile)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
do_chmod(const char * pfile)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
do_chown(const char * pfile)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
cleanup(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
main(int argc,char * argv[])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