Re: [PATCH] utimensat() non-conformances and fixes -- version 2
From: Michael Kerrisk
Date: Fri May 16 2008 - 04:35:24 EST
For completeness here's the test program again:
/* t_utimensat.c
Copyright (C) 2008, Michael Kerrisk <mtk.manpages@xxxxxxxxx>
Licensed under the GPLv2 or later.
A command-line interface for testing the utimensat() system
call.
17 Mar 2008 Initial creation
*/
#define _GNU_SOURCE
#define _ATFILE_SOURCE
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
#define __NR_utimensat 320 /* x86 syscall number */
# define UTIME_NOW ((1l << 30) - 1l)
# define UTIME_OMIT ((1l << 30) - 2l)
static inline int
utimensat(int dirfd, const char *pathname,
const struct timespec times[2], int flags)
{
return syscall(__NR_utimensat, dirfd, pathname, times, flags);
}
static void
usageError(char *progName)
{
fprintf(stderr, "Usage: %s pathname [atime-sec "
"atime-nsec mtime-sec mtime-nsec]\n\n", progName);
fprintf(stderr, "Permitted options are:\n");
fprintf(stderr, " [-d path] "
"open a directory file descriptor"
" (instead of using AT_FDCWD)\n");
fprintf(stderr, " -w Open directory file "
"descriptor with O_RDWR (instead of O_RDONLY)\n");
fprintf(stderr, " -n Use AT_SYMLINK_NOFOLLOW\n");
fprintf(stderr, "\n");
fprintf(stderr, "pathname can be \"NULL\" to use NULL "
"argument in call\n");
fprintf(stderr, "\n");
fprintf(stderr, "Either nsec field can be\n");
fprintf(stderr, " 'n' for UTIME_NOW\n");
fprintf(stderr, " 'o' for UTIME_OMIT\n");
fprintf(stderr, "\n");
fprintf(stderr, "If the time fields are omitted, "
"then a NULL 'times' argument is used\n");
fprintf(stderr, "\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int flags, dirfd, opt, oflag;
struct timespec ts[2];
struct timespec *tsp;
char *pathname, *dirfdPath;
struct stat sb;
flags = 0;
dirfd = AT_FDCWD;
dirfdPath = NULL;
oflag = O_RDONLY;
while ((opt = getopt(argc, argv, "d:nw")) != -1) {
switch (opt) {
case 'd':
dirfdPath = optarg;
break;
case 'n':
flags |= AT_SYMLINK_NOFOLLOW;
printf("Not following symbolic links\n");
break;
case 'w':
oflag = O_RDWR;
break;
default:
usageError(argv[0]);
}
}
if ((optind + 5 != argc) && (optind + 1 != argc))
usageError(argv[0]);
if (dirfdPath != NULL) {
dirfd = open(dirfdPath, oflag);
if (dirfd == -1) errExit("open");
printf("Opened dirfd");
printf(" O_RDWR");
printf(": %s\n", dirfdPath);
}
pathname = (strcmp(argv[optind], "NULL") == 0) ?
NULL : argv[optind];
if (argc == optind + 1) {
tsp = NULL;
} else {
ts[0].tv_sec = atoi(argv[optind + 1]);
if (argv[optind + 2][0] == 'n') {
ts[0].tv_nsec = UTIME_NOW;
} else if (argv[optind + 2][0] == 'o') {
ts[0].tv_nsec = UTIME_OMIT;
} else {
ts[0].tv_nsec = atoi(argv[optind + 2]);
}
ts[1].tv_sec = atoi(argv[optind + 3]);
if (argv[optind + 4][0] == 'n') {
ts[1].tv_nsec = UTIME_NOW;
} else if (argv[optind + 4][0] == 'o') {
ts[1].tv_nsec = UTIME_OMIT;
} else {
ts[1].tv_nsec = atoi(argv[optind + 4]);
}
tsp = ts;
}
/* For testing purposes, it may have been useful to run this
program as set-user-ID-root so that a directory file
descriptor could be opened as root. Now we reset to the
real UID before making the utimensat() call, so that the
permission checking is performed under that UID. */
if (geteuid() == 0) {
uid_t u;
u = getuid();
printf("Resettng UIDs to %ld\n", (long) u);
if (setresuid(u, u, u) == -1)
errExit("setresuid");
}
printf("dirfd is %d\n", dirfd);
printf("pathname is %s\n", pathname);
printf("tsp is %p", tsp);
if (tsp != NULL) {
printf("; struct = { %ld, %ld } { %ld, %ld }",
(long) tsp[0].tv_sec, (long) tsp[0].tv_nsec,
(long) tsp[1].tv_sec, (long) tsp[1].tv_nsec);
}
printf("\n");
printf("flags is %d\n", flags);
if (utimensat(dirfd, pathname, tsp, flags) == -1) {
if (errno == EPERM)
printf("utimensat failed with EPERM\n");
else if (errno == EACCES)
printf("utimensat failed with EACCES\n");
else
perror("utimensat");
exit(EXIT_FAILURE);
}
printf("utimensat() succeeded\n");
if (stat(pathname, &sb) == -1) errExit("stat");
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
printf("Last status change: %s", ctime(&sb.st_ctime));
exit(EXIT_SUCCESS);
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/