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 #!@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. # All rights reserved. Released under the 2-clause BSD license.
description="Saves the caches OpenRC uses to non volatile storage" description="Saves the caches OpenRC uses to non volatile storage"
start() 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" ebegin "Saving dependency cache"
if [ ! -d "${RC_LIBDIR}"/cache ]; then if [ ! -d "${RC_LIBDIR}"/cache ]; then
rm -rf "${RC_LIBDIR}"/cache rm -rf "${RC_LIBDIR}"/cache

View File

@ -1,4 +1,4 @@
.\" Copyright 2007-2008 Roy Marples .\" Copyright 2007-2009 Roy Marples
.\" All rights reserved .\" All rights reserved
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" 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 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Jan 15, 2008 .Dd Jan 10, 2009
.Dt RC-UPDATE 8 SMM .Dt RC-UPDATE 8 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -38,6 +38,7 @@
.Ar service .Ar service
.Op Ar runlevel ... .Op Ar runlevel ...
.Nm .Nm
.Op Fl u , -update
.Op Fl v , -verbose .Op Fl v , -verbose
.Ar show .Ar show
.Op Ar runlevel ... .Op Ar runlevel ...
@ -53,7 +54,7 @@ or
directories. They must also conform to the OpenRC runscript standard. directories. They must also conform to the OpenRC runscript standard.
.Pp .Pp
.Bl -tag -width "Fl a , -delete service" .Bl -tag -width "Fl a , -delete service"
.It Fl a , -add Ar service .It Ar add Ar service
Add the Add the
.Ar service .Ar service
to the 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. runlevels to show, then only those will be included in the output.
.It Fl v , -verbose .It Fl v , -verbose
Show all services. 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 .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr rc 8 , .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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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) librc_hidden_def(rc_deptree_order)
static bool 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; struct stat buf;
time_t mtime; time_t mtime;
@ -565,16 +566,32 @@ mtime_check(const char *source, const char *target, bool newer)
if (newer) { if (newer) {
if (mtime < buf.st_mtime) 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 { } else {
if (mtime > buf.st_mtime) 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 not a dir then reset errno */
if (!(dp = opendir(target))) { if (!(dp = opendir(target))) {
errno = serrno; errno = serrno;
return true; return retval;
} }
/* Check all the entries in the dir */ /* 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] == '.') if (d->d_name[0] == '.')
continue; continue;
snprintf(path, sizeof(path), "%s/%s", target, d->d_name); snprintf(path, sizeof(path), "%s/%s", target, d->d_name);
retval = mtime_check(source, path, newer); if (!mtime_check(source, path, newer, file, rel)) {
if (!retval) retval = false;
break; if (rel == NULL)
break;
}
} }
closedir(dp); closedir(dp);
return retval; return retval;
} }
bool 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) librc_hidden_def(rc_newer_than)
bool 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) librc_hidden_def(rc_older_than)
@ -638,7 +659,7 @@ static const char *const depdirs[] =
}; };
bool bool
rc_deptree_update_needed(void) rc_deptree_update_needed(char *file, time_t *newest)
{ {
bool newer = false; bool newer = false;
RC_STRINGLIST *config; RC_STRINGLIST *config;
@ -652,31 +673,39 @@ rc_deptree_update_needed(void)
/* Quick test to see if anything we use has changed and we have /* Quick test to see if anything we use has changed and we have
* data in our deptree */ * data in our deptree */
if (!existss(RC_DEPTREE_CACHE) || if (!existss(RC_DEPTREE_CACHE))
!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR) || return true;
!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR) || 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 #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 #endif
#ifdef RC_PKG_CONFDIR #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 #endif
#ifdef RC_LOCAL_INITDIR #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 #endif
#ifdef RC_LOCAL_CONFDIR #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 #endif
!rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf")) if (!rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf", file, newest))
return true; newer = true;
/* Some init scripts dependencies change depending on config files /* Some init scripts dependencies change depending on config files
* outside of baselayout, like syslog-ng, so we check those too. */ * outside of baselayout, like syslog-ng, so we check those too. */
config = rc_config_list(RC_DEPCONFIG); config = rc_config_list(RC_DEPCONFIG);
TAILQ_FOREACH(s, config, entries) { 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; newer = true;
break; if (newest == NULL)
break;
} }
} }
rc_stringlist_free(config); rc_stringlist_free(config);

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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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. /*! Check to see if source is newer than target.
* If target is a directory then we traverse it and it's children. * 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 */ * @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. * If target is a directory then we traverse it and it's children.
* @return true if source is newer than target, otherwise false */ * time_t returns the time of the oldest file found if older.
bool rc_older_than(const char *, const char *); * @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, /*! Update the cached dependency tree if it's older than any init script,
* its configuration file or an external configuration file the init script * its configuration file or an external configuration file the init script
* has specified. * 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 */ * @return true if successful, otherwise false */
bool rc_deptree_update(void); bool rc_deptree_update(void);
/*! Check if the cached dependency tree is older than any init script, /*! Check if the cached dependency tree is older than any init script,
* its configuration file or an external configuration file the init script * its configuration file or an external configuration file the init script
* has specified. * has specified.
* @param buffer of PATH_MAX to store newest file
* @param mtime of newest file
* @return true if it needs updating, otherwise false */ * @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. /*! Load the cached dependency tree and return a pointer to it.
* This pointer should be freed with rc_deptree_free when done. * 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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 **); void run_applets(int, char **);
/* Handy function so we can wrap einfo around our deptree */ /* 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 */ /* Test to see if we can see pid 1 or not */
bool _rc_can_find_pids(void); 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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) if (argc < 3)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
while (i < argc) { 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_SUCCESS);
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -461,7 +461,7 @@ void run_applets(int argc, char **argv)
if (argc < 3) if (argc < 3)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
while (i < argc) { 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_FAILURE);
} }
exit(EXIT_SUCCESS); 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -29,17 +29,21 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <getopt.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h>
#include "builtins.h" #include "builtins.h"
#include "einfo.h" #include "einfo.h"
@ -49,13 +53,19 @@
extern const char *applet; extern const char *applet;
RC_DEPTREE * RC_DEPTREE *
_rc_deptree_load(int *regen) { _rc_deptree_load(int force, int *regen) {
int fd; int fd;
int retval; int retval;
int serrno = errno; int serrno = errno;
int merrno; 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 */ /* Test if we have permission to update the deptree */
fd = open(RC_DEPTREE_CACHE, O_WRONLY); fd = open(RC_DEPTREE_CACHE, O_WRONLY);
merrno = errno; merrno = errno;
@ -67,8 +77,30 @@ _rc_deptree_load(int *regen) {
if (regen) if (regen)
*regen = 1; *regen = 1;
ebegin("Caching service dependencies"); ebegin("Caching service dependencies");
retval = rc_deptree_update(); retval = rc_deptree_update() ? 0 : -1;
eend (retval ? 0 : -1, "Failed to update the dependency tree"); 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(); return rc_deptree_load();
} }
@ -104,9 +136,8 @@ rc_depend(int argc, char **argv)
RC_STRINGLIST *depends; RC_STRINGLIST *depends;
RC_STRING *s; RC_STRING *s;
RC_DEPTREE *deptree = NULL; RC_DEPTREE *deptree = NULL;
int options = RC_DEP_TRACE; int options = RC_DEP_TRACE, update = 0;
bool first = true; bool first = true;
bool update = false;
char *runlevel = xstrdup(getenv("RC_RUNLEVEL")); char *runlevel = xstrdup(getenv("RC_RUNLEVEL"));
int opt; int opt;
char *token; char *token;
@ -130,7 +161,7 @@ rc_depend(int argc, char **argv)
rc_stringlist_add(types, token); rc_stringlist_add(types, token);
break; break;
case 'u': case 'u':
update = true; update = 1;
break; break;
case 'T': case 'T':
options &= RC_DEP_TRACE; options &= RC_DEP_TRACE;
@ -140,15 +171,7 @@ rc_depend(int argc, char **argv)
} }
} }
if (update) { if (!(deptree = _rc_deptree_load(update, NULL)))
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)))
eerrorx("failed to load deptree"); eerrorx("failed to load deptree");
if (!runlevel) 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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) if (!svcs)
return; return;
if (!deptree) if (!deptree)
deptree = _rc_deptree_load(NULL); deptree = _rc_deptree_load(0, NULL);
if (!deptree) { if (!deptree) {
TAILQ_FOREACH(s, svcs, entries) TAILQ_FOREACH(s, svcs, entries)
if (!runlevel || if (!runlevel ||
@ -260,7 +260,7 @@ rc_status(int argc, char **argv)
} }
/* Output the services in the order in which they would start */ /* 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) { TAILQ_FOREACH(l, levels, entries) {
print_level(l->value); 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * 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" \ "Usage: rc-update [options] add service <runlevel>\n" \
" rc-update [options] del service <runlevel>\n" \ " rc-update [options] del service <runlevel>\n" \
" rc-update [options] show" " rc-update [options] show"
#define getoptstring getoptstring_COMMON #define getoptstring "u" getoptstring_COMMON
static const struct option longopts[] = { static const struct option longopts[] = {
{ "update", 0, NULL, 'u' },
longopts_COMMON longopts_COMMON
}; };
static const char * const longopts_help[] = { static const char * const longopts_help[] = {
"Force an update of the dependency tree",
longopts_help_COMMON longopts_help_COMMON
}; };
#include "_usage.c" #include "_usage.c"
@ -167,8 +169,11 @@ rc_update(int argc, char **argv)
int ret; int ret;
while ((opt = getopt_long(argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *)0)) != -1)
switch (opt) { switch (opt) {
case 'u':
_rc_deptree_load(-1, &ret);
return ret;
case_RC_COMMON_GETOPT 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -944,8 +944,10 @@ main(int argc, char **argv)
} }
/* Load our deptree */ /* Load our deptree */
if ((deptree = _rc_deptree_load(&regen)) == NULL) if ((deptree = _rc_deptree_load(0, &regen)) == NULL)
eerrorx("failed to load deptree"); eerrorx("failed to load deptree");
if (exists(RC_DEPTREE_SKEWED))
ewarn("WARNING: clock skew detected!");
/* Clean the failed services state dir */ /* Clean the failed services state dir */
clean_failed(); 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 * All rights reserved
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -748,7 +748,7 @@ svc_start(bool deps)
depoptions |= RC_DEP_STRICT; depoptions |= RC_DEP_STRICT;
if (deps) { if (deps) {
if (!deptree && ((deptree = _rc_deptree_load(NULL)) == NULL)) if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL))
eerrorx("failed to load deptree"); eerrorx("failed to load deptree");
if (!types_b) if (!types_b)
setup_types(); setup_types();
@ -977,7 +977,7 @@ svc_stop(bool deps)
if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT) if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT)
depoptions |= RC_DEP_STRICT; 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"); eerrorx("failed to load deptree");
if (!types_m) if (!types_m)
@ -1368,7 +1368,7 @@ runscript(int argc, char **argv)
depoptions |= RC_DEP_STRICT; depoptions |= RC_DEP_STRICT;
if (!deptree && if (!deptree &&
((deptree = _rc_deptree_load(NULL)) == NULL)) ((deptree = _rc_deptree_load(0, NULL)) == NULL))
eerrorx("failed to load deptree"); eerrorx("failed to load deptree");
tmplist = rc_stringlist_new(); tmplist = rc_stringlist_new();