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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2013 by Delphix. All rights reserved.
32 #include <sys/types.h>
35 #include <sys/xattr.h>
50 #define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
52 typedef struct timetest
{
55 int (*func
)(const char *pfile
);
58 static char tfile
[BUFSIZ
] = { 0 };
62 * Verify time will be changed correctly after each operation.
65 * 1. Define time test array.
66 * 2. Loop through each item in this array.
67 * 3. Verify the time is changed after each operation.
72 get_file_time(const char *pfile
, int what
, time_t *ptr
)
76 if (pfile
== NULL
|| ptr
== NULL
) {
80 if (stat(pfile
, &stat_buf
) == -1) {
86 *ptr
= stat_buf
.st_atime
;
89 *ptr
= stat_buf
.st_ctime
;
92 *ptr
= stat_buf
.st_mtime
;
100 get_dirnamelen(const char *path
)
102 const char *end
= strrchr(path
, '/');
103 return (end
? end
- path
: -1);
107 do_read(const char *pfile
)
110 char buf
[BUFSIZ
] = { 0 };
116 if ((fd
= open(pfile
, O_RDONLY
, ALL_MODE
)) == -1) {
119 if (read(fd
, buf
, sizeof (buf
)) == -1) {
120 (void) fprintf(stderr
, "read(%d, buf, %zd) failed with errno "
121 "%d\n", fd
, sizeof (buf
), errno
);
131 do_write(const char *pfile
)
134 char buf
[BUFSIZ
] = "call function do_write()";
140 if ((fd
= open(pfile
, O_WRONLY
, ALL_MODE
)) == -1) {
143 if (write(fd
, buf
, strlen(buf
)) == -1) {
144 (void) fprintf(stderr
, "write(%d, buf, %d) failed with errno "
145 "%d\n", fd
, (int)strlen(buf
), errno
);
155 do_link(const char *pfile
)
158 char link_file
[BUFSIZ
+ 16] = { 0 };
165 * Figure out source file directory name, and create
166 * the link file in the same directory.
168 (void) snprintf(link_file
, sizeof (link_file
),
169 "%.*s/%s", (int)get_dirnamelen(pfile
), pfile
, "link_file");
171 if (link(pfile
, link_file
) == -1) {
172 (void) fprintf(stderr
, "link(%s, %s) failed with errno %d\n",
173 pfile
, link_file
, errno
);
177 (void) unlink(link_file
);
183 do_creat(const char *pfile
)
191 if ((fd
= creat(pfile
, ALL_MODE
)) == -1) {
192 (void) fprintf(stderr
, "creat(%s, ALL_MODE) failed with errno "
193 "%d\n", pfile
, errno
);
202 do_utime(const char *pfile
)
211 * Times of the file are set to the current time
213 if (utime(pfile
, NULL
) == -1) {
214 (void) fprintf(stderr
, "utime(%s, NULL) failed with errno "
215 "%d\n", pfile
, errno
);
223 do_chmod(const char *pfile
)
231 if (chmod(pfile
, ALL_MODE
) == -1) {
232 (void) fprintf(stderr
, "chmod(%s, ALL_MODE) failed with "
233 "errno %d\n", pfile
, errno
);
241 do_chown(const char *pfile
)
249 if (chown(pfile
, getuid(), getgid()) == -1) {
250 (void) fprintf(stderr
, "chown(%s, %d, %d) failed with errno "
251 "%d\n", pfile
, (int)getuid(), (int)getgid(), errno
);
260 do_xattr(const char *pfile
)
263 const char *value
= "user.value";
269 if (setxattr(pfile
, "user.x", value
, strlen(value
), 0) == -1) {
270 (void) fprintf(stderr
, "setxattr(%s, %d, %d) failed with errno "
271 "%d\n", pfile
, (int)getuid(), (int)getgid(), errno
);
281 if ((strlen(tfile
) != 0) && (access(tfile
, F_OK
) == 0)) {
282 (void) unlink(tfile
);
286 static timetest_t timetest_table
[] = {
287 { ST_ATIME
, "st_atime", do_read
},
288 { ST_ATIME
, "st_atime", do_utime
},
289 { ST_MTIME
, "st_mtime", do_creat
},
290 { ST_MTIME
, "st_mtime", do_write
},
291 { ST_MTIME
, "st_mtime", do_utime
},
292 { ST_CTIME
, "st_ctime", do_creat
},
293 { ST_CTIME
, "st_ctime", do_write
},
294 { ST_CTIME
, "st_ctime", do_chmod
},
295 { ST_CTIME
, "st_ctime", do_chown
},
296 { ST_CTIME
, "st_ctime", do_link
},
297 { ST_CTIME
, "st_ctime", do_utime
},
299 { ST_CTIME
, "st_ctime", do_xattr
},
303 #define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
309 const char *penv
[] = {"TESTDIR", "TESTFILE0"};
311 (void) atexit(cleanup
);
314 * Get the environment variable values.
316 for (i
= 0; i
< sizeof (penv
) / sizeof (char *); i
++) {
317 if ((penv
[i
] = getenv(penv
[i
])) == NULL
) {
318 (void) fprintf(stderr
, "getenv(penv[%d])\n", i
);
322 (void) snprintf(tfile
, sizeof (tfile
), "%s/%s", penv
[0], penv
[1]);
325 * If the test file exists, remove it first.
327 if (access(tfile
, F_OK
) == 0) {
328 (void) unlink(tfile
);
330 if ((fd
= open(tfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, ALL_MODE
)) == -1) {
331 (void) fprintf(stderr
, "open(%s) failed: %d\n", tfile
, errno
);
336 for (i
= 0; i
< NCOMMAND
; i
++) {
340 * Get original time before operating.
342 ret
= get_file_time(tfile
, timetest_table
[i
].type
, &t1
);
344 (void) fprintf(stderr
, "get_file_time(%s %d) = %d\n",
345 tfile
, timetest_table
[i
].type
, ret
);
350 * Sleep 2 seconds, then invoke command on given file
353 timetest_table
[i
].func(tfile
);
356 * Get time after operating.
358 ret
= get_file_time(tfile
, timetest_table
[i
].type
, &t2
);
360 (void) fprintf(stderr
, "get_file_time(%s %d) = %d\n",
361 tfile
, timetest_table
[i
].type
, ret
);
367 * Ideally, time change would be exactly two seconds, but allow
368 * a little slack in case of scheduling delays or similar.
370 long delta
= (long)t2
- (long)t1
;
371 if (delta
< 2 || delta
> 4) {
372 (void) fprintf(stderr
,
373 "%s: BAD time change: t1(%ld), t2(%ld)\n",
374 timetest_table
[i
].name
, (long)t1
, (long)t2
);
377 (void) fprintf(stderr
,
378 "%s: good time change: t1(%ld), t2(%ld)\n",
379 timetest_table
[i
].name
, (long)t1
, (long)t2
);