aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init.d/savecache.in9
-rw-r--r--man/rc-update.811
-rw-r--r--src/librc/librc-depend.c77
-rw-r--r--src/librc/rc.h.in18
-rw-r--r--src/rc/builtins.h4
-rw-r--r--src/rc/rc-applets.c6
-rw-r--r--src/rc/rc-depend.c63
-rw-r--r--src/rc/rc-status.c6
-rw-r--r--src/rc/rc-update.c11
-rw-r--r--src/rc/rc.c6
-rw-r--r--src/rc/runscript.c8
11 files changed, 148 insertions, 71 deletions
diff --git a/init.d/savecache.in b/init.d/savecache.in
index 69c75e98..a10de3c2 100644
--- a/init.d/savecache.in
+++ b/init.d/savecache.in
@@ -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
diff --git a/man/rc-update.8 b/man/rc-update.8
index b7a350dc..524e2d3f 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 7fb6b907..dcb54f52 100644
--- a/src/librc/librc-depend.c
+++ b/src/librc/librc-depend.c
@@ -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)
- 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 6f7c64e0..10122742 100644
--- a/src/librc/rc.h.in
+++ b/src/librc/rc.h.in
@@ -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.
diff --git a/src/rc/builtins.h b/src/rc/builtins.h
index 0cd03d3c..d7fab143 100644
--- a/src/rc/builtins.h
+++ b/src/rc/builtins.h
@@ -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);
diff --git a/src/rc/rc-applets.c b/src/rc/rc-applets.c
index 57d03446..3d6ce90c 100644
--- a/src/rc/rc-applets.c
+++ b/src/rc/rc-applets.c
@@ -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);
diff --git a/src/rc/rc-depend.c b/src/rc/rc-depend.c
index 1cd32ffd..5d10da10 100644
--- a/src/rc/rc-depend.c
+++ b/src/rc/rc-depend.c
@@ -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;
-
- 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 619b68c3..88018262 100644
--- a/src/rc/rc-status.c
+++ b/src/rc/rc-status.c
@@ -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);
diff --git a/src/rc/rc-update.c b/src/rc/rc-update.c
index 64e24000..5a0264cd 100644
--- a/src/rc/rc-update.c
+++ b/src/rc/rc-update.c
@@ -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
}
diff --git a/src/rc/rc.c b/src/rc/rc.c
index d0748a99..b5459601 100644
--- a/src/rc/rc.c
+++ b/src/rc/rc.c
@@ -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();
diff --git a/src/rc/runscript.c b/src/rc/runscript.c
index e5077d8d..b7e9f352 100644
--- a/src/rc/runscript.c
+++ b/src/rc/runscript.c
@@ -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();