2005-10-25 01:26:25 +10:00
/** \file builtin_ulimit.c Functions defining the ulimit builtin
2005-10-15 08:33:01 +10:00
2005-10-25 01:26:25 +10:00
Functions used for implementing the ulimit builtin .
2005-10-15 08:33:01 +10:00
*/
2006-03-29 10:14:50 +10:00
# include "config.h"
2005-10-15 08:33:01 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <wctype.h>
# include <sys/time.h>
# include <sys/resource.h>
# include <unistd.h>
# include <errno.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-10-15 08:33:01 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-10-15 08:33:01 +10:00
# include "builtin.h"
# include "common.h"
# include "wgetopt.h"
2006-01-04 22:51:02 +10:00
# include "translate.h"
2005-10-15 08:33:01 +10:00
2005-10-25 01:26:25 +10:00
/**
Struct describing a resource limit
*/
2005-10-15 08:33:01 +10:00
struct resource_t
{
2005-10-25 01:26:25 +10:00
/**
Resource id
*/
2005-10-15 08:33:01 +10:00
int resource ;
2005-10-25 01:26:25 +10:00
/**
Description of resource
*/
2005-10-15 08:33:01 +10:00
const wchar_t * desc ;
2005-10-25 01:26:25 +10:00
/**
Switch used on commandline to specify resource
*/
2005-10-15 08:33:01 +10:00
wchar_t switch_char ;
2005-11-26 00:16:57 +10:00
/**
The implicit multiplier used when setting getting values
*/
int multiplier ;
2005-10-15 08:33:01 +10:00
}
;
2005-10-25 01:26:25 +10:00
/**
Array of resource_t structs , describing all known resource types .
*/
2005-10-15 08:33:01 +10:00
const static struct resource_t resource_arr [ ] =
{
{
2005-11-26 00:16:57 +10:00
RLIMIT_CORE , L " Maximum size of core files created " , L ' c ' , 1024
2005-10-15 08:33:01 +10:00
}
,
{
2005-11-26 00:16:57 +10:00
RLIMIT_DATA , L " Maximum size of a process’ s data segment " , L ' d ' , 1024
2005-10-15 08:33:01 +10:00
}
,
{
2005-11-26 00:16:57 +10:00
RLIMIT_FSIZE , L " Maximum size of files created by the shell " , L ' f ' , 1024
2005-10-15 08:33:01 +10:00
}
,
2006-05-20 01:14:43 +10:00
# ifdef RLIMIT_MEMLOCK
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
RLIMIT_MEMLOCK , L " Maximum size that may be locked into memory " , L ' l ' , 1024
2005-10-15 08:33:01 +10:00
}
,
2005-11-24 21:13:21 +10:00
# endif
2006-05-20 01:14:43 +10:00
# ifdef RLIMIT_RSS
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
RLIMIT_RSS , L " Maximum resident set size " , L ' m ' , 1024
2005-10-15 08:33:01 +10:00
}
,
2005-11-24 21:13:21 +10:00
# endif
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
RLIMIT_NOFILE , L " Maximum number of open file descriptors " , L ' n ' , 1
2005-10-15 08:33:01 +10:00
}
,
{
2005-11-26 00:16:57 +10:00
RLIMIT_STACK , L " Maximum stack size " , L ' s ' , 1024
2005-10-15 08:33:01 +10:00
}
,
{
2005-11-26 00:16:57 +10:00
RLIMIT_CPU , L " Maximum amount of cpu time in seconds " , L ' t ' , 1
2005-10-15 08:33:01 +10:00
}
,
2006-05-20 01:14:43 +10:00
# ifdef RLIMIT_NPROC
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
RLIMIT_NPROC , L " Maximum number of processes available to a single user " , L ' u ' , 1
2005-10-15 08:33:01 +10:00
}
,
2005-11-24 21:13:21 +10:00
# endif
2006-05-20 01:14:43 +10:00
# ifdef RLIMIT_AS
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
RLIMIT_AS , L " Maximum amount of virtual memory available to the shell " , L ' v ' , 1024
2005-10-15 08:33:01 +10:00
}
,
2005-10-17 23:36:57 +10:00
# endif
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
0 , 0 , 0 , 0
2005-10-15 08:33:01 +10:00
}
}
;
2005-10-25 01:26:25 +10:00
/**
Get the implicit multiplication factor for the specified resource limit
*/
2005-10-15 08:33:01 +10:00
static int get_multiplier ( int what )
{
2005-11-26 00:16:57 +10:00
int i ;
for ( i = 0 ; resource_arr [ i ] . desc ; i + + )
2005-10-15 08:33:01 +10:00
{
2005-11-26 00:16:57 +10:00
if ( resource_arr [ i ] . resource = = what )
{
return resource_arr [ i ] . multiplier ;
}
2005-10-15 08:33:01 +10:00
}
2005-11-26 00:16:57 +10:00
return - 1 ;
2005-10-15 08:33:01 +10:00
}
2005-10-25 01:26:25 +10:00
/**
Return the value for the specified resource limit
*/
2005-10-15 08:33:01 +10:00
static rlim_t get ( int resource , int hard )
{
struct rlimit ls ;
getrlimit ( resource , & ls ) ;
return hard ? ls . rlim_max : ls . rlim_cur ;
}
2005-10-25 01:26:25 +10:00
/**
Print the value of the specified resource limit
*/
2005-10-15 08:33:01 +10:00
static void print ( int resource , int hard )
{
rlim_t l = get ( resource , hard ) ;
if ( l = = RLIM_INFINITY )
sb_append ( sb_out , L " unlimited \n " ) ;
else
sb_printf ( sb_out , L " %d \n " , l ) ;
}
2005-10-25 01:26:25 +10:00
/**
Print values of all resource limits
*/
2005-10-15 08:33:01 +10:00
static void print_all ( int hard )
{
int i ;
int w = 0 ;
for ( i = 0 ; resource_arr [ i ] . desc ; i + + )
{
w = maxi ( w , my_wcswidth ( resource_arr [ i ] . desc ) ) ;
}
for ( i = 0 ; resource_arr [ i ] . desc ; i + + )
{
struct rlimit ls ;
rlim_t l ;
getrlimit ( resource_arr [ i ] . resource , & ls ) ;
l = hard ? ls . rlim_max : ls . rlim_cur ;
wchar_t * unit = ( ( resource_arr [ i ] . resource = = RLIMIT_CPU ) ? L " (seconds, " : ( get_multiplier ( resource_arr [ i ] . resource ) = = 1 ? L " ( " : L " (kB, " ) ) ;
sb_printf ( sb_out ,
L " %-*ls %10ls-%lc) " ,
w ,
resource_arr [ i ] . desc ,
unit ,
resource_arr [ i ] . switch_char ) ;
if ( l = = RLIM_INFINITY )
sb_append ( sb_out , L " unlimited \n " ) ;
else
sb_printf ( sb_out , L " %d \n " , l ) ;
}
}
2005-10-25 01:26:25 +10:00
/**
Returns the description for the specified resource limit
*/
2005-10-15 08:33:01 +10:00
static const wchar_t * get_desc ( int what )
{
int i ;
for ( i = 0 ; resource_arr [ i ] . desc ; i + + )
{
if ( resource_arr [ i ] . resource = = what )
{
return resource_arr [ i ] . desc ;
}
}
return L " Not a resource " ;
}
2005-10-25 01:26:25 +10:00
/**
Set the new value of the specified resource limit
*/
2005-10-15 08:33:01 +10:00
static int set ( int resource , int hard , int soft , rlim_t value )
{
struct rlimit ls ;
getrlimit ( resource , & ls ) ;
if ( value ! = RLIM_INFINITY )
value * = get_multiplier ( resource ) ;
if ( hard )
{
ls . rlim_max = value ;
}
if ( soft )
{
ls . rlim_cur = value ;
/*
Do not attempt to set the soft limit higher than the hard limit
*/
if ( ( value = = RLIM_INFINITY & & ls . rlim_max ! = RLIM_INFINITY ) | |
( value ! = RLIM_INFINITY & & ls . rlim_max ! = RLIM_INFINITY & & value > ls . rlim_max ) )
{
ls . rlim_cur = ls . rlim_max ;
}
}
if ( setrlimit ( resource , & ls ) )
{
if ( errno = = EPERM )
sb_printf ( sb_err , L " ulimit: Permission denied when changing resource of type '%ls' \n " , get_desc ( resource ) ) ;
else
builtin_wperror ( L " ulimit " ) ;
return 1 ;
}
return 0 ;
}
2005-10-25 01:26:25 +10:00
/**
Set all resource limits
*/
2005-10-15 08:33:01 +10:00
static int set_all ( int hard , int soft , rlim_t value )
{
int i ;
int res = 0 ;
for ( i = 0 ; resource_arr [ i ] . desc ; i + + )
{
if ( set ( resource_arr [ i ] . resource , hard , soft , value ) )
res = 1 ;
}
return res ;
}
int builtin_ulimit ( wchar_t * * argv )
{
int hard = 0 ;
int soft = 0 ;
int what = RLIMIT_FSIZE ;
int report_all = 0 ;
int argc = builtin_count_args ( argv ) ;
woptind = 0 ;
while ( 1 )
{
const static struct woption
long_options [ ] =
{
{
L " all " , no_argument , 0 , ' a '
}
,
{
L " hard " , no_argument , 0 , ' H '
}
,
{
L " soft " , no_argument , 0 , ' S '
}
,
{
L " core-size " , no_argument , 0 , ' c '
}
,
{
L " data-size " , no_argument , 0 , ' d '
}
,
{
L " file-size " , no_argument , 0 , ' f '
}
,
{
L " lock-size " , no_argument , 0 , ' l '
}
,
{
L " resident-set-size " , no_argument , 0 , ' m '
}
,
{
L " file-descriptor-count " , no_argument , 0 , ' n '
}
,
{
L " pipe-size " , no_argument , 0 , ' p '
}
,
{
L " cpu-time " , no_argument , 0 , ' t '
}
,
{
L " process-count " , no_argument , 0 , ' u '
}
,
{
L " virtual-memory-size " , no_argument , 0 , ' v '
}
,
{
0 , 0 , 0 , 0
}
}
;
int opt_index = 0 ;
int opt = wgetopt_long ( argc ,
argv ,
L " aHScdflmnptuv " ,
long_options ,
& opt_index ) ;
if ( opt = = - 1 )
break ;
switch ( opt )
{
case 0 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
2006-01-04 22:51:02 +10:00
sb_printf ( sb_err ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
2005-10-15 08:33:01 +10:00
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
case L ' a ' :
report_all = 1 ;
break ;
case L ' H ' :
hard = 1 ;
break ;
case L ' S ' :
soft = 1 ;
break ;
case L ' c ' :
what = RLIMIT_CORE ;
break ;
case L ' d ' :
what = RLIMIT_DATA ;
break ;
case L ' f ' :
what = RLIMIT_FSIZE ;
break ;
2006-05-26 21:19:34 +10:00
# ifdef RLIMIT_MEMLOCK
2005-10-15 08:33:01 +10:00
case L ' l ' :
what = RLIMIT_MEMLOCK ;
break ;
2005-11-24 21:13:21 +10:00
# endif
2006-05-26 21:19:34 +10:00
# ifdef RLIMIT_RSS
2005-10-15 08:33:01 +10:00
case L ' m ' :
what = RLIMIT_RSS ;
break ;
2005-11-24 21:13:21 +10:00
# endif
2005-10-15 08:33:01 +10:00
case L ' n ' :
what = RLIMIT_NOFILE ;
break ;
case L ' s ' :
what = RLIMIT_STACK ;
break ;
case L ' t ' :
what = RLIMIT_CPU ;
break ;
2005-11-24 21:13:21 +10:00
2006-05-26 21:19:34 +10:00
# ifdef RLIMIT_NPROC
2005-10-15 08:33:01 +10:00
case L ' u ' :
what = RLIMIT_NPROC ;
break ;
2005-11-24 21:13:21 +10:00
# endif
2005-10-15 08:33:01 +10:00
2006-05-26 21:19:34 +10:00
# ifdef RLIMIT_AS
2005-10-15 08:33:01 +10:00
case L ' v ' :
what = RLIMIT_AS ;
break ;
2005-10-17 23:36:57 +10:00
# endif
2005-10-15 08:33:01 +10:00
case L ' ? ' :
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
switch ( argc - woptind )
{
case 0 :
/*
Show current limit value
*/
if ( report_all )
{
print_all ( hard ) ;
}
else
{
print ( what , hard ) ;
}
break ;
case 1 :
{
/*
Change current limit value
*/
rlim_t new_limit ;
wchar_t * end ;
/*
Set both hard and soft limits if nothing else was specified
*/
if ( ! ( hard + soft ) )
{
hard = soft = 1 ;
}
if ( wcscasecmp ( argv [ woptind ] , L " unlimited " ) = = 0 )
{
new_limit = RLIM_INFINITY ;
}
else if ( wcscasecmp ( argv [ woptind ] , L " hard " ) = = 0 )
{
new_limit = get ( what , 1 ) ;
}
else if ( wcscasecmp ( argv [ woptind ] , L " soft " ) = = 0 )
{
new_limit = get ( what , soft ) ;
}
else
{
errno = 0 ;
new_limit = wcstol ( argv [ woptind ] , & end , 10 ) ;
if ( errno | | * end )
{
sb_printf ( sb_err ,
L " %ls: Invalid limit '%ls' \n " ,
argv [ 0 ] ,
argv [ woptind ] ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
}
}
if ( report_all )
{
return set_all ( hard , soft , new_limit ) ;
}
else
{
return set ( what , hard , soft , new_limit ) ;
}
break ;
}
default :
sb_append2 ( sb_err ,
argv [ 0 ] ,
L " : Too many arguments \n " ,
( void * ) 0 ) ;
builtin_print_help ( argv [ 0 ] , sb_err ) ;
return 1 ;
break ;
}
return 0 ;
}