linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michael Kerrisk <mtk.manpages@googlemail.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>,
	lkml <linux-kernel@vger.kernel.org>,
	Christoph Hellwig <hch@lst.de>,
	Miklos Szeredi <miklos@szeredi.hu>,
	Al Viro <viro@zeniv.linux.org.uk>,
	jamie@shareable.org, Ulrich Drepper <drepper@redhat.com>,
	linux-fsdevel@vger.kernel.org,
	Subrata Modak <subrata@linux.vnet.ibm.com>
Subject: utimensat() non-conformances and fixes [v4] (test suite)
Date: Tue, 03 Jun 2008 22:14:29 +0200	[thread overview]
Message-ID: <4845A625.9000607@gmail.com> (raw)
In-Reply-To: <48454F1D.6060507@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 304 bytes --]

Andrew,

Attached are two files:

test_utimensat.c
a program that can be used to perform command-line-driven tests
of most aspects of the operation of utimensat().

utimensat_tests.sh
a shell script that uses the preceding C program to perform
a battery of tests against utimensat().

Cheers,

Michael



[-- Attachment #2: test_utimensat.c --]
[-- Type: text/x-csrc, Size: 7384 bytes --]

/* test_utimensat.c

   Copyright (C) 2008, Michael Kerrisk <mtk.manpages@gmail.com>
   and Copyright (C) 2008, Linux Foundation

   Licensed under the GPLv2 or later.
  
   A command-line interface for testing the utimensat() system call.

   17 Mar 2008  Initial creation.
   31 May 2008  Reworked for easier test automation.
    2 Jun 2008  Renamed from t_utimensat.c to test_utimensat.c.
*/
#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>

/* We use EXIT_FAILURE for an expected failure from utimensat()
   (e.g., EACCES and EPERM), and one of the following for unexpected
   failures (i.e., something broke in our test setup). */

#define EXIT_bad_usage 3
#define EXIT_failed_syscall 3

#define errExit(msg)    do { perror(msg); exit(EXIT_failed_syscall); \
                        } 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_sc(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, "    -q        Quiet\n");
    fprintf(stderr, "    -w        Open directory file "
            "descriptor with O_RDWR|O_APPEND\n"
            "              (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_bad_usage);
}

int
main(int argc, char *argv[])
{
    int flags, dirfd, opt, oflag;
    struct timespec ts[2];
    struct timespec *tsp;
    char *pathname, *dirfdPath;
    struct stat sb;
    int verbose;

    /* Command-line argument parsing */

    flags = 0;
    verbose = 1;
    dirfd = AT_FDCWD;
    dirfdPath = NULL;
    oflag = O_RDONLY;

    while ((opt = getopt(argc, argv, "d:nqw")) != -1) {
        switch (opt) {
        case 'd':
            dirfdPath = optarg;
            break;

        case 'n':
            flags |= AT_SYMLINK_NOFOLLOW;
            if (verbose)
                printf("Not following symbolic links\n");
            break;

        case 'q':
            verbose = 0;
            break;

        case 'w':
            oflag = O_RDWR | O_APPEND;
            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");

        if (verbose) {
            printf("Opened dirfd %d", oflag);
            if ((oflag & O_ACCMODE) == O_RDWR)
                printf(" O_RDWR");
            if (oflag & O_APPEND)
                printf(" O_APPEND");
            printf(": %s\n", dirfdPath);
        }
    }

    pathname = (strcmp(argv[optind], "NULL") == 0) ?
                        NULL : argv[optind];

    /* Either, we get no values for 'times' fields, in which case
       we give a NULL pointer to utimensat(), or we get four values,
       for secs+nsecs for each of atime and mtime.  The special
       values 'n' and 'o' can be used for tv_nsec settings of
       UTIME_NOW and UTIME_OMIT, respectively. */

    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.  (This allows us to obtain a file descriptor even
       if normal user doesn't have permissions on the file.)  Now we
       reset to the real UID before making the utimensat() call, so that
       the permission checking for the utimensat() call is performed
       under that UID. */

    if (geteuid() == 0) {
        uid_t u;

        u = getuid();

        if (verbose)
            printf("Resetting UIDs to %ld\n", (long) u);

        if (setresuid(u, u, u) == -1)
            errExit("setresuid");
    }

    /* Display information allowing user to verify arguments for call */ 

    if (verbose) {
        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);
    }

    /* Make the call and see what happened */

    if (utimensat_sc(dirfd, pathname, tsp, flags) == -1) {
        if (errno == EPERM) {
            if (verbose)
                printf("utimensat() failed with EPERM\n");
            else
                printf("EPERM\n");
            exit(EXIT_FAILURE);

        } else if (errno == EACCES) {
            if (verbose)
                printf("utimensat() failed with EACCES\n");
            else
                printf("EACCES\n");
            exit(EXIT_FAILURE);

        } else if (errno == EINVAL) {
            if (verbose)
                printf("utimensat() failed with EINVAL\n");
            else
                printf("EINVAL\n");
            exit(EXIT_FAILURE);

        } else {        /* Unexpected failure case from utimensat() */
            errExit("utimensat");
        }
    }

    if (verbose)
        printf("utimensat() succeeded\n");

    if (stat((pathname != NULL) ? pathname : dirfdPath, &sb) == -1)
        errExit("stat");

    if (verbose) {
        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));

    } else {
        printf("SUCCESS %ld %ld\n", (long) sb.st_atime, (long) sb.st_mtime);
    }

    exit(EXIT_SUCCESS);
}


[-- Attachment #3: utimensat_tests.sh --]
[-- Type: application/x-shellscript, Size: 11972 bytes --]

  parent reply	other threads:[~2008-06-03 20:15 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <48454F1D.6060507@gmail.com>
2008-06-03 20:13 ` utimensat() non-conformances and fixes [v4] (patch) Michael Kerrisk
2008-06-03 20:22   ` Andrew Morton
2008-06-03 20:29     ` Michael Kerrisk
2008-06-03 20:14 ` Michael Kerrisk [this message]
     [not found] ` <484569E5.5090108@gmail.com>
2008-06-03 20:15   ` utimensat() non-conformances and fixes [v4] (test results) Michael Kerrisk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4845A625.9000607@gmail.com \
    --to=mtk.manpages@googlemail.com \
    --cc=akpm@linux-foundation.org \
    --cc=drepper@redhat.com \
    --cc=hch@lst.de \
    --cc=jamie@shareable.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=mtk.manpages@gmail.com \
    --cc=subrata@linux.vnet.ibm.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).