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 #include <sys/types.h>
33 #include <sys/stat.h>
34 #ifndef __FreeBSD__
35 #include <sys/xattr.h>
36 #endif
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 #include <string.h>
46
47 #define ST_ATIME 0
48 #define ST_CTIME 1
49 #define ST_MTIME 2
50
51 #define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
52
53 typedef struct timetest {
54 int type;
55 char *name;
56 int (*func)(const char *pfile);
57 } timetest_t;
58
59 static char tfile[BUFSIZ] = { 0 };
60
61 /*
62 * DESCRIPTION:
63 * Verify time will be changed correctly after each operation.
64 *
65 * STRATEGY:
66 * 1. Define time test array.
67 * 2. Loop through each item in this array.
68 * 3. Verify the time is changed after each operation.
69 *
70 */
71
72 static int
get_file_time(const char * pfile,int what,time_t * ptr)73 get_file_time(const char *pfile, int what, time_t *ptr)
74 {
75 struct stat stat_buf;
76
77 if (pfile == NULL || ptr == NULL) {
78 return (-1);
79 }
80
81 if (stat(pfile, &stat_buf) == -1) {
82 return (-1);
83 }
84
85 switch (what) {
86 case ST_ATIME:
87 *ptr = stat_buf.st_atime;
88 return (0);
89 case ST_CTIME:
90 *ptr = stat_buf.st_ctime;
91 return (0);
92 case ST_MTIME:
93 *ptr = stat_buf.st_mtime;
94 return (0);
95 default:
96 return (-1);
97 }
98 }
99
100 static int
do_read(const char * pfile)101 do_read(const char *pfile)
102 {
103 int fd, ret = 0;
104 char buf[BUFSIZ] = { 0 };
105
106 if (pfile == NULL) {
107 return (-1);
108 }
109
110 if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
111 return (-1);
112 }
113 if (read(fd, buf, sizeof (buf)) == -1) {
114 (void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
115 "%d\n", fd, sizeof (buf), errno);
116 (void) close(fd);
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, (int)strlen(buf), errno);
140 (void) close(fd);
141 return (1);
142 }
143 (void) close(fd);
144
145 return (ret);
146 }
147
148 static int
do_link(const char * pfile)149 do_link(const char *pfile)
150 {
151 int ret = 0;
152 char link_file[BUFSIZ] = { 0 };
153 char pfile_copy[BUFSIZ] = { 0 };
154 char *dname;
155
156 if (pfile == NULL) {
157 return (-1);
158 }
159
160 strncpy(pfile_copy, pfile, sizeof (pfile_copy)-1);
161 pfile_copy[sizeof (pfile_copy) - 1] = '\0';
162 /*
163 * Figure out source file directory name, and create
164 * the link file in the same directory.
165 */
166 dname = dirname((char *)pfile_copy);
167 (void) snprintf(link_file, BUFSIZ, "%s/%s", dname, "link_file");
168
169 if (link(pfile, link_file) == -1) {
170 (void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
171 pfile, link_file, errno);
172 return (1);
173 }
174
175 (void) unlink(link_file);
176
177 return (ret);
178 }
179
180 static int
do_creat(const char * pfile)181 do_creat(const char *pfile)
182 {
183 int fd, ret = 0;
184
185 if (pfile == NULL) {
186 return (-1);
187 }
188
189 if ((fd = creat(pfile, ALL_MODE)) == -1) {
190 (void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
191 "%d\n", pfile, errno);
192 return (1);
193 }
194 (void) close(fd);
195
196 return (ret);
197 }
198
199 static int
do_utime(const char * pfile)200 do_utime(const char *pfile)
201 {
202 int ret = 0;
203
204 if (pfile == NULL) {
205 return (-1);
206 }
207
208 /*
209 * Times of the file are set to the current time
210 */
211 if (utime(pfile, NULL) == -1) {
212 (void) fprintf(stderr, "utime(%s, NULL) failed with errno "
213 "%d\n", pfile, errno);
214 return (1);
215 }
216
217 return (ret);
218 }
219
220 static int
do_chmod(const char * pfile)221 do_chmod(const char *pfile)
222 {
223 int ret = 0;
224
225 if (pfile == NULL) {
226 return (-1);
227 }
228
229 if (chmod(pfile, ALL_MODE) == -1) {
230 (void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
231 "errno %d\n", pfile, errno);
232 return (1);
233 }
234
235 return (ret);
236 }
237
238 static int
do_chown(const char * pfile)239 do_chown(const char *pfile)
240 {
241 int ret = 0;
242
243 if (pfile == NULL) {
244 return (-1);
245 }
246
247 if (chown(pfile, getuid(), getgid()) == -1) {
248 (void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
249 "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
250 return (1);
251 }
252
253 return (ret);
254 }
255
256 #ifndef __FreeBSD__
257 static int
do_xattr(const char * pfile)258 do_xattr(const char *pfile)
259 {
260 int ret = 0;
261 char *value = "user.value";
262
263 if (pfile == NULL) {
264 return (-1);
265 }
266
267 if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {
268 (void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "
269 "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
270 return (1);
271 }
272 return (ret);
273 }
274 #endif
275
276 static void
cleanup(void)277 cleanup(void)
278 {
279 if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
280 (void) unlink(tfile);
281 }
282 }
283
284 static timetest_t timetest_table[] = {
285 { ST_ATIME, "st_atime", do_read },
286 { ST_ATIME, "st_atime", do_utime },
287 { ST_MTIME, "st_mtime", do_creat },
288 { ST_MTIME, "st_mtime", do_write },
289 { ST_MTIME, "st_mtime", do_utime },
290 { ST_CTIME, "st_ctime", do_creat },
291 { ST_CTIME, "st_ctime", do_write },
292 { ST_CTIME, "st_ctime", do_chmod },
293 { ST_CTIME, "st_ctime", do_chown },
294 { ST_CTIME, "st_ctime", do_link },
295 { ST_CTIME, "st_ctime", do_utime },
296 #ifndef __FreeBSD__
297 { ST_CTIME, "st_ctime", do_xattr },
298 #endif
299 };
300
301 #define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
302
303 /* ARGSUSED */
304 int
main(int argc,char * argv[])305 main(int argc, char *argv[])
306 {
307 int i, ret, fd;
308 char *penv[] = {"TESTDIR", "TESTFILE0"};
309
310 (void) atexit(cleanup);
311
312 /*
313 * Get the environment variable values.
314 */
315 for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
316 if ((penv[i] = getenv(penv[i])) == NULL) {
317 (void) fprintf(stderr, "getenv(penv[%d])\n", i);
318 return (1);
319 }
320 }
321 (void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
322
323 /*
324 * If the test file is exists, remove it first.
325 */
326 if (access(tfile, F_OK) == 0) {
327 (void) unlink(tfile);
328 }
329 ret = 0;
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);
332 return (1);
333 }
334 (void) close(fd);
335
336 for (i = 0; i < NCOMMAND; i++) {
337 time_t t1, t2;
338
339 /*
340 * Get original time before operating.
341 */
342 ret = get_file_time(tfile, timetest_table[i].type, &t1);
343 if (ret != 0) {
344 (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
345 tfile, timetest_table[i].type, ret);
346 return (1);
347 }
348
349 /*
350 * Sleep 2 seconds, then invoke command on given file
351 */
352 (void) sleep(2);
353 timetest_table[i].func(tfile);
354
355 /*
356 * Get time after operating.
357 */
358 ret = get_file_time(tfile, timetest_table[i].type, &t2);
359 if (ret != 0) {
360 (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
361 tfile, timetest_table[i].type, ret);
362 return (1);
363 }
364
365 if (t1 == t2) {
366 (void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
367 timetest_table[i].name, (long)t1, (long)t2);
368 return (1);
369 } else {
370 (void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n",
371 timetest_table[i].name, (long)t1, (long)t2);
372 }
373 }
374
375 return (0);
376 }
377