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 } 350