Type=idle is much like Type=simple, however between the fork() and the
exec() in the child we wait until PID 1 informs us that no jobs are
left.
This is mostly a cosmetic fix to make gettys appear only after all boot
output is finished and complete.
Note that this does not impact the normal job logic as we do not delay
the completion of any jobs. We just delay the invocation of the actual
binary, and only for services that otherwise would be of Type=simple.
16 files changed:
#include <sys/mount.h>
#include <linux/fs.h>
#include <linux/oom.h>
#include <sys/mount.h>
#include <linux/fs.h>
#include <linux/oom.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
CGroupBonding *cgroup_bondings,
CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
+ if (idle_pipe) {
+ if (idle_pipe[1] >= 0)
+ close_nointr_nofail(idle_pipe[1]);
+ if (idle_pipe[0] >= 0) {
+ fd_wait_for_event(idle_pipe[0], POLLHUP, DEFAULT_TIMEOUT_USEC);
+ close_nointr_nofail(idle_pipe[0]);
+ }
+ }
+
/* Close sockets very early to make sure we don't
* block init reexecution because it cannot bind its
* sockets */
/* Close sockets very early to make sure we don't
* block init reexecution because it cannot bind its
* sockets */
struct CGroupBonding *cgroup_bondings,
struct CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
struct CGroupBonding *cgroup_bondings,
struct CGroupAttribute *cgroup_attributes,
const char *cgroup_suffix,
pid_t *ret);
void exec_command_done(ExecCommand *c);
pid_t *ret);
void exec_command_done(ExecCommand *c);
m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->pin_cgroupfs_fd = -1;
m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->pin_cgroupfs_fd = -1;
+ m->idle_pipe[0] = m->idle_pipe[1] = -1;
#ifdef HAVE_AUDIT
m->audit_fd = -1;
#ifdef HAVE_AUDIT
m->audit_fd = -1;
hashmap_free(m->cgroup_bondings);
set_free_free(m->unit_path_cache);
hashmap_free(m->cgroup_bondings);
set_free_free(m->unit_path_cache);
+ close_pipe(m->idle_pipe);
+
- if (dual_timestamp_is_set(&m->finish_timestamp))
+ if (hashmap_size(m->jobs) > 0)
- if (hashmap_size(m->jobs) > 0)
+ /* Notify Type=idle units that we are done now */
+ close_pipe(m->idle_pipe);
+
+ if (dual_timestamp_is_set(&m->finish_timestamp))
return;
dual_timestamp_get(&m->finish_timestamp);
return;
dual_timestamp_get(&m->finish_timestamp);
unsigned n_installed_jobs;
unsigned n_failed_jobs;
unsigned n_installed_jobs;
unsigned n_failed_jobs;
+
+ /* Type=idle pipes */
+ int idle_pipe[2];
};
int manager_new(ManagerRunningAs running_as, Manager **m);
};
int manager_new(ManagerRunningAs running_as, Manager **m);
UNIT(m)->cgroup_bondings,
UNIT(m)->cgroup_attributes,
NULL,
UNIT(m)->cgroup_bondings,
UNIT(m)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
is_control ? "control" : NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
is_control ? "control" : NULL,
+ s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
- if (s->type == SERVICE_SIMPLE) {
+ if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
/* For simple services we immediately start
* the START_POST binaries. */
/* For simple services we immediately start
* the START_POST binaries. */
[SERVICE_FORKING] = "forking",
[SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
[SERVICE_FORKING] = "forking",
[SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify"
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_IDLE] = "idle"
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+ SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -1
} ServiceType;
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -1
} ServiceType;
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
NULL,
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <unistd.h>
+#include <fcntl.h>
+
#include "transaction.h"
#include "bus-errors.h"
#include "transaction.h"
#include "bus-errors.h"
assert(hashmap_isempty(tr->jobs));
assert(hashmap_isempty(tr->jobs));
+ if (!hashmap_isempty(m->jobs)) {
+ /* Are there any jobs now? Then make sure we have the
+ * idle pipe around. We don't really care too much
+ * whether this works or not, as the idle pipe is a
+ * feature for cosmetics, not actually useful for
+ * anything beyond that. */
+
+ if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
+ pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
+ }
+
[Service]
ExecStart=-/sbin/agetty --noclear -s console 115200,38400,9600
[Service]
ExecStart=-/sbin/agetty --noclear -s console 115200,38400,9600
Restart=always
RestartSec=0
UtmpIdentifier=cons
Restart=always
RestartSec=0
UtmpIdentifier=cons
WorkingDirectory=/root
ExecStart=-/sbin/sulogin
ExecStopPost=-@SYSTEMCTL@ poweroff
WorkingDirectory=/root
ExecStart=-/sbin/sulogin
ExecStopPost=-@SYSTEMCTL@ poweroff
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^D to enter default mode.'
ExecStart=-/sbin/sulogin
ExecStopPost=@SYSTEMCTL@ --fail --no-block default
ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^D to enter default mode.'
ExecStart=-/sbin/sulogin
ExecStopPost=@SYSTEMCTL@ --fail --no-block default
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
[Service]
Environment=TERM=linux
ExecStart=-/sbin/agetty %I 38400
[Service]
Environment=TERM=linux
ExecStart=-/sbin/agetty %I 38400
Restart=always
RestartSec=0
UtmpIdentifier=%I
Restart=always
RestartSec=0
UtmpIdentifier=%I
ExecStart=-/bin/bash -c "exec ${SINGLE}"',
`ExecStart=-/sbin/sulogin'))))
ExecStopPost=-@SYSTEMCTL@ --fail --no-block default
ExecStart=-/bin/bash -c "exec ${SINGLE}"',
`ExecStart=-/sbin/sulogin'))))
ExecStopPost=-@SYSTEMCTL@ --fail --no-block default
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
[Service]
Environment=TERM=vt102
ExecStart=-/sbin/agetty -s %I 115200,38400,9600
[Service]
Environment=TERM=vt102
ExecStart=-/sbin/agetty -s %I 115200,38400,9600
Restart=always
RestartSec=0
UtmpIdentifier=%I
Restart=always
RestartSec=0
UtmpIdentifier=%I