<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Aug 22, 2020 at 11:22 AM Chris Sarra via Toybox <<a href="mailto:toybox@lists.landley.net">toybox@lists.landley.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This patch introduces a simple watchdog implementation for toybox. We<br>
send the appropriate ioctls to set the relevant timeouts, and intercept<br>
signals to safely shut down if required.<br>
---<br>
 toys/pending/watchdog.c | 128 ++++++++++++++++++++++++++++++++++++++++<br>
 1 file changed, 128 insertions(+)<br>
 create mode 100644 toys/pending/watchdog.c<br>
<br>
diff --git a/toys/pending/watchdog.c b/toys/pending/watchdog.c<br>
new file mode 100644<br>
index 00000000..0813fe69<br>
--- /dev/null<br>
+++ b/toys/pending/watchdog.c<br>
@@ -0,0 +1,128 @@<br>
+/* watchdog - start a watchdog timer with configurable kick frequencies<br>
+<br>
+ Author: Chris Sarra, <a href="mailto:chrissarra@google.com" target="_blank">chrissarra@google.com</a></blockquote><div><br></div><div>not sure why we're both working on a Saturday, but...</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
+ Date: 25 July 2019<br>
+ Ref: <a href="http://kernel.org/doc/Documentation/watchdog/watchdog-api.txt" rel="noreferrer" target="_blank">kernel.org/doc/Documentation/watchdog/watchdog-api.txt</a><br></blockquote><div><br></div><div>use the " * " indent from the other source files?</div><div><br></div><div>also mention that there's precedent in a busybox "watchdog", which this is command-line compatible with?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+USE_WATCHDOG(NEWTOY(watchdog, "Ft#T#", TOYFLAG_NEEDROOT|TOYFLAG_BIN))<br></blockquote><div><br></div><div>huh. i didn't realize that USE_ worked _inside_ the comment! probably best to move it below the comment as is the convention though. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+config WATCHDOG<br>
+  bool "watchdog"<br>
+  default y<br>
+  help<br>
+    usage: watchdog [-F] [-t SW_TIMER_S] [-T HW_TIMER_S] DEV<br>
+<br>
+    Start the watchdog timer at DEV with optional timeout parameters.<br></blockquote><div><br></div><div>(blank line here.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    -F run in the foreground (do not daemonize)<br>
+    -t software timer (in seconds)<br>
+    -T hardware timer (in seconds)<br></blockquote><div><br></div><div>say what the defaults are?</div><div><br></div><div>the busybox help implies that it's possible to use more precision than seconds? afaik from the kernel source and kernel docs, though, that's a lie?</div><div><br></div><div>i think it would help to explain that -T is what you set the hardware watchdog to, and -t is how often you kick it. i didn't get that from either your --help or the busybox --help.</div><div><br></div><div>so something like:</div><div><br></div><div>-T N  Set hardware watchdog to N seconds (default 60).</div><div>-t N   Kick watchdog every N seconds (default 30).</div><div><br></div><div>? (note that it should be a tab between the "-T N" part and the "Set ..." part.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+*/<br>
+#define FOR_watchdog<br>
+#include "toys.h"<br>
+#include "linux/watchdog.h"<br>
+<br>
+// Make sure no DEBUG variable is set; change this if you need debug prints!<br>
+#undef WATCHDOG_DEBUG<br></blockquote><div><br></div><div>delete this or turn it into a -v flag, depending on whether it's still useful now the toy has been written, or was just useful during development? (rtcwake, for example, has this kind of thing in -v, but sleep doesn't.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+// Default timeout values in seconds.<br>
+#define WATCHDOG_SW_TIMER_S_DEFAULT (4)<br>
+#define WATCHDOG_HW_TIMER_S_DEFAULT (60)<br></blockquote><div> </div><div>is there a reason these are different from busybox's defaults, which seem to be 30 and 60?</div><div><br></div><div>also, you can declare defaults in the USE_ line with =30 or =60, letting you remove this and the corresponding code.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+GLOBALS(<br>
+  long hw_timer_s;<br>
+  long sw_timer_s;<br>
+  int fd;<br>
+)<br>
+<br>
+static int intercept_signals(void (*fn)(int)) {<br>
+  int rc = 0;<br>
+  struct sigaction sigact;<br>
+  memset(&sigact, 0, sizeof(sigact));<br>
+  sigact.sa_handler = fn;<br>
+<br>
+  rc = sigaction(SIGTERM, &sigact, NULL);<br>
+#if defined(WATCHDOG_DEBUG)<br>
+  if ( rc ) {<br>
+    printf("failed to create new sigaction for SIGTERM: %d\n", rc);<br>
+  }<br>
+#endif<br>
+  return rc;<br>
+}<br></blockquote><div><br></div><div>(this is already written. see call site below.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+void safe_shutdown(int __attribute__((unused))ignored) {<br>
+  write(TT.fd, "V", 1);<br>
+  close(TT.fd);<br>
+  TT.fd = -1;<br>
+  error_exit("safely exited watchdog.");<br>
+}<br>
+<br>
+void watchdog_main(void) {<br>
+  int rc = 0;<br>
+  long hw_timer_sec = 0;<br>
+  char *watchdog_dev = NULL;<br>
+<br>
+  if ( toys.optc > 0 ) {<br>
+    watchdog_dev = toys.optargs[0];<br>
+#if defined(WATCHDOG_DEBUG)<br>
+    printf("using dev @ '%s'\n", watchdog_dev);<br>
+#endif<br>
+  } else {<br>
+    error_exit("watchdog dev required");<br>
+  }<br></blockquote><div><br></div><div>you can replace all this with <1 at the start of the USE_TOY string. (see sleep.c for an example.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  // Set default values for timeouts if no flags<br>
+  if (!(toys.optflags & FLAG_t)) {<br></blockquote><div><br></div><div>FLAG(t), but you can just put this in the USE_TOY as explained above.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    TT.sw_timer_s = WATCHDOG_SW_TIMER_S_DEFAULT;<br>
+#if defined(WATCHDOG_DEBUG)<br>
+    printf("using default sw_timer_s.\n");<br>
+#endif<br>
+  }<br>
+<br>
+  if (!(toys.optflags & FLAG_T)) {<br>
+    TT.hw_timer_s = WATCHDOG_HW_TIMER_S_DEFAULT;<br>
+#if defined(WATCHDOG_DEBUG)<br>
+    printf("using default hw_timer_s.\n");<br>
+#endif<br>
+  }<br>
+<br>
+#if defined(WATCHDOG_DEBUG)<br>
+    printf("hw timer: %ld seconds\n", TT.hw_timer_s);<br>
+    printf("sw timer: %ld seconds\n", TT.sw_timer_s);<br>
+#endif<br>
+<br>
+  if (!(toys.optflags & FLAG_F)) {<br>
+#if defined(WATCHDOG_DEBUG)<br>
+      printf("daemonizing. so long, foreground!\n");<br>
+#endif<br>
+    // Attempt to daemonize<br>
+    rc = daemon(1, 1);<br>
+    if ( rc ) {<br>
+      perror_exit("failed to daemonize: %d", rc);<br></blockquote><div><br></div><div>rc will always be -1 on failure, so all this can just be `if (!FLAG(F) && daemon(1, 1)) perror_exit("daemon failed");`.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    }<br>
+  }<br>
+<br>
+  // Intercept terminating signals so we can call our shutdown routine first.<br>
+  if ( intercept_signals(safe_shutdown) ) {<br>
+    perror_exit("failed to intercept desired signals: %d", rc);<br>
+  }<br>
+#if defined(WATCHDOG_DEBUG)<br>
+    printf("Successfully intercepted signals.\n");<br>
+#endif<br></blockquote><div><br></div><div>sigatexit()</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  TT.fd = open(watchdog_dev, O_WRONLY);<br>
+  if ( TT.fd == -1 ) {<br>
+    perror_exit("failed to open '%s'", watchdog_dev);<br>
+  }<br></blockquote><div><br></div><div> xopen()</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+#if defined(WDIOC_SETTIMEOUT)<br></blockquote><div><br></div><div>as far as i can tell, this has existed since 2.6 kernels, so you don't need the #if?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  // SETTIMEOUT takes time value in seconds: s = ms / (1000 ms/s)<br>
+  hw_timer_sec = TT.hw_timer_s;<br>
+  xioctl(TT.fd, WDIOC_SETTIMEOUT, (void *)&hw_timer_sec);<br></blockquote><div><br></div><div>(no need for this local if you let USE_TOY do the default for you. even when you can't, you can just assign to TT.whatever.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+#endif // WDIOC_SETTIMEOUT<br>
+<br>
+  // Now that we've got the watchdog device open, kick it periodically.<br>
+  while (1) {<br>
+    write(TT.fd, "\0", 1);<br></blockquote><div><br></div><div>xwrite?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    usleep(TT.sw_timer_s * 1000 * 1000);<br></blockquote><div><br></div><div>isn't this just sleep(TT.sw_timer_s)?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  }<br>
+}<br>
-- <br>
2.28.0.297.g1956fa8f8d-goog<br>
<br>
_______________________________________________<br>
Toybox mailing list<br>
<a href="mailto:Toybox@lists.landley.net" target="_blank">Toybox@lists.landley.net</a><br>
<a href="http://lists.landley.net/listinfo.cgi/toybox-landley.net" rel="noreferrer" target="_blank">http://lists.landley.net/listinfo.cgi/toybox-landley.net</a><br>
</blockquote></div></div>