Re: [gdm-list] ConsoleKit shutdown api


Some comments inline, more in your list of questions below.

Matthias Clasen schrieb:
(sent to gdm-list for lack of a better venue to discuss ConsoleKit

ConsoleKit currently offers a somewhat simplistic API for
shutdown/reboot of the system. While working on the PolicyKit one
conversion of CK and gnome-session, it has become apparent that that
simplistic API is not really sufficient.

Currently, gnome-session does some gymnastics with getting the
PolicyKit privileges beforehand, then saving the
session, then calling Restart, but that doesn't work anymore with PolicyKit 1.

And then there are implementations that don't use PolicyKit (yet). So obviously making less assumptions about privilege checking/enforcement and better encapsulating the policy/privilege mechanism is useful for those cases.

Shutdown API for ConsoleKit

Keep Restart/Stop as they are now, and add a new function

QueryStop (out 'u' can_proceed, out 'u' inhibitors, out 'u' sessions)

    Returns information about whether privileges are required to
    go ahead:
    * 0: Cannot proceed
    * 1: Extra privileges required; a PolicyKit dialog may be shown
    * 2: No extra privileges required
    The number of inhibitors
    The number of sessions

This function should be called when the users clicks a 'Restart'
button. It is supposed to return enough information for the session
manager to show an inhibit dialog that lists not only applications in
the session itself, but also other sessions and system processes that
might be affected.

If you are wrapping the privilege handling this way, it could be useful to also have a function to query whether stopping the machine is a non-starter due to lack of privileges without signalling anything to sessions or querying more dynamic runtime state. That could be used so that callers can decide whether they should completely hide any Restart/Shutdown controls (rather than showing controls that will always respond "Sorry ..."), because the user has no privileges anyhow - or maybe because no PolicyKit-style UI should be shown in the context of the caller.

ConsoleKit.Session interface extensions

StopResponse (in 'b' ok, in 's' reason)

Session managers are supposed to call this in response to QueryStop
and Stop signals,  on 'their' session object.

QueryStop signal

Gets emitted by CK in response to a QueryStop call. Sessions should
handle this by doing their own QueryEndSession dance and reporting
back by calling StopResponse. No dialogs should be shown in response
to this, and no user interaction. Sessions may set inhibitors in
response to signal (so-called just-in-time inhibitors). ConsoleKit
will wait for a short time (X seconds) for the StopResponse calls
before continuing.

Stop signal

Gets emitted by CK in response to a Restart or Stop call. Sessions
should handle this by doing their own EndSession dance, end the
session and report back by calling StopResponse. No user interaction.
ConsoleKit will wait for a short time (X seconds) for the StopResponse
calls before continuing.

IsStopping property

A boolean property that ConsoleKit sets during the Restart/Stop calls.
A typical user for this is gdm, which should not allow any new logins
if a restart is in progress.

It seems like this kind of API provides room for all kinds of races, which may be hard to get right. The 'CancelStop' question you raise below is very relevant here.

For IsStopping this means: Should the return value be more than a boolean to distinguish between the 'querystop has been issued' and 'stop in progress' cases?

Run through

1) User clicks Shutdown button
2) gnome-session calls QueryStop on CK
3) CK emits QueryStop
4) All sessions do their own QueryEndSession dance
5) All sessions respond back with StopResponse
6) QueryStop call returns telling gnome-session if privileges are
needed and how many inhibitors and sessions there are
7) gnome-session uses GetInhibitors and GetSessions apis to assemble
list of things to show in the inhibit dialog, in addition to its own
inhibitors. Depending on the can_proceed value returned by QueryStop,
the dialog will have a 'Sorry, can't do' text, or a 'Stop' button or a
'Stop anyway...' button.

| [II] MyEditor (unsaved changes)        |
| - - - - - - - - - - - - - - - - - - - - - - - - |
| [II] Jon (burning CD)                        |
| [II] Ray (active user)                        |
| [II] David (idle for 2 hours)               |
| [II] Tom (formatting disk)                |
| - - - - - - - - - -  - - -  - - - - - - - - - - |
| [II] System backup                         |
| Restarting now wlll disrupt other    |
| users and system processes.          |
| Additional privileges are required.    |
|                                                     |
|            [Cancel] [Restart anyway...]  |

8) User does whatever he needs to with the information, like closing
apps, calling fellow users, etc
9) User clicks on 'Stop anyway...'
10) gnome-session calls Stop on CK
11) CK does the PolicyKit dance to get privileges, possibly showing an
auth dialog
12) CK sets the IsStopping property
13) CK emits Stop
14) Sessions do their own EndSession dance
15) Sessions respond back with StopResponse
16) CK shuts down

Notes and open questions

- In the single-user case, the QueryStop response would indicate 0
sessions, and the Inhibit dialog would become just the regular inhibit

Should inhibit information from the session that originates the request be collected as that for other sessions, or should the session know that it is the originator and not respond? Must shutdown requests always go through the session manager for the originating session? IOW: Is 0 or 1 the right result for the single-user case?

- The password dialog comes up _after_ the inhibit dialog. This is
probably fine, since we have enough in formation in the inhibit dialog
to tell the user that extra privileges will be required.

This order is probably better anyhow, as it allows that the needed privileges depend on the existence and kind of inhibitors to override.

- What identifying information do we need for CK inhibitors. Are app
name and session id (for the session in which an operation originated)
sufficient ? Are object paths nullable, so that they can be optional ?

- Do we need to register sessions with CK, or is it ok to just
broadcast a signal and match up responses with session ids ?

The ConsoleKit manager knows all sessions anyhow, doesn't it? How would GetSessions work otherwise?

In any case Signals with pseudo-synchronous response requirements is something I'm not very comfortable with, so sending to and expecting responses from a known list of sessions is better. This provides additional information, like a warning about sessions that are not responding after expiry of a timeout. This could even propagate to the caller, given a return channel for that information.

Of course you need a timeout to make sure you can shut down when there are hanging sessions, but a timeout that still works on a highly loaded machine would be an onerous delay, if you have to wait it out when there is a single session with no inhibitors. If you know your session, you know when your query round is done and can set timeouts much more defensively.

- Is the summary information (number of inhibitors/sessions) in the
QueryStop response useful ? And is it ok to require session managers
to  collect the necessary information for the dialog itself with
GetInhibitors/GetSessions or should all that information be returned
by QueryStop ?

The summary information is of limited use, because by the time the caller calls GetSessions/GetInhibitors it may already be stale. Of course any returned list might be stale by the time the actual Stop is issued. OTOH there may be callers who treat the results like a boolean value.

- Do we need to have an explicit CancelStop signal if the user cancels
in the inhibit dialog or the password dialog ? Do the sessions return
to the 'running' phase on their own after the QueryEndSession dance ?

There might be some value for dealing with creation/stopping races to have two IsStopping states, so a caller can find out that QueryStop is in progress. That - or any mechanism in the sessions to prevent new potential inhibitors from being started between QueryStop and Stop would require a CancelStop method and signal. Again timeouts don't feel right for returning sessions to fully running status.

- What is the deal with the StopResponse 'reason'. How does that
relate to just-in-time inhibitors ?

Just quick comments that came to mind.

- Jörg

Joerg Barfurth
Software Engineer        mailto:joerg barfurth sun com
Desktop Technology
Thin Client Software
Sun Microsystems GmbH

Sitz der Gesellschaft:
Sun Microsystems GmbH, Sonnenallee 1, D-85551 Kirchheim-Heimstetten
Amtsgericht Muenchen: HRB 161028
Geschaeftsfuehrer: Thomas Schroeder, Wolfgang Engels, Wolf Frenkel
Vorsitzender des Aufsichtsrates: Martin Haering

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]