chiark / gitweb /
fsckd: clean up log messages
[elogind.git] / src / fsckd / fsckd.c
index 36b890a7de73763f474e397acb622228f70b401e..3c587a3f2025358f424fbe0025691658933ce10a 100644 (file)
@@ -47,6 +47,7 @@
 
 #define IDLE_TIME_SECONDS 30
 #define PLYMOUTH_REQUEST_KEY "K\2\2\3"
+#define CLIENTS_MAX 128
 
 struct Manager;
 
@@ -64,6 +65,8 @@ typedef struct Client {
         size_t buflen;
         bool cancelled;
 
+        sd_event_source *event_source;
+
         LIST_FIELDS(struct Client, clients);
 } Client;
 
@@ -71,11 +74,15 @@ typedef struct Manager {
         sd_event *event;
 
         LIST_HEAD(Client, clients);
+        unsigned n_clients;
+
+        size_t clear;
 
-        int clear;
         int connection_fd;
+        sd_event_source *connection_event_source;
+
+        bool show_status_console;
 
-        FILE *console;
         double percent;
         int numdevices;
 
@@ -86,9 +93,42 @@ typedef struct Manager {
         bool cancel_requested;
 } Manager;
 
+static void client_free(Client *c);
 static void manager_free(Manager *m);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Client*, client_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
+static int manager_write_console(Manager *m, const char *message) {
+        _cleanup_fclose_ FILE *console = NULL;
+        int l;
+        size_t j;
+
+        assert(m);
+
+        if (!m->show_status_console)
+                return 0;
+
+        /* Reduce the SAK window by opening and closing console on every request */
+        console = fopen("/dev/console", "we");
+        if (!console)
+                return -errno;
+
+        if (message) {
+                fprintf(console, "\r%s\r%n", message, &l);
+                if (m->clear  < (size_t)l)
+                        m->clear = (size_t)l;
+        } else {
+                fputc('\r', console);
+                for (j = 0; j < m->clear; j++)
+                        fputc(' ', console);
+                fputc('\r', console);
+        }
+        fflush(console);
+
+        return 0;
+}
+
 static double compute_percent(int pass, size_t cur, size_t max) {
         /* Values stolen from e2fsck */
 
@@ -134,8 +174,12 @@ static int client_request_cancel(Client *c) {
 static void client_free(Client *c) {
         assert(c);
 
-        if (c->manager)
+        if (c->manager) {
                 LIST_REMOVE(clients, c->manager->clients, c);
+                c->manager->n_clients--;
+        }
+
+        sd_event_source_unref(c->event_source);
 
         safe_close(c->fd);
         free(c);
@@ -270,7 +314,7 @@ static int manager_update_global_progress(Manager *m) {
         Client *current = NULL;
         _cleanup_free_ char *console_message = NULL;
         _cleanup_free_ char *fsck_message = NULL;
-        int current_numdevices = 0, l = 0, r;
+        int current_numdevices = 0, r;
         double current_percent = 100;
 
         /* get the overall percentage */
@@ -297,19 +341,14 @@ static int manager_update_global_progress(Manager *m) {
                 if (asprintf(&fsck_message, "fsckd:%d:%3.1f:%s", m->numdevices, m->percent, console_message) < 0)
                         return -ENOMEM;
 
-                /* write to console */
-                if (m->console) {
-                        fprintf(m->console, "\r%s\r%n", console_message, &l);
-                        fflush(m->console);
-                }
+                r = manager_write_console(m, console_message);
+                if (r < 0)
+                        return r;
 
                 /* try to connect to plymouth and send message */
                 r = manager_send_plymouth_message(m, fsck_message);
                 if (r < 0)
-                        log_debug("Couldn't send message to plymouth");
-
-                if (l > m->clear)
-                        m->clear = l;
+                        return r;
         }
         return 0;
 }
@@ -338,9 +377,7 @@ static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents,
                 else {
                         log_warning("Closing bad behaving fsck client connection at fd %d", client->fd);
                         client_free(client);
-                        r = manager_update_global_progress(m);
-                        if (r < 0)
-                                log_warning_errno(r, "Couldn't update global progress: %m");
+                        manager_update_global_progress(m);
                 }
                 return 0;
         }
@@ -364,17 +401,16 @@ static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents,
         } else
                 log_error_errno(r, "Unknown error while trying to read fsck data: %m");
 
-        r = manager_update_global_progress(m);
-        if (r < 0)
-                log_warning_errno(r, "Couldn't update global progress: %m");
+        manager_update_global_progress(m);
 
         return 0;
 }
 
 static int manager_new_connection_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_(client_freep) Client *c = NULL;
+        _cleanup_close_ int new_client_fd = -1;
         Manager *m = userdata;
-        Client *client = NULL;
-        int new_client_fd, r;
+        int r;
 
         assert(m);
 
@@ -383,23 +419,37 @@ static int manager_new_connection_handler(sd_event_source *s, int fd, uint32_t r
         if (new_client_fd < 0)
                 return log_error_errno(errno, "Couldn't accept a new connection: %m");
 
+        if (m->n_clients >= CLIENTS_MAX) {
+                log_error("Too many clients, refusing connection.");
+                return 0;
+        }
+
         log_debug("New fsck client connected to fd: %d", new_client_fd);
 
-        client = new0(Client, 1);
-        if (!client)
-                return log_oom();
-        client->fd = new_client_fd;
-        client->manager = m;
-        LIST_PREPEND(clients, m->clients, client);
-        r = sd_event_add_io(m->event, NULL, client->fd, EPOLLIN, client_progress_handler, client);
+        c = new0(Client, 1);
+        if (!c) {
+                log_oom();
+                return 0;
+        }
+
+        c->fd = new_client_fd;
+        new_client_fd = -1;
+
+        r = sd_event_add_io(m->event, &c->event_source, c->fd, EPOLLIN, client_progress_handler, c);
         if (r < 0) {
-                client_free(client);
-                return r;
+                log_oom();
+                return 0;
         }
+
+        LIST_PREPEND(clients, m->clients, c);
+        m->n_clients++;
+        c->manager = m;
+
         /* only request the client to cancel now in case the request is dropped by the client (chance to recancel) */
         if (m->cancel_requested)
-                client_request_cancel(client);
+                client_request_cancel(c);
 
+        c = NULL;
         return 0;
 }
 
@@ -408,16 +458,9 @@ static void manager_free(Manager *m) {
                 return;
 
         /* clear last line */
-        if (m->console && m->clear > 0) {
-                unsigned j;
-
-                fputc('\r', m->console);
-                for (j = 0; j < (unsigned) m->clear; j++)
-                        fputc(' ', m->console);
-                fputc('\r', m->console);
-                fflush(m->console);
-        }
+        manager_write_console(m, NULL);
 
+        sd_event_source_unref(m->connection_event_source);
         safe_close(m->connection_fd);
 
         while (m->clients)
@@ -425,9 +468,6 @@ static void manager_free(Manager *m) {
 
         manager_disconnect_plymouth(m);
 
-        if (m->console)
-                fclose(m->console);
-
         sd_event_unref(m->event);
 
         free(m);
@@ -451,13 +491,10 @@ static int manager_new(Manager **ret, int fd) {
         if (r < 0)
                 return r;
 
-        if (access("/run/systemd/show-status", F_OK) >= 0) {
-                m->console = fopen("/dev/console", "we");
-                if (!m->console)
-                        return -errno;
-        }
+        if (access("/run/systemd/show-status", F_OK) >= 0)
+                m->show_status_console = true;
 
-        r = sd_event_add_io(m->event, NULL, fd, EPOLLIN, manager_new_connection_handler, m);
+        r = sd_event_add_io(m->event, &m->connection_event_source, fd, EPOLLIN, manager_new_connection_handler, m);
         if (r < 0)
                 return r;