From 3d37005a3d0c9a90578fcb249b823f08a6c58f49 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Mon, 12 Jan 2009 23:53:13 +0000 Subject: 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 --- init.d/savecache.in | 9 +++++- man/rc-update.8 | 11 +++++-- src/librc/librc-depend.c | 77 +++++++++++++++++++++++++++++++++--------------- src/librc/rc.h.in | 18 +++++++---- src/rc/builtins.h | 4 +-- src/rc/rc-applets.c | 6 ++-- src/rc/rc-depend.c | 63 ++++++++++++++++++++++++++------------- src/rc/rc-status.c | 6 ++-- src/rc/rc-update.c | 11 +++++-- src/rc/rc.c | 6 ++-- src/rc/runscript.c | 8 ++--- 11 files changed, 148 insertions(+), 71 deletions(-) diff --git a/init.d/savecache.in b/init.d/savecache.in index 69c75e9..a10de3c 100644 --- a/init.d/savecache.in +++ b/init.d/savecache.in @@ -1,11 +1,18 @@ #!@PREFIX@/sbin/runscript -# Copyright 2007-2008 Roy Marples +# Copyright 2007-2009 Roy Marples # 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 diff --git a/man/rc-update.8 b/man/rc-update.8 index b7a350d..524e2d3 100644 --- a/man/rc-update.8 +++ b/man/rc-update.8 @@ -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 , diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 7fb6b90..dcb54f5 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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) - break; + 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,31 +673,39 @@ 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; - break; + if (newest == NULL) + break; } } rc_stringlist_free(config); diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in index 6f7c64e..1012274 100644 --- a/src/librc/rc.h.in +++ b/src/librc/rc.h.in @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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. diff --git a/src/rc/builtins.h b/src/rc/builtins.h index 0cd03d3..d7fab14 100644 --- a/src/rc/builtins.h +++ b/src/rc/builtins.h @@ -1,5 +1,5 @@ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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); diff --git a/src/rc/rc-applets.c b/src/rc/rc-applets.c index 57d0344..3d6ce90 100644 --- a/src/rc/rc-applets.c +++ b/src/rc/rc-applets.c @@ -7,7 +7,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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); diff --git a/src/rc/rc-depend.c b/src/rc/rc-depend.c index 1cd32ff..5d10da1 100644 --- a/src/rc/rc-depend.c +++ b/src/rc/rc-depend.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -29,17 +29,21 @@ * SUCH DAMAGE. */ -#include #include +#include +#include -#include #include #include +#include +#include #include #include #include #include +#include #include +#include #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; - - if (rc_deptree_update_needed()) { + time_t t; + char file[PATH_MAX]; + struct stat st; + struct utimbuf ut; + FILE *fp; + + 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) diff --git a/src/rc/rc-status.c b/src/rc/rc-status.c index 619b68c..8801826 100644 --- a/src/rc/rc-status.c +++ b/src/rc/rc-status.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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); diff --git a/src/rc/rc-update.c b/src/rc/rc-update.c index 64e2400..5a0264c 100644 --- a/src/rc/rc-update.c +++ b/src/rc/rc-update.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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 \n" \ " rc-update [options] del service \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 } diff --git a/src/rc/rc.c b/src/rc/rc.c index d0748a9..b545960 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -9,7 +9,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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(®en)) == NULL) + if ((deptree = _rc_deptree_load(0, ®en)) == NULL) eerrorx("failed to load deptree"); + if (exists(RC_DEPTREE_SKEWED)) + ewarn("WARNING: clock skew detected!"); /* Clean the failed services state dir */ clean_failed(); diff --git a/src/rc/runscript.c b/src/rc/runscript.c index e5077d8..b7e9f35 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -4,7 +4,7 @@ */ /* - * Copyright 2007-2008 Roy Marples + * Copyright 2007-2009 Roy Marples * 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(); -- cgit v1.2.3