@@ -3797,6 +3797,50 @@ def cmd_unmount(args):
37973797 )
37983798
37993799
3800+ def cmd_status (args ):
3801+ """Handle the 'status' subcommand."""
3802+ import json
3803+ from . import platform as plat
3804+
3805+ try :
3806+ mounts = plat .find_amifuse_mounts ()
3807+ except OSError as exc :
3808+ if getattr (args , "json" , False ):
3809+ print (json .dumps ({
3810+ "status" : "error" ,
3811+ "command" : "status" ,
3812+ "error" : f"Process discovery failed: { exc } " ,
3813+ "mounts" : [],
3814+ }, indent = 2 ))
3815+ else :
3816+ print (f"Error: Process discovery failed: { exc } " )
3817+ sys .exit (1 )
3818+
3819+ if getattr (args , "json" , False ):
3820+ print (json .dumps ({
3821+ "status" : "ok" ,
3822+ "command" : "status" ,
3823+ "mounts" : mounts ,
3824+ }, indent = 2 ))
3825+ else :
3826+ if not mounts :
3827+ print ("No active AmiFUSE mounts." )
3828+ else :
3829+ # Tabular output
3830+ print (f"{ 'PID' :<8} { 'Mountpoint' :<20} { 'Image' :<40} { 'Uptime' } " )
3831+ print ("-" * 80 )
3832+ for m in mounts :
3833+ uptime = m .get ("uptime_seconds" )
3834+ if uptime is not None :
3835+ mins , secs = divmod (uptime , 60 )
3836+ hrs , mins = divmod (mins , 60 )
3837+ uptime_str = f"{ hrs } h { mins } m { secs } s"
3838+ else :
3839+ uptime_str = "N/A"
3840+ image = m .get ("image" ) or "N/A"
3841+ print (f"{ m ['pid' ]:<8} { m ['mountpoint' ]:<20} { image :<40} { uptime_str } " )
3842+
3843+
38003844def cmd_doctor (args ):
38013845 """Handle the 'doctor' subcommand."""
38023846 import json
@@ -3946,136 +3990,35 @@ def _kill_mount_owner_processes(mountpoint: Path) -> List[int]:
39463990def _find_mount_owner_pids (mountpoint : Path ) -> List [int ]:
39473991 """Find PIDs of amifuse processes that own the given mountpoint.
39483992
3949- Dispatches to platform-specific discovery: ``ps`` on Unix,
3950- ``wmic`` on Windows .
3993+ Uses platform.find_amifuse_mounts() for process discovery, then
3994+ filters to those matching the given mountpoint .
39513995 """
3952- if sys .platform .startswith ("win" ):
3953- return _find_mount_owner_pids_windows (mountpoint )
3954- return _find_mount_owner_pids_unix (mountpoint )
3955-
3956-
3957- def _find_mount_owner_pids_windows (mountpoint : Path ) -> List [int ]:
3958- """Find amifuse PIDs on Windows using wmic."""
3959- try :
3960- result = subprocess .run (
3961- ["wmic" , "process" , "where" ,
3962- "name like '%python%'" ,
3963- "get" , "ProcessId,CommandLine" ,
3964- "/FORMAT:LIST" ],
3965- check = False ,
3966- capture_output = True ,
3967- text = True ,
3968- )
3969- except OSError :
3970- return []
3971- if result .returncode != 0 :
3972- return []
3996+ from . import platform as plat
39733997
3974- current_pid = os .getpid ()
39753998 raw_mountpoint = str (mountpoint )
39763999 abs_mountpoint = str (mountpoint .resolve (strict = False ))
3977- pids = []
3978-
3979- # wmic /FORMAT:LIST outputs key=value pairs separated by blank lines
3980- current_cmdline = None
3981- current_pid_val = None
3982- for line in result .stdout .splitlines ():
3983- line = line .strip ()
3984- if not line :
3985- # End of a record -- evaluate what we have
3986- if current_cmdline is not None and current_pid_val is not None :
3987- pid = current_pid_val
3988- command = current_cmdline
3989- if pid != current_pid and "amifuse" in command :
3990- try :
3991- tokens = shlex .split (command , posix = False )
3992- except ValueError :
3993- tokens = command .split ()
3994- if _command_matches_mountpoint (tokens , raw_mountpoint , abs_mountpoint ):
3995- pids .append (pid )
3996- current_cmdline = None
3997- current_pid_val = None
3998- continue
3999- if line .startswith ("CommandLine=" ):
4000- current_cmdline = line [len ("CommandLine=" ):]
4001- elif line .startswith ("ProcessId=" ):
4002- try :
4003- current_pid_val = int (line [len ("ProcessId=" ):])
4004- except ValueError :
4005- current_pid_val = None
4006-
4007- # Handle last record if no trailing blank line
4008- if current_cmdline is not None and current_pid_val is not None :
4009- pid = current_pid_val
4010- command = current_cmdline
4011- if pid != current_pid and "amifuse" in command :
4012- try :
4013- tokens = shlex .split (command , posix = False )
4014- except ValueError :
4015- tokens = command .split ()
4016- if _command_matches_mountpoint (tokens , raw_mountpoint , abs_mountpoint ):
4017- pids .append (pid )
4018-
4019- return pids
40204000
4021-
4022- def _find_mount_owner_pids_unix (mountpoint : Path ) -> List [int ]:
4023- """Find amifuse PIDs on Unix using ps."""
40244001 try :
4025- result = subprocess .run (
4026- ["ps" , "-axo" , "pid=,command=" ],
4027- check = False ,
4028- capture_output = True ,
4029- text = True ,
4030- )
4002+ all_mounts = plat .find_amifuse_mounts ()
40314003 except OSError :
40324004 return []
4033- if result .returncode != 0 :
4034- return []
40354005
4036- current_pid = os .getpid ()
4037- raw_mountpoint = str (mountpoint )
4038- abs_mountpoint = str (mountpoint .resolve (strict = False ))
40394006 pids = []
4040-
4041- for line in result .stdout .splitlines ():
4042- line = line .strip ()
4043- if not line :
4007+ for mount in all_mounts :
4008+ mp = mount .get ("mountpoint" )
4009+ if mp is None :
40444010 continue
4045- try :
4046- pid_str , command = line .split (None , 1 )
4047- pid = int (pid_str )
4048- except ValueError :
4049- continue
4050- if pid == current_pid or "amifuse" not in command :
4011+ if mp == raw_mountpoint or mp == abs_mountpoint :
4012+ pids .append (mount ["pid" ])
40514013 continue
40524014 try :
4053- tokens = shlex .split (command )
4054- except ValueError :
4055- continue
4056- if not _command_matches_mountpoint (tokens , raw_mountpoint , abs_mountpoint ):
4057- continue
4058- pids .append (pid )
4059-
4060- return pids
4061-
4062-
4063- def _command_matches_mountpoint (tokens : List [str ], raw_mountpoint : str , abs_mountpoint : str ) -> bool :
4064- for idx , token in enumerate (tokens ):
4065- if token != "--mountpoint" :
4066- continue
4067- if idx + 1 >= len (tokens ):
4068- return False
4069- mount_arg = tokens [idx + 1 ]
4070- if mount_arg == raw_mountpoint or mount_arg == abs_mountpoint :
4071- return True
4072- try :
4073- resolved = str (Path (mount_arg ).expanduser ().resolve (strict = False ))
4015+ resolved = str (Path (mp ).expanduser ().resolve (strict = False ))
40744016 except OSError :
40754017 continue
40764018 if resolved == abs_mountpoint :
4077- return True
4078- return False
4019+ pids .append (mount ["pid" ])
4020+
4021+ return pids
40794022
40804023
40814024def _pid_exists (pid : int ) -> bool :
@@ -4130,6 +4073,9 @@ def main(argv=None):
41304073
41314074 unmount <mountpoint> Unmount an existing AmiFUSE mount.
41324075
4076+ status Show active AmiFUSE mounts on this system.
4077+ --json Output results as JSON.
4078+
41334079 doctor Check prerequisites and environment readiness.
41344080 --json Output results as JSON.
41354081
@@ -4268,6 +4214,16 @@ def main(argv=None):
42684214 unmount_parser .add_argument ("mountpoint" , type = Path , help = "Mounted filesystem path" )
42694215 unmount_parser .set_defaults (func = cmd_unmount )
42704216
4217+ # status subcommand
4218+ status_parser = subparsers .add_parser (
4219+ "status" , help = "Show active AmiFUSE mounts on this system."
4220+ )
4221+ status_parser .add_argument (
4222+ "--json" , action = "store_true" ,
4223+ help = "Output results as JSON." ,
4224+ )
4225+ status_parser .set_defaults (func = cmd_status )
4226+
42714227 # doctor subcommand
42724228 doctor_parser = subparsers .add_parser (
42734229 "doctor" , help = "Check prerequisites and environment readiness."
0 commit comments