diff --git a/codex/codex_patcher.py b/codex/codex_patcher.py index 2a74fc6..ac26e50 100755 --- a/codex/codex_patcher.py +++ b/codex/codex_patcher.py @@ -659,24 +659,57 @@ def rollback(home_dir=None): # ─── Multi-User Support ───────────────────────────────────────────────── -def list_users(): - """List system users with .codex/ or home dirs.""" - users = [] - try: - import pwd - for pw in pwd.getpwall(): - home = pw.pw_dir - if not os.path.isdir(home): +def list_user_homes(): + """List home directories of real users. Returns list of (home_dir, uid, gid).""" + homes = [] + + if IS_MACOS: + # macOS: pwd.getpwall() is unreliable (Directory Services). + # Scan /Users/ directly + /var/root for root. + import stat as st + for base in ["/Users", "/var/root"]: + if base == "/var/root": + if os.path.isdir(base): + info = os.stat(base) + homes.append((base, info.st_uid, info.st_gid)) continue - min_uid = 500 if IS_MACOS else 1000 - if pw.pw_uid < min_uid and pw.pw_uid != 0: + if not os.path.isdir(base): continue - if pw.pw_shell in ("/usr/sbin/nologin", "/bin/false"): - continue - users.append(pw) - except ImportError: - pass - return users + for name in os.listdir(base): + if name.startswith(".") or name == "Shared": + continue + udir = os.path.join(base, name) + if os.path.isdir(udir): + info = os.stat(udir) + homes.append((udir, info.st_uid, info.st_gid)) + else: + # Linux: use pwd + try: + import pwd + for pw in pwd.getpwall(): + if not os.path.isdir(pw.pw_dir): + continue + if pw.pw_uid < 1000 and pw.pw_uid != 0: + continue + if pw.pw_shell in ("/usr/sbin/nologin", "/bin/false"): + continue + homes.append((pw.pw_dir, pw.pw_uid, pw.pw_gid)) + except ImportError: + # Fallback: scan /home + /root + for base in ["/home", "/root"]: + if base == "/root": + if os.path.isdir(base): + homes.append((base, 0, 0)) + continue + if not os.path.isdir(base): + continue + for name in os.listdir(base): + udir = os.path.join(base, name) + if os.path.isdir(udir): + info = os.stat(udir) + homes.append((udir, info.st_uid, info.st_gid)) + + return homes def patch_user(user_home, config, uid=None, gid=None): @@ -748,14 +781,15 @@ def main(): # Patch other users if --all if args.all: - for user in list_users(): - if user.pw_dir == os.path.expanduser("~"): + my_home = os.path.expanduser("~") + for home_dir, uid, gid in list_user_homes(): + if home_dir == my_home: continue try: - patch_user(user.pw_dir, config, uid=user.pw_uid, gid=user.pw_gid) - print(f" Patched {user.pw_name}: {user.pw_dir}/.codex/config.toml") + patch_user(home_dir, config, uid=uid, gid=gid) + print(f" Patched: {home_dir}/.codex/config.toml (uid={uid})") except Exception as e: - print(f" {RED}Failed {user.pw_name}: {e}{RESET}") + print(f" {RED}Failed {home_dir}: {e}{RESET}") return 0 if ok else 1