#include <cstddef>
#include <cstdio>
#include <csignal>
-#include <unistd.h>
#include <cstring>
#include <string>
#include <iostream>
+#include <exception>
#include <sys/reboot.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
#include "cpbuffer.h"
#include "control-cmds.h"
#include "service-constants.h"
#include "dinit-client.h"
+#include "dinit-util.h"
+#include "mconfig.h"
#include "dasynq.h"
// shutdown: shut down the system
-// This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
+// This utility communicates with the dinit daemon via a unix socket (specified in SYSCONTROLSOCKET).
+
+static constexpr uint16_t min_cp_version = 1;
+static constexpr uint16_t max_cp_version = 1;
using loop_t = dasynq::event_loop_n;
using rearm = dasynq::rearm;
bool use_passed_cfd = false;
auto shutdown_type = shutdown_type_t::POWEROFF;
+
+ const char *execname = base_name(argv[0]);
+ if (strcmp(execname, "reboot") == 0) {
+ shutdown_type = shutdown_type_t::REBOOT;
+ }
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
}
if (show_help) {
- cout << "dinit-shutdown : shutdown the system" << endl;
- cout << " --help : show this help" << endl;
- cout << " -r : reboot" << endl;
- cout << " -h : halt system" << endl;
- cout << " -p : power down (default)" << endl;
- cout << " --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD" << endl;
- cout << " environment variable to communicate with the init daemon." << endl;
- cout << " --system : perform shutdown immediately, instead of issuing shutdown" << endl;
- cout << " command to the init program. Not recommended for use" << endl;
- cout << " by users." << endl;
+ cout << execname << " : shutdown the system\n"
+ " --help : show this help\n"
+ " -r : reboot\n"
+ " -h : halt system\n"
+ " -p : power down (default)\n"
+ " --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD\n"
+ " environment variable to communicate with the init daemon.\n"
+ " --system : perform shutdown immediately, instead of issuing shutdown\n"
+ " command to the init program. Not recommended for use\n"
+ " by users.\n";
return 1;
}
long int cfdnum = strtol(dinit_cs_fd_env, &endptr, 10);
if (endptr != dinit_cs_fd_env) {
socknum = (int) cfdnum;
+ // Set non-blocking mode:
+ int sock_flags = fcntl(socknum, F_GETFL, 0);
+ fcntl(socknum, F_SETFL, sock_flags & ~O_NONBLOCK);
}
else {
use_passed_cfd = false;
return 1;
}
- const char *naddr = "/dev/dinitctl";
+ const char *naddr = SYSCONTROLSOCKET;
struct sockaddr_un name;
name.sun_family = AF_UNIX;
try {
cpbuffer_t rbuffer;
- check_protocol_version(0, 0, rbuffer, socknum);
+ check_protocol_version(min_cp_version, max_cp_version, rbuffer, socknum);
// Build buffer;
constexpr int bufsize = 2;
sp_watcher_t sp_watcher;
// Create output pipe
+ bool have_pipe = true;
int pipefds[2];
if (dasynq::pipe2(pipefds, O_NONBLOCK) == -1) {
- // TODO
- std::cout << "*** pipe2 failed ***" << std::endl;
+ sub_buf.append("Warning: ");
+ sub_buf.append(prog_args[0]);
+ sub_buf.append(": could not create pipe for subprocess output\n");
+ have_pipe = false;
+ // Note, we proceed and let the sub-process run with our stdout/stderr.
}
+ subproc_out_watch owatch {sub_buf};
+
+ if (have_pipe) {
+ close(pipefds[1]);
+ try {
+ owatch.add_watch(loop, pipefds[0], dasynq::IN_EVENTS);
+ }
+ catch (...) {
+ // failed to create the watcher for the subprocess output; again, let it run with
+ // our stdout/stderr
+ sub_buf.append("Warning: could not create output watch for subprocess\n");
+ close(pipefds[0]);
+ have_pipe = false;
+ }
+ }
+
+ // If we've buffered any messages/output, give them a chance to go out now:
+ loop.poll();
+
pid_t ch_pid = sp_watcher.fork(loop);
if (ch_pid == 0) {
// child
// Dup output pipe to stdout, stderr
- dup2(pipefds[1], STDOUT_FILENO);
- dup2(pipefds[1], STDERR_FILENO);
- close(pipefds[0]);
- close(pipefds[1]);
+ if (have_pipe) {
+ dup2(pipefds[1], STDOUT_FILENO);
+ dup2(pipefds[1], STDERR_FILENO);
+ close(pipefds[0]);
+ close(pipefds[1]);
+ }
execv(prog_args[0], const_cast<char **>(prog_args));
- puts("Failed to execute subprocess:\n");
+ puts("Failed to execute subprocess: ");
perror(prog_args[0]);
_exit(1);
}
- close(pipefds[1]);
-
- subproc_out_watch owatch {sub_buf};
- owatch.add_watch(loop, pipefds[0], dasynq::IN_EVENTS);
-
do {
loop.run();
} while (! sp_watcher.terminated);
- owatch.deregister(loop);
+ if (have_pipe) {
+ owatch.deregister(loop);
+ }
}
static void unmount_disks(loop_t &loop, subproc_buffer &sub_buf)
{
- const char * unmount_args[] = { "/bin/umount", "-a", "-r", nullptr };
- run_process(unmount_args, loop, sub_buf);
+ try {
+ const char * unmount_args[] = { "/bin/umount", "-a", "-r", nullptr };
+ run_process(unmount_args, loop, sub_buf);
+ }
+ catch (std::exception &e) {
+ sub_buf.append("Couldn't fork for umount: ");
+ sub_buf.append(e.what());
+ sub_buf.append("\n");
+ }
}
static void swap_off(loop_t &loop, subproc_buffer &sub_buf)
{
- const char * swapoff_args[] = { "/sbin/swapoff", "-a", nullptr };
- run_process(swapoff_args, loop, sub_buf);
+ try {
+ const char * swapoff_args[] = { "/sbin/swapoff", "-a", nullptr };
+ run_process(swapoff_args, loop, sub_buf);
+ }
+ catch (std::exception &e) {
+ sub_buf.append("Couldn't fork for swapoff: ");
+ sub_buf.append(e.what());
+ sub_buf.append("\n");
+ }
}