use utimensat(2) and correct and centralize file times handling.

This commit is contained in:
christos 2012-11-03 15:39:23 +00:00
parent 7639cf466f
commit 0a00da6dcc
2 changed files with 59 additions and 23 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.h,v 1.3 2010/05/07 20:43:27 christos Exp $ */
/* $NetBSD: config.h,v 1.4 2012/11/03 15:39:23 christos Exp $ */
/* Copyright 1988,1990,1993,1994 by Paul Vixie
* All rights reserved
@ -93,6 +93,8 @@
#define HAVE_TM_GMTOFF /*-*/
#define HAVE_FCHOWN /*-*/
#define HAVE_UTIMES /*-*/
#define HAVE_UTIMENSAT
#define _INCOMPLETE_XOPEN_C063
/* if your OS supports a BSD-style login.conf file */
/* #define LOGIN_CAP */

View File

@ -1,4 +1,4 @@
/* $NetBSD: crontab.c,v 1.5 2012/03/04 18:38:31 tron Exp $ */
/* $NetBSD: crontab.c,v 1.6 2012/11/03 15:39:23 christos Exp $ */
/* Copyright 1988,1990,1993,1994 by Paul Vixie
* All rights reserved
@ -25,7 +25,7 @@
#if 0
static char rcsid[] = "Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp";
#else
__RCSID("$NetBSD: crontab.c,v 1.5 2012/03/04 18:38:31 tron Exp $");
__RCSID("$NetBSD: crontab.c,v 1.6 2012/11/03 15:39:23 christos Exp $");
#endif
#endif
@ -137,6 +137,48 @@ main(int argc, char *argv[]) {
/*NOTREACHED*/
}
static void
get_time(const struct stat *st, struct timespec *ts)
{
ts[0].tv_sec = st->st_atime;
ts[0].tv_nsec = st->st_atimensec;
ts[1].tv_sec = st->st_mtime;
ts[1].tv_nsec = st->st_mtimensec;
}
static int
change_time(const char *name, const struct timespec *ts)
{
#if defined(HAVE_UTIMENSAT)
return utimensat(AT_FDCWD, name, ts, 0);
#elif defined(HAVE_UTIMES)
struct timeval tv[2];
TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
return utimes(name, tvs);
#else
struct utimebuf ut;
ut.actime = tv[0].tv_sec;
ut.modtime = tv[1].tv_sec;
return utime(name, &ut);
#endif
}
static int
compare_time(const struct stat *st, const struct timespec *ts2)
{
struct timespec ts1[2];
get_time(st, ts1);
return ts1[1].tv_sec == ts2[1].tv_sec
#if defined(HAVE_UTIMENSAT)
&& ts1[1].tv_nsec == ts2[1].tv_nsec
#elif defined(HAVE_UTIMES)
&& ts1[1].tv_nsec / 1000 = ts2[1].tv_nsec / 1000
#endif
;
}
static void
parse_args(int argc, char *argv[]) {
int argch;
@ -322,10 +364,9 @@ edit_cmd(void) {
int ch, t, x;
sig_t oint, oabrt, oquit, ohup;
struct stat statbuf;
struct utimbuf utimebuf;
long mtimensec;
WAIT_T waiter;
PID_T pid, xpid;
struct timespec ts[2];
log_it(RealUser, Pid, "BEGIN EDIT", User);
if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) {
@ -345,9 +386,7 @@ edit_cmd(void) {
warn("cannot stat crontab file");
goto fatal;
}
utimebuf.actime = statbuf.st_atime;
utimebuf.modtime = statbuf.st_mtime;
mtimensec = statbuf.st_mtimensec;
get_time(&statbuf, ts);
/* Turn off signals. */
ohup = signal(SIGHUP, SIG_IGN);
@ -390,7 +429,8 @@ edit_cmd(void) {
if (fflush(NewCrontab) < OK) {
err(ERROR_EXIT, "cannot flush output for `%s'", Filename);
}
(void)utime(Filename, &utimebuf);
if (change_time(Filename, ts) == -1)
err(ERROR_EXIT, "cannot set time info for `%s'", Filename);
again:
rewind(NewCrontab);
if (ferror(NewCrontab)) {
@ -473,8 +513,7 @@ edit_cmd(void) {
warn("cannot stat `%s'", Filename);
goto fatal;
}
if (utimebuf.modtime == statbuf.st_mtime &&
mtimensec == statbuf.st_mtimensec) {
if (compare_time(&statbuf, ts)) {
warnx("no changes made to crontab");
goto remove;
}
@ -599,7 +638,7 @@ replace_cmd(void) {
*/
(void)fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
(void)fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
(void)fprintf(tmp, "# (Cron version %s -- %s)\n", CRON_VERSION, "$NetBSD: crontab.c,v 1.5 2012/03/04 18:38:31 tron Exp $");
(void)fprintf(tmp, "# (Cron version %s -- %s)\n", CRON_VERSION, "$NetBSD: crontab.c,v 1.6 2012/11/03 15:39:23 christos Exp $");
/* copy the crontab to the tmp
*/
@ -717,18 +756,13 @@ done:
static void
poke_daemon(void) {
#ifdef HAVE_UTIMES
struct timeval tvs[2];
struct timezone tz;
(void) gettimeofday(&tvs[0], &tz);
tvs[1] = tvs[0];
if (utimes(SPOOL_DIR, tvs) < OK)
#else
if (utime(SPOOL_DIR, NULL) < OK)
#endif /* HAVE_UTIMES */
warn("can't update mtime on spooldir %s", SPOOL_DIR);
struct timespec ts[2];
(void) clock_gettime(CLOCK_REALTIME, ts);
ts[1] = ts[0];
if (change_time(SPOOL_DIR, ts) == -1)
warn("can't update times on spooldir %s", SPOOL_DIR);
}
/* int allowed(const char *username, const char *allow_file, const char *deny_file)
* returns TRUE if (allow_file exists and user is listed)
* or (deny_file exists and user is NOT listed).