Fix readonly check for vdev user properties
[zfs.git] / tests / zfs-tests / cmd / ctime.c
blob5ff1cea8a869842c300144814fd18d9d59743084
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
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 <errno.h>
42 #include <fcntl.h>
43 #include <libgen.h>
44 #include <string.h>
46 #define ST_ATIME 0
47 #define ST_CTIME 1
48 #define ST_MTIME 2
50 #define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
52 typedef struct timetest {
53 int type;
54 const char *name;
55 int (*func)(const char *pfile);
56 } timetest_t;
58 static char tfile[BUFSIZ] = { 0 };
61 * DESCRIPTION:
62 * Verify time will be changed correctly after each operation.
64 * STRATEGY:
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.
71 static int
72 get_file_time(const char *pfile, int what, time_t *ptr)
74 struct stat stat_buf;
76 if (pfile == NULL || ptr == NULL) {
77 return (-1);
80 if (stat(pfile, &stat_buf) == -1) {
81 return (-1);
84 switch (what) {
85 case ST_ATIME:
86 *ptr = stat_buf.st_atime;
87 return (0);
88 case ST_CTIME:
89 *ptr = stat_buf.st_ctime;
90 return (0);
91 case ST_MTIME:
92 *ptr = stat_buf.st_mtime;
93 return (0);
94 default:
95 return (-1);
99 static ssize_t
100 get_dirnamelen(const char *path)
102 const char *end = strrchr(path, '/');
103 return (end ? end - path : -1);
106 static int
107 do_read(const char *pfile)
109 int fd, ret = 0;
110 char buf[BUFSIZ] = { 0 };
112 if (pfile == NULL) {
113 return (-1);
116 if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
117 return (-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);
122 (void) close(fd);
123 return (1);
125 (void) close(fd);
127 return (ret);
130 static int
131 do_write(const char *pfile)
133 int fd, ret = 0;
134 char buf[BUFSIZ] = "call function do_write()";
136 if (pfile == NULL) {
137 return (-1);
140 if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
141 return (-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);
146 (void) close(fd);
147 return (1);
149 (void) close(fd);
151 return (ret);
154 static int
155 do_link(const char *pfile)
157 int ret = 0;
158 char link_file[BUFSIZ + 16] = { 0 };
160 if (pfile == NULL) {
161 return (-1);
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);
174 return (1);
177 (void) unlink(link_file);
179 return (ret);
182 static int
183 do_creat(const char *pfile)
185 int fd, ret = 0;
187 if (pfile == NULL) {
188 return (-1);
191 if ((fd = creat(pfile, ALL_MODE)) == -1) {
192 (void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
193 "%d\n", pfile, errno);
194 return (1);
196 (void) close(fd);
198 return (ret);
201 static int
202 do_utime(const char *pfile)
204 int ret = 0;
206 if (pfile == NULL) {
207 return (-1);
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);
216 return (1);
219 return (ret);
222 static int
223 do_chmod(const char *pfile)
225 int ret = 0;
227 if (pfile == NULL) {
228 return (-1);
231 if (chmod(pfile, ALL_MODE) == -1) {
232 (void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
233 "errno %d\n", pfile, errno);
234 return (1);
237 return (ret);
240 static int
241 do_chown(const char *pfile)
243 int ret = 0;
245 if (pfile == NULL) {
246 return (-1);
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);
252 return (1);
255 return (ret);
258 #ifndef __FreeBSD__
259 static int
260 do_xattr(const char *pfile)
262 int ret = 0;
263 const char *value = "user.value";
265 if (pfile == NULL) {
266 return (-1);
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);
272 return (1);
274 return (ret);
276 #endif
278 static void
279 cleanup(void)
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 },
298 #ifndef __FreeBSD__
299 { ST_CTIME, "st_ctime", do_xattr },
300 #endif
303 #define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
306 main(void)
308 int i, ret, fd;
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);
319 return (1);
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);
332 return (1);
334 (void) close(fd);
336 for (i = 0; i < NCOMMAND; i++) {
337 time_t t1, t2;
340 * Get original time before operating.
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);
350 * Sleep 2 seconds, then invoke command on given file
352 (void) sleep(2);
353 timetest_table[i].func(tfile);
356 * Get time after operating.
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);
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);
375 return (1);
376 } else {
377 (void) fprintf(stderr,
378 "%s: good time change: t1(%ld), t2(%ld)\n",
379 timetest_table[i].name, (long)t1, (long)t2);
383 return (0);