1 #include "system.h"
2 
3 #include <dbus/dbus.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <rpm/rpmlog.h>
8 #include <rpm/rpmts.h>
9 #include "lib/rpmplugin.h"
10 
11 static int lock_fd = -1;
12 
inhibit(void)13 static int inhibit(void)
14 {
15     DBusError err;
16     DBusConnection *bus = NULL;
17     DBusMessage *msg = NULL;
18     DBusMessage *reply = NULL;
19     int fd = -1;
20 
21     dbus_error_init(&err);
22     bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
23 
24     if (bus) {
25 	msg = dbus_message_new_method_call("org.freedesktop.login1",
26 					   "/org/freedesktop/login1",
27 					   "org.freedesktop.login1.Manager",
28 					   "Inhibit");
29     }
30 
31     if (msg) {
32 	const char *what = "idle:sleep:shutdown";
33 	const char *mode = "block";
34 	const char *who = "RPM";
35 	const char *reason = "Transaction running";
36 
37 	dbus_message_append_args(msg,
38 				 DBUS_TYPE_STRING, &what,
39 				 DBUS_TYPE_STRING, &who,
40 				 DBUS_TYPE_STRING, &reason,
41 				 DBUS_TYPE_STRING, &mode,
42 				 DBUS_TYPE_INVALID);
43 
44 	reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &err);
45 	dbus_message_unref(msg);
46     }
47 
48     if (reply) {
49 	dbus_message_get_args(reply, &err,
50 			      DBUS_TYPE_UNIX_FD, &fd,
51 			      DBUS_TYPE_INVALID);
52 	dbus_message_unref(reply);
53     }
54 
55     if (dbus_error_is_set(&err)) {
56 	if (!dbus_error_has_name(&err, DBUS_ERROR_NO_SERVER) &&
57 	    !dbus_error_has_name(&err, DBUS_ERROR_FILE_NOT_FOUND))
58 	{
59 	    rpmlog(RPMLOG_WARNING,
60 	       "Unable to get systemd shutdown inhibition lock: %s\n",
61 		err.message);
62 	}
63 	dbus_error_free(&err);
64     }
65 
66     if (bus) {
67 	dbus_connection_close(bus);
68 	dbus_connection_unref(bus);
69     }
70 
71     return fd;
72 }
73 
systemd_inhibit_init(rpmPlugin plugin,rpmts ts)74 static rpmRC systemd_inhibit_init(rpmPlugin plugin, rpmts ts)
75 {
76     struct stat st;
77 
78     if (lstat("/run/systemd/system/", &st) == 0) {
79         if (S_ISDIR(st.st_mode)) {
80             return RPMRC_OK;
81         }
82     }
83 
84     return RPMRC_NOTFOUND;
85 }
86 
systemd_inhibit_tsm_pre(rpmPlugin plugin,rpmts ts)87 static rpmRC systemd_inhibit_tsm_pre(rpmPlugin plugin, rpmts ts)
88 {
89     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
90 	return RPMRC_OK;
91 
92     lock_fd = inhibit();
93 
94     if (lock_fd >= 0) {
95 	rpmlog(RPMLOG_DEBUG, "System shutdown blocked (fd %d)\n", lock_fd);
96     }
97 
98     return RPMRC_OK;
99 }
100 
systemd_inhibit_tsm_post(rpmPlugin plugin,rpmts ts,int res)101 static rpmRC systemd_inhibit_tsm_post(rpmPlugin plugin, rpmts ts, int res)
102 {
103     if (lock_fd >= 0) {
104 	close(lock_fd);
105 	lock_fd = -1;
106 	rpmlog(RPMLOG_DEBUG, "System shutdown unblocked\n");
107     }
108     return RPMRC_OK;
109 }
110 
111 struct rpmPluginHooks_s systemd_inhibit_hooks = {
112     .init = systemd_inhibit_init,
113     .tsm_pre = systemd_inhibit_tsm_pre,
114     .tsm_post = systemd_inhibit_tsm_post,
115 };
116