22import os
33import logging
44import re
5- from typing import Dict , Optional
5+ from typing import Dict , Any , Optional
66
77
88import constants
1313def modify_config_file (config_path : str , setting : str , new_value : str ) -> bool :
1414 """
1515 Modifies a specific setting in the bluestacks.conf file.
16-
17- If the setting exists, its value is updated. If it doesn't exist,
18- it's appended to the end of the file. Handles values enclosed
19- in double quotes. Ensures the file is only written if changes are made.
20-
21- Args:
22- config_path: Absolute path to the bluestacks.conf file.
23- setting: The configuration key to modify (e.g., "bst.instance.Nougat64.enable_root_access").
24- new_value: The desired string value for the setting (e.g., "1", "0").
25-
26- Returns:
27- True if the file was modified, False otherwise.
28-
29- Raises:
30- FileNotFoundError: If config_path does not point to an existing file.
31- IOError: If there are problems reading or writing the file (caught as Exception).
32- Exception: For other unexpected file I/O errors.
3316 """
3417 if not os .path .isfile (config_path ):
3518 logger .error (f"Config file not found: { config_path } " )
@@ -40,10 +23,8 @@ def modify_config_file(config_path: str, setting: str, new_value: str) -> bool:
4023 )
4124
4225 new_line_content = f'{ setting } ="{ new_value } "'
43-
4426 lines = []
4527 try :
46-
4728 with open (config_path , "r" , encoding = "utf-8" ) as file :
4829 lines = file .readlines ()
4930 except Exception as e :
@@ -58,19 +39,14 @@ def modify_config_file(config_path: str, setting: str, new_value: str) -> bool:
5839
5940 for line in lines :
6041 stripped_line = line .strip ()
61-
6242 if setting_pattern .match (stripped_line ):
63-
6443 if stripped_line != new_line_content :
6544 logger .info (
6645 f"Updating setting '{ setting } '. Old line: '{ stripped_line } ', New line: '{ new_line_content } '"
6746 )
6847 updated_lines .append (new_line_content + "\n " )
6948 changed = True
7049 else :
71- logger .debug (
72- f"Setting '{ setting } ' already has the desired value '{ new_value } '. No change needed."
73- )
7450 updated_lines .append (line )
7551 setting_found_and_updated = True
7652 else :
@@ -80,7 +56,6 @@ def modify_config_file(config_path: str, setting: str, new_value: str) -> bool:
8056 logger .info (
8157 f"Setting '{ setting } ' not found. Appending with value '{ new_value } '."
8258 )
83-
8459 if updated_lines and not updated_lines [- 1 ].endswith ("\n " ):
8560 updated_lines [- 1 ] += "\n "
8661 updated_lines .append (new_line_content + "\n " )
@@ -96,31 +71,30 @@ def modify_config_file(config_path: str, setting: str, new_value: str) -> bool:
9671 raise IOError (
9772 f"Error writing updated configuration file { config_path } : { e } "
9873 ) from e
99- else :
100- logger .debug (f"No changes were made to { config_path } ." )
10174
10275 return changed
10376
10477
105- def get_all_instance_root_statuses (config_path : str ) -> Dict [str , bool ]:
78+ def get_complete_root_statuses (config_path : str ) -> Dict [str , Any ]:
10679 """
107- Reads the config file and returns a dictionary of instance names
108- and their root status (True if enabled, False otherwise).
80+ Reads a config file and returns all instance root statuses AND the global rooting feature status.
10981
11082 Args:
11183 config_path: Path to the bluestacks.conf file.
11284
11385 Returns:
114- A dictionary mapping instance name (str) to root status (bool).
115- Returns an empty dictionary if the file is not found or an error occurs during reading.
86+ A dictionary like: {'global_status': bool, 'instance_statuses': {name: bool}}
11687 """
117- statuses : Dict [str , bool ] = {}
88+ instance_statuses : Dict [str , bool ] = {}
89+ global_status : bool = False
90+
11891 if not os .path .isfile (config_path ):
11992 logger .warning (
12093 f"Config file not found for reading root statuses: { config_path } "
12194 )
122- return statuses
95+ return { "global_status" : False , "instance_statuses" : {}}
12396
97+ # FIX: Regex for both instance-specific and global root keys
12498 instance_pattern = re .compile (
12599 r"^"
126100 + re .escape (constants .INSTANCE_PREFIX )
@@ -129,24 +103,28 @@ def get_all_instance_root_statuses(config_path: str) -> Dict[str, bool]:
129103 + r'\s*=\s*"([^"]*)"' ,
130104 re .IGNORECASE ,
131105 )
106+ global_pattern = re .compile (
107+ r"^" + re .escape (constants .FEATURE_ROOTING_KEY ) + r'\s*=\s*"1"' , re .IGNORECASE
108+ )
132109
133110 try :
134111 with open (config_path , "r" , encoding = "utf-8" ) as file :
135112 for line in file :
136- match = instance_pattern .match (line .strip ())
113+ stripped_line = line .strip ()
114+
115+ # Check for global key
116+ if global_pattern .match (stripped_line ):
117+ global_status = True
118+ logger .debug (f"Found global root status in { config_path } : Enabled" )
119+
120+ # Check for instance key
121+ match = instance_pattern .match (stripped_line )
137122 if match :
138- instance_name = match .group (1 )
139- value = match .group (2 )
123+ instance_name , value = match .group (1 ), match .group (2 )
140124 is_enabled = value == "1"
141- statuses [instance_name ] = is_enabled
142- logger .debug (
143- f"Found root status for instance '{ instance_name } ': { 'Enabled' if is_enabled else 'Disabled' } "
144- )
125+ instance_statuses [instance_name ] = is_enabled
145126 except Exception :
146127 logger .exception (f"Error reading config file { config_path } for root statuses." )
147- return {}
148-
149- if not statuses :
150- logger .info (f"No instance root status settings found in { config_path } ." )
128+ return {"global_status" : False , "instance_statuses" : {}}
151129
152- return statuses
130+ return { "global_status" : global_status , "instance_statuses" : instance_statuses }
0 commit comments