Skip to content

Commit faac0a6

Browse files
committed
User switching now happens directly, without involving WSL through lxrun. This way broken installations can be repaired without failing at the 'Probing the Linux subsystem' step.
1 parent 68ff460 commit faac0a6

File tree

2 files changed

+63
-55
lines changed

2 files changed

+63
-55
lines changed

install.py

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import time
66
import atexit
77
import shutil
8-
import struct
98
import tarfile
109
import os.path
1110
import subprocess
1211

1312
from collections import OrderedDict
1413
from ntfsea import ntfsea, lxattrb, stmode
15-
from utils import Fore, ProgressFileObject, parse_image_arg, probe_wsl, get_label, show_cursor, hide_cursor, draw_progress, clear_progress, escape_ntfs_invalid
14+
from utils import *
1615

1716
try:
1817
import PySquashfsImage
@@ -45,39 +44,31 @@
4544

4645
basedir, lxpath = probe_wsl()
4746

47+
uid = 0
48+
gid = 0
4849
user = ''
4950
isroot = False
5051
homedir = ''
5152
homedirw = ''
5253

53-
# somewhat a major issue, stdout and stderr can't be redirected, so this script can't monitor the output
54-
# of any of the launched commands. it can, however, receive the exit status, so that's something, I guess.
55-
# ref: https://github.com/Microsoft/BashOnWindows/issues/2
56-
5754
try:
58-
subprocess.check_call(['cmd', '/C', lxpath + '\\bash.exe', '-c', 'echo $HOME > /tmp/.wsl_usr.txt; echo $USER >> /tmp/.wsl_usr.txt'])
59-
out = os.path.join(basedir, 'rootfs/tmp/.wsl_usr.txt')
60-
61-
if not os.path.isfile(out):
62-
print('%s[!]%s Failed to get home directory of default user in WSL: Output file %s%s%s not present.' % (Fore.RED, Fore.RESET, Fore.BLUE, out, Fore.RESET))
63-
sys.exit(-1)
55+
uid, gid, user = get_lxss_user()
6456

65-
with open(out) as f:
66-
homedir = f.readline().strip()
67-
homedirw = os.path.join(basedir, homedir.lstrip('/'))
57+
if uid == 0:
58+
isroot = True
59+
homedir = '/root'
60+
else:
61+
homedir = '/home/' + user
6862

69-
if len(homedir) == 0 or not os.path.isdir(homedirw):
70-
print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET))
71-
sys.exit(-1)
63+
homedirw = os.path.join(basedir, homedir.lstrip('/'))
7264

73-
user = f.readline().strip()
74-
isroot = user == 'root'
65+
if len(homedir) == 0 or not os.path.isdir(homedirw):
66+
print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET))
67+
sys.exit(-1)
7568

7669
print('%s[*]%s Default user is %s%s%s at %s%s%s.' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, user, Fore.RESET, Fore.BLUE, homedir, Fore.RESET))
7770

78-
os.unlink(out)
79-
80-
except subprocess.CalledProcessError as err:
71+
except BaseException as err:
8172
print('%s[!]%s Failed to get home directory of default user in WSL: %s' % (Fore.RED, Fore.RESET, err))
8273
sys.exit(-1)
8374

@@ -456,54 +447,32 @@ def retry_rw(operation, name, exc):
456447
print('%s[*]%s Switching default user to %sroot%s...' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, Fore.RESET))
457448

458449
try:
459-
subprocess.check_output(['cmd', '/C', lxpath + '\\lxrun.exe', '/setdefaultuser', 'root'])
450+
set_lxss_user(0, 0, 'root')
460451

461-
except subprocess.CalledProcessError as err:
452+
except BaseException as err:
462453
print('%s[!]%s Failed to switch default user in WSL: %s' % (Fore.RED, Fore.RESET, err))
463454
sys.exit(-1)
464455

465-
try:
466-
subprocess.check_call(['cmd', '/C', lxpath + '\\bash.exe', '-c',
467-
'echo $HOME > /tmp/.wsl_usr.txt; echo $USER >> /tmp/.wsl_usr.txt'])
468-
out = os.path.join(basedir, 'rootfs/tmp/.wsl_usr.txt')
469-
470-
if not os.path.isfile(out):
471-
print('%s[!]%s Failed to get home directory of default user in WSL: Output file %s%s%s not present.' % (Fore.RED, Fore.RESET, Fore.BLUE, out, Fore.RESET))
472-
sys.exit(-1)
473-
474-
with open(out) as f:
475-
homedir = f.readline().strip()
476-
homedirw = os.path.join(basedir, homedir.lstrip('/'))
477-
478-
if len(homedir) == 0 or not os.path.isdir(homedirw):
479-
print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET))
480-
sys.exit(-1)
481-
482-
user2 = f.readline().strip()
483-
484-
if user2 != 'root':
485-
print('%s[!]%s Failed to switch default user to %sroot%s.' % (Fore.RED, Fore.RESET, Fore.YELLOW, Fore.RESET))
486-
sys.exit(-1)
456+
homedir = '/root'
457+
homedirw = os.path.join(basedir, homedir.lstrip('/'))
487458

488-
os.unlink(out)
489-
490-
except subprocess.CalledProcessError as err:
491-
print('%s[!]%s Failed to get home directory of default user in WSL: %s' % (Fore.RED, Fore.RESET, err))
459+
if not os.path.isdir(homedirw):
460+
print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET))
492461
sys.exit(-1)
493462

494463
# since we switched to root, switch back to regular user on exit
495464

496-
def switch_user_back(user):
465+
def switch_user_back(uid, gid, user):
497466
print('%s[*]%s Switching default user back to %s%s%s...' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, user, Fore.RESET))
498467

499468
try:
500-
subprocess.check_output(['cmd', '/C', lxpath + '\\lxrun.exe', '/setdefaultuser', user])
469+
set_lxss_user(uid, gid, user)
501470

502-
except subprocess.CalledProcessError as err:
471+
except BaseException as err:
503472
print('%s[!]%s Failed to switch default user in WSL: %s' % (Fore.RED, Fore.RESET, err))
504473
sys.exit(-1)
505474

506-
atexit.register(switch_user_back, user)
475+
atexit.register(switch_user_back, uid, gid, user)
507476

508477
# run post-install hooks, if any
509478

utils.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
import glob
77
import time
8+
import winreg
89

910
# try to get colors, but don't make it a nuisance by requiring dependencies
1011

@@ -445,3 +446,41 @@ def clear_progress():
445446
sys.stdout.write('\033]9;4;0\033\\\033[39m')
446447

447448
sys.stdout.flush()
449+
450+
451+
# functions to interact with the registry
452+
453+
def get_lxss_user():
454+
"""
455+
Gets the active user inside WSL.
456+
457+
:return: Tuple of UID, GID and the name of the user.
458+
"""
459+
460+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss', access = winreg.KEY_READ | winreg.KEY_WOW64_64KEY) as lxreg:
461+
uid, uid_type = winreg.QueryValueEx(lxreg, 'DefaultUid')
462+
gid, gid_type = winreg.QueryValueEx(lxreg, 'DefaultGid')
463+
user, user_type = winreg.QueryValueEx(lxreg, 'DefaultUsername')
464+
465+
if uid_type != winreg.REG_DWORD or gid_type != winreg.REG_DWORD:
466+
raise WindowsError('DefaultUid or DefaultGid is not DWORD.')
467+
468+
if user_type != winreg.REG_SZ:
469+
raise WindowsError('DefaultUsername is not string.')
470+
471+
return uid, gid, user
472+
473+
474+
def set_lxss_user(uid, gid, user):
475+
"""
476+
Switches the active user inside WSL to the requested one.
477+
478+
:param uid: UID of the new user.
479+
:param gid: GID of the new user.
480+
:param user: Name of the new user.
481+
"""
482+
483+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss', access = winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY) as lxreg:
484+
winreg.SetValueEx(lxreg, 'DefaultUid', 0, winreg.REG_DWORD, uid)
485+
winreg.SetValueEx(lxreg, 'DefaultGid', 0, winreg.REG_DWORD, gid)
486+
winreg.SetValueEx(lxreg, 'DefaultUsername', 0, winreg.REG_SZ, user)

0 commit comments

Comments
 (0)