// shutdown: shut down the system
// This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
-void do_system_shutdown(ShutdownType shutdown_type);
+void do_system_shutdown(shutdown_type_t shutdown_type);
static void unmount_disks();
static void swap_off();
-static void wait_for_reply(CPBuffer<1024> &rbuffer, int fd);
+static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd);
class ReadCPException
bool show_help = false;
bool sys_shutdown = false;
+ bool use_passed_cfd = false;
- auto shutdown_type = ShutdownType::POWEROFF;
+ auto shutdown_type = shutdown_type_t::POWEROFF;
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
sys_shutdown = true;
}
else if (strcmp(argv[i], "-r") == 0) {
- shutdown_type = ShutdownType::REBOOT;
+ shutdown_type = shutdown_type_t::REBOOT;
}
else if (strcmp(argv[i], "-h") == 0) {
- shutdown_type = ShutdownType::HALT;
+ shutdown_type = shutdown_type_t::HALT;
}
else if (strcmp(argv[i], "-p") == 0) {
- shutdown_type = ShutdownType::POWEROFF;
+ shutdown_type = shutdown_type_t::POWEROFF;
+ }
+ else if (strcmp(argv[i], "--use-passed-cfd") == 0) {
+ use_passed_cfd = true;
}
else {
cerr << "Unrecognized command-line parameter: " << argv[i] << 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;
do_system_shutdown(shutdown_type);
return 0;
}
-
- int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
- if (socknum == -1) {
- perror("socket");
- return 1;
- }
signal(SIGPIPE, SIG_IGN);
- const char *naddr = "/dev/dinitctl";
-
- struct sockaddr_un name;
- name.sun_family = AF_UNIX;
- strcpy(name.sun_path, naddr);
- int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
+ int socknum = 0;
- int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
- if (connr == -1) {
- perror("connect");
- return 1;
+ if (use_passed_cfd) {
+ char * dinit_cs_fd_env = getenv("DINIT_CS_FD");
+ if (dinit_cs_fd_env != nullptr) {
+ char * endptr;
+ long int cfdnum = strtol(dinit_cs_fd_env, &endptr, 10);
+ if (endptr != dinit_cs_fd_env) {
+ socknum = (int) cfdnum;
+ }
+ else {
+ use_passed_cfd = false;
+ }
+ }
+ else {
+ use_passed_cfd = false;
+ }
}
+ if (! use_passed_cfd) {
+ socknum = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (socknum == -1) {
+ perror("socket");
+ return 1;
+ }
+
+ const char *naddr = "/dev/dinitctl";
+
+ struct sockaddr_un name;
+ name.sun_family = AF_UNIX;
+ strcpy(name.sun_path, naddr);
+ int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
+
+ int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
+ if (connr == -1) {
+ perror("connect");
+ return 1;
+ }
+ }
+
// Build buffer;
- //uint16_t sname_len = strlen(service_name);
- int bufsize = 2;
- char * buf = new char[bufsize];
+ constexpr int bufsize = 2;
+ char buf[bufsize];
buf[0] = DINIT_CP_SHUTDOWN;
buf[1] = static_cast<char>(shutdown_type);
// cout << "Received acknowledgement. System should now shut down." << endl;
//}
- CPBuffer<1024> rbuffer;
+ cpbuffer<1024> rbuffer;
try {
wait_for_reply(rbuffer, socknum);
// errcode = 0 if end of stream (remote end closed)
// errcode = errno if another error occurred
// Note that EINTR is ignored (i.e. the read will be re-tried).
-static void fillBufferTo(CPBuffer<1024> *buf, int fd, int rlength)
+static void fillBufferTo(cpbuffer<1024> *buf, int fd, int rlength)
{
do {
int r = buf->fill_to(fd, rlength);
// Wait for a reply packet, skipping over any information packets
// that are received in the meantime.
-static void wait_for_reply(CPBuffer<1024> &rbuffer, int fd)
+static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
{
fillBufferTo(&rbuffer, fd, 1);
while (rbuffer[0] >= 100) {
// Information packet; discard.
- fillBufferTo(&rbuffer, fd, 1);
+ fillBufferTo(&rbuffer, fd, 2);
int pktlen = (unsigned char) rbuffer[1];
rbuffer.consume(1); // Consume one byte so we'll read one byte of the next packet
}
// Actually shut down the system.
-void do_system_shutdown(ShutdownType shutdown_type)
+void do_system_shutdown(shutdown_type_t shutdown_type)
{
using namespace std;
+ // Mask all signals to prevent death of our parent etc from terminating us
+ sigset_t allsigs;
+ sigfillset(&allsigs);
+ sigprocmask(SIG_SETMASK, &allsigs, nullptr);
+
int reboot_type = 0;
- if (shutdown_type == ShutdownType::REBOOT) reboot_type = RB_AUTOBOOT;
- else if (shutdown_type == ShutdownType::POWEROFF) reboot_type = RB_POWER_OFF;
+ if (shutdown_type == shutdown_type_t::REBOOT) reboot_type = RB_AUTOBOOT;
+ else if (shutdown_type == shutdown_type_t::POWEROFF) reboot_type = RB_POWER_OFF;
else reboot_type = RB_HALT_SYSTEM;
// Write to console rather than any terminal, since we lose the terminal it seems:
dup2(consfd, STDOUT_FILENO);
}
- cout << "Sending TERM/KILL to all processes..." << endl; // DAV
+ cout << "Sending TERM/KILL to all processes..." << endl;
// Send TERM/KILL to all (remaining) processes
kill(-1, SIGTERM);