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