When logd is restarted while 'logread -f' is running, the
logread process terminates, which cumbers debugging in
different use-cases.

This patch adds re-connect functionality to logread. In
follow mode, when the ustream to logd is disconnected,
instead of terminating, it tries to re-connect to logd
and re-issue the original request.

Signed-off-by: Zefir Kurtisi <zefir.kurt...@neratec.com>
---
v2: in follow mode, don't exit if the initial
    ubus lookup for logd fails

 log/logread.c | 143 +++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 91 insertions(+), 52 deletions(-)

diff --git a/log/logread.c b/log/logread.c
index ad06f2a..8229c98 100644
--- a/log/logread.c
+++ b/log/logread.c
@@ -65,6 +65,10 @@ static int log_type = LOG_STDOUT;
 static int log_size, log_udp, log_follow, log_trailer_null = 0;
 static int log_timestamp;
 static int last_errno = 0;
+static struct ubus_context *ctx;
+static int lines;
+
+static void logread_reconnect_cb(struct uloop_timeout *timeout);
 
 static const char* getcodetext(int value, CODE *codetable) {
        CODE *i;
@@ -268,29 +272,82 @@ static void logread_fd_data_cb(struct ustream *s, int 
bytes)
        }
 }
 
+/*
+ * Reconnect Handling
+ * while following log
+ * - after logd removal
+ *   - destroy ustream
+ *   - cyclically try to re-connect to new logd object
+ *   - re-issue original request
+ *
+ * Note: if a re-connection appears while a 'logread -l' request is active, the
+ *       number of returned lines will not match (i.e. you get some lines from
+ *       the old instance plus the number of lines requested from the new one)
+ */
+
+/* flag to prevent printing error messages during reconnect cycles */
+static int object_reconnect_active;
+
+static void logread_restart_reconnect_timer(struct uloop_timeout *timeout)
+{
+       const int LOG_RECONNECT_TIMEOUT_MS = 250;
+       uloop_timeout_set(timeout, LOG_RECONNECT_TIMEOUT_MS);
+}
+
 static void logread_fd_state_cb(struct ustream *s)
 {
-       uloop_end();
+       static struct uloop_timeout ubus_timer;
+       /* force re-opening of stream */
+       s->free(s);
+
+       object_reconnect_active = 1;
+       ubus_timer.cb = logread_reconnect_cb;
+       logread_restart_reconnect_timer(&ubus_timer);
 }
 
 static void logread_fd_cb(struct ubus_request *req, int fd)
 {
        static struct ustream_fd test_fd;
-
        test_fd.stream.notify_read = logread_fd_data_cb;
        test_fd.stream.notify_state = logread_fd_state_cb;
        ustream_fd_init(&test_fd, fd);
 }
 
-int main(int argc, char **argv)
+static int logread_process(void)
 {
+       static struct blob_buf b;
        static struct ubus_request req;
-       struct ubus_context *ctx;
        uint32_t id;
+       int ret = ubus_lookup_id(ctx, "log", &id);
+       if (ret) {
+               if (!object_reconnect_active)
+                       fprintf(stderr, "Failed to find log object\n");
+               return ret;
+       }
+       blob_buf_init(&b, 0);
+       blobmsg_add_u8(&b, "stream", 1);
+       if (lines)
+               blobmsg_add_u32(&b, "lines", lines);
+       else if (log_follow)
+               blobmsg_add_u32(&b, "lines", 0);
+
+       ubus_invoke_async(ctx, id, "read", b.head, &req);
+       req.fd_cb = logread_fd_cb;
+       ubus_complete_request_async(ctx, &req);
+
+       return 0;
+}
+
+static void logread_reconnect_cb(struct uloop_timeout *timeout)
+{
+       if (logread_process())
+               logread_restart_reconnect_timer(timeout);
+}
+
+int main(int argc, char **argv)
+{
        const char *ubus_socket = NULL;
-       int ch, ret, lines = 0;
-       static struct blob_buf b;
-       int tries = 5;
+       int ch, ret;
 
        signal(SIGPIPE, SIG_IGN);
 
@@ -354,58 +411,40 @@ int main(int argc, char **argv)
        }
        ubus_add_uloop(ctx);
 
-       /* ugly ugly ugly ... we need a real reconnect logic */
-       do {
-               ret = ubus_lookup_id(ctx, "log", &id);
-               if (ret) {
-                       fprintf(stderr, "Failed to find log object: %s\n", 
ubus_strerror(ret));
-                       sleep(1);
-                       continue;
-               }
-
-               blob_buf_init(&b, 0);
-               blobmsg_add_u8(&b, "stream", 1);
-               blobmsg_add_u8(&b, "oneshot", !log_follow);
-               if (lines)
-                       blobmsg_add_u32(&b, "lines", lines);
-               else if (log_follow)
-                       blobmsg_add_u32(&b, "lines", 0);
-               if (log_follow) {
-                       if (pid_file) {
-                               FILE *fp = fopen(pid_file, "w+");
-                               if (fp) {
-                                       fprintf(fp, "%d", getpid());
-                                       fclose(fp);
-                               }
+       if (log_follow) {
+               if (pid_file) {
+                       FILE *fp = fopen(pid_file, "w+");
+                       if (fp) {
+                               fprintf(fp, "%d", getpid());
+                               fclose(fp);
                        }
                }
+       }
 
-               if (log_ip && log_port) {
-                       openlog("logread", LOG_PID, LOG_DAEMON);
-                       log_type = LOG_NET;
-                       sender.cb = log_handle_fd;
-                       retry.cb = log_handle_reconnect;
-                       uloop_timeout_set(&retry, 1000);
-               } else if (log_file) {
-                       log_type = LOG_FILE;
-                       sender.fd = open(log_file, O_CREAT | O_WRONLY| 
O_APPEND, 0600);
-                       if (sender.fd < 0) {
-                               fprintf(stderr, "failed to open %s: %s\n", 
log_file, strerror(errno));
-                               exit(-1);
-                       }
-               } else {
-                       sender.fd = STDOUT_FILENO;
+       if (log_ip && log_port) {
+               openlog("logread", LOG_PID, LOG_DAEMON);
+               log_type = LOG_NET;
+               sender.cb = log_handle_fd;
+               retry.cb = log_handle_reconnect;
+               uloop_timeout_set(&retry, 1000);
+       } else if (log_file) {
+               log_type = LOG_FILE;
+               sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600);
+               if (sender.fd < 0) {
+                       fprintf(stderr, "failed to open %s: %s\n", log_file, 
strerror(errno));
+                       exit(-1);
                }
+       } else {
+               sender.fd = STDOUT_FILENO;
+       }
 
-               ubus_invoke_async(ctx, id, "read", b.head, &req);
-               req.fd_cb = logread_fd_cb;
-               ubus_complete_request_async(ctx, &req);
-
+       ret = logread_process();
+       /* unless we are following, immediately exit when logd is not up */
+       if (!ret || log_follow)
                uloop_run();
-               ubus_free(ctx);
-               uloop_done();
 
-       } while (ret && tries--);
+       ubus_free(ctx);
+       uloop_done();
 
        return ret;
 }
-- 
2.14.1


_______________________________________________
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev

Reply via email to