]> git.ipfire.org Git - pakfire.git/commitdiff
daemon: Prevent the system from shutting down when jobs are running
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 27 Jan 2025 11:29:28 +0000 (11:29 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 27 Jan 2025 11:29:28 +0000 (11:29 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/daemon.c

index 78112062decfda4ada7236e67c592f279edb1f20..a906fc747433904af60e6956027bb988148b04fb 100644 (file)
@@ -70,6 +70,7 @@ struct pakfire_daemon {
 
        // dbus
        sd_bus* bus;
+       int inhibitfd;
 
        // Kerberos Authentication
        struct {
@@ -352,6 +353,77 @@ ERROR:
        return r;
 }
 
+/*
+ * Prevents that the system can be shut down when there are jobs running...
+ */
+static int pakfire_daemon_inhibit_shutdown(struct pakfire_daemon* daemon) {
+       sd_bus_error error = SD_BUS_ERROR_NULL;
+       sd_bus_message* reply = NULL;
+       int r;
+
+       // Don't do this again if we are already holding the lock
+       if (daemon->inhibitfd >= 0)
+               return 0;
+
+       // Call the Inhibit method
+       r = sd_bus_call_method(
+               daemon->bus,
+
+               // Destination, Path & Interface
+               "org.freedesktop.login1",
+               "/org/freedesktop/login1",
+               "org.freedesktop.login1.Manager",
+
+               // Method
+               "Inhibit",
+
+               // Error
+               &error,
+
+               // Reply
+               &reply,
+
+               // Arguments
+               "ssss",
+               "shutdown:sleep:idle",
+               "pakfire-daemon",
+               "Prevent shutdown while build jobs are running",
+               "block"
+       );
+       if (r < 0) {
+               ERROR(daemon->ctx, "Failed to inhibit shutdown: %s\n", error.message);
+               goto ERROR;
+       }
+
+    // Read the file descriptor from the reply
+       r = sd_bus_message_read(reply, "h", &daemon->inhibitfd);
+       if (r < 0) {
+               ERROR(daemon->ctx, "Failed to parse response message: %s\n", strerror(-r));
+               goto ERROR;
+    }
+
+       DEBUG(daemon->ctx, "Successfully inhibited shutdown\n");
+
+ERROR:
+    sd_bus_error_free(&error);
+    if (reply)
+           sd_bus_message_unref(reply);
+
+       return r;
+}
+
+static int pakfire_daemon_release_inhibit_shutdown(struct pakfire_daemon* daemon) {
+       // If we don't hold the lock, we cannot release it
+       if (daemon->inhibitfd >= 0) {
+               close(daemon->inhibitfd);
+               daemon->inhibitfd = -EBADF;
+
+               DEBUG(daemon->ctx, "Released shutdown inhibition\n");
+       }
+
+       return 0;
+}
+
 /*
        Called when a new job has been received
 */
@@ -360,11 +432,16 @@ static int pakfire_daemon_job(struct pakfire_daemon* daemon, json_object* m) {
        struct json_object* data = NULL;
        int r;
 
+       // Inhibit shutdown
+       r = pakfire_daemon_inhibit_shutdown(daemon);
+       if (r < 0)
+               goto ERROR;
+
        // Fetch the data from the message
        if (!json_object_object_get_ex(m, "data", &data)) {
                ERROR(daemon->ctx, "Job does not have any data\n");
-
-               return -EINVAL;
+               r = -EINVAL;
+               goto ERROR;
        }
 
        // Create a new job
@@ -946,6 +1023,9 @@ ERROR:
 }
 
 static void pakfire_daemon_free(struct pakfire_daemon* daemon) {
+       // Release shutdown inhibition
+       pakfire_daemon_release_inhibit_shutdown(daemon);
+
        if (daemon->krb5.principal)
                krb5_free_principal(daemon->krb5.ctx, daemon->krb5.principal);
        if (daemon->krb5.ccache)
@@ -989,6 +1069,9 @@ int pakfire_daemon_create(struct pakfire_daemon** daemon, struct pakfire_ctx* ct
        // Initialize the reference counter
        d->nrefs = 1;
 
+       // Initialize file descriptors
+       d->inhibitfd = -EBADF;
+
        // Read configuration
        r = pakfire_daemon_configure(d);
        if (r < 0)
@@ -1088,6 +1171,8 @@ ERROR:
        Called after a job has exited
 */
 int pakfire_daemon_job_finished(struct pakfire_daemon* daemon, struct pakfire_job* job) {
+       int r;
+
        DEBUG(daemon->ctx, "Removing job %p\n", job);
 
        for (unsigned int i = 0; i < MAX_JOBS; i++) {
@@ -1104,6 +1189,13 @@ int pakfire_daemon_job_finished(struct pakfire_daemon* daemon, struct pakfire_jo
        // Now we have one less job running
        daemon->running_jobs--;
 
+       // Release the shutdown inhibition if there are no more jobs running
+       if (!daemon->running_jobs) {
+               r = pakfire_daemon_release_inhibit_shutdown(daemon);
+               if (r < 0)
+                       return r;
+       }
+
        return 0;
 }