From: Todd C. Miller Date: Tue, 7 Sep 2004 19:57:00 +0000 (+0000) Subject: Add checks for st_mtim and st_mtimespec and add macros for pulling X-Git-Tag: SUDO_1_6_8p1~31 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c0bfcc95c3fd5cc062b302c0fc2ff60a2150ff95;p=sudo Add checks for st_mtim and st_mtimespec and add macros for pulling the mtime sec and nsec out of struct stat. These are used in sudo_edit() to better tell whether or not the file has changed. --- diff --git a/config.h.in b/config.h.in index 6c6a49e96..1f1b1fcae 100644 --- a/config.h.in +++ b/config.h.in @@ -177,7 +177,7 @@ /* Define if you use Kerberos V. */ #undef HAVE_KERB5 -/* Define if your LDAP needs . (OpenLDAP does not) */ +/* Define to 1 if your LDAP needs . (OpenLDAP does not) */ #undef HAVE_LBER_H /* Define if you use LDAP. */ @@ -309,6 +309,12 @@ /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR +/* Define if your struct stat has an st_mtim member */ +#undef HAVE_ST_MTIM + +/* Define if your struct stat has an st_mtimespec member */ +#undef HAVE_ST_MTIMESPEC + /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF @@ -375,7 +381,7 @@ /* Define if you want the hostname to be entered into the log file. */ #undef HOST_IN_LOG -/* Define if you want to ignore '.' and empty $PATH elements */ +/* Define if you want to ignore '.' and empty PATH elements */ #undef IGNORE_DOT_PATH /* The message given when a bad password is entered. */ @@ -552,6 +558,22 @@ code using `volatile' can become incorrect without. Disable with care. */ #undef volatile +/* + * Macros to pull sec and nsec parts of mtime from struct stat. + */ +#ifdef HAVE_ST_MTIM +# define mtim_getsec(_x) ((_x).st_mtim.tv_sec) +# define mtim_getnsec(_x) ((_x).st_mtim.tv_nsec) +#else +# ifdef HAVE_ST_MTIMESPEC +# define mtim_getsec(_x) ((_x).st_mtimespec.tv_sec) +# define mtim_getnsec(_x) ((_x).st_mtimespec.tv_nsec) +# else +# define mtim_getsec(_x) ((_x).st_mtime) +# define mtim_getnsec(_x) (0) +# endif /* HAVE_ST_MTIMESPEC */ +#endif /* HAVE_ST_MTIM */ + /* * Emulate a subset of waitpid() if we don't have it. */ diff --git a/configure b/configure index 9cfad54ae..72cef7c78 100755 --- a/configure +++ b/configure @@ -26441,6 +26441,191 @@ else fi done + + + + +echo "$as_me:$LINENO: checking for struct stat.st_mtim" >&5 +echo $ECHO_N "checking for struct stat.st_mtim... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_mtim+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_mtim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_mtim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_mtim) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_mtim=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_stat_st_mtim=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_mtim" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_mtim" >&6 +if test $ac_cv_member_struct_stat_st_mtim = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_ST_MTIM 1 +_ACEOF + +else + echo "$as_me:$LINENO: checking for struct stat.st_mtimespec" >&5 +echo $ECHO_N "checking for struct stat.st_mtimespec... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_mtimespec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_mtimespec) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_mtimespec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_mtimespec) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_mtimespec=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_stat_st_mtimespec=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_mtimespec" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_mtimespec" >&6 +if test $ac_cv_member_struct_stat_st_mtimespec = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_ST_MTIMESPEC 1 +_ACEOF + +fi + +fi + cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ diff --git a/configure.in b/configure.in index 77fa87c13..a37319717 100644 --- a/configure.in +++ b/configure.in @@ -1709,6 +1709,9 @@ SUDO_FUNC_FNMATCH(AC_DEFINE(HAVE_FNMATCH, 1, [Define if you have the `fnmatch' f SUDO_FUNC_ISBLANK AC_REPLACE_FUNCS(strerror strcasecmp sigaction strlcpy strlcat closefrom) AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf, , [NEED_SNPRINTF=1]) +AH_TEMPLATE(HAVE_ST_MTIM, [Define if your struct stat has an st_mtim member]) +AH_TEMPLATE(HAVE_ST_MTIMESPEC, [Define if your struct stat has an st_mtimespec member]) +AC_CHECK_MEMBER([struct stat.st_mtim], AC_DEFINE(HAVE_ST_MTIM), [AC_CHECK_MEMBER([struct stat.st_mtimespec], AC_DEFINE([HAVE_ST_MTIMESPEC]))]) dnl dnl Check for the dirfd function/macro. If not found, look for dd_fd in DIR. dnl @@ -2240,6 +2243,22 @@ AH_TOP([#ifndef _SUDO_CONFIG_H #define _SUDO_CONFIG_H]) AH_BOTTOM([/* + * Macros to pull sec and nsec parts of mtime from struct stat. + */ +#ifdef HAVE_ST_MTIM +# define mtim_getsec(_x) ((_x).st_mtim.tv_sec) +# define mtim_getnsec(_x) ((_x).st_mtim.tv_nsec) +#else +# ifdef HAVE_ST_MTIMESPEC +# define mtim_getsec(_x) ((_x).st_mtimespec.tv_sec) +# define mtim_getnsec(_x) ((_x).st_mtimespec.tv_nsec) +# else +# define mtim_getsec(_x) ((_x).st_mtime) +# define mtim_getnsec(_x) (0) +# endif /* HAVE_ST_MTIMESPEC */ +#endif /* HAVE_ST_MTIM */ + +/* * Emulate a subset of waitpid() if we don't have it. */ #ifdef HAVE_WAITPID diff --git a/sudo_edit.c b/sudo_edit.c index c5a638b41..a1893565e 100644 --- a/sudo_edit.c +++ b/sudo_edit.c @@ -17,7 +17,9 @@ #include "config.h" #include +#include #include +#include #include #include #include @@ -49,6 +51,7 @@ #include #include #include +#include #include "sudo.h" @@ -76,9 +79,9 @@ int sudo_edit(argc, argv) struct tempfile { char *tfile; char *ofile; - int tfd; - time_t omtime; /* XXX - use st_mtimespec / st_mtim? */ + struct timespec ots; off_t osize; + int tfd; } *tf; /* @@ -122,11 +125,11 @@ int sudo_edit(argc, argv) i--; continue; } - sb.st_mtime = 0; - sb.st_size = 0; + memset(&sb, 0, sizeof(sb)); } tf[i].ofile = *ap; - tf[i].omtime = sb.st_mtime; + tf[i].ots.tv_sec = mtim_getsec(sb); + tf[i].ots.tv_nsec = mtim_getnsec(sb); tf[i].osize = sb.st_size; if ((cp = strrchr(tf[i].ofile, '/')) != NULL) cp++; @@ -159,9 +162,11 @@ int sudo_edit(argc, argv) * file's mtime. It is better than nothing and we only use the info * to determine whether or not a file has been modified. */ - if (touch(tf[i].tfd, NULL, tf[i].omtime, 0) == -1) { - if (fstat(tf[i].tfd, &sb) == 0) - tf[i].omtime = sb.st_mtime; + if (touch(tf[i].tfd, NULL, tf[i].ots.tv_sec, tf[i].ots.tv_nsec) == -1) { + if (fstat(tf[i].tfd, &sb) == 0) { + tf[i].ots.tv_sec = mtim_getsec(sb); + tf[i].ots.tv_nsec = mtim_getnsec(sb); + } } #endif } @@ -262,7 +267,9 @@ int sudo_edit(argc, argv) } #ifdef HAVE_FSTAT if (fstat(tf[i].tfd, &sb) == 0) { - if (tf[i].osize == sb.st_size && tf[i].omtime == sb.st_mtime) { + if (tf[i].osize == sb.st_size && + tf[i].ots.tv_sec == mtim_getsec(sb) && + tf[i].ots.tv_nsec == mtim_getnsec(sb)) { warnx("%s unchanged", tf[i].ofile); unlink(tf[i].tfile); close(tf[i].tfd);