On Mon, 3 Jul 2023, Andrej Picej wrote:
Gentle ping.

On 5. 06. 23 10:57, Andrej Picej wrote:
In kernel 5.16 special ioctls were introduced to get/set RTC parameters.
Add option to get/set parameters into busybox version of hwclock.
Implementation is similar to the one already used in linux-utils hwclock
tool.

Example of parameter get use:
$ hwclock -g 2
The RTC parameter 0x2 is set to 0x2.
$ hwclock --param-get bsm
The RTC parameter 0x2 is set to 0x2.

Example of parameter set use:
$ hwclock -p 2=1
The RTC parameter 0x2 will be set to 0x1.
$ hwclock -p bsm=2
The RTC parameter 0x2 will be set to 0x2.

Signed-off-by: Andrej Picej <[email protected]>
---
  include/rtc_.h       |  23 +++++++++
  util-linux/hwclock.c | 119 +++++++++++++++++++++++++++++++++++++++++--
  2 files changed, 137 insertions(+), 5 deletions(-)

diff --git a/include/rtc_.h b/include/rtc_.h
index 24ff536..4b8d9fc 100644
--- a/include/rtc_.h
+++ b/include/rtc_.h
@@ -22,6 +22,11 @@ int rtc_xopen(const char **default_rtc, int flags) FAST_FUNC;
  void rtc_read_tm(struct tm *ptm, int fd) FAST_FUNC;
  time_t rtc_tm2time(struct tm *ptm, int utc) FAST_FUNC;
  +struct hwclock_param {
+       int id;
+       const char *name;
+       const char *help;
+};
    /*
   * Everything below this point has been copied from linux/rtc.h
@@ -46,6 +51,17 @@ struct linux_rtc_wkalrm {
        struct linux_rtc_time time;  /* time the alarm is set to */
  };
  +struct rtc_param {
+       __u64 param;
+       union {
+               __u64 uvalue;
+               __s64 svalue;
+               __u64 ptr;
+       };
+       __u32 index;
+       __u32 __pad;
+};
+
  /*
   * ioctl calls that are permitted to the /dev/rtc interface, if
   * any of the RTC drivers are enabled.
@@ -71,12 +87,19 @@ struct linux_rtc_wkalrm {
#define RTC_WKALM_SET _IOW('p', 0x0f, struct linux_rtc_wkalrm)/* Set wakeup alarm*/ #define RTC_WKALM_RD _IOR('p', 0x10, struct linux_rtc_wkalrm)/* Get wakeup alarm*/ +#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */ +#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */
+
  /* interrupt flags */
  #define RTC_IRQF 0x80 /* any of the following is active */
  #define RTC_PF 0x40
  #define RTC_AF 0x20
  #define RTC_UF 0x10
  +# define RTC_PARAM_FEATURES          0
+# define RTC_PARAM_CORRECTION          1
+# define RTC_PARAM_BACKUP_SWITCH_MODE  2
+
  POP_SAVED_FUNCTION_VISIBILITY
    #endif
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index 723b095..0a49671 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -48,6 +48,19 @@
  # define LIBC_IS_MUSL 0
  #endif
  +static const struct hwclock_param hwclock_params[] =
+{
+       { RTC_PARAM_FEATURES,  "features", "supported features" },
+       { RTC_PARAM_CORRECTION, "correction", "time correction" },
+       { RTC_PARAM_BACKUP_SWITCH_MODE, "bsm", "backup switch mode" },
+       { }
+};
+
+const struct hwclock_param *get_hwclock_params(void)
+{
+       return hwclock_params;
+}
+
    /* diff code is disabled: it's not sys/hw clock diff, it's some useless
   * "time between hwclock was started and we saw CMOS tick" quantity.
@@ -320,6 +333,89 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
                close(rtc);
  }
  +static int resolve_rtc_param_alias(const char *alias, __u64 *value)
+{
+       const struct hwclock_param *param = &hwclock_params[0];
+
+       while (param->name) {
+               if (!strcmp(alias, param->name)) {

Per docs/style-guide.txt, please use strcmp() == 0

+                       *value = param->id;
+                       return 0;
+               }
+               param++;
+       }
+
+       return 1;
+}
+
+static void get_rtc_param(const char **pp_rtcname, const char *rtc_param)
+{
+       int rtc;
+       struct rtc_param param = { .param = 0 };
+
+       if (resolve_rtc_param_alias(rtc_param, &param.param) != 0) {
+               param.param = bb_strtoull(rtc_param, NULL, 0);
+               if (errno)
+ bb_error_msg_and_die("could not convert parameter name: '%s' to number", rtc_param);
+       }
+
+       rtc = rtc_xopen(pp_rtcname, O_RDONLY);
+
+       xioctl(rtc, RTC_PARAM_GET, &param);
+
+       printf("The RTC parameter 0x%jx is set to 0x%jx.\n",
+               (uintmax_t) param.param, (uintmax_t) param.uvalue);
+
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(rtc);
+}
+
+static void set_rtc_param(const char **pp_rtcname, const char *rtc_param)
+{
+       int rtc;
+       int  ret = 1;
+       struct rtc_param param = { .param = 0 };
+       char *tok, *opt = xstrdup(rtc_param);
+
+       /* handle param name */
+       tok = strtok(opt, "=");
+       if (resolve_rtc_param_alias(tok, &param.param) != 0) {
+               param.param = bb_strtoull(tok, NULL, 0);
+               if (errno) {
+ bb_error_msg("could not convert parameter name: '%s' to number", tok);
+                       goto done;
+               }
+       }
+
+       /* handle param value */
+       tok = strtok(NULL, "=");
+       if (!tok) {
+               bb_error_msg("expected <param>=<value>");
+               goto done;
+       }
+       param.uvalue = bb_strtoull(tok, NULL, 0);
+       if (errno) {
+               bb_error_msg("could not convert parameter value to number");
+               goto done;

Could possibly replace all these {bb_error_msg();goto done;} with
bb_error_msg_and_die(), then kill ret?

+       }
+
+       rtc = rtc_xopen(pp_rtcname, O_WRONLY);
+
+       printf("The RTC parameter 0x%jx will be set to 0x%jx.\n",
+               (uintmax_t) param.param, (uintmax_t) param.uvalue);
+
+       xioctl(rtc, RTC_PARAM_SET, &param);
+
+       if (ENABLE_FEATURE_CLEAN_UP)
+               close(rtc);
+
+       ret = 0;
+done:
+       free(opt);
+       if (ret)
+               bb_error_msg_and_die("error: %d", ret);
+}
+
  // hwclock from util-linux 2.36.1
  // hwclock [function] [option...]
  //Functions:
@@ -346,10 +442,10 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
    //usage:#define hwclock_trivial_usage
  //usage:      IF_LONG_OPTS(
-//usage:       "[-swul] [--systz] [-f DEV]"
+//usage: "[-swul] [--systz] [--param-get PARAM] [--param-set PARAM=VAL] [-f DEV]"
  //usage:      )
  //usage:      IF_NOT_LONG_OPTS(
-//usage:       "[-swult] [-f DEV]"
+//usage:       "[-swult] [-g PARAM] [-p PARAM=VAL] [-f DEV]"
  //usage:      )
  //usage:#define hwclock_full_usage "\n\n"
  //usage:       "Show or set hardware clock (RTC)\n"
@@ -360,6 +456,8 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
  //usage:      IF_LONG_OPTS(
  //usage:     "\n --systz Set in-kernel timezone, correct system time"
  //usage:     "\n         if RTC is kept in local time"
+//usage:     "\n  --param-get PARAM       Get RTC parameter"
+//usage:     "\n  --param-set PARAM=VAL   Set RTC parameter"
  //usage:      )
  //usage:     "\n -f DEV  Use specified device (e.g. /dev/rtc2)"
  //usage:     "\n -u      Assume RTC is kept in UTC"
@@ -375,11 +473,14 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
  #define HWCLOCK_OPT_SYSTOHC     0x10
  #define HWCLOCK_OPT_SYSTZ       0x20
  #define HWCLOCK_OPT_RTCFILE     0x40
+#define HWCLOCK_OPT_PARAM_GET   0x80
+#define HWCLOCK_OPT_PARAM_SET   0x100
    int hwclock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  int hwclock_main(int argc UNUSED_PARAM, char **argv)
  {
        const char *rtcname = NULL;
+       const char *param = NULL;
        unsigned opt;
        int utc;
  #if ENABLE_LONG_OPTS
@@ -391,14 +492,18 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
                "systohc\0"   No_argument "w"
                "systz\0"     No_argument "t" /* short opt is non-standard */
                "rtc\0"       Required_argument "f"
+ "param-get\0" Required_argument "g" /* short opt is non-standard */ + "param-set\0" Required_argument "p" /* short opt is non-standard */

Could this be big enough to warrant a feature guard?
e.g. FEATURE_HWCLOCK_SUPPORT_PARAM

                ;
  #endif
        opt = getopt32long(argv,
-               "^""lurswtf:v" /* -v is accepted and ignored */
+               "^""lurswtf:g:p:v" /* -v is accepted and ignored */
                "\0"
-               "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l",
+ "r--wstgp:w--rstgp:s--wrtgp:t--rswgp:g--rswtp:p--rswtg:l--u:u--l",
                hwclock_longopts,
-               &rtcname
+               &rtcname,
+               &param,
+               &param
        );
        /* If -u or -l wasn't given, check if we are using utc */
@@ -413,6 +518,10 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
                from_sys_clock(&rtcname, utc);
        else if (opt & HWCLOCK_OPT_SYSTZ)
                set_kernel_timezone_and_clock(utc, NULL);
+       else if (opt & HWCLOCK_OPT_PARAM_GET)
+               get_rtc_param(&rtcname, param);
+       else if (opt & HWCLOCK_OPT_PARAM_SET)
+               set_rtc_param(&rtcname, param);
        else
                /* default HWCLOCK_OPT_SHOW */
                show_clock(&rtcname, utc);
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to