@@ -12,7 +12,7 @@ use std::process::{Command, Stdio};
1212use crate :: cgroup;
1313use crate :: cgroup:: Cgroup ;
1414use crate :: chroot:: chroot;
15- use crate :: resource_limits:: ResourceLimits ;
15+ use crate :: resource_limits:: { ResourceLimits , FSIZE_ARG , NO_FILE_ARG } ;
1616use crate :: { Error , Result } ;
1717use std:: io;
1818use std:: io:: Write ;
@@ -169,7 +169,10 @@ impl Env {
169169 }
170170 }
171171
172- let resource_limits = ResourceLimits :: default ( ) ;
172+ let mut resource_limits = ResourceLimits :: default ( ) ;
173+ if let Some ( args) = arguments. multiple_values ( "resource-limit" ) {
174+ Env :: parse_resource_limits ( & mut resource_limits, args) ?;
175+ }
173176
174177 Ok ( Env {
175178 id : id. to_owned ( ) ,
@@ -201,6 +204,24 @@ impl Env {
201204 self . uid
202205 }
203206
207+ fn parse_resource_limits ( resource_limits : & mut ResourceLimits , args : & [ String ] ) -> Result < ( ) > {
208+ for arg in args {
209+ let ( name, value) = arg
210+ . split_once ( '=' )
211+ . ok_or_else ( || Error :: ResLimitFormat ( arg. to_string ( ) ) ) ?;
212+
213+ let limit_value = value
214+ . parse :: < u64 > ( )
215+ . map_err ( |err| Error :: ResLimitValue ( value. to_string ( ) , err. to_string ( ) ) ) ?;
216+ match name {
217+ FSIZE_ARG => resource_limits. set_file_size ( limit_value) ,
218+ NO_FILE_ARG => resource_limits. set_no_file ( limit_value) ,
219+ _ => return Err ( Error :: ResLimitArgument ( name. to_string ( ) ) ) ,
220+ }
221+ }
222+ Ok ( ( ) )
223+ }
224+
204225 fn exec_into_new_pid_ns ( & mut self , chroot_exec_file : PathBuf ) -> Result < ( ) > {
205226 // Unshare into a new PID namespace.
206227 // The current process will not be moved into the newly created namespace, but its first
@@ -562,6 +583,7 @@ mod tests {
562583 pub daemonize : bool ,
563584 pub new_pid_ns : bool ,
564585 pub cgroups : Vec < & ' a str > ,
586+ pub resource_limits : Vec < & ' a str > ,
565587 }
566588
567589 impl ArgVals < ' _ > {
@@ -577,6 +599,7 @@ mod tests {
577599 daemonize : true ,
578600 new_pid_ns : true ,
579601 cgroups : vec ! [ "cpu.shares=2" , "cpuset.mems=0" ] ,
602+ resource_limits : vec ! [ "no-file=1024" , "fsize=1048575" ] ,
580603 }
581604 }
582605 }
@@ -607,6 +630,12 @@ mod tests {
607630 arg_vec. push ( ( * cg) . to_string ( ) ) ;
608631 }
609632
633+ // Append limits arguments
634+ for limit in & arg_vals. resource_limits {
635+ arg_vec. push ( "--resource-limit" . to_string ( ) ) ;
636+ arg_vec. push ( ( * limit) . to_string ( ) ) ;
637+ }
638+
610639 if let Some ( s) = arg_vals. netns {
611640 arg_vec. push ( "--netns" . to_string ( ) ) ;
612641 arg_vec. push ( s. to_string ( ) ) ;
@@ -702,6 +731,16 @@ mod tests {
702731 args. parse ( & make_args ( & invalid_cgroup_arg_vals) ) . unwrap ( ) ;
703732 assert ! ( Env :: new( & args, 0 , 0 ) . is_err( ) ) ;
704733
734+ let invalid_res_limit_arg_vals = ArgVals {
735+ resource_limits : vec ! [ "zzz" ] ,
736+ ..base_invalid_arg_vals. clone ( )
737+ } ;
738+
739+ let arg_parser = build_arg_parser ( ) ;
740+ args = arg_parser. arguments ( ) . clone ( ) ;
741+ args. parse ( & make_args ( & invalid_res_limit_arg_vals) ) . unwrap ( ) ;
742+ assert ! ( Env :: new( & args, 0 , 0 ) . is_err( ) ) ;
743+
705744 let invalid_id_arg_vals = ArgVals {
706745 id : "/ad./sa12" ,
707746 ..base_invalid_arg_vals. clone ( )
@@ -884,6 +923,7 @@ mod tests {
884923 daemonize : false ,
885924 new_pid_ns : false ,
886925 cgroups : Vec :: new ( ) ,
926+ resource_limits : Vec :: new ( ) ,
887927 } ;
888928 fs:: write ( some_file_path, "some_content" ) . unwrap ( ) ;
889929 args. parse ( & make_args ( & some_arg_vals) ) . unwrap ( ) ;
@@ -1006,6 +1046,71 @@ mod tests {
10061046 assert ! ( Env :: new( & args, 0 , 0 ) . is_ok( ) ) ;
10071047 }
10081048
1049+ #[ test]
1050+ fn test_parse_resource_limits ( ) {
1051+ let mut resource_limits = ResourceLimits :: default ( ) ;
1052+
1053+ // Cases that should fail
1054+
1055+ // Check invalid formats
1056+ let invalid_formats = [ "" , "foo" ] ;
1057+ for format in invalid_formats. iter ( ) {
1058+ let arg = vec ! [ format. to_string( ) ] ;
1059+ assert_eq ! (
1060+ format!(
1061+ "{:?}" ,
1062+ Env :: parse_resource_limits( & mut resource_limits, & * arg)
1063+ . err( )
1064+ . unwrap( )
1065+ ) ,
1066+ format!( "{:?}" , Error :: ResLimitFormat ( format. to_string( ) ) )
1067+ ) ;
1068+ }
1069+
1070+ // Check invalid resource arguments
1071+ let invalid_resources = [ "foo" , "" , " " ] ;
1072+ for res in invalid_resources. iter ( ) {
1073+ let arg = format ! ( "{}=2" , res) ;
1074+ assert_eq ! (
1075+ format!(
1076+ "{:?}" ,
1077+ Env :: parse_resource_limits( & mut resource_limits, & * vec![ arg] )
1078+ . err( )
1079+ . unwrap( )
1080+ ) ,
1081+ format!( "{:?}" , Error :: ResLimitArgument ( res. to_string( ) ) )
1082+ ) ;
1083+ }
1084+
1085+ // Check invalid limit values
1086+ let invalid_values = [ "foo" , "2.3" , "2-3" , " " ] ;
1087+ for val in invalid_values. iter ( ) {
1088+ let arg = format ! ( "fsize={}" , val) ;
1089+ assert_eq ! (
1090+ format!(
1091+ "{:?}" ,
1092+ Env :: parse_resource_limits( & mut resource_limits, & * vec![ arg] )
1093+ . err( )
1094+ . unwrap( )
1095+ ) ,
1096+ format!(
1097+ "{:?}" ,
1098+ Error :: ResLimitValue (
1099+ val. to_string( ) ,
1100+ "invalid digit found in string" . to_string( )
1101+ )
1102+ )
1103+ ) ;
1104+ }
1105+
1106+ // Check valid cases
1107+ let resources = [ FSIZE_ARG , NO_FILE_ARG ] ;
1108+ for resource in resources. iter ( ) {
1109+ let arg = vec ! [ resource. to_string( ) + & "=4098" . to_string( ) ] ;
1110+ Env :: parse_resource_limits ( & mut resource_limits, & * arg) . unwrap ( ) ;
1111+ }
1112+ }
1113+
10091114 #[ test]
10101115 #[ cfg( target_arch = "aarch64" ) ]
10111116 fn test_copy_cache_info ( ) {
0 commit comments