mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
fix(void): updated dms-greeter stability support
- Updates will land in DMS v1.5.1 and users are advised to hold off on v1.5.0 Related #2788 Port 1.5
This commit is contained in:
@@ -1081,8 +1081,11 @@ func ensureGreetdEnabled() error {
|
|||||||
if !runitServiceInstalled("greetd") {
|
if !runitServiceInstalled("greetd") {
|
||||||
return fmt.Errorf("greetd service not found in %s. Please install greetd first", runitSvDir)
|
return fmt.Errorf("greetd service not found in %s. Please install greetd first", runitSvDir)
|
||||||
}
|
}
|
||||||
// Seat + runtime-dir setup that logind handles automatically on systemd.
|
if greeter.IsVoidLinux() {
|
||||||
ensureRunitSeat("_greeter")
|
ensureVoidLogindGreeter("_greeter")
|
||||||
|
} else {
|
||||||
|
ensureRunitSeat("_greeter")
|
||||||
|
}
|
||||||
ensureGreetdPamRundir()
|
ensureGreetdPamRundir()
|
||||||
if err := enableRunitService("greetd"); err != nil {
|
if err := enableRunitService("greetd"); err != nil {
|
||||||
return fmt.Errorf("failed to enable greetd: %w", err)
|
return fmt.Errorf("failed to enable greetd: %w", err)
|
||||||
@@ -1261,6 +1264,9 @@ func enableGreeter(nonInteractive bool) error {
|
|||||||
if err := greeter.EnsureGreeterCacheDir(logFunc, ""); err != nil {
|
if err := greeter.EnsureGreeterCacheDir(logFunc, ""); err != nil {
|
||||||
fmt.Printf("⚠ Could not ensure cache directory: %v\n Run: sudo mkdir -p %s && sudo chown root:%s %s && sudo chmod 2770 %s\n", err, greeter.GreeterCacheDir, greeterGroup, greeter.GreeterCacheDir, greeter.GreeterCacheDir)
|
fmt.Printf("⚠ Could not ensure cache directory: %v\n Run: sudo mkdir -p %s && sudo chown root:%s %s && sudo chmod 2770 %s\n", err, greeter.GreeterCacheDir, greeterGroup, greeter.GreeterCacheDir, greeter.GreeterCacheDir)
|
||||||
}
|
}
|
||||||
|
if err := greeter.EnsureVoidLogindGreetdCommand(logFunc, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := ensureGraphicalTarget(); err != nil {
|
if err := ensureGraphicalTarget(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1475,12 +1481,23 @@ func extractGreeterWrapperFromCommand(command string) string {
|
|||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
wrapper := strings.Trim(tokens[0], "\"")
|
wrapperIndex := 0
|
||||||
|
if filepath.Base(strings.Trim(tokens[0], "\"")) == "env" {
|
||||||
|
wrapperIndex = 1
|
||||||
|
for wrapperIndex < len(tokens) && strings.Contains(tokens[wrapperIndex], "=") {
|
||||||
|
wrapperIndex++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wrapperIndex >= len(tokens) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper := strings.Trim(tokens[wrapperIndex], "\"")
|
||||||
if wrapper == "" {
|
if wrapper == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if len(tokens) > 1 {
|
if wrapperIndex+1 < len(tokens) {
|
||||||
next := strings.Trim(tokens[1], "\"")
|
next := strings.Trim(tokens[wrapperIndex+1], "\"")
|
||||||
if next != "" && (filepath.Base(wrapper) == "bash" || filepath.Base(wrapper) == "sh") && strings.Contains(filepath.Base(next), "dms-greeter") {
|
if next != "" && (filepath.Base(wrapper) == "bash" || filepath.Base(wrapper) == "sh") && strings.Contains(filepath.Base(next), "dms-greeter") {
|
||||||
return fmt.Sprintf("%s (script: %s)", wrapper, next)
|
return fmt.Sprintf("%s (script: %s)", wrapper, next)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,13 @@ func TestGreeterStatusStateDirHonorsExplicitOverrideOnNixOS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExtractGreeterWrapperFromEnvCommand(t *testing.T) {
|
||||||
|
command := "env LIBSEAT_BACKEND=logind DMS_VOID=1 /usr/bin/dms-greeter --command niri"
|
||||||
|
if got := extractGreeterWrapperFromCommand(command); got != "/usr/bin/dms-greeter" {
|
||||||
|
t.Fatalf("extractGreeterWrapperFromCommand() = %q, want %q", got, "/usr/bin/dms-greeter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRejectNixOSGreeterMutationBlocksImperativeCommands(t *testing.T) {
|
func TestRejectNixOSGreeterMutationBlocksImperativeCommands(t *testing.T) {
|
||||||
origGreeterIsNixOSFn := greeterIsNixOSFn
|
origGreeterIsNixOSFn := greeterIsNixOSFn
|
||||||
greeterIsNixOSFn = func() bool { return true }
|
greeterIsNixOSFn = func() bool { return true }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/greeter"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/privesc"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/privesc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -83,9 +84,31 @@ func ensureRunitSeat(greeterUser string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensureGreetdPamRundir adds pam_rundir to the greetd PAM stack so the post-login
|
// ensureVoidLogindGreeter configures the elogind-backed greeter on Void.
|
||||||
// session gets an XDG_RUNTIME_DIR on systems without logind (Void with seatd).
|
func ensureVoidLogindGreeter(greeterUser string) {
|
||||||
// Appended outside DMS's managed auth block so it survives `dms greeter sync`.
|
for _, service := range []string{"dbus", "elogind"} {
|
||||||
|
if err := enableRunitService(service); err != nil {
|
||||||
|
fmt.Printf(" ⚠ could not enable %s: %v\n", service, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" ✓ %s enabled\n", service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
greeter.EnsureVoidGreetdRunScript(func(msg string) { fmt.Println(" " + msg) }, "")
|
||||||
|
if runitServiceEnabled("seatd") {
|
||||||
|
if err := disableRunitService("seatd"); err != nil {
|
||||||
|
fmt.Printf(" ⚠ could not disable seatd: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(" ✓ seatd disabled (elogind manages the seat)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := privesc.Run(context.Background(), "", "usermod", "-aG", "video,input", greeterUser); err != nil {
|
||||||
|
fmt.Printf(" ⚠ could not add %s to video/input groups: %v\n", greeterUser, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" ✓ %s added to video/input groups (elogind manages the seat)\n", greeterUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureGreetdPamRundir provides XDG_RUNTIME_DIR to runit greeter sessions.
|
||||||
func ensureGreetdPamRundir() {
|
func ensureGreetdPamRundir() {
|
||||||
const pamPath = "/etc/pam.d/greetd"
|
const pamPath = "/etc/pam.d/greetd"
|
||||||
data, err := os.ReadFile(pamPath)
|
data, err := os.ReadFile(pamPath)
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ func (v *VoidDistribution) DetectDependenciesWithTerminal(ctx context.Context, w
|
|||||||
dependencies = append(dependencies, v.detectAccountsService())
|
dependencies = append(dependencies, v.detectAccountsService())
|
||||||
dependencies = append(dependencies, v.detectDBus())
|
dependencies = append(dependencies, v.detectDBus())
|
||||||
dependencies = append(dependencies, v.detectElogind())
|
dependencies = append(dependencies, v.detectElogind())
|
||||||
|
dependencies = append(dependencies, v.detectMesaDri())
|
||||||
|
|
||||||
if wm == deps.WindowManagerHyprland {
|
if wm == deps.WindowManagerHyprland {
|
||||||
dependencies = append(dependencies, v.detectHyprlandTools()...)
|
dependencies = append(dependencies, v.detectHyprlandTools()...)
|
||||||
@@ -142,6 +143,10 @@ func (v *VoidDistribution) detectElogind() deps.Dependency {
|
|||||||
return v.detectPackage("elogind", "loginctl/logind provider for power management and session tracking", v.packageInstalled("elogind") || v.commandExists("loginctl"))
|
return v.detectPackage("elogind", "loginctl/logind provider for power management and session tracking", v.packageInstalled("elogind") || v.commandExists("loginctl"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *VoidDistribution) detectMesaDri() deps.Dependency {
|
||||||
|
return v.detectPackage("mesa-dri", "Mesa DRI/EGL drivers (GPU rendering; compositors find no outputs without it)", v.packageInstalled("mesa-dri"))
|
||||||
|
}
|
||||||
|
|
||||||
func (v *VoidDistribution) detectXwaylandSatellite() deps.Dependency {
|
func (v *VoidDistribution) detectXwaylandSatellite() deps.Dependency {
|
||||||
return v.detectPackage("xwayland-satellite", "Xwayland support", v.packageInstalled("xwayland-satellite"))
|
return v.detectPackage("xwayland-satellite", "Xwayland support", v.packageInstalled("xwayland-satellite"))
|
||||||
}
|
}
|
||||||
@@ -172,6 +177,7 @@ func (v *VoidDistribution) GetPackageMappingWithVariants(wm deps.WindowManager,
|
|||||||
"accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
|
"accountsservice": {Name: "accountsservice", Repository: RepoTypeSystem},
|
||||||
"dbus": {Name: "dbus", Repository: RepoTypeSystem},
|
"dbus": {Name: "dbus", Repository: RepoTypeSystem},
|
||||||
"elogind": {Name: "elogind", Repository: RepoTypeSystem},
|
"elogind": {Name: "elogind", Repository: RepoTypeSystem},
|
||||||
|
"mesa-dri": {Name: "mesa-dri", Repository: RepoTypeSystem},
|
||||||
|
|
||||||
"quickshell": {Name: "quickshell", Repository: RepoTypeSystem},
|
"quickshell": {Name: "quickshell", Repository: RepoTypeSystem},
|
||||||
"matugen": {Name: "matugen", Repository: RepoTypeSystem},
|
"matugen": {Name: "matugen", Repository: RepoTypeSystem},
|
||||||
@@ -305,6 +311,7 @@ func (v *VoidDistribution) ensureSessionServices(ctx context.Context, sudoPasswo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// D-Bus activation alone starts elogind without its wrapper mounts; the runit service is required.
|
||||||
for _, service := range []string{"dbus", "elogind"} {
|
for _, service := range []string{"dbus", "elogind"} {
|
||||||
if !v.runitServiceInstalled(service) {
|
if !v.runitServiceInstalled(service) {
|
||||||
v.log(fmt.Sprintf("Warning: %s runit service not found in %s; power/session actions may not work until %s is installed", service, voidRunitSvDir, service))
|
v.log(fmt.Sprintf("Warning: %s runit service not found in %s; power/session actions may not work until %s is installed", service, voidRunitSvDir, service))
|
||||||
|
|||||||
@@ -115,6 +115,52 @@ func ensureRunitSeat(greeterUser, sudoPassword string, logFunc func(string)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VoidGreetdRunScript orders greetd after dbus/elogind so the first greeter session can't race elogind's runtime-dir setup.
|
||||||
|
const VoidGreetdRunScript = `#!/bin/sh
|
||||||
|
sv check dbus >/dev/null || exit 1
|
||||||
|
sv check elogind >/dev/null || exit 1
|
||||||
|
exec greetd
|
||||||
|
`
|
||||||
|
|
||||||
|
// EnsureVoidGreetdRunScript rewrites /etc/sv/greetd/run with dbus/elogind ordering (greetd updates restore stock; enable re-asserts).
|
||||||
|
func EnsureVoidGreetdRunScript(logFunc func(string), sudoPassword string) {
|
||||||
|
const runPath = "/etc/sv/greetd/run"
|
||||||
|
if data, err := os.ReadFile(runPath); err == nil && strings.Contains(string(data), "sv check elogind") {
|
||||||
|
logFunc("✓ greetd run script already waits for elogind")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
script := fmt.Sprintf("cat > %s <<'EOF'\n%sEOF\nchmod 755 %s", runPath, VoidGreetdRunScript, runPath)
|
||||||
|
if err := privesc.Run(context.Background(), sudoPassword, "sh", "-c", script); err != nil {
|
||||||
|
logFunc(fmt.Sprintf("⚠ could not update %s: %v", runPath, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logFunc("✓ greetd run script now waits for dbus/elogind")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureVoidLogindGreeter configures the elogind-backed greeter on Void.
|
||||||
|
func ensureVoidLogindGreeter(greeterUser, sudoPassword string, logFunc func(string)) {
|
||||||
|
for _, service := range []string{"dbus", "elogind"} {
|
||||||
|
if err := enableRunitService(service, sudoPassword); err != nil {
|
||||||
|
logFunc(fmt.Sprintf("⚠ could not enable %s: %v", service, err))
|
||||||
|
} else {
|
||||||
|
logFunc(fmt.Sprintf("✓ %s enabled", service))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EnsureVoidGreetdRunScript(logFunc, sudoPassword)
|
||||||
|
if runitServiceEnabled("seatd") {
|
||||||
|
if err := disableRunitService("seatd", sudoPassword); err != nil {
|
||||||
|
logFunc(fmt.Sprintf("⚠ could not disable seatd: %v", err))
|
||||||
|
} else {
|
||||||
|
logFunc("✓ seatd disabled (elogind manages the seat)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := privesc.Run(context.Background(), sudoPassword, "usermod", "-aG", "video,input", greeterUser); err != nil {
|
||||||
|
logFunc(fmt.Sprintf("⚠ could not add %s to video/input groups: %v", greeterUser, err))
|
||||||
|
} else {
|
||||||
|
logFunc(fmt.Sprintf("✓ %s added to video/input groups (elogind manages the seat)", greeterUser))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ensureGreetdPamRundir(sudoPassword string, logFunc func(string)) {
|
func ensureGreetdPamRundir(sudoPassword string, logFunc func(string)) {
|
||||||
const pamPath = "/etc/pam.d/greetd"
|
const pamPath = "/etc/pam.d/greetd"
|
||||||
data, err := os.ReadFile(pamPath)
|
data, err := os.ReadFile(pamPath)
|
||||||
@@ -1740,6 +1786,10 @@ func syncGreeterColorSource(homeDir, cacheDir string, state greeterThemeSyncStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string) error {
|
func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string) error {
|
||||||
|
if err := EnsureVoidLogindGreetdCommand(logFunc, sudoPassword); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get user home directory: %w", err)
|
return fmt.Errorf("failed to get user home directory: %w", err)
|
||||||
@@ -2271,13 +2321,7 @@ vt = 1
|
|||||||
return fmt.Errorf("failed to read greetd config: %w", err)
|
return fmt.Errorf("failed to read greetd config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapperCmd := resolveGreeterWrapperPath()
|
commandValue := buildGreetdCommand(resolveGreeterWrapperPath(), compositor, dmsPath, IsVoidLinux())
|
||||||
|
|
||||||
compositorLower := strings.ToLower(compositor)
|
|
||||||
commandValue := fmt.Sprintf("%s --command %s --cache-dir %s", wrapperCmd, compositorLower, GreeterCacheDir)
|
|
||||||
if dmsPath != "" {
|
|
||||||
commandValue = fmt.Sprintf("%s -p %s", commandValue, dmsPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
commandLine := fmt.Sprintf(`command = "%s"`, commandValue)
|
commandLine := fmt.Sprintf(`command = "%s"`, commandValue)
|
||||||
newConfig := upsertDefaultSession(configContent, greeterUser, commandLine)
|
newConfig := upsertDefaultSession(configContent, greeterUser, commandLine)
|
||||||
@@ -2289,6 +2333,84 @@ vt = 1
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildGreetdCommand(wrapperCmd, compositor, dmsPath string, useVoidLogind bool) string {
|
||||||
|
commandValue := fmt.Sprintf("%s --command %s --cache-dir %s", wrapperCmd, strings.ToLower(compositor), GreeterCacheDir)
|
||||||
|
if dmsPath != "" {
|
||||||
|
commandValue = fmt.Sprintf("%s -p %s", commandValue, dmsPath)
|
||||||
|
}
|
||||||
|
if useVoidLogind {
|
||||||
|
commandValue = "env LIBSEAT_BACKEND=logind DMS_VOID=1 " + commandValue
|
||||||
|
}
|
||||||
|
return commandValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureVoidLogindGreetdCommand migrates DMS greeter commands on Void.
|
||||||
|
func EnsureVoidLogindGreetdCommand(logFunc func(string), sudoPassword string) error {
|
||||||
|
if !IsVoidLinux() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const configPath = "/etc/greetd/config.toml"
|
||||||
|
data, err := os.ReadFile(configPath)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read greetd config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configContent := string(data)
|
||||||
|
command := extractDefaultSessionCommand(configContent)
|
||||||
|
if command == "" || !strings.Contains(command, "dms-greeter") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
migratedCommand := voidLogindGreeterCommand(command)
|
||||||
|
if migratedCommand == command {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
greeterUser := extractDefaultSessionUser(configContent)
|
||||||
|
if greeterUser == "" {
|
||||||
|
greeterUser = DetectGreeterUser()
|
||||||
|
}
|
||||||
|
newConfig := upsertDefaultSession(configContent, greeterUser, fmt.Sprintf(`command = "%s"`, migratedCommand))
|
||||||
|
return writeGreetdConfig(configPath, newConfig, logFunc, sudoPassword, "✓ Updated existing Void greeter to use elogind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractDefaultSessionCommand(configContent string) string {
|
||||||
|
inDefaultSession := false
|
||||||
|
for line := range strings.SplitSeq(configContent, "\n") {
|
||||||
|
if section, ok := parseTomlSection(line); ok {
|
||||||
|
inDefaultSession = section == "default_session"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !inDefaultSession {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
trimmed := stripTomlComment(line)
|
||||||
|
if !strings.HasPrefix(trimmed, "command =") && !strings.HasPrefix(trimmed, "command=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(trimmed, "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if command := strings.Trim(strings.TrimSpace(parts[1]), `"`); command != "" {
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func voidLogindGreeterCommand(command string) string {
|
||||||
|
if strings.Contains(command, "LIBSEAT_BACKEND=logind") && strings.Contains(command, "DMS_VOID=1") {
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
return "env LIBSEAT_BACKEND=logind DMS_VOID=1 " + command
|
||||||
|
}
|
||||||
|
|
||||||
func stripConfigFlag(command string) string {
|
func stripConfigFlag(command string) string {
|
||||||
for _, flag := range []string{" -C ", " --config "} {
|
for _, flag := range []string{" -C ", " --config "} {
|
||||||
idx := strings.Index(command, flag)
|
idx := strings.Index(command, flag)
|
||||||
@@ -2430,7 +2552,11 @@ func EnableGreetd(sudoPassword string, logFunc func(string)) error {
|
|||||||
if !runitServiceInstalled("greetd") {
|
if !runitServiceInstalled("greetd") {
|
||||||
return fmt.Errorf("greetd service not found in %s; ensure greetd is installed", runitSvDir)
|
return fmt.Errorf("greetd service not found in %s; ensure greetd is installed", runitSvDir)
|
||||||
}
|
}
|
||||||
ensureRunitSeat(DetectGreeterUser(), sudoPassword, logFunc)
|
if IsVoidLinux() {
|
||||||
|
ensureVoidLogindGreeter(DetectGreeterUser(), sudoPassword, logFunc)
|
||||||
|
} else {
|
||||||
|
ensureRunitSeat(DetectGreeterUser(), sudoPassword, logFunc)
|
||||||
|
}
|
||||||
ensureGreetdPamRundir(sudoPassword, logFunc)
|
ensureGreetdPamRundir(sudoPassword, logFunc)
|
||||||
if err := enableRunitService("greetd", sudoPassword); err != nil {
|
if err := enableRunitService("greetd", sudoPassword); err != nil {
|
||||||
return fmt.Errorf("failed to enable greetd: %w", err)
|
return fmt.Errorf("failed to enable greetd: %w", err)
|
||||||
|
|||||||
@@ -169,6 +169,56 @@ func TestStripDesktopExecCodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildGreetdCommand(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
wrapper string
|
||||||
|
compositor string
|
||||||
|
dmsPath string
|
||||||
|
useVoidLogind bool
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "standard command",
|
||||||
|
wrapper: "/usr/bin/dms-greeter",
|
||||||
|
compositor: "Niri",
|
||||||
|
want: "/usr/bin/dms-greeter --command niri --cache-dir /var/cache/dms-greeter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "void selects elogind and keeps custom DMS path",
|
||||||
|
wrapper: "/usr/bin/dms-greeter",
|
||||||
|
compositor: "Niri",
|
||||||
|
dmsPath: "/usr/share/quickshell/dms-greeter",
|
||||||
|
useVoidLogind: true,
|
||||||
|
want: "env LIBSEAT_BACKEND=logind DMS_VOID=1 /usr/bin/dms-greeter --command niri --cache-dir /var/cache/dms-greeter -p /usr/share/quickshell/dms-greeter",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if got := buildGreetdCommand(tt.wrapper, tt.compositor, tt.dmsPath, tt.useVoidLogind); got != tt.want {
|
||||||
|
t.Fatalf("buildGreetdCommand() = %q, want %q", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVoidLogindGreeterCommand(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const oldCommand = "/usr/bin/dms-greeter --command niri -C /etc/greetd/niri.kdl"
|
||||||
|
const want = "env LIBSEAT_BACKEND=logind DMS_VOID=1 " + oldCommand
|
||||||
|
if got := voidLogindGreeterCommand(oldCommand); got != want {
|
||||||
|
t.Fatalf("voidLogindGreeterCommand() = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
if got := voidLogindGreeterCommand(want); got != want {
|
||||||
|
t.Fatalf("voidLogindGreeterCommand() must be idempotent, got %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResolveGreeterAutoLoginState(t *testing.T) {
|
func TestResolveGreeterAutoLoginState(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
+16
-7
@@ -58,7 +58,8 @@ checkout at `srcpkgs/<pkg>/template` to build or submit it.
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
Installing `dms` automatically pulls in `quickshell`, `accountsservice`, `dgop`,
|
Installing `dms` automatically pulls in `quickshell`, `accountsservice`, `dgop`,
|
||||||
`matugen` (which drives the Material You theming), `dbus`, and `elogind`.
|
`matugen` (which drives the Material You theming), `dbus`, `elogind`, and
|
||||||
|
`mesa-dri` (GL drivers, required for compositors to render).
|
||||||
The rest are optional, install whichever features you want:
|
The rest are optional, install whichever features you want:
|
||||||
|
|
||||||
| Package | Enables |
|
| Package | Enables |
|
||||||
@@ -123,7 +124,7 @@ sudo ln -sf /etc/sv/dbus /var/service/dbus
|
|||||||
sudo ln -sf /etc/sv/elogind /var/service/elogind
|
sudo ln -sf /etc/sv/elogind /var/service/elogind
|
||||||
```
|
```
|
||||||
|
|
||||||
The `dankinstall` Void path does this automatically after installing packages.
|
The `dankinstall` Void path enables both services after installing packages.
|
||||||
|
|
||||||
## Greeter (optional)
|
## Greeter (optional)
|
||||||
|
|
||||||
@@ -134,8 +135,16 @@ dms greeter enable # configures greetd + the Void seat/PAM bits below
|
|||||||
dms greeter sync # optional: share theming with the shell
|
dms greeter sync # optional: share theming with the shell
|
||||||
```
|
```
|
||||||
|
|
||||||
`dms greeter enable` handles what logind does automatically on systemd: it points
|
`dms-greeter` requires D-Bus and elogind. `dms greeter enable` enables the
|
||||||
greetd at the greeter, enables `seatd`, adds `_greeter` to the `_seatd`/`video`/
|
`dbus` and `elogind` runit services, configures greetd for elogind
|
||||||
`input` groups, and adds `pam_rundir` to `/etc/pam.d/greetd` (so the post-login
|
(`LIBSEAT_BACKEND=logind`), adds `_greeter` to the `video` and `input` groups,
|
||||||
session gets an `XDG_RUNTIME_DIR`). A Wayland compositor and a working DRM device
|
and adds `pam_rundir` to `/etc/pam.d/greetd` (so the post-login session gets an
|
||||||
(`/dev/dri/card*`) are required and not pulled in automatically.
|
`XDG_RUNTIME_DIR`). It disables seatd if enabled: on Void, seatd is the
|
||||||
|
alternative to elogind, and running both fights over the seat. Greeter sessions
|
||||||
|
are launched through `dbus-run-session`. A Wayland compositor and a working DRM
|
||||||
|
device (`/dev/dri/card*`) are required and not pulled in automatically.
|
||||||
|
|
||||||
|
`dms greeter enable` also rewrites `/etc/sv/greetd/run` to wait for the `dbus`
|
||||||
|
and `elogind` services, preventing a first-boot race that can leave the greeter
|
||||||
|
on a black screen. greetd package updates restore the stock run script; re-run
|
||||||
|
`dms greeter enable` afterwards.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# Setup is done by `dms greeter enable`, not by this package — see distro/void/README.md.
|
# Setup is done by `dms greeter enable`, not by this package — see distro/void/README.md.
|
||||||
pkgname=dms-greeter
|
pkgname=dms-greeter
|
||||||
version=1.5.0
|
version=1.5.0
|
||||||
revision=1
|
revision=2
|
||||||
short_desc="DankMaterialShell greeter for greetd"
|
short_desc="DankMaterialShell greeter for greetd"
|
||||||
maintainer="AvengeMedia <AvengeMedia.US@gmail.com>"
|
maintainer="AvengeMedia <AvengeMedia.US@gmail.com>"
|
||||||
license="MIT"
|
license="MIT"
|
||||||
@@ -14,7 +14,7 @@ homepage="https://danklinux.com"
|
|||||||
distfiles="https://github.com/AvengeMedia/DankMaterialShell/archive/refs/tags/v${version}.tar.gz"
|
distfiles="https://github.com/AvengeMedia/DankMaterialShell/archive/refs/tags/v${version}.tar.gz"
|
||||||
checksum=14f2678d6a15223ba069d1b8c8a21a5564b735d190c231f62ed44fd8bf48677c
|
checksum=14f2678d6a15223ba069d1b8c8a21a5564b735d190c231f62ed44fd8bf48677c
|
||||||
|
|
||||||
depends="greetd quickshell acl-progs seatd pam_rundir"
|
depends="greetd quickshell acl-progs dbus elogind pam_rundir mesa-dri"
|
||||||
|
|
||||||
# Cache dir the greeter uses as $HOME (owned by greetd's _greeter user).
|
# Cache dir the greeter uses as $HOME (owned by greetd's _greeter user).
|
||||||
make_dirs="/var/cache/dms-greeter 0750 _greeter _greeter"
|
make_dirs="/var/cache/dms-greeter 0750 _greeter _greeter"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# CI rewrites version/checksum from the selected release tag before building.
|
# CI rewrites version/checksum from the selected release tag before building.
|
||||||
pkgname=dms
|
pkgname=dms
|
||||||
version=1.5.0
|
version=1.5.0
|
||||||
revision=1
|
revision=2
|
||||||
build_style=go
|
build_style=go
|
||||||
build_wrksrc="core"
|
build_wrksrc="core"
|
||||||
go_import_path="github.com/AvengeMedia/DankMaterialShell/core"
|
go_import_path="github.com/AvengeMedia/DankMaterialShell/core"
|
||||||
@@ -23,7 +23,7 @@ distfiles="https://github.com/AvengeMedia/DankMaterialShell/archive/refs/tags/v$
|
|||||||
checksum=14f2678d6a15223ba069d1b8c8a21a5564b735d190c231f62ed44fd8bf48677c
|
checksum=14f2678d6a15223ba069d1b8c8a21a5564b735d190c231f62ed44fd8bf48677c
|
||||||
|
|
||||||
# Optional feature deps are listed in distro/void/README.md.
|
# Optional feature deps are listed in distro/void/README.md.
|
||||||
depends="quickshell accountsservice dgop matugen dbus elogind"
|
depends="quickshell accountsservice dgop matugen dbus elogind mesa-dri"
|
||||||
|
|
||||||
post_install() {
|
post_install() {
|
||||||
# QML shell tree (build_style=go already installed the dms binary)
|
# QML shell tree (build_style=go already installed the dms binary)
|
||||||
|
|||||||
@@ -2001,6 +2001,8 @@ Item {
|
|||||||
greeterAutoLoginPendingProcess.running = true;
|
greeterAutoLoginPendingProcess.running = true;
|
||||||
pendingLaunchCommand = sessionCmd;
|
pendingLaunchCommand = sessionCmd;
|
||||||
pendingLaunchEnv = ["XDG_SESSION_TYPE=wayland"];
|
pendingLaunchEnv = ["XDG_SESSION_TYPE=wayland"];
|
||||||
|
if (Quickshell.env("DMS_VOID") === "1")
|
||||||
|
pendingLaunchEnv.push("LIBSEAT_BACKEND=logind");
|
||||||
memoryFlushTimer.restart();
|
memoryFlushTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2052,7 +2054,14 @@ Item {
|
|||||||
const launchEnv = pendingLaunchEnv;
|
const launchEnv = pendingLaunchEnv;
|
||||||
pendingLaunchCommand = "";
|
pendingLaunchCommand = "";
|
||||||
pendingLaunchEnv = [];
|
pendingLaunchEnv = [];
|
||||||
Greetd.launch(sessionCommand.split(" "), launchEnv);
|
const sessionArgs = sessionCommand.trim().split(/\s+/);
|
||||||
|
const needsVoidDbusSession = Quickshell.env("DMS_VOID") === "1"
|
||||||
|
&& !Quickshell.env("DBUS_SESSION_BUS_ADDRESS")
|
||||||
|
&& sessionArgs[0] !== "dbus-run-session";
|
||||||
|
const launchArgs = needsVoidDbusSession
|
||||||
|
? ["dbus-run-session"].concat(sessionArgs)
|
||||||
|
: sessionArgs;
|
||||||
|
Greetd.launch(launchArgs, launchEnv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user