shutdown: sets INIT_HALT as first argument, should be the last

Bug #303574 reported by Arkadiusz Miśkiewicz
12
Affects Status Importance Assigned to Milestone
upstart
Invalid
High
Unassigned
0.5
Fix Released
High
Unassigned

Bug Description

upstart 0.5.0 with sysvinit compat.

When issuing poweroff then "The system is going down for power off NOW!" message is printed but nothing else happens. It doesn't start poweroff procedure.

Pasting #upstart conversation with myself... This should explain the problem.

23:12 < arekm> hi, is there anyone alive who could help me track one issue? poweroff from upstart is broadcasting message about system going "for
               power off" but it's not doing actual poweroff. Nothing else happens. This is custom distro that wants to use upstart
23:17 < arekm> I'm looking into ubuntu configs and actually I don't see where poweroff events are handled
23:31 < arekm> strace shows that init gets some message with "INIT_HALT=POWEROFF" but does nothing
23:42 < arekm> Nov 21 23:42:02 arm init: event_new: Pending runlevel event
23:42 < arekm> Nov 21 23:42:02 arm init: event_finished: Finished runlevel event
23:42 < arekm> but hm, nothing is run
00:21 < arekm> "telinit 0" on the other hand works well
00:26 < arekm> "shutdown -P" now also does nothing but "shutdown -P now -h' shutdowns system and powersoff
00:26 < arekm> while according to manual -P implies -h
00:26 < arekm> s/manual/shutdown --help/
00:39 < arekm> looks like NIH_MUST (e = nih_sprintf (NULL, "INIT_HALT=%s", init_halt));
00:40 < arekm> or any other env sent (NIH_MUST (e = nih_sprintf (NULL, "BLABLA=ZIMA"));)
00:40 < arekm> causes init to behave wrongly

So INIT_HALT= is handled in a wrong way it seems.

Revision history for this message
Jeff Oliver (jeffrey-oliver) wrote :

I'm wondering if your problem is related to a question I posted (Question #51683).

Upstart has an event that is self-emitted called "startup", that kicks off the boot process, but I fail to see an event that is the opposite of that. A "runlevel 0" event can be used to stop all of the jobs, but I need something at the end that ends up actually rebooting the machine.

It appears that upstart relys on how sysvinit does its shutdown. Basically kill all of the processes, then run SXXkillall and SXXhalt or SXXreboot. The latter two do the actual reboot or halt. But what it I dont have sysvinit doing that? How can I do a reboot or halt without sysvinit's help?

Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

Could I confirm something:

Are you using a standard set of SysV shutdown scripts that call /sbin/halt, or are you attempting a custom upstart-based distribution and expected the shutdown command to call /sbin/halt and was surprised that it didn't?

Changed in upstart:
status: New → Incomplete
Revision history for this message
Arkadiusz Miśkiewicz (arekm) wrote :

/sbin/halt has nothing to do with initial bugreport (Jeff comment is simply not on the original subject)? Yes, I use SysV scripts but these are not run at all, so /sbin/halt is also not run.

Avoiding
NIH_MUST (e = nih_sprintf (NULL, "INIT_HALT=%s", init_halt));
(or any other environment variable)
makes things work as expected.

Changed in upstart:
status: Incomplete → New
Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

Right.

So it sounds like you haven't written your shutdown sequence to read INIT_HALT and call halt or poweroff appropriately?

The current shutdown stuff is modelled after the SysV stuff, there is no native shutdown yet.

Changed in upstart:
importance: Undecided → Wishlist
status: New → Confirmed
Revision history for this message
Arkadiusz Miśkiewicz (arekm) wrote :

Could you enlighten me on what exactly you mean by sating "read INIT_HALT" ?

I have rc0 job:

start on runlevel 0

stop on runlevel

console output
script
        set $(runlevel || true)
        if [ "$2" != "0" ] && [ "$2" != "6" ]; then
            set $(runlevel --set 0 || true)
        fi

        if [ "$1" != "unknown" ]; then
            PREVLEVEL=$1
            RUNLEVEL=$2
            export PREVLEVEL RUNLEVEL
        fi

        exec /etc/rc.d/rc 0
end script

but /etc/rc.d/rc isn't called. I guess I even tested echo "blabla" on beginning of the "script" part. Note that "reboot" command runs rc script fine. I assume that on poweroff /etc/rc.d/rc also should be run, right?

Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

Sounds like this is actually a bug, since another report has come in that poweroff doesn't do anything in 0.5

Changed in upstart:
importance: Wishlist → High
Revision history for this message
Sandeep (spuddupa) wrote :

The reason this does not work is as follows.
When we do a proweoff "shutdown -P now", in the code in shutdown.c, we set environment variable INIT_HALT="POWEROFF"
When rc0 is executed, the environment variables come in the order INIT_HALT=POWEROFF RUNLEVEL=0 PREVLEVEL=3

In the upstart job file for rc0, we expect RUNLEVEL to be the first environment variable. (start on runlevel 0). Since RUNLEVEL is not the first variable, your rc0 job file is not executed.
Simply modifying the job file rc0's start on condition to
start on runlevel RUNLEVEL=0
will make this work.
Alternatively, you can modify the shutdown.c file function
to do the following

    NIH_MUST (e = nih_sprintf (NULL, "RUNLEVEL=%s", runlevel));
    NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));
    NIH_MUST (e = nih_sprintf (NULL, "PREVLEVEL=%s", prev_level()));
    NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));
   /* set this environment variable after RUNLEVEL and PREVLEVEL are set */
    if (init_halt) {
        NIH_MUST (e = nih_sprintf (NULL, "INIT_HALT=%s", init_halt));
        NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));
    }
instead of
    if (init_halt) {
        NIH_MUST (e = nih_sprintf (NULL, "INIT_HALT=%s", init_halt));
        NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));
    }

    NIH_MUST (e = nih_sprintf (NULL, "RUNLEVEL=%s", runlevel));
    NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));
    NIH_MUST (e = nih_sprintf (NULL, "PREVLEVEL=%s", prev_level()));
    NIH_MUST (nih_str_array_addp (&env, NULL, NULL, e));

This is also true if you do "shutdown -H now"

Revision history for this message
Sandeep (spuddupa) wrote :

Missed this info in the previous post
The function is shutdown_now() in the file util/shutdown.c

Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

You're quite right, well spotted!

In 0.3, INIT_HALT was an environment variable while RUNLEVEL and PREVLEVEL were just arguments.

In 0.5, they're the same thing, so order matters - and shutdown wasn't properly modified to take this into account (blames Casey :p)

Changed in upstart:
milestone: none → 0.3.11
status: Confirmed → Triaged
summary: - poweroff does nothing (beside writting message)
+ shutdown sets INIT_HALT as first argument, should be the last
Changed in upstart:
milestone: 0.3.11 → none
summary: - shutdown sets INIT_HALT as first argument, should be the last
+ shutdown: sets INIT_HALT as first argument, should be the last
Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :
Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

0.5 branch only

Changed in upstart:
status: Triaged → Invalid
Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

0.5.3 2009-06-22 "Britain's Flag Carrier"

        * Fixed segfault when initctl status called with arguments.
          (Bug: #388753)

        * Fixed segfault when initctl log-priority called with no argument.
          (Bug: #280529)

        * Fixed shutdown to pass $INIT_HALT variable as last argument, not
          as first. (Bug: #303574)

        * Added temporary support for "telinit u" until we have true re-exec
          support. This will be replaced by an initctl command in future.
          (Bug: #388742)

        * Corrected formatting of initctl(8) manpage. (Bug: #388745)

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.