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