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 9*271171e0SMartin 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 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 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 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 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 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 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 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 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 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 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 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 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 ret = 0; 331716fd348SMartin Matuska if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) { 332716fd348SMartin Matuska (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno); 333716fd348SMartin Matuska return (1); 334716fd348SMartin Matuska } 335716fd348SMartin Matuska (void) close(fd); 336716fd348SMartin Matuska 337716fd348SMartin Matuska for (i = 0; i < NCOMMAND; i++) { 338716fd348SMartin Matuska time_t t1, t2; 339716fd348SMartin Matuska 340716fd348SMartin Matuska /* 341716fd348SMartin Matuska * Get original time before operating. 342716fd348SMartin Matuska */ 343716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t1); 344716fd348SMartin Matuska if (ret != 0) { 345716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n", 346716fd348SMartin Matuska tfile, timetest_table[i].type, ret); 347716fd348SMartin Matuska return (1); 348716fd348SMartin Matuska } 349716fd348SMartin Matuska 350716fd348SMartin Matuska /* 351716fd348SMartin Matuska * Sleep 2 seconds, then invoke command on given file 352716fd348SMartin Matuska */ 353716fd348SMartin Matuska (void) sleep(2); 354716fd348SMartin Matuska timetest_table[i].func(tfile); 355716fd348SMartin Matuska 356716fd348SMartin Matuska /* 357716fd348SMartin Matuska * Get time after operating. 358716fd348SMartin Matuska */ 359716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t2); 360716fd348SMartin Matuska if (ret != 0) { 361716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n", 362716fd348SMartin Matuska tfile, timetest_table[i].type, ret); 363716fd348SMartin Matuska return (1); 364716fd348SMartin Matuska } 365716fd348SMartin Matuska 366716fd348SMartin Matuska if (t1 == t2) { 367716fd348SMartin Matuska (void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n", 368716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2); 369716fd348SMartin Matuska return (1); 370716fd348SMartin Matuska } else { 371716fd348SMartin Matuska (void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n", 372716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2); 373716fd348SMartin Matuska } 374716fd348SMartin Matuska } 375716fd348SMartin Matuska 376716fd348SMartin Matuska return (0); 377716fd348SMartin Matuska } 378