1*716fd348SMartin Matuska /* 2*716fd348SMartin Matuska * CDDL HEADER START 3*716fd348SMartin Matuska * 4*716fd348SMartin Matuska * The contents of this file are subject to the terms of the 5*716fd348SMartin Matuska * Common Development and Distribution License (the "License"). 6*716fd348SMartin Matuska * You may not use this file except in compliance with the License. 7*716fd348SMartin Matuska * 8*716fd348SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*716fd348SMartin Matuska * or http://www.opensolaris.org/os/licensing. 10*716fd348SMartin Matuska * See the License for the specific language governing permissions 11*716fd348SMartin Matuska * and limitations under the License. 12*716fd348SMartin Matuska * 13*716fd348SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 14*716fd348SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*716fd348SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 16*716fd348SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 17*716fd348SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 18*716fd348SMartin Matuska * 19*716fd348SMartin Matuska * CDDL HEADER END 20*716fd348SMartin Matuska */ 21*716fd348SMartin Matuska 22*716fd348SMartin Matuska /* 23*716fd348SMartin Matuska * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*716fd348SMartin Matuska * Use is subject to license terms. 25*716fd348SMartin Matuska */ 26*716fd348SMartin Matuska 27*716fd348SMartin Matuska /* 28*716fd348SMartin Matuska * Copyright (c) 2013 by Delphix. All rights reserved. 29*716fd348SMartin Matuska */ 30*716fd348SMartin Matuska 31*716fd348SMartin Matuska 32*716fd348SMartin Matuska #include <sys/types.h> 33*716fd348SMartin Matuska #include <sys/stat.h> 34*716fd348SMartin Matuska #ifndef __FreeBSD__ 35*716fd348SMartin Matuska #include <sys/xattr.h> 36*716fd348SMartin Matuska #endif 37*716fd348SMartin Matuska #include <utime.h> 38*716fd348SMartin Matuska #include <stdio.h> 39*716fd348SMartin Matuska #include <stdlib.h> 40*716fd348SMartin Matuska #include <unistd.h> 41*716fd348SMartin Matuska #include <errno.h> 42*716fd348SMartin Matuska #include <fcntl.h> 43*716fd348SMartin Matuska #include <libgen.h> 44*716fd348SMartin Matuska #include <string.h> 45*716fd348SMartin Matuska 46*716fd348SMartin Matuska #define ST_ATIME 0 47*716fd348SMartin Matuska #define ST_CTIME 1 48*716fd348SMartin Matuska #define ST_MTIME 2 49*716fd348SMartin Matuska 50*716fd348SMartin Matuska #define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO) 51*716fd348SMartin Matuska 52*716fd348SMartin Matuska typedef struct timetest { 53*716fd348SMartin Matuska int type; 54*716fd348SMartin Matuska char *name; 55*716fd348SMartin Matuska int (*func)(const char *pfile); 56*716fd348SMartin Matuska } timetest_t; 57*716fd348SMartin Matuska 58*716fd348SMartin Matuska static char tfile[BUFSIZ] = { 0 }; 59*716fd348SMartin Matuska 60*716fd348SMartin Matuska /* 61*716fd348SMartin Matuska * DESCRIPTION: 62*716fd348SMartin Matuska * Verify time will be changed correctly after each operation. 63*716fd348SMartin Matuska * 64*716fd348SMartin Matuska * STRATEGY: 65*716fd348SMartin Matuska * 1. Define time test array. 66*716fd348SMartin Matuska * 2. Loop through each item in this array. 67*716fd348SMartin Matuska * 3. Verify the time is changed after each operation. 68*716fd348SMartin Matuska * 69*716fd348SMartin Matuska */ 70*716fd348SMartin Matuska 71*716fd348SMartin Matuska static int 72*716fd348SMartin Matuska get_file_time(const char *pfile, int what, time_t *ptr) 73*716fd348SMartin Matuska { 74*716fd348SMartin Matuska struct stat stat_buf; 75*716fd348SMartin Matuska 76*716fd348SMartin Matuska if (pfile == NULL || ptr == NULL) { 77*716fd348SMartin Matuska return (-1); 78*716fd348SMartin Matuska } 79*716fd348SMartin Matuska 80*716fd348SMartin Matuska if (stat(pfile, &stat_buf) == -1) { 81*716fd348SMartin Matuska return (-1); 82*716fd348SMartin Matuska } 83*716fd348SMartin Matuska 84*716fd348SMartin Matuska switch (what) { 85*716fd348SMartin Matuska case ST_ATIME: 86*716fd348SMartin Matuska *ptr = stat_buf.st_atime; 87*716fd348SMartin Matuska return (0); 88*716fd348SMartin Matuska case ST_CTIME: 89*716fd348SMartin Matuska *ptr = stat_buf.st_ctime; 90*716fd348SMartin Matuska return (0); 91*716fd348SMartin Matuska case ST_MTIME: 92*716fd348SMartin Matuska *ptr = stat_buf.st_mtime; 93*716fd348SMartin Matuska return (0); 94*716fd348SMartin Matuska default: 95*716fd348SMartin Matuska return (-1); 96*716fd348SMartin Matuska } 97*716fd348SMartin Matuska } 98*716fd348SMartin Matuska 99*716fd348SMartin Matuska static ssize_t 100*716fd348SMartin Matuska get_dirnamelen(const char *path) 101*716fd348SMartin Matuska { 102*716fd348SMartin Matuska const char *end = strrchr(path, '/'); 103*716fd348SMartin Matuska return (end ? end - path : -1); 104*716fd348SMartin Matuska } 105*716fd348SMartin Matuska 106*716fd348SMartin Matuska static int 107*716fd348SMartin Matuska do_read(const char *pfile) 108*716fd348SMartin Matuska { 109*716fd348SMartin Matuska int fd, ret = 0; 110*716fd348SMartin Matuska char buf[BUFSIZ] = { 0 }; 111*716fd348SMartin Matuska 112*716fd348SMartin Matuska if (pfile == NULL) { 113*716fd348SMartin Matuska return (-1); 114*716fd348SMartin Matuska } 115*716fd348SMartin Matuska 116*716fd348SMartin Matuska if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) { 117*716fd348SMartin Matuska return (-1); 118*716fd348SMartin Matuska } 119*716fd348SMartin Matuska if (read(fd, buf, sizeof (buf)) == -1) { 120*716fd348SMartin Matuska (void) fprintf(stderr, "read(%d, buf, %zd) failed with errno " 121*716fd348SMartin Matuska "%d\n", fd, sizeof (buf), errno); 122*716fd348SMartin Matuska (void) close(fd); 123*716fd348SMartin Matuska return (1); 124*716fd348SMartin Matuska } 125*716fd348SMartin Matuska (void) close(fd); 126*716fd348SMartin Matuska 127*716fd348SMartin Matuska return (ret); 128*716fd348SMartin Matuska } 129*716fd348SMartin Matuska 130*716fd348SMartin Matuska static int 131*716fd348SMartin Matuska do_write(const char *pfile) 132*716fd348SMartin Matuska { 133*716fd348SMartin Matuska int fd, ret = 0; 134*716fd348SMartin Matuska char buf[BUFSIZ] = "call function do_write()"; 135*716fd348SMartin Matuska 136*716fd348SMartin Matuska if (pfile == NULL) { 137*716fd348SMartin Matuska return (-1); 138*716fd348SMartin Matuska } 139*716fd348SMartin Matuska 140*716fd348SMartin Matuska if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) { 141*716fd348SMartin Matuska return (-1); 142*716fd348SMartin Matuska } 143*716fd348SMartin Matuska if (write(fd, buf, strlen(buf)) == -1) { 144*716fd348SMartin Matuska (void) fprintf(stderr, "write(%d, buf, %d) failed with errno " 145*716fd348SMartin Matuska "%d\n", fd, (int)strlen(buf), errno); 146*716fd348SMartin Matuska (void) close(fd); 147*716fd348SMartin Matuska return (1); 148*716fd348SMartin Matuska } 149*716fd348SMartin Matuska (void) close(fd); 150*716fd348SMartin Matuska 151*716fd348SMartin Matuska return (ret); 152*716fd348SMartin Matuska } 153*716fd348SMartin Matuska 154*716fd348SMartin Matuska static int 155*716fd348SMartin Matuska do_link(const char *pfile) 156*716fd348SMartin Matuska { 157*716fd348SMartin Matuska int ret = 0; 158*716fd348SMartin Matuska char link_file[BUFSIZ + 16] = { 0 }; 159*716fd348SMartin Matuska 160*716fd348SMartin Matuska if (pfile == NULL) { 161*716fd348SMartin Matuska return (-1); 162*716fd348SMartin Matuska } 163*716fd348SMartin Matuska 164*716fd348SMartin Matuska /* 165*716fd348SMartin Matuska * Figure out source file directory name, and create 166*716fd348SMartin Matuska * the link file in the same directory. 167*716fd348SMartin Matuska */ 168*716fd348SMartin Matuska (void) snprintf(link_file, sizeof (link_file), 169*716fd348SMartin Matuska "%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file"); 170*716fd348SMartin Matuska 171*716fd348SMartin Matuska if (link(pfile, link_file) == -1) { 172*716fd348SMartin Matuska (void) fprintf(stderr, "link(%s, %s) failed with errno %d\n", 173*716fd348SMartin Matuska pfile, link_file, errno); 174*716fd348SMartin Matuska return (1); 175*716fd348SMartin Matuska } 176*716fd348SMartin Matuska 177*716fd348SMartin Matuska (void) unlink(link_file); 178*716fd348SMartin Matuska 179*716fd348SMartin Matuska return (ret); 180*716fd348SMartin Matuska } 181*716fd348SMartin Matuska 182*716fd348SMartin Matuska static int 183*716fd348SMartin Matuska do_creat(const char *pfile) 184*716fd348SMartin Matuska { 185*716fd348SMartin Matuska int fd, ret = 0; 186*716fd348SMartin Matuska 187*716fd348SMartin Matuska if (pfile == NULL) { 188*716fd348SMartin Matuska return (-1); 189*716fd348SMartin Matuska } 190*716fd348SMartin Matuska 191*716fd348SMartin Matuska if ((fd = creat(pfile, ALL_MODE)) == -1) { 192*716fd348SMartin Matuska (void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno " 193*716fd348SMartin Matuska "%d\n", pfile, errno); 194*716fd348SMartin Matuska return (1); 195*716fd348SMartin Matuska } 196*716fd348SMartin Matuska (void) close(fd); 197*716fd348SMartin Matuska 198*716fd348SMartin Matuska return (ret); 199*716fd348SMartin Matuska } 200*716fd348SMartin Matuska 201*716fd348SMartin Matuska static int 202*716fd348SMartin Matuska do_utime(const char *pfile) 203*716fd348SMartin Matuska { 204*716fd348SMartin Matuska int ret = 0; 205*716fd348SMartin Matuska 206*716fd348SMartin Matuska if (pfile == NULL) { 207*716fd348SMartin Matuska return (-1); 208*716fd348SMartin Matuska } 209*716fd348SMartin Matuska 210*716fd348SMartin Matuska /* 211*716fd348SMartin Matuska * Times of the file are set to the current time 212*716fd348SMartin Matuska */ 213*716fd348SMartin Matuska if (utime(pfile, NULL) == -1) { 214*716fd348SMartin Matuska (void) fprintf(stderr, "utime(%s, NULL) failed with errno " 215*716fd348SMartin Matuska "%d\n", pfile, errno); 216*716fd348SMartin Matuska return (1); 217*716fd348SMartin Matuska } 218*716fd348SMartin Matuska 219*716fd348SMartin Matuska return (ret); 220*716fd348SMartin Matuska } 221*716fd348SMartin Matuska 222*716fd348SMartin Matuska static int 223*716fd348SMartin Matuska do_chmod(const char *pfile) 224*716fd348SMartin Matuska { 225*716fd348SMartin Matuska int ret = 0; 226*716fd348SMartin Matuska 227*716fd348SMartin Matuska if (pfile == NULL) { 228*716fd348SMartin Matuska return (-1); 229*716fd348SMartin Matuska } 230*716fd348SMartin Matuska 231*716fd348SMartin Matuska if (chmod(pfile, ALL_MODE) == -1) { 232*716fd348SMartin Matuska (void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with " 233*716fd348SMartin Matuska "errno %d\n", pfile, errno); 234*716fd348SMartin Matuska return (1); 235*716fd348SMartin Matuska } 236*716fd348SMartin Matuska 237*716fd348SMartin Matuska return (ret); 238*716fd348SMartin Matuska } 239*716fd348SMartin Matuska 240*716fd348SMartin Matuska static int 241*716fd348SMartin Matuska do_chown(const char *pfile) 242*716fd348SMartin Matuska { 243*716fd348SMartin Matuska int ret = 0; 244*716fd348SMartin Matuska 245*716fd348SMartin Matuska if (pfile == NULL) { 246*716fd348SMartin Matuska return (-1); 247*716fd348SMartin Matuska } 248*716fd348SMartin Matuska 249*716fd348SMartin Matuska if (chown(pfile, getuid(), getgid()) == -1) { 250*716fd348SMartin Matuska (void) fprintf(stderr, "chown(%s, %d, %d) failed with errno " 251*716fd348SMartin Matuska "%d\n", pfile, (int)getuid(), (int)getgid(), errno); 252*716fd348SMartin Matuska return (1); 253*716fd348SMartin Matuska } 254*716fd348SMartin Matuska 255*716fd348SMartin Matuska return (ret); 256*716fd348SMartin Matuska } 257*716fd348SMartin Matuska 258*716fd348SMartin Matuska #ifndef __FreeBSD__ 259*716fd348SMartin Matuska static int 260*716fd348SMartin Matuska do_xattr(const char *pfile) 261*716fd348SMartin Matuska { 262*716fd348SMartin Matuska int ret = 0; 263*716fd348SMartin Matuska char *value = "user.value"; 264*716fd348SMartin Matuska 265*716fd348SMartin Matuska if (pfile == NULL) { 266*716fd348SMartin Matuska return (-1); 267*716fd348SMartin Matuska } 268*716fd348SMartin Matuska 269*716fd348SMartin Matuska if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) { 270*716fd348SMartin Matuska (void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno " 271*716fd348SMartin Matuska "%d\n", pfile, (int)getuid(), (int)getgid(), errno); 272*716fd348SMartin Matuska return (1); 273*716fd348SMartin Matuska } 274*716fd348SMartin Matuska return (ret); 275*716fd348SMartin Matuska } 276*716fd348SMartin Matuska #endif 277*716fd348SMartin Matuska 278*716fd348SMartin Matuska static void 279*716fd348SMartin Matuska cleanup(void) 280*716fd348SMartin Matuska { 281*716fd348SMartin Matuska if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) { 282*716fd348SMartin Matuska (void) unlink(tfile); 283*716fd348SMartin Matuska } 284*716fd348SMartin Matuska } 285*716fd348SMartin Matuska 286*716fd348SMartin Matuska static timetest_t timetest_table[] = { 287*716fd348SMartin Matuska { ST_ATIME, "st_atime", do_read }, 288*716fd348SMartin Matuska { ST_ATIME, "st_atime", do_utime }, 289*716fd348SMartin Matuska { ST_MTIME, "st_mtime", do_creat }, 290*716fd348SMartin Matuska { ST_MTIME, "st_mtime", do_write }, 291*716fd348SMartin Matuska { ST_MTIME, "st_mtime", do_utime }, 292*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_creat }, 293*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_write }, 294*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_chmod }, 295*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_chown }, 296*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_link }, 297*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_utime }, 298*716fd348SMartin Matuska #ifndef __FreeBSD__ 299*716fd348SMartin Matuska { ST_CTIME, "st_ctime", do_xattr }, 300*716fd348SMartin Matuska #endif 301*716fd348SMartin Matuska }; 302*716fd348SMartin Matuska 303*716fd348SMartin Matuska #define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0])) 304*716fd348SMartin Matuska 305*716fd348SMartin Matuska int 306*716fd348SMartin Matuska main(void) 307*716fd348SMartin Matuska { 308*716fd348SMartin Matuska int i, ret, fd; 309*716fd348SMartin Matuska char *penv[] = {"TESTDIR", "TESTFILE0"}; 310*716fd348SMartin Matuska 311*716fd348SMartin Matuska (void) atexit(cleanup); 312*716fd348SMartin Matuska 313*716fd348SMartin Matuska /* 314*716fd348SMartin Matuska * Get the environment variable values. 315*716fd348SMartin Matuska */ 316*716fd348SMartin Matuska for (i = 0; i < sizeof (penv) / sizeof (char *); i++) { 317*716fd348SMartin Matuska if ((penv[i] = getenv(penv[i])) == NULL) { 318*716fd348SMartin Matuska (void) fprintf(stderr, "getenv(penv[%d])\n", i); 319*716fd348SMartin Matuska return (1); 320*716fd348SMartin Matuska } 321*716fd348SMartin Matuska } 322*716fd348SMartin Matuska (void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]); 323*716fd348SMartin Matuska 324*716fd348SMartin Matuska /* 325*716fd348SMartin Matuska * If the test file exists, remove it first. 326*716fd348SMartin Matuska */ 327*716fd348SMartin Matuska if (access(tfile, F_OK) == 0) { 328*716fd348SMartin Matuska (void) unlink(tfile); 329*716fd348SMartin Matuska } 330*716fd348SMartin Matuska ret = 0; 331*716fd348SMartin Matuska if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) { 332*716fd348SMartin Matuska (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno); 333*716fd348SMartin Matuska return (1); 334*716fd348SMartin Matuska } 335*716fd348SMartin Matuska (void) close(fd); 336*716fd348SMartin Matuska 337*716fd348SMartin Matuska for (i = 0; i < NCOMMAND; i++) { 338*716fd348SMartin Matuska time_t t1, t2; 339*716fd348SMartin Matuska 340*716fd348SMartin Matuska /* 341*716fd348SMartin Matuska * Get original time before operating. 342*716fd348SMartin Matuska */ 343*716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t1); 344*716fd348SMartin Matuska if (ret != 0) { 345*716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n", 346*716fd348SMartin Matuska tfile, timetest_table[i].type, ret); 347*716fd348SMartin Matuska return (1); 348*716fd348SMartin Matuska } 349*716fd348SMartin Matuska 350*716fd348SMartin Matuska /* 351*716fd348SMartin Matuska * Sleep 2 seconds, then invoke command on given file 352*716fd348SMartin Matuska */ 353*716fd348SMartin Matuska (void) sleep(2); 354*716fd348SMartin Matuska timetest_table[i].func(tfile); 355*716fd348SMartin Matuska 356*716fd348SMartin Matuska /* 357*716fd348SMartin Matuska * Get time after operating. 358*716fd348SMartin Matuska */ 359*716fd348SMartin Matuska ret = get_file_time(tfile, timetest_table[i].type, &t2); 360*716fd348SMartin Matuska if (ret != 0) { 361*716fd348SMartin Matuska (void) fprintf(stderr, "get_file_time(%s %d) = %d\n", 362*716fd348SMartin Matuska tfile, timetest_table[i].type, ret); 363*716fd348SMartin Matuska return (1); 364*716fd348SMartin Matuska } 365*716fd348SMartin Matuska 366*716fd348SMartin Matuska if (t1 == t2) { 367*716fd348SMartin Matuska (void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n", 368*716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2); 369*716fd348SMartin Matuska return (1); 370*716fd348SMartin Matuska } else { 371*716fd348SMartin Matuska (void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n", 372*716fd348SMartin Matuska timetest_table[i].name, (long)t1, (long)t2); 373*716fd348SMartin Matuska } 374*716fd348SMartin Matuska } 375*716fd348SMartin Matuska 376*716fd348SMartin Matuska return (0); 377*716fd348SMartin Matuska } 378