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