blob: f7b38ebb8e3cf329f518a634183e12b7ce89c3df [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"
43#include "usctest.h"
subrata_modak317251d2008-07-21 10:38:43 +000044#include "linux_syscall_numbers.h"
subrata_modak27439682008-06-06 08:44:40 +000045
subrata_modak56207ce2009-03-23 13:35:39 +000046char *TCID = "utimensat01"; /* Test program identifier. */
47int TST_TOTAL = 0; /* Total number of test cases. */
subrata_modak47745f62008-12-12 07:24:37 +000048
subrata_modak24fc2132008-11-11 05:57:38 +000049#define cleanup tst_exit
50
subrata_modak27439682008-06-06 08:44:40 +000051/* We use EXIT_FAILURE for an expected failure from utimensat()
52 (e.g., EACCES and EPERM), and one of the following for unexpected
53 failures (i.e., something broke in our test setup). */
54
subrata_modak0f27b4f2008-09-05 06:14:11 +000055#ifndef AT_FDCWD
subrata_modak56207ce2009-03-23 13:35:39 +000056#define AT_FDCWD -100
subrata_modak0f27b4f2008-09-05 06:14:11 +000057#endif
58#ifndef AT_SYMLINK_NOFOLLOW
subrata_modak56207ce2009-03-23 13:35:39 +000059#define AT_SYMLINK_NOFOLLOW 0x100
subrata_modak0f27b4f2008-09-05 06:14:11 +000060#endif
61
subrata_modak27439682008-06-06 08:44:40 +000062#define EXIT_bad_usage 3
63#define EXIT_failed_syscall 3
64
65#define errExit(msg) do { perror(msg); exit(EXIT_failed_syscall); \
66 } while (0)
67
Wanlong Gao354ebb42012-12-07 10:10:04 +080068#define UTIME_NOW ((1l << 30) - 1l)
69#define UTIME_OMIT ((1l << 30) - 2l)
subrata_modak27439682008-06-06 08:44:40 +000070
71static inline int
72utimensat_sc(int dirfd, const char *pathname,
subrata_modak56207ce2009-03-23 13:35:39 +000073 const struct timespec times[2], int flags)
subrata_modak27439682008-06-06 08:44:40 +000074{
Jan Stancek359980f2013-02-15 10:16:05 +010075 return ltp_syscall(__NR_utimensat, dirfd, pathname, times, flags);
subrata_modak27439682008-06-06 08:44:40 +000076}
77
subrata_modak56207ce2009-03-23 13:35:39 +000078static void usageError(char *progName)
subrata_modak27439682008-06-06 08:44:40 +000079{
subrata_modak56207ce2009-03-23 13:35:39 +000080 fprintf(stderr, "Usage: %s pathname [atime-sec "
81 "atime-nsec mtime-sec mtime-nsec]\n\n", progName);
82 fprintf(stderr, "Permitted options are:\n");
83 fprintf(stderr, " [-d path] "
84 "open a directory file descriptor"
85 " (instead of using AT_FDCWD)\n");
86 fprintf(stderr, " -q Quiet\n");
87 fprintf(stderr, " -w Open directory file "
88 "descriptor with O_RDWR|O_APPEND\n"
89 " (instead of O_RDONLY)\n");
90 fprintf(stderr, " -n Use AT_SYMLINK_NOFOLLOW\n");
91 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +000092
subrata_modak56207ce2009-03-23 13:35:39 +000093 fprintf(stderr, "pathname can be \"NULL\" to use NULL "
94 "argument in call\n");
95 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +000096
subrata_modak56207ce2009-03-23 13:35:39 +000097 fprintf(stderr, "Either nsec field can be\n");
98 fprintf(stderr, " 'n' for UTIME_NOW\n");
99 fprintf(stderr, " 'o' for UTIME_OMIT\n");
100 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +0000101
subrata_modak56207ce2009-03-23 13:35:39 +0000102 fprintf(stderr, "If the time fields are omitted, "
103 "then a NULL 'times' argument is used\n");
104 fprintf(stderr, "\n");
subrata_modak27439682008-06-06 08:44:40 +0000105
subrata_modak56207ce2009-03-23 13:35:39 +0000106 exit(EXIT_bad_usage);
subrata_modak27439682008-06-06 08:44:40 +0000107}
108
subrata_modak56207ce2009-03-23 13:35:39 +0000109int main(int argc, char *argv[])
subrata_modak27439682008-06-06 08:44:40 +0000110{
subrata_modak56207ce2009-03-23 13:35:39 +0000111 int flags, dirfd, opt, oflag;
112 struct timespec ts[2];
113 struct timespec *tsp;
114 char *pathname, *dirfdPath;
115 struct stat sb;
116 int verbose;
subrata_modak27439682008-06-06 08:44:40 +0000117
subrata_modak56207ce2009-03-23 13:35:39 +0000118 /* Command-line argument parsing */
subrata_modak27439682008-06-06 08:44:40 +0000119
subrata_modak56207ce2009-03-23 13:35:39 +0000120 flags = 0;
121 verbose = 1;
122 dirfd = AT_FDCWD;
123 dirfdPath = NULL;
124 oflag = O_RDONLY;
subrata_modak27439682008-06-06 08:44:40 +0000125
subrata_modak56207ce2009-03-23 13:35:39 +0000126 while ((opt = getopt(argc, argv, "d:nqw")) != -1) {
127 switch (opt) {
128 case 'd':
129 dirfdPath = optarg;
130 break;
subrata_modak27439682008-06-06 08:44:40 +0000131
subrata_modak56207ce2009-03-23 13:35:39 +0000132 case 'n':
133 flags |= AT_SYMLINK_NOFOLLOW;
134 if (verbose)
135 printf("Not following symbolic links\n");
136 break;
subrata_modak27439682008-06-06 08:44:40 +0000137
subrata_modak56207ce2009-03-23 13:35:39 +0000138 case 'q':
139 verbose = 0;
140 break;
subrata_modak27439682008-06-06 08:44:40 +0000141
subrata_modak56207ce2009-03-23 13:35:39 +0000142 case 'w':
143 oflag = O_RDWR | O_APPEND;
144 break;
subrata_modak27439682008-06-06 08:44:40 +0000145
subrata_modak56207ce2009-03-23 13:35:39 +0000146 default:
147 usageError(argv[0]);
148 }
149 }
subrata_modak27439682008-06-06 08:44:40 +0000150
subrata_modak56207ce2009-03-23 13:35:39 +0000151 if ((optind + 5 != argc) && (optind + 1 != argc))
152 usageError(argv[0]);
subrata_modak27439682008-06-06 08:44:40 +0000153
subrata_modak56207ce2009-03-23 13:35:39 +0000154 if (dirfdPath != NULL) {
155 dirfd = open(dirfdPath, oflag);
156 if (dirfd == -1)
157 errExit("open");
subrata_modak27439682008-06-06 08:44:40 +0000158
subrata_modak56207ce2009-03-23 13:35:39 +0000159 if (verbose) {
160 printf("Opened dirfd %d", oflag);
161 if ((oflag & O_ACCMODE) == O_RDWR)
162 printf(" O_RDWR");
163 if (oflag & O_APPEND)
164 printf(" O_APPEND");
165 printf(": %s\n", dirfdPath);
166 }
167 }
subrata_modak27439682008-06-06 08:44:40 +0000168
subrata_modak56207ce2009-03-23 13:35:39 +0000169 pathname = (strcmp(argv[optind], "NULL") == 0) ? NULL : argv[optind];
subrata_modak27439682008-06-06 08:44:40 +0000170
subrata_modak56207ce2009-03-23 13:35:39 +0000171 /* Either, we get no values for 'times' fields, in which case
172 we give a NULL pointer to utimensat(), or we get four values,
173 for secs+nsecs for each of atime and mtime. The special
174 values 'n' and 'o' can be used for tv_nsec settings of
175 UTIME_NOW and UTIME_OMIT, respectively. */
subrata_modak27439682008-06-06 08:44:40 +0000176
subrata_modak56207ce2009-03-23 13:35:39 +0000177 if (argc == optind + 1) {
178 tsp = NULL;
subrata_modak27439682008-06-06 08:44:40 +0000179
subrata_modak56207ce2009-03-23 13:35:39 +0000180 } else {
181 ts[0].tv_sec = atoi(argv[optind + 1]);
182 if (argv[optind + 2][0] == 'n') {
183 ts[0].tv_nsec = UTIME_NOW;
184 } else if (argv[optind + 2][0] == 'o') {
185 ts[0].tv_nsec = UTIME_OMIT;
186 } else {
187 ts[0].tv_nsec = atoi(argv[optind + 2]);
188 }
subrata_modak27439682008-06-06 08:44:40 +0000189
subrata_modak56207ce2009-03-23 13:35:39 +0000190 ts[1].tv_sec = atoi(argv[optind + 3]);
191 if (argv[optind + 4][0] == 'n') {
192 ts[1].tv_nsec = UTIME_NOW;
193 } else if (argv[optind + 4][0] == 'o') {
194 ts[1].tv_nsec = UTIME_OMIT;
195 } else {
196 ts[1].tv_nsec = atoi(argv[optind + 4]);
197 }
subrata_modak27439682008-06-06 08:44:40 +0000198
subrata_modak56207ce2009-03-23 13:35:39 +0000199 tsp = ts;
200 }
subrata_modak27439682008-06-06 08:44:40 +0000201
subrata_modak56207ce2009-03-23 13:35:39 +0000202 /* For testing purposes, it may have been useful to run this program
203 as set-user-ID-root so that a directory file descriptor could be
204 opened as root. (This allows us to obtain a file descriptor even
205 if normal user doesn't have permissions on the file.) Now we
206 reset to the real UID before making the utimensat() call, so that
207 the permission checking for the utimensat() call is performed
208 under that UID. */
subrata_modak27439682008-06-06 08:44:40 +0000209
subrata_modak56207ce2009-03-23 13:35:39 +0000210 if (geteuid() == 0) {
211 uid_t u;
subrata_modak27439682008-06-06 08:44:40 +0000212
subrata_modak56207ce2009-03-23 13:35:39 +0000213 u = getuid();
subrata_modak27439682008-06-06 08:44:40 +0000214
subrata_modak56207ce2009-03-23 13:35:39 +0000215 if (verbose)
216 printf("Resetting UIDs to %ld\n", (long)u);
subrata_modak27439682008-06-06 08:44:40 +0000217
subrata_modak56207ce2009-03-23 13:35:39 +0000218 if (setresuid(u, u, u) == -1)
219 errExit("setresuid");
220 }
subrata_modak27439682008-06-06 08:44:40 +0000221
subrata_modak56207ce2009-03-23 13:35:39 +0000222 /* Display information allowing user to verify arguments for call */
subrata_modak27439682008-06-06 08:44:40 +0000223
subrata_modak56207ce2009-03-23 13:35:39 +0000224 if (verbose) {
225 printf("dirfd is %d\n", dirfd);
226 printf("pathname is %s\n", pathname);
227 printf("tsp is %p", tsp);
228 if (tsp != NULL) {
229 printf("; struct = { %ld, %ld } { %ld, %ld }",
230 (long)tsp[0].tv_sec, (long)tsp[0].tv_nsec,
231 (long)tsp[1].tv_sec, (long)tsp[1].tv_nsec);
232 }
233 printf("\n");
234 printf("flags is %d\n", flags);
235 }
subrata_modak27439682008-06-06 08:44:40 +0000236
subrata_modak56207ce2009-03-23 13:35:39 +0000237 /* Make the call and see what happened */
subrata_modak27439682008-06-06 08:44:40 +0000238
subrata_modak56207ce2009-03-23 13:35:39 +0000239 if (utimensat_sc(dirfd, pathname, tsp, flags) == -1) {
240 if (errno == EPERM) {
241 if (verbose)
242 printf("utimensat() failed with EPERM\n");
243 else
244 printf("EPERM\n");
245 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000246
subrata_modak56207ce2009-03-23 13:35:39 +0000247 } else if (errno == EACCES) {
248 if (verbose)
249 printf("utimensat() failed with EACCES\n");
250 else
251 printf("EACCES\n");
252 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000253
subrata_modak56207ce2009-03-23 13:35:39 +0000254 } else if (errno == EINVAL) {
255 if (verbose)
256 printf("utimensat() failed with EINVAL\n");
257 else
258 printf("EINVAL\n");
259 exit(EXIT_FAILURE);
subrata_modak27439682008-06-06 08:44:40 +0000260
subrata_modak56207ce2009-03-23 13:35:39 +0000261 } else { /* Unexpected failure case from utimensat() */
262 errExit("utimensat");
263 }
264 }
subrata_modak27439682008-06-06 08:44:40 +0000265
subrata_modak56207ce2009-03-23 13:35:39 +0000266 if (verbose)
267 printf("utimensat() succeeded\n");
subrata_modak27439682008-06-06 08:44:40 +0000268
subrata_modak56207ce2009-03-23 13:35:39 +0000269 if (stat((pathname != NULL) ? pathname : dirfdPath, &sb) == -1)
270 errExit("stat");
subrata_modak27439682008-06-06 08:44:40 +0000271
subrata_modak56207ce2009-03-23 13:35:39 +0000272 if (verbose) {
273 printf("Last file access: %s", ctime(&sb.st_atime));
274 printf("Last file modification: %s", ctime(&sb.st_mtime));
275 printf("Last status change: %s", ctime(&sb.st_ctime));
subrata_modak27439682008-06-06 08:44:40 +0000276
subrata_modak56207ce2009-03-23 13:35:39 +0000277 } else {
278 printf("SUCCESS %ld %ld\n", (long)sb.st_atime,
279 (long)sb.st_mtime);
280 }
subrata_modak27439682008-06-06 08:44:40 +0000281
subrata_modak56207ce2009-03-23 13:35:39 +0000282 exit(EXIT_SUCCESS);
Garrett Cooper5df02602010-12-21 11:24:30 -0800283}