build-sys: split _PATH_ADJTIME to two files

This patch introduces:

* _PATH_HWCLOCK_MODE_FILE for clock mode (UTC or LOCAL), default is
   _PATH_ADJTIME (/etc/adjtime).

* _PATH_HWCLOCK_DRIFT_FILE - optional file for clock drift information,
  the default is /var/lib/hwclock/drift. If the file does not exist than
  default to _PATH_HWCLOCK_MODE_FILE.

The both files use 'adjtime' file format for better backward compatibility.

The file /etc/adjtime is de-facto standard and it's used by more 3rd party
utils (e.g. systemd). Unfortunately, keep state files in /etc is bad
idea. This change makes /etc/adjtime read-only for UTC / LOCAL info
and rest is maintained in /var/lib/hwclock/drift.

Note that /var/lib/hwclock/drift is not automatically created. It's up
to downstream (or system admin) to create the file, for example by:

 		cp /etc/adjtime /var/lib/hwclock/drift

otherwise binary will fall back to /etc/adjtime. This idea makes
hwclock backwardly compatible and more portable without recompilation.
(This patch does not implement changes for hwclock.)

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2021-03-05 15:53:22 +01:00
parent 81329c8d1c
commit b200c2aab0
5 changed files with 90 additions and 10 deletions

View file

@ -141,6 +141,8 @@ edit_cmd = sed \
-e 's|@usrsbin_execdir[@]|$(usrsbin_execdir)|g' \
-e 's|@VERSION[@]|$(VERSION)|g' \
-e 's|@ADJTIME_PATH[@]|$(ADJTIME_PATH)|g' \
-e 's|@CLOCKMODE_PATH[@]|$(CLOCKMODE_PATH)|g' \
-e 's|@CLOCKDRIFT_PATH[@]|$(CLOCKDRIFT_PATH)|g' \
-e 's|@LIBUUID_VERSION[@]|$(LIBUUID_VERSION)|g' \
-e 's|@LIBMOUNT_VERSION[@]|$(LIBMOUNT_VERSION)|g' \
-e 's|@LIBMOUNT_MAJOR_VERSION[@]|$(LIBMOUNT_MAJOR_VERSION)|g' \

View file

@ -2572,14 +2572,23 @@ AC_ARG_VAR([SOLIB_LDFLAGS],
[LDFLAGS used for shared libraries])
AC_ARG_VAR([ADJTIME_PATH],
[Path to hwclock adjtime file, default /etc/adjtime])
[Path to adjtime file; fallback if CLOCKMODE_PATH or CLOCKDRIFT_PATH do not exist, default is /etc/adjtime])
AS_IF([test "x$ADJTIME_PATH" = x], [ADJTIME_PATH="/etc/adjtime"])
AC_DEFINE_UNQUOTED([CONFIG_ADJTIME_PATH], "$ADJTIME_PATH", [Path to hwclock adjtime file])
AC_DEFINE_UNQUOTED([CONFIG_ADJTIME_FILE], "$ADJTIME_PATH", [Path to adjtime file])
AC_ARG_VAR([CLOCKMODE_PATH],
[Path to hwclock utc/local setting file, default ADJTIME_PATH])
AS_IF([test "x$CLOCKMODE_PATH" = x], [CLOCKMODE_PATH=$ADJTIME_PATH])
AC_DEFINE_UNQUOTED([CONFIG_HWCLOCK_MODE_FILE], "$CLOCKMODE_PATH", [Path to hwclock utc/local mode file])
AC_ARG_VAR([CLOCKDRIFT_PATH],
[Path to hwclock drift status file, default /var/lib/hwclock/drift])
AS_IF([test "x$CLOCKDRIFT_PATH" = x], [CLOCKDRIFT_PATH="/var/lib/hwclock/drift"])
AC_DEFINE_UNQUOTED([CONFIG_HWCLOCK_DRIFT_FILE], "$CLOCKDRIFT_PATH", [Path to hwclock drift status file])
LIBS=""
AC_CONFIG_HEADERS([config.h])
#

View file

@ -156,11 +156,9 @@
#define _PATH_DEV_BYPARTUUID "/dev/disk/by-partuuid"
/* hwclock paths */
#ifdef CONFIG_ADJTIME_PATH
# define _PATH_ADJTIME CONFIG_ADJTIME_PATH
#else
# define _PATH_ADJTIME "/etc/adjtime"
#endif
#define _PATH_HWCLOCK_DRIFT_FILE CONFIG_HWCLOCK_DRIFT_FILE
#define _PATH_HWCLOCK_MODE_FILE CONFIG_HWCLOCK_MODE_FILE
#define _PATH_ADJTIME CONFIG_ADJTIME_FILE
#ifdef __ia64__
# define _PATH_RTC_DEV "/dev/efirtc"

View file

@ -89,4 +89,8 @@ int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, si
extern time_t timegm(struct tm *tm);
#endif
const char *ul_hwclock_get_drift_file(void);
const char *ul_hwclock_get_mode_file(void);
int ul_hwclock_mode_is_utc(const char *modefile, int *rc);
#endif /* UTIL_LINUX_TIME_UTIL_H */

View file

@ -29,6 +29,7 @@
#include "nls.h"
#include "strutils.h"
#include "timeutils.h"
#include "pathnames.h"
#define WHITESPACE " \t\n\r"
@ -568,6 +569,59 @@ time_t timegm(struct tm *tm)
}
#endif /* HAVE_TIMEGM */
/* hwclock drift information */
const char *ul_hwclock_get_drift_file(void)
{
if (access(_PATH_HWCLOCK_DRIFT_FILE, F_OK) == 0)
return _PATH_HWCLOCK_DRIFT_FILE;
return ul_hwclock_get_mode_file();
}
const char *ul_hwclock_get_mode_file(void)
{
if (strcmp(_PATH_HWCLOCK_MODE_FILE, _PATH_ADJTIME) != 0
&& access(_PATH_HWCLOCK_MODE_FILE, F_OK) == 0)
return _PATH_HWCLOCK_MODE_FILE;
return _PATH_ADJTIME; /* backward compatible default */
}
int ul_hwclock_mode_is_utc(const char *modefile, int *rc)
{
FILE *fp = NULL;
char linebuf[8];
*rc = EINVAL;
if (!modefile)
modefile = ul_hwclock_get_mode_file();
fp = fopen(modefile, "r");
if (!fp) {
*rc = errno;
goto dflt;
}
if (skip_fline(fp) || skip_fline(fp)) /* skip two lines */
goto dflt;
if (!fgets(linebuf, sizeof linebuf, fp)) /* read 3rd line */
goto dflt;
fclose(fp);
fp = NULL;
if (strncmp(linebuf, "LOCAL", 5) == 0) {
*rc = 0;
return 0;
}
if (strncmp(linebuf, "UTC", 3) == 0)
*rc = 0;
dflt:
if (fp)
fclose(fp);
return 1;
}
#ifdef TEST_PROGRAM_TIMEUTILS
int main(int argc, char *argv[])
@ -576,16 +630,29 @@ int main(int argc, char *argv[])
char buf[ISO_BUFSIZ];
if (argc < 2) {
fprintf(stderr, "usage: %s [<time> [<usec>]] | [--timestamp <str>]\n", argv[0]);
fprintf(stderr, "usage: %1$s <time> [<usec>]\n"
" %1$s --timestamp <str>\n"
" %1$s --clockmode\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "--timestamp") == 0) {
if (strcmp(argv[1], "--clockmode") == 0) {
int rc = 0,
utc = ul_hwclockmode_is_utc(NULL, &rc);
printf("%s: mode is %s [rc=%d]\n",
ul_hwclock_get_mode_file(),
utc ? "UTC" : "LOCAL", rc);
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
} else if (strcmp(argv[1], "--timestamp") == 0) {
usec_t usec = 0;
parse_timestamp(argv[2], &usec);
tv.tv_sec = (time_t) (usec / 1000000);
tv.tv_usec = usec % 1000000;
} else {
tv.tv_sec = strtos64_or_err(argv[1], "failed to parse <time>");
if (argc == 3)