@@ -742,6 +742,57 @@ def FromOutput(cls, stdout: str) -> ServicesEntry:
742742 return cls .FromDict (result )
743743
744744
745+ class SubIDEntry (object ):
746+ """
747+ Combined subordinate ID ranges for user.
748+ """
749+
750+ def __init__ (self , id : int , name : str , range_start : int , range_size : int ) -> None :
751+
752+ self .id : int = id
753+ """ User id """
754+
755+ self .name : str = name
756+ """ User name"""
757+
758+ self .range_start : int = range_start
759+ """ SubID range start """
760+
761+ self .range_size : int = range_size
762+ """ SubID range size """
763+
764+ def __str__ (self ) -> str :
765+ return f"id:{ self .id } , owner:{ self .name } , start:{ self .range_start } , size:{ self .range_size } )"
766+
767+ def __repr__ (self ) -> str :
768+ return str (self )
769+
770+ @classmethod
771+ def FromDict (cls , d : dict [str , Any ]) -> SubIDEntry :
772+ return cls (
773+ id = d .get ("id" , "" ),
774+ name = d .get ("name" , "" ),
775+ range_start = d .get ("range_start" , 0 ),
776+ range_size = d .get ("range_size" , 0 ),
777+ )
778+
779+ @classmethod
780+ def FromOutput (cls , stdout : str ) -> SubIDEntry :
781+ line = stdout .strip ()
782+ if ":" in line :
783+ parts = line .split (":" , 1 )
784+ if len (parts ) == 2 :
785+ rest = parts [1 ].strip ().split ()
786+ if len (rest ) >= 3 :
787+ return cls (
788+ id = int (parts [0 ].strip ()),
789+ name = rest [0 ],
790+ range_start = int (rest [1 ]),
791+ range_size = int (rest [2 ]),
792+ )
793+ return cls (id = 0 , name = "" , range_start = 0 , range_size = 0 )
794+
795+
745796class LinuxToolsUtils (MultihostUtility [MultihostHost ]):
746797 """
747798 Run various standard commands on remote host.
@@ -762,6 +813,27 @@ def __init__(self, host: MultihostHost, fs: LinuxFileSystem) -> None:
762813 self .__fs : LinuxFileSystem = fs
763814 self .__rollback : list [str ] = []
764815
816+ def getsubid (self , name : str , group : bool = False ) -> SubIDEntry | None :
817+ """
818+ Call ``getsubid $name``
819+
820+ :param name: User name.
821+ :type name: str
822+ :param group: Get group range switch, optional
823+ :type group: bool, defaults to False
824+ :return: SubIDEntry data, None if not found
825+ :type: SubIDEntry | None
826+ """
827+ args = ""
828+ if group :
829+ args = "-g"
830+
831+ command = self .host .conn .run (f"getsubids { args } { name } " , raise_on_error = False )
832+ if command .rc != 0 :
833+ return None
834+
835+ return SubIDEntry .FromOutput (command .stdout )
836+
765837 def id (self , name : str | int ) -> IdEntry | None :
766838 """
767839 Run ``id`` command.
0 commit comments