We now warn about clock skews

rc-update -u will force a regen of the dep tree
rc_newer_than and rc_olderthan now take another two parameters for newest/oldest file and mtime
This commit is contained in:
Roy Marples 2009-01-12 23:53:13 +00:00
parent 2243c01390
commit 3d37005a3d
11 changed files with 147 additions and 70 deletions

View File

@ -1,11 +1,18 @@
#!@PREFIX@/sbin/runscript
# Copyright 2007-2008 Roy Marples <roy@marples.name>
# Copyright 2007-2009 Roy Marples <roy@marples.name>
# All rights reserved. Released under the 2-clause BSD license.
description="Saves the caches OpenRC uses to non volatile storage"
start()
{
if [ -e "${RC_SVCDIR}"/clock-skewed ]; then
ewarn "WARNING: clock skew detected!"
if ! yesno "savecache_skewed"; then
eerror "Not saving deptree cache"
return 1
fi
fi
ebegin "Saving dependency cache"
if [ ! -d "${RC_LIBDIR}"/cache ]; then
rm -rf "${RC_LIBDIR}"/cache

View File

@ -1,4 +1,4 @@
.\" Copyright 2007-2008 Roy Marples
.\" Copyright 2007-2009 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd Jan 15, 2008
.Dd Jan 10, 2009
.Dt RC-UPDATE 8 SMM
.Os OpenRC
.Sh NAME
@ -38,6 +38,7 @@
.Ar service
.Op Ar runlevel ...
.Nm
.Op Fl u , -update
.Op Fl v , -verbose
.Ar show
.Op Ar runlevel ...
@ -53,7 +54,7 @@ or
directories. They must also conform to the OpenRC runscript standard.
.Pp
.Bl -tag -width "Fl a , -delete service"
.It Fl a , -add Ar service
.It Ar add Ar service
Add the
.Ar service
to the
@ -72,6 +73,10 @@ Show all enabled services and the runlevels they belong to. If you specify
runlevels to show, then only those will be included in the output.
.It Fl v , -verbose
Show all services.
.It Fl u , -update
Forces an update of the dependency tree cache.
This may be needed in the even of clock skew (a file in /etc is newer than the
system clock).
.El
.Sh SEE ALSO
.Xr rc 8 ,

View File

@ -4,7 +4,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -544,7 +544,8 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options)
librc_hidden_def(rc_deptree_order)
static bool
mtime_check(const char *source, const char *target, bool newer)
mtime_check(const char *source, const char *target, bool newer,
char *file, time_t *rel)
{
struct stat buf;
time_t mtime;
@ -565,16 +566,32 @@ mtime_check(const char *source, const char *target, bool newer)
if (newer) {
if (mtime < buf.st_mtime)
return false;
retval = false;
if (rel != NULL) {
if (*rel < buf.st_mtime) {
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
} else
return retval;
} else {
if (mtime > buf.st_mtime)
return false;
retval = false;
if (rel != NULL) {
if (*rel > buf.st_mtime) {
if (file)
strlcpy(file, target, PATH_MAX);
*rel = buf.st_mtime;
}
} else
return retval;
}
/* If not a dir then reset errno */
if (!(dp = opendir(target))) {
errno = serrno;
return true;
return retval;
}
/* Check all the entries in the dir */
@ -582,26 +599,30 @@ mtime_check(const char *source, const char *target, bool newer)
if (d->d_name[0] == '.')
continue;
snprintf(path, sizeof(path), "%s/%s", target, d->d_name);
retval = mtime_check(source, path, newer);
if (!retval)
if (!mtime_check(source, path, newer, file, rel)) {
retval = false;
if (rel == NULL)
break;
}
}
closedir(dp);
return retval;
}
bool
rc_newer_than(const char *source, const char *target)
rc_newer_than(const char *source, const char *target,
char *file, time_t *newest)
{
return mtime_check(source, target, true);
return mtime_check(source, target, true, file, newest);
}
librc_hidden_def(rc_newer_than)
bool
rc_older_than(const char *source, const char *target)
rc_older_than(const char *source, const char *target,
char *file, time_t *oldest)
{
return mtime_check(source, target, false);
return mtime_check(source, target, false, file, oldest);
}
librc_hidden_def(rc_older_than)
@ -638,7 +659,7 @@ static const char *const depdirs[] =
};
bool
rc_deptree_update_needed(void)
rc_deptree_update_needed(char *file, time_t *newest)
{
bool newer = false;
RC_STRINGLIST *config;
@ -652,30 +673,38 @@ rc_deptree_update_needed(void)
/* Quick test to see if anything we use has changed and we have
* data in our deptree */
if (!existss(RC_DEPTREE_CACHE) ||
!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR) ||
!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR) ||
if (!existss(RC_DEPTREE_CACHE))
return true;
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR, file, newest))
newer = true;
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR, file, newest))
newer = true;
#ifdef RC_PKG_INITDIR
!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR) ||
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR, file, newest))
newer = true;
#endif
#ifdef RC_PKG_CONFDIR
!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR) ||
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR, file, newest))
newer = true;
#endif
#ifdef RC_LOCAL_INITDIR
!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR) ||
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR, file, newest))
newer = true;
#endif
#ifdef RC_LOCAL_CONFDIR
!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR) ||
if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR, file, newest))
newer = true;
#endif
!rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf"))
return true;
if (!rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf", file, newest))
newer = true;
/* Some init scripts dependencies change depending on config files
* outside of baselayout, like syslog-ng, so we check those too. */
config = rc_config_list(RC_DEPCONFIG);
TAILQ_FOREACH(s, config, entries) {
if (!rc_newer_than(RC_DEPTREE_CACHE, s->value)) {
if (!rc_newer_than(RC_DEPTREE_CACHE, s->value, file, newest)) {
newer = true;
if (newest == NULL)
break;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -304,25 +304,31 @@ typedef void *RC_DEPTREE;
/*! Check to see if source is newer than target.
* If target is a directory then we traverse it and it's children.
* time_t returns the time of the newest file found if newer.
* @return true if source is newer than target, otherwise false */
bool rc_newer_than(const char *, const char *);
bool rc_newer_than(const char *, const char *, char *, time_t *);
/*! Check to see if source is newer than target.
/*! Check to see if source is older than target.
* If target is a directory then we traverse it and it's children.
* @return true if source is newer than target, otherwise false */
bool rc_older_than(const char *, const char *);
* time_t returns the time of the oldest file found if older.
* @return true if source is older than target, otherwise false */
bool rc_older_than(const char *, const char *, char *, time_t *);
/*! Update the cached dependency tree if it's older than any init script,
* its configuration file or an external configuration file the init script
* has specified.
* time_t returns the time of the newest file that the dependency tree
* will be checked against.
* @return true if successful, otherwise false */
bool rc_deptree_update(void);
/*! Check if the cached dependency tree is older than any init script,
* its configuration file or an external configuration file the init script
* has specified.
* @param buffer of PATH_MAX to store newest file
* @param mtime of newest file
* @return true if it needs updating, otherwise false */
bool rc_deptree_update_needed(void);
bool rc_deptree_update_needed(char *, time_t *);
/*! Load the cached dependency tree and return a pointer to it.
* This pointer should be freed with rc_deptree_free when done.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -39,7 +39,7 @@ int start_stop_daemon(int, char **);
void run_applets(int, char **);
/* Handy function so we can wrap einfo around our deptree */
RC_DEPTREE *_rc_deptree_load (int *);
RC_DEPTREE *_rc_deptree_load (int, int *);
/* Test to see if we can see pid 1 or not */
bool _rc_can_find_pids(void);

View File

@ -7,7 +7,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -451,7 +451,7 @@ void run_applets(int argc, char **argv)
if (argc < 3)
exit (EXIT_FAILURE);
while (i < argc) {
if (!rc_newer_than(argv[1], argv[i++]))
if (!rc_newer_than(argv[1], argv[i++], NULL, NULL))
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
@ -461,7 +461,7 @@ void run_applets(int argc, char **argv)
if (argc < 3)
exit (EXIT_FAILURE);
while (i < argc) {
if (!rc_newer_than(argv[1], argv[i++]))
if (!rc_newer_than(argv[1], argv[i++], NULL, NULL))
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);

View File

@ -4,7 +4,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -29,17 +29,21 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include "builtins.h"
#include "einfo.h"
@ -49,13 +53,19 @@
extern const char *applet;
RC_DEPTREE *
_rc_deptree_load(int *regen) {
_rc_deptree_load(int force, int *regen) {
int fd;
int retval;
int serrno = errno;
int merrno;
time_t t;
char file[PATH_MAX];
struct stat st;
struct utimbuf ut;
FILE *fp;
if (rc_deptree_update_needed()) {
t = 0;
if (rc_deptree_update_needed(file, &t) || force != 0) {
/* Test if we have permission to update the deptree */
fd = open(RC_DEPTREE_CACHE, O_WRONLY);
merrno = errno;
@ -67,8 +77,30 @@ _rc_deptree_load(int *regen) {
if (regen)
*regen = 1;
ebegin("Caching service dependencies");
retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree");
retval = rc_deptree_update() ? 0 : -1;
eend (retval, "Failed to update the dependency tree");
if (retval == 0) {
stat(RC_DEPTREE_CACHE, &st);
if (st.st_mtime < t) {
eerror("Clock skew detected with `%s'", file);
eerrorn("Adjusting mtime of `" RC_DEPTREE_CACHE
"' to %s", ctime(&t));
fp = fopen(RC_DEPTREE_SKEWED, "w");
if (fp != NULL) {
fprintf(fp, RC_DEPTREE_SKEWED "\n");
fclose(fp);
}
ut.actime = t;
ut.modtime = t;
utime(RC_DEPTREE_CACHE, &ut);
} else {
if (exists(RC_DEPTREE_SKEWED))
unlink(RC_DEPTREE_SKEWED);
}
}
if (force == -1 && regen != NULL)
*regen = retval;
}
return rc_deptree_load();
}
@ -104,9 +136,8 @@ rc_depend(int argc, char **argv)
RC_STRINGLIST *depends;
RC_STRING *s;
RC_DEPTREE *deptree = NULL;
int options = RC_DEP_TRACE;
int options = RC_DEP_TRACE, update = 0;
bool first = true;
bool update = false;
char *runlevel = xstrdup(getenv("RC_RUNLEVEL"));
int opt;
char *token;
@ -130,7 +161,7 @@ rc_depend(int argc, char **argv)
rc_stringlist_add(types, token);
break;
case 'u':
update = true;
update = 1;
break;
case 'T':
options &= RC_DEP_TRACE;
@ -140,15 +171,7 @@ rc_depend(int argc, char **argv)
}
}
if (update) {
ebegin("Caching service dependencies");
update = rc_deptree_update();
eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
if (!update)
eerrorx("Failed to update the dependency tree");
}
if (!(deptree = _rc_deptree_load(NULL)))
if (!(deptree = _rc_deptree_load(update, NULL)))
eerrorx("failed to load deptree");
if (!runlevel)

View File

@ -4,7 +4,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -140,7 +140,7 @@ print_services(const char *runlevel, RC_STRINGLIST *svcs)
if (!svcs)
return;
if (!deptree)
deptree = _rc_deptree_load(NULL);
deptree = _rc_deptree_load(0, NULL);
if (!deptree) {
TAILQ_FOREACH(s, svcs, entries)
if (!runlevel ||
@ -260,7 +260,7 @@ rc_status(int argc, char **argv)
}
/* Output the services in the order in which they would start */
deptree = _rc_deptree_load(NULL);
deptree = _rc_deptree_load(0, NULL);
TAILQ_FOREACH(l, levels, entries) {
print_level(l->value);

View File

@ -4,7 +4,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -138,11 +138,13 @@ show(RC_STRINGLIST *runlevels, bool verbose)
"Usage: rc-update [options] add service <runlevel>\n" \
" rc-update [options] del service <runlevel>\n" \
" rc-update [options] show"
#define getoptstring getoptstring_COMMON
#define getoptstring "u" getoptstring_COMMON
static const struct option longopts[] = {
{ "update", 0, NULL, 'u' },
longopts_COMMON
};
static const char * const longopts_help[] = {
"Force an update of the dependency tree",
longopts_help_COMMON
};
#include "_usage.c"
@ -167,8 +169,11 @@ rc_update(int argc, char **argv)
int ret;
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
longopts, (int *)0)) != -1)
switch (opt) {
case 'u':
_rc_deptree_load(-1, &ret);
return ret;
case_RC_COMMON_GETOPT
}

View File

@ -9,7 +9,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -944,8 +944,10 @@ main(int argc, char **argv)
}
/* Load our deptree */
if ((deptree = _rc_deptree_load(&regen)) == NULL)
if ((deptree = _rc_deptree_load(0, &regen)) == NULL)
eerrorx("failed to load deptree");
if (exists(RC_DEPTREE_SKEWED))
ewarn("WARNING: clock skew detected!");
/* Clean the failed services state dir */
clean_failed();

View File

@ -4,7 +4,7 @@
*/
/*
* Copyright 2007-2008 Roy Marples <roy@marples.name>
* Copyright 2007-2009 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -748,7 +748,7 @@ svc_start(bool deps)
depoptions |= RC_DEP_STRICT;
if (deps) {
if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL))
eerrorx("failed to load deptree");
if (!types_b)
setup_types();
@ -977,7 +977,7 @@ svc_stop(bool deps)
if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT)
depoptions |= RC_DEP_STRICT;
if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL))
eerrorx("failed to load deptree");
if (!types_m)
@ -1368,7 +1368,7 @@ runscript(int argc, char **argv)
depoptions |= RC_DEP_STRICT;
if (!deptree &&
((deptree = _rc_deptree_load(NULL)) == NULL))
((deptree = _rc_deptree_load(0, NULL)) == NULL))
eerrorx("failed to load deptree");
tmplist = rc_stringlist_new();