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  * $FreeBSD$
21  */
22 
23 /*
24  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"@(#)ctime_001_pos.c	1.1	07/05/25 SMI"
29 
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <utime.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 
40 #define	ST_ATIME 0
41 #define	ST_CTIME 1
42 #define	ST_MTIME 2
43 
44 #define	ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
45 
46 typedef struct timetest {
47 	int	type;
48 	char	*name;
49 	int	(*func)(const char *pfile);
50 } timetest_t;
51 
52 #ifdef __stc_assertion__
53 
54 /*
55  * ID: ctime_001_pos
56  *
57  * DESCRIPTION:
58  * 	Verify time will be changed correctly according to relevant operating.
59  *
60  * STRATEGY:
61  *	1. Define time test array.
62  *	2. loop each item in this array.
63  *	3. Verify the time will be changed after relevant operating.
64  *
65  * TESTABILITY: explicit
66  *
67  * TEST_AUTOMATION_LEVEL: automated
68  *
69  * CODING_STATUS: COMPLETED (2007-01-30)
70  *
71  */
72 
73 #endif	/* __stc_assertion__ */
74 
75 /*
76  * Get file specific time information.
77  */
78 int get_file_time(char *pfile, int what, time_t *ptr);
79 
80 int do_read(const char *pfile);
81 int do_write(const char *pfile);
82 int do_link(const char *pfile);
83 int do_creat(const char *pfile);
84 int do_utime(const char *pfile);
85 int do_chmod(const char *pfile);
86 int do_chown(const char *pfile);
87 
88 static char tfile[BUFSIZ] = { 0 };
89 static char msg[BUFSIZ] = { 0 };
90 
91 static timetest_t timetest_table[] = {
92 	{ ST_ATIME,	"st_atime",	do_read		},
93 	{ ST_ATIME,	"st_atime",	do_utime	},
94 	{ ST_MTIME,	"st_mtime",	do_creat	},
95 	{ ST_MTIME,	"st_mtime",	do_write	},
96 	{ ST_MTIME,	"st_mtime",	do_utime	},
97 	{ ST_CTIME,	"st_ctime",	do_creat	},
98 	{ ST_CTIME,	"st_ctime",	do_write	},
99 	{ ST_CTIME,	"st_ctime",	do_chmod	},
100 	{ ST_CTIME,	"st_ctime",	do_chown 	},
101 	{ ST_CTIME,	"st_ctime",	do_link		},
102 	{ ST_CTIME,	"st_ctime",	do_utime	},
103 };
104 
105 #define	NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
106 
107 int
108 main(int argc, char *argv[])
109 {
110 	int i, ret, fd;
111 	const char *env_names[2] = {"TESTDIR", "TESTFILE"};
112 	char *env_vals[2];
113 
114 	/*
115 	 * Get envirnment variable value
116 	 */
117 	for (i = 0; i < sizeof (env_names) / sizeof (char *); i++) {
118 		if ((env_vals[i] = getenv(env_names[i])) == NULL) {
119 			fprintf(stderr, "getenv(%s) returned NULL\n",
120 			    env_names[i]);
121 			exit(1);
122 		}
123 	}
124 	(void) snprintf(tfile, sizeof (tfile), "%s/%s", env_vals[0],
125 	    env_vals[1]);
126 
127 	/*
128 	 * If the test file is existing, remove it firstly
129 	 */
130 	if (access(tfile, F_OK) == 0) {
131 		unlink(tfile);
132 	}
133 	fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE);
134 	if (fd < 0) {
135 		perror("open");
136 		exit(1);
137 	}
138 	(void) close(fd);
139 
140 	for (i = 0; i < NCOMMAND; i++) {
141 		time_t t1, t2;
142 
143 		/*
144 		 * Get original time before operating.
145 		 */
146 		ret = get_file_time(tfile, timetest_table[i].type, &t1);
147 		if (ret != 0) {
148 			fprintf(stderr,
149 			    "ERROR: get_file_time(%s, %d, &t1) returned %d\n",
150 			    tfile, timetest_table[i].type, ret);
151 			exit(1);
152 		}
153 
154 		/*
155 		 * Sleep 2 seconds to be sure that the timeofday has changed,
156 		 * then invoke command on given file
157 		 */
158 		sleep(2);
159 		timetest_table[i].func(tfile);
160 
161 		/*
162 		 * Get time after operating.
163 		 */
164 		ret = get_file_time(tfile, timetest_table[i].type, &t2);
165 		if (ret != 0) {
166 			fprintf(stderr, "get_file_time(%s, %d, &t2)\n",
167 			    tfile, timetest_table[i].type);
168 			exit(1);
169 		}
170 
171 		if (t1 == t2) {
172 			fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
173 			    timetest_table[i].name, (long)t1, (long)t2);
174 			exit(1);
175 		}
176 	}
177 
178 	(void) unlink(tfile);
179 
180 	return (0);
181 }
182 
183 int
184 get_file_time(char *pfile, int what, time_t *ptr)
185 {
186 	struct stat stat_buf;
187 
188 	if (pfile == NULL || ptr == NULL) {
189 		return (-1);
190 	}
191 
192 	if (stat(pfile, &stat_buf) == -1) {
193 		return (-1);
194 	}
195 
196 	switch (what) {
197 		case ST_ATIME:
198 			*ptr = stat_buf.st_atime;
199 			return (0);
200 		case ST_CTIME:
201 			*ptr = stat_buf.st_ctime;
202 			return (0);
203 		case ST_MTIME:
204 			*ptr = stat_buf.st_mtime;
205 			return (0);
206 		default:
207 			return (-1);
208 	}
209 }
210 
211 int
212 do_read(const char *pfile)
213 {
214 	int fd, ret = 0;
215 	char buf[BUFSIZ] = { 0 };
216 
217 	if (pfile == NULL) {
218 		return (-1);
219 	}
220 
221 	if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
222 		return (-1);
223 	}
224 	if (read(fd, buf, sizeof (buf)) == -1) {
225 		ret = errno;
226 	}
227 	(void) close(fd);
228 
229 	if (ret != 0) {
230 		fprintf(stderr, "read(%d, buf, %zu)\n", fd, sizeof (buf));
231 		exit(1);
232 	}
233 
234 	return (ret);
235 }
236 
237 int
238 do_write(const char *pfile)
239 {
240 	int fd, ret = 0;
241 	char buf[BUFSIZ] = "call function do_write()";
242 
243 	if (pfile == NULL) {
244 		return (-1);
245 	}
246 
247 	if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
248 		return (-1);
249 	}
250 	if (write(fd, buf, strlen(buf)) == -1) {
251 		ret = errno;
252 	}
253 	(void) close(fd);
254 
255 	if (ret != 0) {
256 		fprintf(stderr, "write(%d, buf, %zu)\n", fd, strlen(buf));
257 		exit(1);
258 	}
259 
260 	return (ret);
261 }
262 
263 int
264 do_link(const char *pfile)
265 {
266 	int ret = 0;
267 	char link_file[BUFSIZ] = { 0 };
268 	char *ptr = link_file;
269 
270 	if (pfile == NULL) {
271 		return (-1);
272 	}
273 
274 	/*
275 	 * Figure out source file directory name, and create
276 	 * the link file in the same directory.
277 	 */
278 	snprintf(link_file, sizeof (link_file), "%s", pfile);
279 	ptr = strrchr(link_file, '/');
280 	snprintf(ptr + 1,
281 	    sizeof (link_file) - (ptr + 1 - link_file), "link_file");
282 
283 	if (link(pfile, link_file) == -1) {
284 		ret = errno;
285 	}
286 	if (ret != 0) {
287 		fprintf(stderr, "link(%s, %s)\n", pfile, link_file);
288 		exit(1);
289 	}
290 
291 	unlink(link_file);
292 	return (ret);
293 }
294 
295 int
296 do_creat(const char *pfile)
297 {
298 	int fd, ret = 0;
299 
300 	if (pfile == NULL) {
301 		return (-1);
302 	}
303 
304 	if ((fd = creat(pfile, ALL_MODE)) == -1) {
305 		ret = errno;
306 	}
307 	if (fd != -1) {
308 		(void) close(fd);
309 	}
310 
311 	if (ret != 0) {
312 		fprintf(stderr, "creat(%s, ALL_MODE)\n", pfile);
313 		exit(1);
314 	}
315 
316 	return (ret);
317 }
318 
319 int
320 do_utime(const char *pfile)
321 {
322 	int ret = 0;
323 
324 	if (pfile == NULL) {
325 		return (-1);
326 	}
327 
328 	/*
329 	 * Times of the file are set to the current time
330 	 */
331 	if (utime(pfile, NULL) == -1) {
332 		ret = errno;
333 	}
334 	if (ret != 0) {
335 		fprintf(stderr, "utime(%s, NULL)\n", pfile);
336 		exit(1);
337 	}
338 
339 	return (ret);
340 }
341 
342 int
343 do_chmod(const char *pfile)
344 {
345 	int ret = 0;
346 
347 	if (pfile == NULL) {
348 		return (-1);
349 	}
350 
351 	if (chmod(pfile, ALL_MODE) == -1) {
352 		ret = errno;
353 	}
354 	if (ret != 0) {
355 		fprintf(stderr, "chmod(%s, ALL_MODE)\n", pfile);
356 		exit(1);
357 	}
358 
359 	return (ret);
360 }
361 
362 int
363 do_chown(const char *pfile)
364 {
365 	int ret = 0;
366 
367 	if (pfile == NULL) {
368 		return (-1);
369 	}
370 
371 	if (chown(pfile, getuid(), getgid()) == -1) {
372 		ret = errno;
373 	}
374 	if (ret != 0) {
375 		fprintf(stderr, "chown(%s, %d, %d)\n", pfile, (int)getuid(),
376 		    (int)getgid());
377 		exit(1);
378 	}
379 
380 	return (ret);
381 }
382