Message ID | 4fdf0d9993bb3375797ca807d894f66920bd81d2.1704553618.git.~@wolfsden.cz |
---|---|
State | New |
Headers | show |
Series | [bug#68289] services: xorg: Add xorg-start-command-xinit procedure. | expand |
Hi Tomas, Thanks for patch 68289 re `xorg-start-command-xinit'. I think it'd be great to have a command like that in Guix. In a clumsy attempt to review the patch, I've compared it with the code for `startx' that I found here⁰. My comments, including some general observations that might help other reviewers, follow. tl;dr: - I hope someone more Xorg savvy than me can have a look. - Other than a couple of questions (below), things look alright to me. - I haven't tested the patch on my system yet, but I plan to do it soon. Thanks, have a great day, Fabio. ⁰ https://gitlab.freedesktop.org/xorg/app/xinit/-/blob/master/startx.cpp `(determine-unused-display n)' maps closely to this code block: ,---- | XCOMM Automatically determine an unused $DISPLAY | d=0 | while true ; do | [ -e "/tmp/.X$d-lock" -o -S "/tmp/.X11-unix/X$d" ] || break | d=$(($d + 1)) | done | defaultdisplay=":$d" | unset d `---- `(determine-vty)' is similar to the block below, but `startx' relies on the `tty' command from Coreutils. Do you think there might be any advantage in using it in `(determine-vty)'? A slight simplification perhaps? ,---- | #ifdef __linux__ | XCOMM When starting the defaultserver start X on the current tty to avoid | XCOMM the startx session being seen as inactive: | XCOMM "https://bugzilla.redhat.com/show_bug.cgi?id=806491" | tty=$(tty) | if expr "$tty" : '/dev/tty[0-9][0-9]*$' > /dev/null; then | tty_num=$(echo "$tty" | grep -oE '[0-9]+$') | vtarg="vt$tty_num -keeptty" | fi | #endif `---- `(enable-xauth server-auth-file display)' maps closely to: ,---- | XCOMM create a file with auth information for the server. ':0' is a dummy. | xserverauthfile=$HOME/.serverauth.$$ | trap "rm -f '$xserverauthfile'" HUP INT QUIT ILL TRAP KILL BUS TERM | xauth -q -f "$xserverauthfile" << EOF | add :$dummy . $mcookie | EOF | #if defined(__APPLE__) || defined(__CYGWIN__) | xserverauthfilequoted=$(echo ${xserverauthfile} | sed "s/'/'\\\\''/g") | serverargs=${serverargs}" -auth '"${xserverauthfilequoted}"'" | #else | serverargs=${serverargs}" -auth "${xserverauthfile} | #endif | | XCOMM now add the same credentials to the client authority file | XCOMM if '$displayname' already exists do not overwrite it as another | XCOMM server may need it. Add them to the '$xserverauthfile' instead. | for displayname in $authdisplay $hostname$authdisplay; do | authcookie=`XAUTH list "$displayname" @@ | | sed -n "s/.*$displayname[[:space:]*].*[[:space:]*]//p"` 2>/dev/null; | if [ "z${authcookie}" = "z" ] ; then | XAUTH -q << EOF | add $displayname . $mcookie | EOF `---- The patch saves the server's auth file in `/tmp' whereas `startx' uses the home directory. I wonder if this might make any difference in terms of security. Related, how can we be sure that `(mkstemp "/tmp/serverauth.XXXXXX")' will be setting the right file permissions? Here's the two relevant bits: ,---- | (server-auth-port (mkstemp "/tmp/serverauth.XXXXXX")) | (server-auth-file (port-filename server-auth-port)) `---- ,---- | xserverauthfile=$HOME/.serverauth.$$ | trap "rm -f '$xserverauthfile'" HUP INT QUIT ILL TRAP KILL BUS TERM `---- Finally, on a purely cosmetic side, any reason to have `(define X (xorg-wrapper config))' outside the G-expression, while the other definitions are inside?
Hi, a quick follow-up on a couple of points. On 2024-04-16, 19:29 +0100, Fabio Natali <me@fabionatali.com> wrote: > - I haven't tested the patch on my system yet, but I plan to do it > soon. I've tested the patch and it works as expected on my system. > `(determine-vty)' is similar to the block below, but `startx' relies > on the `tty' command from Coreutils. Do you think there might be any > advantage in using it in `(determine-vty)'? A slight simplification > perhaps? Looking into this more closely, the `tty' command wouldn't be a simplification. It might be a bit more consistent with other parts of the patch and it'd abstract away the hardcoded `/proc/self/fd/0', but probably not worth the change? > The patch saves the server's auth file in `/tmp' whereas `startx' uses > the home directory. I wonder if this might make any difference in > terms of security. Related, how can we be sure that `(mkstemp > "/tmp/serverauth.XXXXXX")' will be setting the right file permissions? I see the reason why we want to use `/tmp', as otherwise the number of stale `serverauth.XXXXXX' files would grow indefinitely. Using `/tmp', at least we know they'll be garbage collected at every reboot. Any way to emulate `startx' and use some sort of `trap' to remove the file on exit? > Finally, on a purely cosmetic side, any reason to have `(define X > (xorg-wrapper config))' outside the G-expression, while the other > definitions are inside? Oh yes, the `(define X ...)' has to be outside the G-expression, of course. The security aspect (in relation to the server auth file, its permissions and location) is the only remaining point where I'd like an extra pair of eyes. The rest of the patch LGTM. There's a couple of microscopic formatting issues (e.g. an occurrence of tty where I'd write TTY instead), I'll list them all in a follow-up. Thanks, best wishes, Fabio.
On 2024-04-17, 10:30 +0100, Fabio Natali <me@fabionatali.com> wrote:
> Hi, a quick follow-up on a couple of points.
Also, I suppose one could use Guix's 'invoke' instead of a custom
'checked-system*'?
https://issues.guix.gnu.org/issue/68289/#0-lineno88
Cheers, F.
Hello Fabio, first, let me thank you for the review, and apologize for somewhat late response, sadly I have been busy. On 2024-04-17 10:30:12 +0100, Fabio Natali wrote: > Hi, a quick follow-up on a couple of points. > > On 2024-04-16, 19:29 +0100, Fabio Natali <me@fabionatali.com> wrote: > > - I haven't tested the patch on my system yet, but I plan to do it > > soon. > > I've tested the patch and it works as expected on my system. Great! :) > > > `(determine-vty)' is similar to the block below, but `startx' relies > > on the `tty' command from Coreutils. Do you think there might be any > > advantage in using it in `(determine-vty)'? A slight simplification > > perhaps? > > Looking into this more closely, the `tty' command wouldn't be a > simplification. It might be a bit more consistent with other parts of > the patch and it'd abstract away the hardcoded `/proc/self/fd/0', but > probably not worth the change? I think the current way is fine, since this is Guix specific code, so it does not have to be extremely portable. But that is just my opinion. Would be nice to know if it works on Hurd. > > > The patch saves the server's auth file in `/tmp' whereas `startx' uses > > the home directory. I wonder if this might make any difference in > > terms of security. Related, how can we be sure that `(mkstemp > > "/tmp/serverauth.XXXXXX")' will be setting the right file permissions? While POSIX does not seem to specify the permissions of the created file, the Guile's manual is pretty clear regarding it: POSIX doesn’t specify the permissions mode of the file. On GNU and most systems it’s ‘#o600’; an application can use ‘chmod’ to relax that if desired. In my understanding that makes this usage safe. > > I see the reason why we want to use `/tmp', as otherwise the number of > stale `serverauth.XXXXXX' files would grow indefinitely. Using `/tmp', > at least we know they'll be garbage collected at every reboot. Any way > to emulate `startx' and use some sort of `trap' to remove the file on > exit? Yes, the clean up was the main motivator. The script could *try* to clean up, but even then it would leave garbage in the $HOME in situations like power failure and kernel crashes. So using /tmp seems like simple yet reliable solution. > > > Finally, on a purely cosmetic side, any reason to have `(define X > > (xorg-wrapper config))' outside the G-expression, while the other > > definitions are inside? > > Oh yes, the `(define X ...)' has to be outside the G-expression, of > course. > > The security aspect (in relation to the server auth file, its > permissions and location) is the only remaining point where I'd like an > extra pair of eyes. The rest of the patch LGTM. > > There's a couple of microscopic formatting issues (e.g. an occurrence of > tty where I'd write TTY instead), I'll list them all in a follow-up. > > Thanks, best wishes, Fabio. Have a nice day, Tomas -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
On 2024-04-18 19:43:41 +0100, Fabio Natali wrote: > On 2024-04-17, 10:30 +0100, Fabio Natali <me@fabionatali.com> wrote: > > Hi, a quick follow-up on a couple of points. > > Also, I suppose one could use Guix's 'invoke' instead of a custom > 'checked-system*'? > > https://issues.guix.gnu.org/issue/68289/#0-lineno88 > > Cheers, F. Yes, that would be an option. I do not remember why I wrote it like this, it is possible I just did not know about `invoke' at that time (the code is over a year old). However I am not sure whether it is fine to depend on code in the (guix build utils) module for non-build purposes. Assuming it is fine, I have no problem sending a v2. Cheers, T. -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
On 2024-04-18, 23:09 +0200, Tomas Volf <~@wolfsden.cz> wrote: > first, let me thank you for the review, and apologize for somewhat > late response, sadly I have been busy. Contrarily, thank you for getting back to my points. 🙏 It all sounds good. I'll try and bring this up on IRC or during one of the patch review sessions organised by Futurile - in case there's a committer who's willing to merge it. Have a nice day. Best, Fabio.
On 2024-04-19, 13:25 +0100, Fabio Natali <me@fabionatali.com> wrote: > On 2024-04-18, 23:09 +0200, Tomas Volf <~@wolfsden.cz> wrote: >> first, let me thank you for the review, and apologize for somewhat >> late response, sadly I have been busy. Hi Tomas, Sorry for the slow follow-up. After some further testing and some input from other Guix friends, this is my humble feedback on what I'd put in a v2 patch. - Use Guix's 'invoke' instead of a custom 'checked-system*' procedure. - Where possible, use '#$(file-append foobar "/bin/foo")' instead of '(string-append #$foobar "/bin/foo")', so that as much computation as possible happens at build time as opposed to run time. It's a microscopic difference, but still worth the change I think. What do you think? Not urgent, but do you think this is something you might be interested to include in a v2? No problem if you're busy, but let me know if there's anything I can help with. Tangentally, with regard to 'capture-stdout', I'm exploring if this is something that could be added to '(guix build utils)'⁰ or perhaps addressed in Guile¹ instead of Guix. This can be left as it is in the patch, and potentially refactored away once a similar procedure is available from Guix or Guile. Thanks, best wishes, Fabio. ⁰ https://lists.gnu.org/archive/html/guix-devel/2024-04/msg00199.html ¹ https://lists.gnu.org/archive/html/bug-guile/2024-04/msg00015.html
On 2024-04-24 12:59:55 +0100, Fabio Natali wrote: > On 2024-04-19, 13:25 +0100, Fabio Natali <me@fabionatali.com> wrote: > > On 2024-04-18, 23:09 +0200, Tomas Volf <~@wolfsden.cz> wrote: > >> first, let me thank you for the review, and apologize for somewhat > >> late response, sadly I have been busy. > > Hi Tomas, > > Sorry for the slow follow-up. After some further testing and some input > from other Guix friends, this is my humble feedback on what I'd put in a > v2 patch. > > - Use Guix's 'invoke' instead of a custom 'checked-system*' procedure. > > - Where possible, use '#$(file-append foobar "/bin/foo")' instead of > '(string-append #$foobar "/bin/foo")', so that as much computation as > possible happens at build time as opposed to run time. It's a > microscopic difference, but still worth the change I think. > > What do you think? Not urgent, but do you think this is something you > might be interested to include in a v2? No problem if you're busy, but > let me know if there's anything I can help with. All sounds reasonable, will send v2, cannot guarantee when, hopefully this week. > > Tangentally, with regard to 'capture-stdout', I'm exploring if this is > something that could be added to '(guix build utils)'⁰ or perhaps > addressed in Guile¹ instead of Guix. This can be left as it is in the > patch, and potentially refactored away once a similar procedure is > available from Guix or Guile. > > Thanks, best wishes, Fabio. Yes, I noticed the thread. Having the option of doing basically (with-output-to-string (λ _ (invoke "date"))) would be amazing. I hope someone will take it up and implement. :) Have a nice day, Tomas -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
Hi! Tomas Volf <~@wolfsden.cz> skribis: > On 2024-04-24 12:59:55 +0100, Fabio Natali wrote: >> On 2024-04-19, 13:25 +0100, Fabio Natali <me@fabionatali.com> wrote: >> > On 2024-04-18, 23:09 +0200, Tomas Volf <~@wolfsden.cz> wrote: >> >> first, let me thank you for the review, and apologize for somewhat >> >> late response, sadly I have been busy. >> >> Hi Tomas, >> >> Sorry for the slow follow-up. After some further testing and some input >> from other Guix friends, this is my humble feedback on what I'd put in a >> v2 patch. >> >> - Use Guix's 'invoke' instead of a custom 'checked-system*' procedure. >> >> - Where possible, use '#$(file-append foobar "/bin/foo")' instead of >> '(string-append #$foobar "/bin/foo")', so that as much computation as >> possible happens at build time as opposed to run time. It's a >> microscopic difference, but still worth the change I think. >> >> What do you think? Not urgent, but do you think this is something you >> might be interested to include in a v2? No problem if you're busy, but >> let me know if there's anything I can help with. > > All sounds reasonable, will send v2, cannot guarantee when, hopefully this week. I hadn’t seen this patch; having a ‘startx’ command is something that has often been asked, so I’m glad you’re fixing it! The patch and the suggestions Fabio made look great to me. Perhaps a useful addition would be to add a service so one can write nothing more than: (service startx-command-service-type) to get a ‘startx’ command? (Not a blocker though.) Ludo’.
On 2024-05-02 11:55:28 +0200, Ludovic Courtès wrote: > Hi! Hi :) > Tomas Volf <~@wolfsden.cz> skribis: > > [..] > > I hadn’t seen this patch; having a ‘startx’ command is something that > has often been asked, so I’m glad you’re fixing it! > > The patch and the suggestions Fabio made look great to me. Perhaps a > useful addition would be to add a service so one can write nothing more > than: > > (service startx-command-service-type) > > to get a ‘startx’ command? (Not a blocker though.) That sounds useful and I have no issue adding it into the v2. Could I just ask you for a guidance regarding how to achieve that? Currently I just place the script into ~/bin (which I have in the $PATH). I assume the service will have to place the file... somewhere? on the $PATH to achieve the same. Is there already existing service I could use as an inspiration? Thanks, Tomas -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
Hi! Tomas Volf <~@wolfsden.cz> skribis: > On 2024-05-02 11:55:28 +0200, Ludovic Courtès wrote: [...] >> The patch and the suggestions Fabio made look great to me. Perhaps a >> useful addition would be to add a service so one can write nothing more >> than: >> >> (service startx-command-service-type) >> >> to get a ‘startx’ command? (Not a blocker though.) > > That sounds useful and I have no issue adding it into the v2. Could I just ask > you for a guidance regarding how to achieve that? Currently I just place the > script into ~/bin (which I have in the $PATH). I assume the service will have > to place the file... somewhere? on the $PATH to achieve the same. I would extend ‘profile-service-type’ such that ‘startx’ appears in /run/current-system/profile/bin. It does mean that you need to create a computed-file that produces /gnu/store/…/bin/startx (‘startx’ must be in a bin/ sub-directory). How does that sound? Ludo’.
Hello :) On 2024-05-03 11:57:07 +0200, Ludovic Courtès wrote: > I would extend ‘profile-service-type’ such that ‘startx’ appears in > /run/current-system/profile/bin. > > It does mean that you need to create a computed-file that produces > /gnu/store/…/bin/startx (‘startx’ must be in a bin/ sub-directory). > > How does that sound? Right, so I finally found some time to look into it and produced a v2. I took inspiration from already existing services in (gnu services xorg), and in the end it was not that hard to do. Let me know what you think. Have a nice day, Tomas -- There are only two hard things in Computer Science: cache invalidation, naming things and off-by-one errors.
diff --git a/doc/guix.texi b/doc/guix.texi index a648a106b3..72c5527270 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -23177,6 +23177,24 @@ X Window Usually the X server is started by a login manager. @end deffn +@deffn {Procedure} xorg-start-command-xinit [config] +Return a @code{startx} script in which the modules, fonts, +etc. specified in @var{config}, are available. The result should be +used in place of @code{startx}. Compared to the +@code{xorg-start-command} it calls xinit, therefore it works well when +executed from tty. If you are using a desktop environment, you are +unlikely to have a need for this procedure. + +The resulting file should be invoked by user from the tty after login, +common name for the program would be @code{startx}. Convenience link +can be created by (for example) this home service: + +@lisp +(simple-service 'home-files home-files-service-type + `(("bin/startx" ,(xorg-start-command-xinit)))) +@end lisp +@end deffn + @defvar screen-locker-service-type Type for a service that adds a package for a screen locker or screen diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm index 1ee15ea90c..2f5aa3b4f3 100644 --- a/gnu/services/xorg.scm +++ b/gnu/services/xorg.scm @@ -53,6 +53,7 @@ (define-module (gnu services xorg) #:use-module (gnu packages gnome) #:use-module (gnu packages admin) #:use-module (gnu packages bash) + #:use-module (gnu packages linux) #:use-module (gnu system shadow) #:use-module (guix build-system glib-or-gtk) #:use-module (guix build-system trivial) @@ -84,6 +85,7 @@ (define-module (gnu services xorg) xorg-wrapper xorg-start-command + xorg-start-command-xinit xinitrc xorg-server-service-type @@ -414,6 +416,86 @@ (define* (xorg-start-command #:optional (config (xorg-configuration))) (program-file "startx" exp)) +(define* (xorg-start-command-xinit #:optional (config (xorg-configuration))) + "Return a @code{startx} script in which the modules, fonts, etc. specified in +@var{config}, are available. The result should be used in place of +@code{startx}. Compared to the @code{xorg-start-command} it calls xinit, +therefore it works well when executed from tty." + (define X + (xorg-wrapper config)) + + (define exp + ;; Small wrapper providing subset of functionality of typical startx script + ;; from distributions like alpine. + #~(begin + (use-modules (ice-9 popen) + (ice-9 textual-ports)) + + (define (checked-system* . args) + (if (= 0 (status:exit-val (apply system* args))) + #t + (error "command failed"))) + + (define (capture-stdout . prog+args) + (let* ((port (apply open-pipe* OPEN_READ prog+args)) + (data (get-string-all port))) + (if (= 0 (status:exit-val (close-pipe port))) + (string-trim-right data #\newline) + (error "command failed")))) + + (define (determine-unused-display n) + (let ((lock-file (format #f "/tmp/.X~a-lock" n)) + (sock-file (format #f "/tmp/.X11-unix/X~a" n))) + (if (or (file-exists? lock-file) + (false-if-exception + (eq? 'socket (stat:type (stat sock-file))))) + (determine-unused-display (+ n 1)) + (format #f ":~a" n)))) + (define (determine-vty) + (let ((fd0 (readlink "/proc/self/fd/0")) + (pref "/dev/tty")) + (if (string-prefix? pref fd0) + (string-append "vt" (substring fd0 (string-length pref))) + (error (format #f "Cannot determine VT from: ~a" fd0))))) + + (define (enable-xauth server-auth-file display) + ;; Configure and enable X authority + (or (getenv "XAUTHORITY") + (setenv "XAUTHORITY" (string-append (getenv "HOME") "/.Xauthority"))) + + (let* ((bin/xauth (string-append #$xauth "/bin/xauth")) + (bin/mcookie (string-append #$util-linux "/bin/mcookie")) + + (mcookie (capture-stdout bin/mcookie))) + (checked-system* bin/xauth "-qf" server-auth-file + "add" display "." mcookie) + (checked-system* bin/xauth "-q" + "add" display "." mcookie))) + + (let* ((xinit (string-append #$xinit "/bin/xinit")) + (display (determine-unused-display 0)) + (vty (determine-vty)) + (server-auth-port (mkstemp "/tmp/serverauth.XXXXXX")) + (server-auth-file (port-filename server-auth-port))) + (close-port server-auth-port) + (enable-xauth server-auth-file display) + (apply execl + xinit + xinit + "--" + #$X + display + vty + "-keeptty" + "-auth" server-auth-file + ;; These are set by xorg-start-command, so do the same to keep + ;; it consistent. + "-logverbose" "-verbose" "-terminate" + #$@(xorg-configuration-server-arguments config) + (cdr (command-line)))))) + + (program-file "startx" exp)) + (define* (xinitrc #:key fallback-session) "Return a system-wide xinitrc script that starts the specified X session, which should be passed to this script as the first argument. If not, the