|
@@ -38,6 +38,7 @@ class subproc_buffer;
|
|
|
void do_system_shutdown(shutdown_type_t shutdown_type);
|
|
|
static void unmount_disks(loop_t &loop, subproc_buffer &sub_buf);
|
|
|
static void swap_off(loop_t &loop, subproc_buffer &sub_buf);
|
|
|
+static int run_process(const char * prog_args[], loop_t &loop, subproc_buffer &sub_buf);
|
|
|
|
|
|
constexpr static int subproc_bufsize = 4096;
|
|
|
|
|
@@ -453,12 +454,45 @@ void do_system_shutdown(shutdown_type_t shutdown_type)
|
|
|
} while (! timeout_reached);
|
|
|
|
|
|
kill(-1, SIGKILL);
|
|
|
+
|
|
|
+ // Attempt to execute shutdown hook at three possible locations:
|
|
|
+ const char * const hook_paths[] = {
|
|
|
+ "/etc/dinit/shutdown-hook",
|
|
|
+ "/lib/dinit/shutdown-hook"
|
|
|
+ };
|
|
|
|
|
|
+ bool do_unmount_ourself = true;
|
|
|
+ const int execmask = S_IXOTH | S_IXGRP | S_IXUSR;
|
|
|
+ struct stat statbuf;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < sizeof(hook_paths) / sizeof(hook_paths[0]); ++i) {
|
|
|
+ int stat_r = lstat(hook_paths[i], &statbuf);
|
|
|
+ if (stat_r == 0 && (statbuf.st_mode & execmask) != 0) {
|
|
|
+ sub_buf.append("Executing shutdown hook...\n");
|
|
|
+ const char *prog_args[] = { hook_paths[i], nullptr };
|
|
|
+ try {
|
|
|
+ int r = run_process(prog_args, loop, sub_buf);
|
|
|
+ if (r == 0) {
|
|
|
+ do_unmount_ourself = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (std::exception &e) {
|
|
|
+ sub_buf.append("Couldn't fork for shutdown-hook: ");
|
|
|
+ sub_buf.append(e.what());
|
|
|
+ sub_buf.append("\n");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// perform shutdown
|
|
|
- sub_buf.append("Turning off swap...\n");
|
|
|
- swap_off(loop, sub_buf);
|
|
|
- sub_buf.append("Unmounting disks...\n");
|
|
|
- unmount_disks(loop, sub_buf);
|
|
|
+ if (do_unmount_ourself) {
|
|
|
+ sub_buf.append("Turning off swap...\n");
|
|
|
+ swap_off(loop, sub_buf);
|
|
|
+ sub_buf.append("Unmounting disks...\n");
|
|
|
+ unmount_disks(loop, sub_buf);
|
|
|
+ }
|
|
|
+
|
|
|
sync();
|
|
|
|
|
|
sub_buf.append("Issuing shutdown via kernel...\n");
|
|
@@ -521,16 +555,18 @@ class subproc_out_watch : public loop_t::fd_watcher_impl<subproc_out_watch>
|
|
|
|
|
|
// Run process, put its output through the subprocess buffer
|
|
|
// may throw: std::system_error, std::bad_alloc
|
|
|
-static void run_process(const char * prog_args[], loop_t &loop, subproc_buffer &sub_buf)
|
|
|
+static int run_process(const char * prog_args[], loop_t &loop, subproc_buffer &sub_buf)
|
|
|
{
|
|
|
class sp_watcher_t : public loop_t::child_proc_watcher_impl<sp_watcher_t>
|
|
|
{
|
|
|
public:
|
|
|
bool terminated = false;
|
|
|
+ int exit_status;
|
|
|
|
|
|
rearm status_change(loop_t &, pid_t child, int status)
|
|
|
{
|
|
|
terminated = true;
|
|
|
+ exit_status = status;
|
|
|
return rearm::REMOVE;
|
|
|
}
|
|
|
};
|
|
@@ -594,6 +630,8 @@ static void run_process(const char * prog_args[], loop_t &loop, subproc_buffer &
|
|
|
owatch.deregister(loop);
|
|
|
close(pipefds[0]);
|
|
|
}
|
|
|
+
|
|
|
+ return sp_watcher.exit_status;
|
|
|
}
|
|
|
|
|
|
static void unmount_disks(loop_t &loop, subproc_buffer &sub_buf)
|