unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Proof of concept: Shepherd + DBus = ♥
@ 2023-02-24 20:55 Liliana Marie Prikler
  2023-02-25  3:29 ` Maxim Cournoyer
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Liliana Marie Prikler @ 2023-02-24 20:55 UTC (permalink / raw)
  To: guix-devel

Hi Guix,

this comes a little late, as Gnome folks have decided that evaluating
arbitrary Javascript over DBus is perhaps not always the wisest idea¹,
but I want to share with you a cool nifty tool regardless.

For starters, recall that Guix can only really set up its profile
environment variables during login – that is if all processes are to
respect them.  This brings us into a weird chimera state after running
`guix package': Any new variable introduced in our profile will be lost
until we restart our shell.  Or will it?

Enter guile-ac-d-bus.  With the newest version of Guile (3.0.9 at time
of writing), we can actually connect to the session bus and do cool
stuff with it.  Watch me:

--8<---------------cut here---------------start------------->8---
(define (d-bus-send/wait-for-reply bus message)
  (let ((serial (d-bus-write-message bus message)))
    (d-bus-conn-flush bus)
    (let loop ((msg (d-bus-read-message bus)))
      (if (equal? (d-bus-headers-ref (d-bus-message-headers msg)
                                     'REPLY_SERIAL)
                  serial)
          msg
          (loop (d-bus-read-message bus))))))

(let ((bus (d-bus-connect))
      (message (make-d-bus-message
                MESSAGE_TYPE_METHOD_CALL 0 #f '()
                (vector
                 (header-PATH "/org/freedesktop/DBus")
                 (header-DESTINATION "org.freedesktop.DBus")
                 (header-INTERFACE "org.freedesktop.DBus")
                 (header-MEMBER "Hello"))
                #f)))
  (write (d-bus-send/wait-for-reply bus message))
  (d-bus-disconnect bus))
--8<---------------cut here---------------end--------------->8---

Okay, but how does this solve our aforementioned problem?
Well...

--8<---------------cut here---------------start------------->8---
(define shell
  (make <service>
    #:docstring "Communicate with the GNOME Shell"
    #:provides '(gnome shell)
    #:start
    (lambda ()
      (let ((bus (d-bus-connect))
            (message (make-d-bus-message
                      MESSAGE_TYPE_METHOD_CALL 0 #f '()
                      (vector
                       (header-PATH "/org/freedesktop/DBus")
                       (header-DESTINATION "org.freedesktop.DBus")
                       (header-INTERFACE "org.freedesktop.DBus")
                       (header-MEMBER "Hello"))
                      #f)))
        (d-bus-send/wait-for-reply bus message)
        bus))
    #:stop
    (lambda (conn)
      (when conn (d-bus-disconnect conn))
      #f)
    #:actions
    (let ((action->js
           (lambda (action . args)
             (format #f "imports.gi.GLib.~a(~{~s~^,~})" action args)))
          (shell-exec
           (lambda (conn js)
             (let ((method-call
                    (make-d-bus-message
                     MESSAGE_TYPE_METHOD_CALL 0 #f '()
                     (vector
                      (header-PATH        "/org/gnome/Shell")
                      (header-DESTINATION "org.gnome.Shell")
                      (header-INTERFACE   "org.gnome.Shell")
                      (header-SIGNATURE   "s")
                      (header-MEMBER      "Eval"))
                     (list js))))
               (let ((reply (d-bus-send/wait-for-reply conn 
                                                       method-call)))
                 (apply peek 'reply (d-bus-message-body reply)))))))
      (make-actions
       (getenv
        (lambda (conn var)
          (and=> conn (cut shell-exec <>
                           (action->js 'getenv var)))))
       (setenv
        (lambda (conn var val)
          (and=> conn (cut shell-exec <>
                           (action->js 'setenv var val)))))
       (unsetenv
        (lambda (conn var)
          (and=> conn (cut shell-exec <>
                           (action->js 'unsetenv var)))))))))
--8<---------------cut here---------------end--------------->8---

Once you set the unsafe flag in Looking Glass and promise to be a very
good girl, you can now extract environment variables.

--8<---------------cut here---------------start------------->8---
$ herd getenv gnome PATH              

;;; (reply #t "\"/gnu/store/s43dhx83c3a2g79vs5anf3wdmv9lwpi3-glib-
2.70.2-bin/bin:/run/setuid-
programs:/home/yuri/.config/guix/current/bin:$HOME/.guix-
profile/bin:$HOME/.guix-profile/sbin:/run/current-
system/profile/bin:/run/current-system/profile/sbin\"")
--8<---------------cut here---------------end--------------->8---

If you were naughty and didn't do the magic dance, you get a rather
unhelpful result instead.

--8<---------------cut here---------------start------------->8---
$ herd getenv gnome PATH              

;;; (reply #f "")
--8<---------------cut here---------------end--------------->8---

Anyway, we can now talk to DBus services from Shepherd, although doing
so is currently a bit of a pain in the buttocks.  Much of this is due
to guile-ac-d-bus being somewhat obtuse and not having enough fibers in
it.  That being said, I'm sure there's some other use-case out there
that is a good fit for this (wanna talk to loginctl for hibernation
perhaps?)

Cheers

¹ How dare they?  Don't they know that this breaks my spacebar heating
workflow?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-02-24 20:55 Proof of concept: Shepherd + DBus = ♥ Liliana Marie Prikler
@ 2023-02-25  3:29 ` Maxim Cournoyer
  2023-02-25 18:38 ` Ludovic Courtès
  2023-04-11 13:44 ` Simon Tournier
  2 siblings, 0 replies; 7+ messages in thread
From: Maxim Cournoyer @ 2023-02-25  3:29 UTC (permalink / raw)
  To: Liliana Marie Prikler; +Cc: guix-devel

Hi Liliana,

Liliana Marie Prikler <liliana.prikler@gmail.com> writes:

> Hi Guix,
>
> this comes a little late, as Gnome folks have decided that evaluating
> arbitrary Javascript over DBus is perhaps not always the wisest idea¹,
> but I want to share with you a cool nifty tool regardless.
>
> For starters, recall that Guix can only really set up its profile
> environment variables during login – that is if all processes are to
> respect them.  This brings us into a weird chimera state after running
> `guix package': Any new variable introduced in our profile will be lost
> until we restart our shell.  Or will it?
>
> Enter guile-ac-d-bus.  With the newest version of Guile (3.0.9 at time
> of writing), we can actually connect to the session bus and do cool
> stuff with it.  Watch me:
>
> (define (d-bus-send/wait-for-reply bus message)
>   (let ((serial (d-bus-write-message bus message)))
>     (d-bus-conn-flush bus)
>     (let loop ((msg (d-bus-read-message bus)))
>       (if (equal? (d-bus-headers-ref (d-bus-message-headers msg)
>                                      'REPLY_SERIAL)
>                   serial)
>           msg
>           (loop (d-bus-read-message bus))))))
>
> (let ((bus (d-bus-connect))
>       (message (make-d-bus-message
>                 MESSAGE_TYPE_METHOD_CALL 0 #f '()
>                 (vector
>                  (header-PATH "/org/freedesktop/DBus")
>                  (header-DESTINATION "org.freedesktop.DBus")
>                  (header-INTERFACE "org.freedesktop.DBus")
>                  (header-MEMBER "Hello"))
>                 #f)))
>   (write (d-bus-send/wait-for-reply bus message))
>   (d-bus-disconnect bus))
>
>
> Okay, but how does this solve our aforementioned problem?
> Well...
>
> (define shell
>   (make <service>
>     #:docstring "Communicate with the GNOME Shell"
>     #:provides '(gnome shell)
>     #:start
>     (lambda ()
>       (let ((bus (d-bus-connect))
>             (message (make-d-bus-message
>                       MESSAGE_TYPE_METHOD_CALL 0 #f '()
>                       (vector
>                        (header-PATH "/org/freedesktop/DBus")
>                        (header-DESTINATION "org.freedesktop.DBus")
>                        (header-INTERFACE "org.freedesktop.DBus")
>                        (header-MEMBER "Hello"))
>                       #f)))
>         (d-bus-send/wait-for-reply bus message)
>         bus))
>     #:stop
>     (lambda (conn)
>       (when conn (d-bus-disconnect conn))
>       #f)
>     #:actions
>     (let ((action->js
>            (lambda (action . args)
>              (format #f "imports.gi.GLib.~a(~{~s~^,~})" action args)))
>           (shell-exec
>            (lambda (conn js)
>              (let ((method-call
>                     (make-d-bus-message
>                      MESSAGE_TYPE_METHOD_CALL 0 #f '()
>                      (vector
>                       (header-PATH        "/org/gnome/Shell")
>                       (header-DESTINATION "org.gnome.Shell")
>                       (header-INTERFACE   "org.gnome.Shell")
>                       (header-SIGNATURE   "s")
>                       (header-MEMBER      "Eval"))
>                      (list js))))
>                (let ((reply (d-bus-send/wait-for-reply conn 
>                                                        method-call)))
>                  (apply peek 'reply (d-bus-message-body reply)))))))
>       (make-actions
>        (getenv
>         (lambda (conn var)
>           (and=> conn (cut shell-exec <>
>                            (action->js 'getenv var)))))
>        (setenv
>         (lambda (conn var val)
>           (and=> conn (cut shell-exec <>
>                            (action->js 'setenv var val)))))
>        (unsetenv
>         (lambda (conn var)
>           (and=> conn (cut shell-exec <>
>                            (action->js 'unsetenv var)))))))))
>

Interesting!

[...]

> Anyway, we can now talk to DBus services from Shepherd, although doing
> so is currently a bit of a pain in the buttocks.  Much of this is due
> to guile-ac-d-bus being somewhat obtuse and not having enough fibers in
> it.  That being said, I'm sure there's some other use-case out there
> that is a good fit for this (wanna talk to loginctl for hibernation
> perhaps?)

One use case I saw while working on jami-service-type, where I used
guile-ac-d-bus (you may want to take a peek at (guix build
dbus-service)) to talk to its daemon via its D-Bus interface, was to
wait until a D-Bus service is truly 'activated'.

We've had problems in the past for example where services would start
before a critical D-Bus service was truly up (activated), and this could
be used to poll for the D-Bus service.  The 'dbus-available-services'
procedure from (guix build dbus-services) could be used to poll and
delay a service to start until its D-Bus requirement is running.

-- 
Thanks,
Maxim


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-02-24 20:55 Proof of concept: Shepherd + DBus = ♥ Liliana Marie Prikler
  2023-02-25  3:29 ` Maxim Cournoyer
@ 2023-02-25 18:38 ` Ludovic Courtès
  2023-02-25 19:34   ` Liliana Marie Prikler
  2023-04-11 13:44 ` Simon Tournier
  2 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2023-02-25 18:38 UTC (permalink / raw)
  To: Liliana Marie Prikler; +Cc: guix-devel

Hello!

Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:

> this comes a little late, as Gnome folks have decided that evaluating
> arbitrary Javascript over DBus is perhaps not always the wisest idea¹,

Too bad, what could possibly go wrong?

[...]

> Once you set the unsafe flag in Looking Glass and promise to be a very
> good girl, you can now extract environment variables.
>
> $ herd getenv gnome PATH              
>
> ;;; (reply #t "\"/gnu/store/s43dhx83c3a2g79vs5anf3wdmv9lwpi3-glib-
> 2.70.2-bin/bin:/run/setuid-
> programs:/home/yuri/.config/guix/current/bin:$HOME/.guix-
> profile/bin:$HOME/.guix-profile/sbin:/run/current-
> system/profile/bin:/run/current-system/profile/sbin\"")
>
>
> If you were naughty and didn't do the magic dance, you get a rather
> unhelpful result instead.
>
> $ herd getenv gnome PATH              
>
> ;;; (reply #f "")

This is super cool and super useful.  Is there some way we could achieve
this (getenv/setenv in the GNOME Shell process) without resorting to JS?

(💡 Did you know?  On GNU/Hurd, each process implements the “msg” RPC
interface, which, among other things, lets you inspect and change its
environment variables!  If you have a childhurd running, try something
like: “msgport --getenv=PATH -p $$”.)

> Anyway, we can now talk to DBus services from Shepherd, although doing
> so is currently a bit of a pain in the buttocks.  Much of this is due
> to guile-ac-d-bus being somewhat obtuse and not having enough fibers in
> it.  That being said, I'm sure there's some other use-case out there
> that is a good fit for this (wanna talk to loginctl for hibernation
> perhaps?)

Yes!  Provided suitable Fibers integration, we could have services that
automatically start/stop based on some notification received on the bus
(devices plugged/unplugged, power or network condition changes, etc.).
Pretty exciting.

Thanks for sharing!

Ludo’.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-02-25 18:38 ` Ludovic Courtès
@ 2023-02-25 19:34   ` Liliana Marie Prikler
  2023-03-06 17:28     ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Liliana Marie Prikler @ 2023-02-25 19:34 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

Hi

Am Samstag, dem 25.02.2023 um 19:38 +0100 schrieb Ludovic Courtès:
> Hello!
> 
> Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:
> 
> > this comes a little late, as Gnome folks have decided that
> > evaluating arbitrary Javascript over DBus is perhaps not always the
> > wisest idea¹,
> 
> Too bad, what could possibly go wrong?
Well, I could imagine a fair number of scenarios from denial of service
attacks to privilege escalation.  Once you have limited code execution
on the target machine, that is – you would need to at least be able to
send messages over DBus after all.  I'm not sure what the Gnome team
has in mind exactly, but in any case, they consider Eval to be a
private, rather than public API.

> > Once you set the unsafe flag in Looking Glass and promise to be a
> > very good girl, you can now extract environment variables.
> > 
> > $ herd getenv gnome PATH              
> > 
> > ;;; (reply #t "\"/gnu/store/s43dhx83c3a2g79vs5anf3wdmv9lwpi3-glib-
> > 2.70.2-bin/bin:/run/setuid-
> > programs:/home/yuri/.config/guix/current/bin:$HOME/.guix-
> > profile/bin:$HOME/.guix-profile/sbin:/run/current-
> > system/profile/bin:/run/current-system/profile/sbin\"")
> > 
> > 
> > If you were naughty and didn't do the magic dance, you get a rather
> > unhelpful result instead.
> > 
> > $ herd getenv gnome PATH              
> > 
> > ;;; (reply #f "")
> 
> This is super cool and super useful.  Is there some way we could
> achieve this (getenv/setenv in the GNOME Shell process) without
> resorting to JS?
Well, we could patch the Gnome Shell DBus API to expose getenv(s),
setenv(ss) and unsetenv(s) – note the DBus method signature in
brackets.  As far as I'm aware, there is currently no such public API.

> (💡 Did you know?  On GNU/Hurd, each process implements the “msg” RPC
> interface, which, among other things, lets you inspect and change its
> environment variables!  If you have a childhurd running, try
> something like: “msgport --getenv=PATH -p $$”.)
Sounds fun.

> 
> Provided suitable Fibers integration, we could have services that
> automatically start/stop based on some notification received on the
> bus (devices plugged/unplugged, power or network condition changes,
> etc.).
Even better, we could (at some time) go full systemd and take control
over all services spawned via DBus. 

Cheers


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-02-25 19:34   ` Liliana Marie Prikler
@ 2023-03-06 17:28     ` Ludovic Courtès
  0 siblings, 0 replies; 7+ messages in thread
From: Ludovic Courtès @ 2023-03-06 17:28 UTC (permalink / raw)
  To: Liliana Marie Prikler; +Cc: guix-devel

Hi!

Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:

[...]

>> > If you were naughty and didn't do the magic dance, you get a rather
>> > unhelpful result instead.
>> > 
>> > $ herd getenv gnome PATH              
>> > 
>> > ;;; (reply #f "")
>> 
>> This is super cool and super useful.  Is there some way we could
>> achieve this (getenv/setenv in the GNOME Shell process) without
>> resorting to JS?
> Well, we could patch the Gnome Shell DBus API to expose getenv(s),
> setenv(ss) and unsetenv(s) – note the DBus method signature in
> brackets.  As far as I'm aware, there is currently no such public API.

Maybe it’s worth trying.  We could always submit that upstream.

>> Provided suitable Fibers integration, we could have services that
>> automatically start/stop based on some notification received on the
>> bus (devices plugged/unplugged, power or network condition changes,
>> etc.).
> Even better, we could (at some time) go full systemd and take control
> over all services spawned via DBus. 

Yes!

Ludo’.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-02-24 20:55 Proof of concept: Shepherd + DBus = ♥ Liliana Marie Prikler
  2023-02-25  3:29 ` Maxim Cournoyer
  2023-02-25 18:38 ` Ludovic Courtès
@ 2023-04-11 13:44 ` Simon Tournier
  2023-04-12  5:30   ` Liliana Marie Prikler
  2 siblings, 1 reply; 7+ messages in thread
From: Simon Tournier @ 2023-04-11 13:44 UTC (permalink / raw)
  To: Liliana Marie Prikler, guix-devel

Hi,

Wow!  Very cool!

(Being very late to the party does not mean the party is not fun. ;-))

On ven., 24 févr. 2023 at 21:55, Liliana Marie Prikler <liliana.prikler@gmail.com> wrote:

> --8<---------------cut here---------------start------------->8---
> $ herd getenv gnome PATH              
>
> ;;; (reply #t "\"/gnu/store/s43dhx83c3a2g79vs5anf3wdmv9lwpi3-glib-
> 2.70.2-bin/bin:/run/setuid-
> programs:/home/yuri/.config/guix/current/bin:$HOME/.guix-
> profile/bin:$HOME/.guix-profile/sbin:/run/current-
> system/profile/bin:/run/current-system/profile/sbin\"")
> --8<---------------cut here---------------end--------------->8---

[...]

> Anyway, we can now talk to DBus services from Shepherd, although doing
> so is currently a bit of a pain in the buttocks.  Much of this is due
> to guile-ac-d-bus being somewhat obtuse and not having enough fibers in
> it.  That being said, I'm sure there's some other use-case out there
> that is a good fit for this (wanna talk to loginctl for hibernation
> perhaps?)

Does it open a way to have dedicated and/or isolated Gnome “workspace“
setting some paths?  Say, on this workspace 1 only Web related
applications and on that workspace 2 only Emacs related stuff, etc.


Cheers,
simon


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Proof of concept: Shepherd + DBus = ♥
  2023-04-11 13:44 ` Simon Tournier
@ 2023-04-12  5:30   ` Liliana Marie Prikler
  0 siblings, 0 replies; 7+ messages in thread
From: Liliana Marie Prikler @ 2023-04-12  5:30 UTC (permalink / raw)
  To: Simon Tournier, guix-devel

Am Dienstag, dem 11.04.2023 um 15:44 +0200 schrieb Simon Tournier:
> Does it open a way to have dedicated and/or isolated Gnome
> “workspace“ setting some paths?  Say, on this workspace 1 only Web
> related applications and on that workspace 2 only Emacs related
> stuff, etc.
If you treat multiple sessions as workspaces, and set their environment
variables through Shepherd, sure.  I think you could probably get a
session within a session rolling via Xephyr or possibly some Wayland
thing I know too little about.

Cheers


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-04-12  5:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-24 20:55 Proof of concept: Shepherd + DBus = ♥ Liliana Marie Prikler
2023-02-25  3:29 ` Maxim Cournoyer
2023-02-25 18:38 ` Ludovic Courtès
2023-02-25 19:34   ` Liliana Marie Prikler
2023-03-06 17:28     ` Ludovic Courtès
2023-04-11 13:44 ` Simon Tournier
2023-04-12  5:30   ` Liliana Marie Prikler

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).