Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/ctime.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* 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.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright 2007 Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627/*28* Copyright (c) 2013 by Delphix. All rights reserved.29*/303132#include <sys/types.h>33#include <sys/stat.h>34#ifndef __FreeBSD__35#include <sys/xattr.h>36#endif37#include <utime.h>38#include <stdio.h>39#include <stdlib.h>40#include <unistd.h>41#include <errno.h>42#include <fcntl.h>43#include <libgen.h>44#include <string.h>4546#define ST_ATIME 047#define ST_CTIME 148#define ST_MTIME 24950#define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)5152typedef struct timetest {53int type;54const char *name;55int (*func)(const char *pfile);56} timetest_t;5758static char tfile[BUFSIZ] = { 0 };5960/*61* DESCRIPTION:62* Verify time will be changed correctly after each operation.63*64* STRATEGY:65* 1. Define time test array.66* 2. Loop through each item in this array.67* 3. Verify the time is changed after each operation.68*69*/7071static int72get_file_time(const char *pfile, int what, time_t *ptr)73{74struct stat stat_buf;7576if (pfile == NULL || ptr == NULL) {77return (-1);78}7980if (stat(pfile, &stat_buf) == -1) {81return (-1);82}8384switch (what) {85case ST_ATIME:86*ptr = stat_buf.st_atime;87return (0);88case ST_CTIME:89*ptr = stat_buf.st_ctime;90return (0);91case ST_MTIME:92*ptr = stat_buf.st_mtime;93return (0);94default:95return (-1);96}97}9899static ssize_t100get_dirnamelen(const char *path)101{102const char *end = strrchr(path, '/');103return (end ? end - path : -1);104}105106static int107do_read(const char *pfile)108{109int fd, ret = 0;110char buf[BUFSIZ] = { 0 };111112if (pfile == NULL) {113return (-1);114}115116if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {117return (-1);118}119if (read(fd, buf, sizeof (buf)) == -1) {120(void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "121"%d\n", fd, sizeof (buf), errno);122(void) close(fd);123return (1);124}125(void) close(fd);126127return (ret);128}129130static int131do_write(const char *pfile)132{133int fd, ret = 0;134char buf[BUFSIZ] = "call function do_write()";135136if (pfile == NULL) {137return (-1);138}139140if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {141return (-1);142}143if (write(fd, buf, strlen(buf)) == -1) {144(void) fprintf(stderr, "write(%d, buf, %d) failed with errno "145"%d\n", fd, (int)strlen(buf), errno);146(void) close(fd);147return (1);148}149(void) close(fd);150151return (ret);152}153154static int155do_link(const char *pfile)156{157int ret = 0;158char link_file[BUFSIZ + 16] = { 0 };159160if (pfile == NULL) {161return (-1);162}163164/*165* Figure out source file directory name, and create166* the link file in the same directory.167*/168(void) snprintf(link_file, sizeof (link_file),169"%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file");170171if (link(pfile, link_file) == -1) {172(void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",173pfile, link_file, errno);174return (1);175}176177(void) unlink(link_file);178179return (ret);180}181182static int183do_creat(const char *pfile)184{185int fd, ret = 0;186187if (pfile == NULL) {188return (-1);189}190191if ((fd = creat(pfile, ALL_MODE)) == -1) {192(void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "193"%d\n", pfile, errno);194return (1);195}196(void) close(fd);197198return (ret);199}200201static int202do_utime(const char *pfile)203{204int ret = 0;205206if (pfile == NULL) {207return (-1);208}209210/*211* Times of the file are set to the current time212*/213if (utime(pfile, NULL) == -1) {214(void) fprintf(stderr, "utime(%s, NULL) failed with errno "215"%d\n", pfile, errno);216return (1);217}218219return (ret);220}221222static int223do_chmod(const char *pfile)224{225int ret = 0;226227if (pfile == NULL) {228return (-1);229}230231if (chmod(pfile, ALL_MODE) == -1) {232(void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "233"errno %d\n", pfile, errno);234return (1);235}236237return (ret);238}239240static int241do_chown(const char *pfile)242{243int ret = 0;244245if (pfile == NULL) {246return (-1);247}248249if (chown(pfile, getuid(), getgid()) == -1) {250(void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "251"%d\n", pfile, (int)getuid(), (int)getgid(), errno);252return (1);253}254255return (ret);256}257258#ifndef __FreeBSD__259static int260do_xattr(const char *pfile)261{262int ret = 0;263const char *value = "user.value";264265if (pfile == NULL) {266return (-1);267}268269if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {270(void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "271"%d\n", pfile, (int)getuid(), (int)getgid(), errno);272return (1);273}274return (ret);275}276#endif277278static void279cleanup(void)280{281if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {282(void) unlink(tfile);283}284}285286static timetest_t timetest_table[] = {287{ ST_ATIME, "st_atime", do_read },288{ ST_ATIME, "st_atime", do_utime },289{ ST_MTIME, "st_mtime", do_creat },290{ ST_MTIME, "st_mtime", do_write },291{ ST_MTIME, "st_mtime", do_utime },292{ ST_CTIME, "st_ctime", do_creat },293{ ST_CTIME, "st_ctime", do_write },294{ ST_CTIME, "st_ctime", do_chmod },295{ ST_CTIME, "st_ctime", do_chown },296{ ST_CTIME, "st_ctime", do_link },297{ ST_CTIME, "st_ctime", do_utime },298#ifndef __FreeBSD__299{ ST_CTIME, "st_ctime", do_xattr },300#endif301};302303#define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))304305int306main(void)307{308int i, ret, fd;309const char *penv[] = {"TESTDIR", "TESTFILE0"};310311(void) atexit(cleanup);312313/*314* Get the environment variable values.315*/316for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {317if ((penv[i] = getenv(penv[i])) == NULL) {318(void) fprintf(stderr, "getenv(penv[%d])\n", i);319return (1);320}321}322(void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);323324/*325* If the test file exists, remove it first.326*/327if (access(tfile, F_OK) == 0) {328(void) unlink(tfile);329}330if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {331(void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);332return (1);333}334(void) close(fd);335336for (i = 0; i < NCOMMAND; i++) {337time_t t1, t2;338339/*340* Get original time before operating.341*/342ret = get_file_time(tfile, timetest_table[i].type, &t1);343if (ret != 0) {344(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",345tfile, timetest_table[i].type, ret);346return (1);347}348349/*350* Sleep 2 seconds, then invoke command on given file351*/352(void) sleep(2);353timetest_table[i].func(tfile);354355/*356* Get time after operating.357*/358ret = get_file_time(tfile, timetest_table[i].type, &t2);359if (ret != 0) {360(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",361tfile, timetest_table[i].type, ret);362return (1);363}364365366/*367* Ideally, time change would be exactly two seconds, but allow368* a little slack in case of scheduling delays or similar.369*/370long delta = (long)t2 - (long)t1;371if (delta < 2 || delta > 4) {372(void) fprintf(stderr,373"%s: BAD time change: t1(%ld), t2(%ld)\n",374timetest_table[i].name, (long)t1, (long)t2);375return (1);376} else {377(void) fprintf(stderr,378"%s: good time change: t1(%ld), t2(%ld)\n",379timetest_table[i].name, (long)t1, (long)t2);380}381}382383return (0);384}385386387