{"id":19151807,"url":"https://github.com/rudojaksa/xx","last_synced_at":"2026-06-24T00:31:16.674Z","repository":{"id":236592147,"uuid":"792920971","full_name":"rudojaksa/xx","owner":"rudojaksa","description":"X server starting script","archived":false,"fork":false,"pushed_at":"2024-06-08T20:08:41.000Z","size":36,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-22T21:14:02.973Z","etag":null,"topics":["pulseaudio","startx","xauthority","xinit","xinitrc","xorg"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rudojaksa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-27T23:35:26.000Z","updated_at":"2024-06-08T20:01:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"4e53dd46-f914-4fdd-9497-e6a53a8ba941","html_url":"https://github.com/rudojaksa/xx","commit_stats":null,"previous_names":["rudojaksa/xx"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/rudojaksa/xx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fxx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fxx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fxx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fxx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rudojaksa","download_url":"https://codeload.github.com/rudojaksa/xx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fxx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34712578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pulseaudio","startx","xauthority","xinit","xinitrc","xorg"],"created_at":"2024-11-09T08:15:45.496Z","updated_at":"2026-06-24T00:31:16.652Z","avatar_url":"https://github.com/rudojaksa.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `xx` - the X server starting script\n\nMinimal script to start the X server (and audio server) manually from the text\nconsole (simplified annotated customization-friendly alternative to the\nstartx).\n\n\u003ch3 align=\"center\"\u003e\n\u003ctt\u003e\u0026nbsp;boot to console\u0026nbsp;\u003c/tt\u003e \u0026nbsp;\u0026rarr;\u0026nbsp;\n\u003ctt\u003e\u0026nbsp;login\u0026nbsp;\u003c/tt\u003e \u0026nbsp;\u0026rarr;\u0026nbsp;\n\u003ctt\u003e\u0026nbsp;run xx\u0026nbsp;\u003c/tt\u003e \u0026nbsp; \u0026nbsp; \u0026nbsp; \u003c/h3\u003e\n\nThe `xx` name is convenient when it has to be typed from a misconfigured\nkeyboard after an arbitrary boot problem.  Single `x` would be even simpler,\nbut it would be also prone to launch unintentionally.  The `xx` script itself\ndoes:\n\n1. Creates the session data directory `/tmp/X0`.\n2. Starts the user's dbus for the browser to work correctly.\n3. Starts user's pulseaudio sound server.\n4. Sets the xauthority authentication cookie for X.\n5. Moves the `Xorg.0.log` to `/tmp/X0`.\n6. Makes temporary xinitrc to start a window manager.\n7. Runs the X server.\n8. Removes all session data after the X is closed.\n\nThe graphics and audio servers are the foundation of the computer desktop, step\none.  This script tries to handle them transparently.  And the dbus is an\naddition.\n\n#### 1. `/tmp/X0` - runtime data and logs\n\nAll X runtime files will be created or redirected into `/tmp/X0`.  The `X0`\nstands for the \"X display 0\".  The main runtime files will be:\n\n```\n/tmp/X0/dbus\t\t-\u003e dbus socket file\n/tmp/X0/dbus.log\t-\u003e dbus log\n/tmp/X0/xauthority\t-\u003e authentication cookie\n/tmp/X0/xinitrc\t\t-\u003e xinitrc\n/tmp/X0/xorg.log\t-\u003e standard X log\n/tmp/X0/xorg.stdout\t-\u003e console messages from X\n```\n  \n#### 2. `dbus` - for the browser\n\nUnfortunately, the user's session dbus daemon is needed for the browser to\nobtain links from apps, or for some other bigger/container apps to interact\nwith each other.  Otherwise, it is not needed.\n\nThe environment variable `$DBUS_SESSION_BUS_ADDRESS` needs to be exported to\ndefine the path to a socket file.  The standard location\n`DBUS_SESSION_BUS_ADDRESS=\"unix:path=/run/user/$UID/bus\"` is not reliable\n(might be missing), so we use our `/tmp/X0/dbus` instead.\n\nBefore starting the `dbus-daemon` we kill the one hanging from the previous\nsession.  In this step, a potential stalled socket file was already removed,\nwhen we removed a whole `/tmp/X0` directory in the previous step.  We log dbus\ninfo into `/tmp/X0/dbus.log`, instead of the default syslog.\n\n\u003ci\u003e Unfortunately, the `DBUS_SESSION_BUS_ADDRESS` name was chosen as the\nstandard, instead of a simple `DBUS`. \u003c/i\u003e\n\n#### 3. `pulseaudio` - for the browser\n\nUnfortunately, the X server is not enough and one more running server is\nneeded: the audio server.  Typically, the `pulseaudio` is required by applications.\nIt would be nice if applications don't hang up if the audio server is not\nrunning...\n\nPulseaudio stores its runtime stuff in `~/.config/pulse`, in\n`/var/run/user/ID/pulse` plus logs in syslog or journal.  To move all these\nfiles to `/tmp/pulse` we need to set `PULSE_RUNTIME_PATH` and `XDG_CONFIG_HOME`\nand let pulseaudio clients know about it using the `/etc/pulse/clients.conf`:\n\n```\nextra-arguments = --log-target=stderr\ncookie-file = /tmp/pulse/cookie\n```\n\nMain pulseaudio runtime files will be:\n\n```\n/tmp/pulse/cookie\t-\u003e authentication cookie\n/tmp/pulse/socket\t-\u003e sound server socket\n/tmp/pulse/pulse.log\t-\u003e sound server log file\n/tmp/pulse/pid\t\t-\u003e sound server PID\n```\n\nWe chose `/tmp/pulse` instead of `/tmp/X0/pulse`, as the pulseaudio is\npotentially independent of X.  Also, this path has to be referenced as a string\nin `/etc/pulse/client.conf` and `/etc/pulse/default.pa`, so the simple\nindependent path would be the best choice.\n\nRegarding logs, the pulseaudio `--log-target=file` wraps some logic over the\n\"file\".  To avoid working around it, the `--daemonize=no --log-target=stderr`\ncan be used with a redirect of stderr to a file.\n\n##### Authentication\n\nSimilarly to the X authentication in section 4. we can grant a group access to\nthe `pulseaudio` by changing the `/tmp/pulse` permissions, but we also need to\nnegotiate the common socket file location by adding this line to the\n`/etc/pulse/clients.conf`:\n\n```\ndefault-server = unix:/tmp/pulse/socket\n```\n\nand this line to `/etc/pulse/default.pa`:\n\n```\nload-module module-native-protocol-unix auth-anonymous=1 socket=/tmp/pulse/socket\n```\n\nThis `clients.conf` and `default.pa` setup is done automatically by the `make\ninstall` with an interactive approval.\n\n##### Multi-user access\n\nTo use the `/tmp/pulse/cookie` instead of creating a new one in\n`~/.config/pulse/cookie` the other users have to set the `$XDG_CONFIG_HOME` in\n`.bashrc` or `.zshrc`:\n\n```\nexport XDG_CONFIG_HOME=/tmp\n```\n\n##### System setup\n\nAny custom pulseaudio setup, which will otherwise go into `~/.config/pulse`\nneeds to be copied by the xx script to the `/tmp/pulse`, similar to the xinitrc\nfile in step 6.  Alternatively, pulseaudio setup can be done system-wide in the\n`/etc/pulse` files.\n\nOn Ubuntu or other systemd-based systems, the pulseaudio daemon is started on\nuser's login, to stop it and use only the xx pulseaudio do something like:\n\n```\nln -sf /dev/null /etc/systemd/user/default.target.wants/pulseaudio.service\nln -sf /dev/null /etc/systemd/user/sockets.target.wants/pulseaudio.socket\n```\n\n#### 4. `xauthority` - authentication cookie\n\nAn authentication cookie file is used to secure the X access to only a single\nuser.  User-run applications can use the X only if they can read the cookie\nfile.  In this script, we can use the same cookie file for the X server and for\nthe client (user application), because we expect the server to be run by the\nuser too.\n\nThe location of the cookie file is revealed to clients by the `XAUTHORITY`\nenvironment variable, and to the X server by the `-auth` switch.  Without the\n`touch $XAUTHORITY` the `xx` will work but complain.  Without the manual\n`xauth` setup, X will create and use the `~/.Xauthority` file.  For the\nhost-based access the default `600` permissions set by `xauth` need to be\noverridden to allow other users to read the cookie too by adding: `chmod 644\n$XAUTHORITY` to the `xx` script.\n\nSimilarly, the group based access can be granted by creating a group `xorg`\n(for instance) and assigning users to it by `echo \"xorg:x:200:user1,user2\" \u003e\u003e\n/etc/group` (for instance).  Then, a re-login is needed to activate the `xorg`\ngroup.  Finally, we can grant access to the cookie for a whole group in the\n`xx` script by adding:\n\n```\nchgrp xorg $XAUTHORITY\nchmod 640 $XAUTHORITY\n```\n\nThe `ssh -X/Y` from remote to this host will create its own `~/.Xauthority`\ncookie on this host.  This cookie is different from `/tmp/X0/xauthority`, it is\nunique for every ssh session, and you can remove it after the ssh session.\n\n\u003ci\u003e Why have more users share a single X session?  Modern trend is to force\nmultiuser operating systems to accept only a single user, or support/suggest\nsingle-user usage scenarios.  However, it gradually becomes more advantageous\nfor a single human to use multiple user accounts concurrently.  Modern\napplications tend to automatically store settings, profiles, states, caches,\ndependencies for a particular user and to modify their own functionality\naccordingly.  But, people often work on several completely different projects\nrequiring to use tools in different ways, to remember different coworkers,\ndifferent passwords, bookmarks, folders, etc.  Multiple user accounts for a\nsingle human can help!  To fully use the advantage of multiple accounts you\nneed to be able to open windows from two accounts at the same time to\ncopy-paste, compare, etc. ...and it is easy! \u003c/i\u003e\n\n#### 5. `Xorg.0.log` - X server log file\n\nThe default location of the user-run X server is in the user's home directory\n`~/.local/share/xorg/Xorg.0.log`.  This path is hardcoded in the X server\nprogram and the `-logfile` option is available only to the root user.  Thus to\nmove the user-run X log from `/home` to `/tmp/X0` we must use a symlink, which\nis what we do in this step.\n\nThe log file of the root-run X can be stored in the `/tmp/X0` using the\n`-logfile`, but also by the symlink: `ln -s /var/log/Xorg.0.log /tmp/X0/xorg.log`.\n\n\u003ci\u003e TODO: Hack the X server to allow to log directly to the `/tmp/X0` as a user.\u003c/i\u003e\n\n#### 6. `xinitrc` - which window manager to start\n\nIn this step, we just copy the `~/.xinitrc` to our runtime directory `/tmp/X0`.\nHowever, instead of this copying, the xinitrc content can be generated on the\nfly in the `xx` script to contain the whole X setup in a single file.  Like\nthis:\n\n```\necho \"setxkbmap dvorak\"    \u003e $XINITRC\necho \"fvwm -f ~/.fvwmcfg\" \u003e\u003e $XINITRC\n```\n\nAnother mechanism to set up the X are the `/usr/share/X11/xorg.conf.d` files.\nHowever, some things have to be set by the xinitrc even if they are already set\nin `xorg.conf`.  For instance, if a keyboard is configured only in the\n`xorg.conf`, then the window manager which is run from the xinitrc might not\nhave the keyboard correctly configured in the time it is initialized.\n\n#### 7. `Xorg` - start the X server\n\nHere we run the X server `Xorg` through the `xinit` program for the display\n`:0` reusing the current virtual console.  We also log the X server stdout\nmessages to the `xorg.stdout` alongside its logfile `xorg.log`.\n\n#### 8. cleanup at exit\n\nIn this step, we clean up everything that was created for the X to run:\n\n * kill the dbus daemon,\n * remove all runtime and log files, all of which we placed into `/tmp/X0`.\n\nRemoval commands are run in background to not block anything.\n\nThe X server also creates `/tmp/.X11-unix` and `/tmp/.ICE-unix` which we cannot\nremove due to their root privileges.  Also, if the X is run as root the log is\nstored in `/var/log/Xorg.0.log` and can be removed only by root.\n\n---\n\n### Install\n\nSimply:\n```\nmake install\n```\n\nProvided Makefile can install the `xx` script to the private `~/bin` directory:\n\n 1. Edit your `~/.xinitrc`, or the section 6. of `xx`,\n 2. `make install` to copy the `xx` to `~/bin`, or `sudo make install` if needed to modify `/etc/pulse`.\n\nAlternatively:\n\n * use `make install4group` to install the modified `xx` for group-based access,\n * or `make install4host` for host-based access.\n * The default is a single-user access mode.\n\nFor the system-wide install:\n\n 1. use `make install` or install4group/install4host to prepare the `xx` in `~/bin`,\n 2. then move it to the system `/bin` or elsewhere.\n\n##### Group-based access\n\nThe X and pulseaudio group-based access used in steps 3 and 4 has the\nprimary-secondary roles: the initiating user is the primary one with the write\nprivileges, other users in the `xorg` group are secondary with only the read\naccess.  Instead of the `xorg`, a good name for the group would be the name of\nprimary user.\n\n### `/tmp` directory\n\n`Xx` tries to put all X and all pulseaudio runtime data into `/tmp` and remove\nthem at the end of the session.  This way:\n\n * no waste data are stored,\n * data are together, easier to inspect!\n\n### `rc` startup files\n\nThe `dbusrc` and `pulserc` files for the startup of daemons allow the\n\"fire-and-forget\" approach.  If something in these \"less-important\" services\nfails, it will not stop the X from starting.  If something takes too long, it\nwill not slow-down the main routine.\n\n### Limitations\n\n`Xx` is written only for the display `:0`.\n\n### See also\n\nhttps://gitlab.freedesktop.org/xorg/app/xinit \u0026larr; startx \u0026 xinit sources  \n\n\u003cbr\u003e\u003cdiv align=right\u003e\u003ci\u003eR.Jaksa 2023,2024\u003c/i\u003e\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudojaksa%2Fxx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frudojaksa%2Fxx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudojaksa%2Fxx/lists"}