blob: 3ff9483e6cf5b1bd3f8d3c10197168a01a4e2ad4 [file] [log] [blame]
subrata_modak4bb656a2009-02-26 12:02:09 +00001/*************************************************************************************/
subrata_modak27439682008-06-06 08:44:40 +00002/* */
3/* Copyright (C) 2008, Michael Kerrisk <mtk.manpages@gmail.com>, */
4/* Copyright (C) 2008, Linux Foundation */
5/* */
6/* This program is free software; you can redistribute it and/or modify */
7/* it under the terms of the GNU General Public License as published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
14/* the GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
Wanlong Gao4548c6c2012-10-19 18:03:36 +080018/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
subrata_modak27439682008-06-06 08:44:40 +000019/*************************************************************************************/
20/* */
21/* File: utimnsat01.c */
22/* Description: A command-line interface for testing the utimensat() system call. */
23/* Author: Michael Kerrisk <mtk.manpages@gmail.com> */
24/* History: */
25/* 17 Mar 2008 Initial creation, */
26/* 31 May 2008 Reworked for easier test automation, */
27/* 2 June 2008 Renamed from t_utimensat.c to test_utimensat.c, */
28/* 05 June 2008 Submitted to LTP by Subrata Modak <subrata@linux.vnet.ibm.com> */
29/*************************************************************************************/
30
subrata_modak27439682008-06-06 08:44:40 +000031#define _GNU_SOURCE
32#define _ATFILE_SOURCE
33#include <stdio.h>
34#include <time.h>
35#include <errno.h>
36#include <stdlib.h>
37#include <unistd.h>
subrata_modak4bb656a2009-02-26 12:02:09 +000038#include <sys/syscall.h>
subrata_modak27439682008-06-06 08:44:40 +000039#include <fcntl.h>
40#include <string.h>
41#include <sys/stat.h>
Garrett Cooper5df02602010-12-21 11:24:30 -080042#include "test.h"
subrata_modak317251d2008-07-21 10:38:43 +000043#include "linux_syscall_numbers.h"
subrata_modak27439682008-06-06 08:44:40 +000044
Cyril Hrubisfdce7d52013-04-04 18:35:48 +020045char *TCID = "utimensat01";
46int TST_TOTAL = 0;
subrata_modak47745f62008-12-12 07:24:37 +000047
subrata_modak24fc2132008-11-11 05:57:38 +000048#define cleanup tst_exit
49
subrata_modak27439682008-06-06 08:44:40 +000050/* We use EXIT_FAILURE for an expected failure from utimensat()
51 (e.g., EACCES and EPERM), and one of the following for unexpected
52 failures (i.e., something broke in our test setup). */
53
subrata_modak0f27b4f2008-09-05 06:14:11 +000054#ifndef AT_FDCWD
subrata_modak56207ce2009-03-23 13:35:39 +000055#define AT_FDCWD -100
subrata_modak0f27b4f2008-09-05 06:14:11 +000056#endif
57#ifndef AT_SYMLINK_NOFOLLOW
subrata_modak56207ce2009-03-23 13:35:39 +000058#define AT_SYMLINK_NOFOLLOW 0x100
subrata_modak0f27b4f2008-09-05 06:14:11 +000059#endif
60
subrata_modak27439682008-06-06 08:44:40 +000061#define EXIT_bad_usage 3
62#define EXIT_failed_syscall 3
63
64#define errExit(msg) do { perror(msg); exit(EXIT_failed_syscall); \
65 } while (0)
66
Wanlong Gao354ebb42012-12-07 10:10:04 +080067#define UTIME_NOW ((1l << 30) - 1l)
68#define UTIME_OMIT ((1l << 30) - 2l)
subrata_modak27439682008-06-06 08:44:40 +000069
70static inline int
71utimensat_sc(int dirfd, const char *pathname,
subrata_modak56207ce2009-03-23 13:35:39 +000072 const struct timespec times[2], int flags)
subrata_modak27439682008-06-06 08:44:40 +000073{
Jan Stancek359980f2013-02-15 10:16:05 +010074 return ltp_syscall(__NR_utimensat, dirfd, pathname, times, flags);
subrata_modak27439682008-06-06 08:44:40 +000075}
76
subrata_modak56207ce2009-03-23 13:35:39 +000077static void usageError(char *progName)
subrata_modak27439682008-06-06 08:44:40 +000078{
subrata_modak56207ce2009-03-23 13:35:39 +000079 fprintf(stderr, "Usage: %s pathname [atime-sec "
80 "atime-nsec mtime-sec mtime-nsec]\n\n", progName);
81 fprintf(stderr, "Permitted options are:\n");
82 fprintf(stderr, " [-d path] "
83 "open a directory file descriptor"
84 " (instead of using AT_FDCWD)\n");
85 fprintf(stderr, " -q Quiet\n");
86 fprintf(stderr, " -w Open directory file "
87 "descriptor with O_RDWR|O_APPEND\n"
88 " (instead of O_RDONLY)\n");
89 fprintf(stderr, " -n Use AT_SYMLINK_NOFOLLOW\n");
90 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +000091
subrata_modak56207ce2009-03-23 13:35:39 +000092 fprintf(stderr, "pathname can be \"NULL\" to use NULL "
93 "argument in call\n");
94 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +000095
subrata_modak56207ce2009-03-23 13:35:39 +000096 fprintf(stderr, "Either nsec field can be\n");
97 fprintf(stderr, " 'n' for UTIME_NOW\n");
98 fprintf(stderr, " 'o' for UTIME_OMIT\n");
99 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +0000100
subrata_modak56207ce2009-03-23 13:35:39 +0000101 fprintf(stderr, "If the time fields are omitted, "
102 "then a NULL 'times' argument is used\n");
103 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +0000104
subrata_modak56207ce2009-03-23 13:35:39 +0000105 exit(EXIT_bad_usage);
subrata_modak27439682008-06-06 08:44:40 +0000106}
107
subrata_modak56207ce2009-03-23 13:35:39 +0000108int main(int argc, char *argv[])
subrata_modak27439682008-06-06 08:44:40 +0000109{
subrata_modak56207ce2009-03-23 13:35:39 +0000110 int flags, dirfd, opt, oflag;
111 struct timespec ts[2];
112 struct timespec *tsp;
113 char *pathname, *dirfdPath;
114 struct stat sb;
115 int verbose;
subrata_modak27439682008-06-06 08:44:40 +0000116
subrata_modak56207ce2009-03-23 13:35:39 +0000117 /* Command-line argument parsing */
subrata_modak27439682008-06-06 08:44:40 +0000118
subrata_modak56207ce2009-03-23 13:35:39 +0000119 flags = 0;
120 verbose = 1;
121 dirfd = AT_FDCWD;
122 dirfdPath = NULL;
123 oflag = O_RDONLY;
subrata_modak27439682008-06-06 08:44:40 +0000124
subrata_modak56207ce2009-03-23 13:35:39 +0000125 while ((opt = getopt(argc, argv, "d:nqw")) != -1) {
126 switch (opt) {
127 case 'd':
128 dirfdPath = optarg;
129 break;
subrata_modak27439682008-06-06 08:44:40 +0000130
subrata_modak56207ce2009-03-23 13:35:39 +0000131 case 'n':
132 flags |= AT_SYMLINK_NOFOLLOW;
133 if (verbose)
134 printf("Not following symbolic links\n");
135 break;
subrata_modak27439682008-06-06 08:44:40 +0000136
subrata_modak56207ce2009-03-23 13:35:39 +0000137 case 'q':
138 verbose = 0;
139 break;
subrata_modak27439682008-06-06 08:44:40 +0000140
subrata_modak56207ce2009-03-23 13:35:39 +0000141 case 'w':
142 oflag = O_RDWR | O_APPEND;
143 break;
subrata_modak27439682008-06-06 08:44:40 +0000144
subrata_modak56207ce2009-03-23 13:35:39 +0000145 default:
146 usageError(argv[0]);
147 }
148 }
subrata_modak27439682008-06-06 08:44:40 +0000149
subrata_modak56207ce2009-03-23 13:35:39 +0000150 if ((optind + 5 != argc) && (optind + 1 != argc))
151 usageError(argv[0]);
subrata_modak27439682008-06-06 08:44:40 +0000152
subrata_modak56207ce2009-03-23 13:35:39 +0000153 if (dirfdPath != NULL) {
154 dirfd = open(dirfdPath, oflag);
155 if (dirfd == -1)
156 errExit("open");
subrata_modak27439682008-06-06 08:44:40 +0000157
subrata_modak56207ce2009-03-23 13:35:39 +0000158 if (verbose) {
159 printf("Opened dirfd %d", oflag);
160 if ((oflag & O_ACCMODE) == O_RDWR)
161 printf(" O_RDWR");
162 if (oflag & O_APPEND)
163 printf(" O_APPEND");
164 printf(": %s\n", dirfdPath);
165 }
166 }
subrata_modak27439682008-06-06 08:44:40 +0000167
subrata_modak56207ce2009-03-23 13:35:39 +0000168 pathname = (strcmp(argv[optind], "NULL") == 0) ? NULL : argv[optind];
subrata_modak27439682008-06-06 08:44:40 +0000169
subrata_modak56207ce2009-03-23 13:35:39 +0000170 /* Either, we get no values for 'times' fields, in which case
171 we give a NULL pointer to utimensat(), or we get four values,
172 for secs+nsecs for each of atime and mtime. The special
173 values 'n' and 'o' can be used for tv_nsec settings of
174 UTIME_NOW and UTIME_OMIT, respectively. */
subrata_modak27439682008-06-06 08:44:40 +0000175
subrata_modak56207ce2009-03-23 13:35:39 +0000176 if (argc == optind + 1) {
177 tsp = NULL;
subrata_modak27439682008-06-06 08:44:40 +0000178
subrata_modak56207ce2009-03-23 13:35:39 +0000179 } else {
180 ts[0].tv_sec = atoi(argv[optind + 1]);
181 if (argv[optind + 2][0] == 'n') {
182 ts[0].tv_nsec = UTIME_NOW;
183 } else if (argv[optind + 2][0] == 'o') {
184 ts[0].tv_nsec = UTIME_OMIT;
185 } else {
186 ts[0].tv_nsec = atoi(argv[optind + 2]);
187 }
subrata_modak27439682008-06-06 08:44:40 +0000188
subrata_modak56207ce2009-03-23 13:35:39 +0000189 ts[1].tv_sec = atoi(argv[optind + 3]);
190 if (argv[optind + 4][0] == 'n') {
191 ts[1].tv_nsec = UTIME_NOW;
192 } else if (argv[optind + 4][0] == 'o') {
193 ts[1].tv_nsec = UTIME_OMIT;
194 } else {
195 ts[1].tv_nsec = atoi(argv[optind + 4]);
196 }
subrata_modak27439682008-06-06 08:44:40 +0000197
subrata_modak56207ce2009-03-23 13:35:39 +0000198 tsp = ts;
199 }
subrata_modak27439682008-06-06 08:44:40 +0000200
subrata_modak56207ce2009-03-23 13:35:39 +0000201 /* For testing purposes, it may have been useful to run this program
202 as set-user-ID-root so that a directory file descriptor could be
203 opened as root. (This allows us to obtain a file descriptor even
204 if normal user doesn't have permissions on the file.) Now we
205 reset to the real UID before making the utimensat() call, so that
206 the permission checking for the utimensat() call is performed
207 under that UID. */
subrata_modak27439682008-06-06 08:44:40 +0000208
subrata_modak56207ce2009-03-23 13:35:39 +0000209 if (geteuid() == 0) {
210 uid_t u;
subrata_modak27439682008-06-06 08:44:40 +0000211
subrata_modak56207ce2009-03-23 13:35:39 +0000212 u = getuid();
subrata_modak27439682008-06-06 08:44:40 +0000213
subrata_modak56207ce2009-03-23 13:35:39 +0000214 if (verbose)
215 printf("Resetting UIDs to %ld\n", (long)u);
subrata_modak27439682008-06-06 08:44:40 +0000216
subrata_modak56207ce2009-03-23 13:35:39 +0000217 if (setresuid(u, u, u) == -1)
218 errExit("setresuid");
219 }
subrata_modak27439682008-06-06 08:44:40 +0000220
subrata_modak56207ce2009-03-23 13:35:39 +0000221 /* Display information allowing user to verify arguments for call */
subrata_modak27439682008-06-06 08:44:40 +0000222
subrata_modak56207ce2009-03-23 13:35:39 +0000223 if (verbose) {
224 printf("dirfd is %d\n", dirfd);
225 printf("pathname is %s\n", pathname);
226 printf("tsp is %p", tsp);
227 if (tsp != NULL) {
228 printf("; struct = { %ld, %ld } { %ld, %ld }",
229 (long)tsp[0].tv_sec, (long)tsp[0].tv_nsec,
230 (long)tsp[1].tv_sec, (long)tsp[1].tv_nsec);
231 }
232 printf("\n");
233 printf("flags is %d\n", flags);
234 }
subrata_modak27439682008-06-06 08:44:40 +0000235
subrata_modak56207ce2009-03-23 13:35:39 +0000236 /* Make the call and see what happened */
subrata_modak27439682008-06-06 08:44:40 +0000237
subrata_modak56207ce2009-03-23 13:35:39 +0000238 if (utimensat_sc(dirfd, pathname, tsp, flags) == -1) {
239 if (errno == EPERM) {
240 if (verbose)
241 printf("utimensat() failed with EPERM\n");
242 else
243 printf("EPERM\n");
244 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000245
subrata_modak56207ce2009-03-23 13:35:39 +0000246 } else if (errno == EACCES) {
247 if (verbose)
248 printf("utimensat() failed with EACCES\n");
249 else
250 printf("EACCES\n");
251 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000252
subrata_modak56207ce2009-03-23 13:35:39 +0000253 } else if (errno == EINVAL) {
254 if (verbose)
255 printf("utimensat() failed with EINVAL\n");
256 else
257 printf("EINVAL\n");
258 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000259
subrata_modak56207ce2009-03-23 13:35:39 +0000260 } else { /* Unexpected failure case from utimensat() */
261 errExit("utimensat");
262 }
263 }
subrata_modak27439682008-06-06 08:44:40 +0000264
subrata_modak56207ce2009-03-23 13:35:39 +0000265 if (verbose)
266 printf("utimensat() succeeded\n");
subrata_modak27439682008-06-06 08:44:40 +0000267
subrata_modak56207ce2009-03-23 13:35:39 +0000268 if (stat((pathname != NULL) ? pathname : dirfdPath, &sb) == -1)
269 errExit("stat");
subrata_modak27439682008-06-06 08:44:40 +0000270
subrata_modak56207ce2009-03-23 13:35:39 +0000271 if (verbose) {
272 printf("Last file access: %s", ctime(&sb.st_atime));
273 printf("Last file modification: %s", ctime(&sb.st_mtime));
274 printf("Last status change: %s", ctime(&sb.st_ctime));
subrata_modak27439682008-06-06 08:44:40 +0000275
subrata_modak56207ce2009-03-23 13:35:39 +0000276 } else {
277 printf("SUCCESS %ld %ld\n", (long)sb.st_atime,
278 (long)sb.st_mtime);
279 }
subrata_modak27439682008-06-06 08:44:40 +0000280
subrata_modak56207ce2009-03-23 13:35:39 +0000281 exit(EXIT_SUCCESS);
Garrett Cooper5df02602010-12-21 11:24:30 -0800282}