diff --git a/CMakeLists.txt b/CMakeLists.txt index 664d92cf0..a92cf6af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,8 +97,6 @@ install(DIRECTORY DESTINATION libexec/darling/usr/local/share) InstallSymlink(/Volumes/SystemRoot/dev ${CMAKE_INSTALL_PREFIX}/libexec/darling/dev) InstallSymlink(private/tmp ${CMAKE_INSTALL_PREFIX}/libexec/darling/tmp) -InstallSymlink(/Volumes/SystemRoot/home ${CMAKE_INSTALL_PREFIX}/libexec/darling/Users) -InstallSymlink(Users ${CMAKE_INSTALL_PREFIX}/libexec/darling/home) InstallSymlink(/proc/self/mounts ${CMAKE_INSTALL_PREFIX}/libexec/darling/etc/mtab) InstallSymlink(/Volumes/SystemRoot/etc/passwd ${CMAKE_INSTALL_PREFIX}/libexec/darling/etc/passwd) diff --git a/src/libelfloader/loader.c b/src/libelfloader/loader.c index 7804458be..add9369d2 100644 --- a/src/libelfloader/loader.c +++ b/src/libelfloader/loader.c @@ -84,16 +84,36 @@ __attribute__((constructor)) static unsigned long processEnvVariable(const char* var) { - if (strncmp(var, "HOME=/Users/", 12) == 0) + if (strncmp(var, "HOME=", 5) == 0) { - const size_t len = strlen(var); - char* home = malloc(len); // 1 byte shorter + char* home = (char*) malloc(512); + char* symlink_path = (char*) malloc(strlen(var+5) + 10); - strcpy(home, "HOME=/home/"); - strcpy(home + 11, var+12); + strcpy(symlink_path, var+5); + strcat(symlink_path, "/LinuxHome"); + + int len = readlink(symlink_path, home, 512-1); + free(symlink_path); + + if (len < 0) + { + free(home); + goto out; + } + home[len] = '\0'; + + if (strncmp(home, SYSTEM_ROOT, sizeof(SYSTEM_ROOT) - 1) != 0) + { + free(home); + goto out; + } + + strcpy(home, "HOME="); + memmove(home+5, home + sizeof(SYSTEM_ROOT) - 1, len - sizeof(SYSTEM_ROOT) + 2); return (unsigned long) home; } +out: return (unsigned long) var; } diff --git a/src/startup/darling.c b/src/startup/darling.c index 7621435b4..e1438ba15 100644 --- a/src/startup/darling.c +++ b/src/startup/darling.c @@ -1,7 +1,7 @@ /* This file is part of Darling. -Copyright (C) 2016-2018 Lubos Dolezel +Copyright (C) 2016-2020 Lubos Dolezel Darling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -561,16 +561,16 @@ void spawnShell(const char** argv) "/sbin:" "/usr/local/bin"); - const char *home = getenv("HOME"); - if (home) + const char* login = getlogin(); + if (!login) { - if (sscanf(home, "/home/%4096s", buffer1) == 1) - snprintf(buffer2, sizeof(buffer2), "HOME=/Users/%s", buffer1); - else - snprintf(buffer2, sizeof(buffer2), "HOME=" SYSTEM_ROOT "%s", home); - pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, buffer2); + fprintf(stderr, "Cannot determine your user name\n"); + exit(1); } + snprintf(buffer2, sizeof(buffer2), "HOME=/Users/%s", login); + pushShellspawnCommand(sockfd, SHELLSPAWN_SETENV, buffer2); + // Push shell arguments if (buffer != NULL) { @@ -747,6 +747,8 @@ pid_t spawnInitProcess(void) free(opts); + setupUserHome(); + // This is executed once at prefix creation if (g_fixPermissions) fixDirectoryPermissions(prefix); @@ -1238,3 +1240,96 @@ void setupCoredumpPattern(void) fclose(f); } } + +const char* xdgDirectory(const char* name) +{ + static char dir[4096]; + char* cmd = (char*) malloc(16 + strlen(name)); + + sprintf(cmd, "xdg-user-dir %s", name); + + FILE* proc = popen(cmd, "r"); + + free(cmd); + + if (!proc) + return NULL; + + fgets(dir, sizeof(dir)-1, proc); + + pclose(proc); + + size_t len = strlen(dir); + if (len <= 1) + return NULL; + + if (dir[len-1] == '\n') + dir[len-1] = '\0'; + return dir; +} + +void setupUserHome(void) +{ + char buf[4096], buf2[4096]; + + snprintf(buf, sizeof(buf), "%s/Users", prefix); + + // Remove the old /Users symlink that may exist + unlink(buf); + + // mkdir /Users + mkdir(buf, 0777); + + // mkdir /Users/Shared + strcat(buf, "/Shared"); + mkdir(buf, 0777); + + const char* home = getenv("HOME"); + const char* login = getlogin(); + if (!login) + { + fprintf(stderr, "Cannot determine your user name\n"); + exit(1); + } + if (!home) + { + fprintf(stderr, "Cannot determine your home directory\n"); + exit(1); + } + + snprintf(buf, sizeof(buf), "%s/Users/%s", prefix, login); + + // mkdir /Users/$LOGIN + mkdir(buf, 0755); + + snprintf(buf2, sizeof(buf2), "/Volumes/SystemRoot%s", home); + + strcat(buf, "/LinuxHome"); + unlink(buf); + + // symlink /Users/$LOGIN/LinuxHome -> $HOME + symlink(buf2, buf); + + static const char* xdgmap[][2] = { + { "DESKTOP", "Desktop" }, + { "DOWNLOAD", "Downloads" }, + { "PUBLICSHARE", "Public" }, + { "DOCUMENTS", "Documents" }, + { "MUSIC", "Music" }, + { "PICTURES", "Pictures" }, + { "VIDEOS", "Movies" }, + }; + + for (int i = 0; i < sizeof(xdgmap) / sizeof(xdgmap[0]); i++) + { + const char* dir = xdgDirectory(xdgmap[i][0]); + if (!dir) + continue; + + snprintf(buf2, sizeof(buf2), "/Volumes/SystemRoot%s", dir); + snprintf(buf, sizeof(buf), "%s/Users/%s/%s", prefix, login, xdgmap[i][1]); + + unlink(buf); + symlink(buf2, buf); + } +} diff --git a/src/startup/darling.h b/src/startup/darling.h index 683a5f37a..ff0761dc3 100644 --- a/src/startup/darling.h +++ b/src/startup/darling.h @@ -67,5 +67,6 @@ void loadKernelModule(void); void joinNamespace(pid_t pid, int type, const char* typeName); void setupCoredumpPattern(void); +void setupUserHome(void); #endif