| /* upstart |
| * |
| * Copyright © 2010 Canonical Ltd. |
| * Author: Scott James Remnant <scott@netsplit.com>. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2, as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif /* HAVE_CONFIG_H */ |
| |
| |
| #include <sys/reboot.h> |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <nih/macros.h> |
| #include <nih/alloc.h> |
| #include <nih/main.h> |
| #include <nih/option.h> |
| #include <nih/logging.h> |
| #include <nih/error.h> |
| |
| #include "utmp.h" |
| |
| |
| /** |
| * DEV: |
| * |
| * Directory containing device nodes. |
| **/ |
| #ifndef DEV |
| #define DEV "/dev" |
| #endif |
| |
| /** |
| * SBINDIR: |
| * |
| * Directory containing system binaries. |
| **/ |
| #ifndef SBINDIR |
| #define SBINDIR "/sbin" |
| #endif |
| |
| /** |
| * SHUTDOWN: |
| * |
| * Program to call when not called with -f. |
| **/ |
| #ifndef SHUTDOWN |
| #define SHUTDOWN SBINDIR "/shutdown" |
| #endif |
| |
| #ifdef ENABLE_MANATEE |
| const char MANATEE_CLIENT[] = "/usr/bin/manatee"; |
| #endif |
| |
| |
| /* Operation modes */ |
| enum { |
| REBOOT, |
| HALT, |
| POWEROFF |
| }; |
| |
| |
| /** |
| * no_sync: |
| * |
| * TRUE to suppress the call to sync() before reboot(). |
| **/ |
| static int no_sync = FALSE; |
| |
| /** |
| * force: |
| * |
| * TRUE to behave as if we're called by shutdown. |
| **/ |
| static int force = FALSE; |
| |
| /** |
| * poweroff: |
| * |
| * TRUE if the power should be switched off. |
| **/ |
| static int poweroff = FALSE; |
| |
| /** |
| * exit_only: |
| * |
| * TRUE if we should exit immediately. |
| **/ |
| static int exit_only = FALSE; |
| |
| |
| /** |
| * options: |
| * |
| * Command-line options accepted. |
| **/ |
| static NihOption options[] = { |
| { 'n', "no-sync", N_("don't sync before reboot or halt"), |
| NULL, NULL, &no_sync, NULL }, |
| { 'f', "force", N_("force reboot or halt, don't call shutdown(8)"), |
| NULL, NULL, &force, NULL }, |
| { 'p', "poweroff", N_("switch off the power when called as halt"), |
| NULL, NULL, &poweroff, NULL }, |
| { 'w', "wtmp-only", N_("don't actually reboot or halt, just write wtmp record"), |
| NULL, NULL, &exit_only, NULL }, |
| |
| /* Compatibility options, all ignored */ |
| { 'd', NULL, NULL, NULL, NULL, NULL, NULL }, |
| { 'i', NULL, NULL, NULL, NULL, NULL, NULL }, |
| { 'h', NULL, NULL, NULL, NULL, NULL, NULL }, |
| |
| NIH_OPTION_LAST |
| }; |
| |
| |
| int |
| main (int argc, |
| char *argv[]) |
| { |
| char **args; |
| int mode; |
| int runlevel; |
| |
| nih_main_init (argv[0]); |
| |
| mode = REBOOT; |
| if (! strcmp (program_name, "halt")) { |
| mode = HALT; |
| nih_option_set_synopsis (_("Halt the system.")); |
| } else if (! strcmp (program_name, "poweroff")) { |
| mode = POWEROFF; |
| nih_option_set_synopsis (_("Power off the system.")); |
| } else { |
| mode = REBOOT; |
| nih_option_set_synopsis (_("Reboot the system.")); |
| } |
| |
| nih_option_set_help ( |
| _("This command is intended to instruct the kernel " |
| "to reboot or halt the system; when run without the -f " |
| "option, or when in a system runlevel other than 0 or 6, " |
| "it will actually execute /sbin/shutdown.\n")); |
| |
| args = nih_option_parser (NULL, argc, argv, options, FALSE); |
| if (! args) |
| exit (1); |
| |
| /* Check we're root */ |
| setuid (geteuid ()); |
| if (getuid ()) { |
| nih_fatal (_("Need to be root")); |
| exit (1); |
| } |
| |
| /* If the system runlevel is 0 or 6, we always behave as if --force |
| * were given. |
| */ |
| runlevel = utmp_get_runlevel (NULL, NULL); |
| if (runlevel < 0) { |
| nih_free (nih_error_get ()); |
| } else if ((runlevel == '0') || (runlevel == '6')) { |
| force = TRUE; |
| } |
| |
| /* Check for -p if halt */ |
| if ((mode == HALT) && poweroff) |
| mode = POWEROFF; |
| |
| /* Normally we just exec shutdown, which notifies everyone and |
| * signals init. |
| */ |
| if ((! force) && (! exit_only)) { |
| char *args[5]; |
| int i = 0; |
| |
| args[i++] = SHUTDOWN; |
| |
| switch (mode) { |
| case REBOOT: |
| args[i++] = "-r"; |
| break; |
| case HALT: |
| args[i++] = "-h"; |
| args[i++] = "-H"; |
| break; |
| case POWEROFF: |
| args[i++] = "-h"; |
| args[i++] = "-P"; |
| break; |
| } |
| |
| args[i++] = "now"; |
| args[i] = NULL; |
| |
| nih_info (_("Calling shutdown")); |
| execv (args[0], args); |
| |
| nih_fatal (_("Unable to execute shutdown: %s"), |
| strerror (errno)); |
| exit (1); |
| } |
| |
| /* Write the shutdown record */ |
| if (utmp_write_shutdown (NULL, NULL) < 0) |
| nih_free (nih_error_get ()); |
| |
| if (exit_only) |
| exit (0); |
| |
| if (! no_sync) |
| sync (); |
| |
| /* Re-enable Control-Alt-Delete in case it breaks */ |
| reboot (RB_ENABLE_CAD); |
| |
| #ifdef ENABLE_MANATEE |
| int val = fork (); |
| if (val == 0) { |
| const char *flag; |
| /* Do the syscall */ |
| switch (mode) { |
| case REBOOT: |
| nih_info (_("Rebooting")); |
| flag = "--reboot"; |
| break; |
| case HALT: |
| nih_info (_("Halting")); |
| flag = "--halt"; |
| break; |
| case POWEROFF: |
| nih_info (_("Powering off")); |
| flag = "--poweroff"; |
| break; |
| } |
| const char *manatee_args[] = { MANATEE_CLIENT, flag }; |
| execv (manatee_args[0], manatee_args); |
| } else { |
| waitpid (val, NULL, 0); |
| } |
| #endif |
| |
| /* Do the syscall */ |
| switch (mode) { |
| case REBOOT: |
| nih_info (_("Rebooting")); |
| reboot (RB_AUTOBOOT); |
| break; |
| case HALT: |
| nih_info (_("Halting")); |
| reboot (RB_HALT_SYSTEM); |
| break; |
| case POWEROFF: |
| nih_info (_("Powering off")); |
| reboot (RB_POWER_OFF); |
| break; |
| } |
| |
| /* Shouldn't get here, but if we do, carry on */ |
| reboot (RB_DISABLE_CAD); |
| |
| return 0; |
| } |