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
9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
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;
54a0b956f5SMartin 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
get_file_time(const char * pfile,int what,time_t * ptr)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
get_dirnamelen(const char * path)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
do_read(const char * pfile)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
do_write(const char * pfile)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
do_link(const char * pfile)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
do_creat(const char * pfile)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
do_utime(const char * pfile)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
do_chmod(const char * pfile)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
do_chown(const char * pfile)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
do_xattr(const char * pfile)260716fd348SMartin Matuska do_xattr(const char *pfile)
261716fd348SMartin Matuska {
262716fd348SMartin Matuska int ret = 0;
263a0b956f5SMartin 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
cleanup(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
main(void)306716fd348SMartin Matuska main(void)
307716fd348SMartin Matuska {
308716fd348SMartin Matuska int i, ret, fd;
309a0b956f5SMartin 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 if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
331716fd348SMartin Matuska (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
332716fd348SMartin Matuska return (1);
333716fd348SMartin Matuska }
334716fd348SMartin Matuska (void) close(fd);
335716fd348SMartin Matuska
336716fd348SMartin Matuska for (i = 0; i < NCOMMAND; i++) {
337716fd348SMartin Matuska time_t t1, t2;
338716fd348SMartin Matuska
339716fd348SMartin Matuska /*
340716fd348SMartin Matuska * Get original time before operating.
341716fd348SMartin Matuska */
342716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t1);
343716fd348SMartin Matuska if (ret != 0) {
344716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
345716fd348SMartin Matuska tfile, timetest_table[i].type, ret);
346716fd348SMartin Matuska return (1);
347716fd348SMartin Matuska }
348716fd348SMartin Matuska
349716fd348SMartin Matuska /*
350716fd348SMartin Matuska * Sleep 2 seconds, then invoke command on given file
351716fd348SMartin Matuska */
352716fd348SMartin Matuska (void) sleep(2);
353716fd348SMartin Matuska timetest_table[i].func(tfile);
354716fd348SMartin Matuska
355716fd348SMartin Matuska /*
356716fd348SMartin Matuska * Get time after operating.
357716fd348SMartin Matuska */
358716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t2);
359716fd348SMartin Matuska if (ret != 0) {
360716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
361716fd348SMartin Matuska tfile, timetest_table[i].type, ret);
362716fd348SMartin Matuska return (1);
363716fd348SMartin Matuska }
364716fd348SMartin Matuska
365*78ae60b4SMartin Matuska
366*78ae60b4SMartin Matuska /*
367*78ae60b4SMartin Matuska * Ideally, time change would be exactly two seconds, but allow
368*78ae60b4SMartin Matuska * a little slack in case of scheduling delays or similar.
369*78ae60b4SMartin Matuska */
370*78ae60b4SMartin Matuska long delta = (long)t2 - (long)t1;
371*78ae60b4SMartin Matuska if (delta < 2 || delta > 4) {
372*78ae60b4SMartin Matuska (void) fprintf(stderr,
373*78ae60b4SMartin Matuska "%s: BAD time change: t1(%ld), t2(%ld)\n",
374716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2);
375716fd348SMartin Matuska return (1);
376716fd348SMartin Matuska } else {
377*78ae60b4SMartin Matuska (void) fprintf(stderr,
378*78ae60b4SMartin Matuska "%s: good time change: t1(%ld), t2(%ld)\n",
379716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2);
380716fd348SMartin Matuska }
381716fd348SMartin Matuska }
382716fd348SMartin Matuska
383716fd348SMartin Matuska return (0);
384716fd348SMartin Matuska }
385