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
44typedef 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 */
76int get_file_time(char *pfile, int what, time_t *ptr);
77
78int do_read(const char *pfile);
79int do_write(const char *pfile);
80int do_link(const char *pfile);
81int do_creat(const char *pfile);
82int do_utime(const char *pfile);
83int do_chmod(const char *pfile);
84int do_chown(const char *pfile);
85
86static char tfile[BUFSIZ] = { 0 };
87static char msg[BUFSIZ] = { 0 };
88
89static 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
105int
106main(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
181int
182get_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
209int
210do_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
235int
236do_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
261int
262do_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
293int
294do_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
317int
318do_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
340int
341do_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
360int
361do_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