I took a long while until the VirtualBox Guest Additions for Solaris become available. So long that I used to not count on it ever more. But then all of a sudden for some reason I can't remember why I mounted the VirtualBox 5.1.18 Guest Additions on a Solaris 11.3 and happily noticed that, yes, they were there! It's an old (SVr4) Solaris package file (.pkg extension). So I immediately set to install it but, as usual, there was no available documentation, at least I couldn't easily find it. At first I tried an unattended SVr4 package install but it didn't work so I was forced to do it interactively.
For recap I started by mounting the VirtualBox Guest Additions as follows:
And then the usual optical media icon kicked in on my desktop:
But double-clicking on it won't work as expected, unfortunately. They probably didn't have the time for this final perfection, but I wonder if that was a typical case of lazyness; whatever, I went to the very comfortable CLI and served myself:
# cd /media/VBOXADDITIONS_5.1.18_114002
# ll *.pkg
-r-xr-xr-x 1 root root 17M ... VBoxSolarisAdditions.pkg
# pkgadd -d VBoxSolarisAdditions.pkg all
Processing package instance <SUNWvboxguest> from </media/VBOXADDITIONS_5.1.18_114002/VBoxSolarisAdditions.pkg>
Oracle VM VirtualBox Guest Additions(i386) 5.1.18,REV=r114002.2017.03.15.16.33
Oracle Corporation
Using </> as the package base directory.
## Processing package information.
## Processing system information.
## Verifying package dependencies.
## Verifying disk space requirements.
## Checking for conflicts with packages already installed.
## Checking for setuid/setgid programs.
... contains scripts which will be executed with super-user
permission during the process of installing this package.
... continue with the installation of <SUNWvboxguest> [y,n,?] y
Installing ... Guest Additions as <SUNWvboxguest>
## Installing part 1 of 1.
/etc/fs/vboxfs/mount <symbolic link>
/opt/VirtualBoxAdditions/1099.vboxclient
/opt/VirtualBoxAdditions/LICENSE
/opt/VirtualBoxAdditions/VBox.sh
/opt/VirtualBoxAdditions/VBoxControl
/opt/VirtualBoxAdditions/amd64/VBoxClient.Z
/opt/VirtualBoxAdditions/amd64/VBoxControl.Z
/opt/VirtualBoxAdditions/amd64/VBoxService.Z
/opt/VirtualBoxAdditions/amd64/pam_vbox.so
/opt/VirtualBoxAdditions/amd64/vboxfs
/opt/VirtualBoxAdditions/amd64/vboxfs_s10
/opt/VirtualBoxAdditions/amd64/vboxfsmount
/opt/VirtualBoxAdditions/amd64/vboxmslnk
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_110.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_111.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_112.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_113.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_114.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_117.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_118.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_13.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_14.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_15.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_16.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_17.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_18.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_19.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_70.so.Z
/opt/VirtualBoxAdditions/amd64/vboxvideo_drv_71.so.Z
/opt/VirtualBoxAdditions/i386/VBoxClient.Z
/opt/VirtualBoxAdditions/i386/VBoxControl.Z
/opt/VirtualBoxAdditions/i386/VBoxService.Z
/opt/VirtualBoxAdditions/i386/pam_vbox.so
/opt/VirtualBoxAdditions/i386/vboxfs
/opt/VirtualBoxAdditions/i386/vboxfs_s10
/opt/VirtualBoxAdditions/i386/vboxfsmount
/opt/VirtualBoxAdditions/i386/vboxmslnk
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_110.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_111.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_112.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_113.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_114.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_117.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_118.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_13.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_14.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_15.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_16.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_17.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_18.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_19.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_70.so.Z
/opt/VirtualBoxAdditions/i386/vboxvideo_drv_71.so.Z
/opt/VirtualBoxAdditions/solaris_xorg.conf
/opt/VirtualBoxAdditions/solaris_xorg_modeless.conf
/opt/VirtualBoxAdditions/vbox_vendor_select
/opt/VirtualBoxAdditions/vboxclient.desktop
/opt/VirtualBoxAdditions/vboxguest.sh
/opt/VirtualBoxAdditions/x11config15sol.pl
/opt/VirtualBoxAdditions/x11restore.pl
/usr/bin/VBoxClient <symbolic link>
/usr/bin/VBoxClient-all <symbolic link>
/usr/bin/VBoxControl <symbolic link>
/usr/bin/VBoxService <symbolic link>
/usr/kernel/drv/amd64/vboxguest
/usr/kernel/drv/amd64/vboxms
/usr/kernel/drv/vboxguest
/usr/kernel/drv/vboxguest.conf
/usr/kernel/drv/vboxms
/usr/kernel/drv/vboxms.conf
/usr/lib/VBoxOGL.so
/usr/lib/VBoxOGLarrayspu.so
/usr/lib/VBoxOGLcrutil.so
/usr/lib/VBoxOGLerrorspu.so
/usr/lib/VBoxOGLfeedbackspu.so
/usr/lib/VBoxOGLpackspu.so
/usr/lib/VBoxOGLpassthroughspu.so
/usr/lib/amd64/VBoxOGL.so
/usr/lib/amd64/VBoxOGLarrayspu.so
/usr/lib/amd64/VBoxOGLcrutil.so
/usr/lib/amd64/VBoxOGLerrorspu.so
/usr/lib/amd64/VBoxOGLfeedbackspu.so
/usr/lib/amd64/VBoxOGLpackspu.so
/usr/lib/amd64/VBoxOGLpassthroughspu.so
/usr/sbin/vboxmslnk <sUnattended SVr4 pkg installymbolic link>
[ verifying class <none> ]
/opt/VirtualBoxAdditions/VBoxClient <linked pathname>
/opt/VirtualBoxAdditions/VBoxISAExec <linked pathname>
/opt/VirtualBoxAdditions/VBoxService <linked pathname>
/opt/VirtualBoxAdditions/vboxmslnk <linked pathname>
[ verifying class <manifest> ]
## Executing postinstall script.
Uncompressing files...
Configuring VirtualBox guest kernel module...
VirtualBox guest kernel module loaded.
VirtualBox pointer integration module loaded.
Creating links...
Installing video driver for X.Org 1.14.5...
Configuring client...
Installing 64-bit shared folders module...
Installing 32-bit shared folders module...
Configuring services (this might take a while)...
Enabling services...
Updating boot archive...
Done.
Please re-login to activate the X11 guest additions.
If ... just un-installed the previous ... a REBOOT is required.
Installation of <SUNWvboxguest> was successful.
# eject
$ pkginfo -l SUNWvboxguest
PKGINST: SUNWvboxguest
NAME: Oracle VM VirtualBox Guest Additions
CATEGORY: application
ARCH: i386
VERSION: 5.1.18,REV=r114002.2017.03.15.16.33
BASEDIR: /
VENDOR: Oracle Corporation
DESC: ... Guest Additions for Solaris guests
PSTAMP: vboxguest20170315163319_r114002
INSTDATE: May 08 2017 17:03
HOTLINE: Please contact your local service provider
EMAIL: info@virtualbox.org
STATUS: completely installed
FILES: 80 installed pathnames
4 linked files
5 directories
21 executables
37263 blocks used (approx)
Personal notes and recipes, views and opinions.
If it must run, it runs on Solaris!
Monday, May 8, 2017
Friday, April 28, 2017
Resource control - rc-03
This program (rc-03) uses the Solaris interface to resource control.
It lists all the controls that are active to its running process.
Following the listing there's a sample output.
#include <rctl.h>
#include <alloca.h>
#include <cstdlib>
#include <cerrno>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <iostream>
#include <iomanip>
//
// Convenience "special" vector.
//
template< typename T >
struct vector : public std::vector< T >
{
};
//
// Convenience operator for just the "special" vector.
// For simplicity, not dealing with formatting or state issues.
//
template< typename T >
std::istream & operator >> ( std::istream & is, vector<T> & v )
{
typename vector<T>::value_type element;
if ( is >> element )
v.push_back( element );
return is;
}
//
// The main data structure for organization.
// Key: resource containment.
// Data: list of controls.
//
std::map< const std::string, vector< std::string > > resource;
//
// The resource walking routine.
//
int active( const char * name, void * )
{
std::istringstream iss( name );
std::string containment;
if ( std::getline( iss, containment, '.' ) )
iss >> resource[ containment ];
return 0;
}
const size_t size = ::rctlblk_size( );
typedef ::rctlblk_t * p_blk;
// May suffer from stream formatting issues...
void print_limit( const p_blk rl )
{
//
// Type
//
std::cout
<< "\t\t"
<< std::setw( 11 ) << std::left;
switch ( ::rctlblk_get_privilege( rl ) )
{
case RCPRIV_BASIC:
std::cout << "basic";
break;
case RCPRIV_PRIVILEGED:
std::cout << "privileged";
break;
case RCPRIV_SYSTEM:
std::cout << "system";
break;
}
//
// Value
//
std::cout
<< ":"
<< std::setw( 21 ) << std::right
<< ::rctlblk_get_value( rl );
std::cout
<< std::endl;
std::cout
<< std::setw( 0 ) << std::left;
}
// May suffer from stream formatting issues...
void print_control( std::string containment,
vector< std::string > & control_list )
{
p_blk rl = static_cast < p_blk >
(
// Never leaks memory
::alloca( size )
);
containment += ".";
std::sort( control_list.begin( ), control_list.end( ) );
for ( auto & control : control_list )
{
std::cout
<< "\t";
std::cout
<< std::setw( 32 ) << std::left
<< control;
const std::string name = containment + control;
p_blk p = 0; // Tracking pointer
int rv = ::getrctl( name.c_str(), p, rl, RCTL_FIRST );
const int gflags = ::rctlblk_get_global_flags( rl );
std::cout
<< std::setw( 9 ) << std::right
<<
(
gflags & RCTL_GLOBAL_BYTES ? "(bytes)" :
gflags & RCTL_GLOBAL_SECONDS ? "(seconds)" :
gflags & RCTL_GLOBAL_COUNT ? "(count)" :
"(?)"
)
<< std::endl;
std::cout
<< std::setw( 0 ) << std::left;
while ( rv == 0 )
{
print_limit( rl );
p = rl; // Smart(?) move...
rv = ::getrctl( name.c_str(), p, rl, RCTL_NEXT );
}
if ( errno != ENOENT )
std::cout
<< "\t\tError getting limits!"
<< std::endl;
std::cout
<< std::endl;
}
}
// May suffer from stream formatting issues...
void print( )
{
std::cout
<< std::endl
<< "Printing active resource controls..."
<< std::endl
<< std::endl;
// I want to list containments as ordered below
auto known = { "process", "task", "project", "zone" };
for ( auto & containment : known )
{
std::cout
<< containment
<< std::endl
<< std::endl;
print_control( containment, resource[ containment ] );
}
//
// In case new (currently unknown) containments appear
// in the future, just list them at the bottom.
//
for ( auto & r : resource )
{
auto c = r.first; // A containment
if ( std::none_of( known.begin( ), known.end( ),
[ &c ]( const char * s ) { return s == c; } ) )
{
std::cout
<< c // An unknown containment
<< std::endl
<< std::endl;
print_control( r.first, r.second );
}
}
}
// May suffer from stream formatting issues...
int main( )
{
std::cout
<< std::endl
<< "Gathering active resource controls..."
<< std::endl
<< std::endl;
std::cout
<< "\tRC walk starting..."
<< std::endl;
if ( ::rctl_walk( active, 0 ) == 0 )
std::cout
<< "\tRC walk completed successfuly!"
<< std::endl;
print( );
return EXIT_SUCCESS;
}
A possible output is:
$ ./rc-03
Gathering active resource controls...
RC walk starting...
RC walk completed successfuly!
Printing active resource controls...
process
max-address-space (bytes)
privileged : 18446744073709551615
system : 18446744073709551615
max-core-size (bytes)
privileged : 9223372036854775807
system : 9223372036854775807
max-cpu-time (seconds)
privileged : 18446744073709551615
system : 18446744073709551615
max-data-size (bytes)
privileged : 18446744073709551615
system : 18446744073709551615
max-deferred-posts (count)
basic : 32
privileged : 100
system : 8192
max-file-descriptor (count)
basic : 1024
privileged : 65536
system : 2147483647
max-file-size (bytes)
privileged : 9223372036854775807
system : 9223372036854775807
max-itimers (count)
privileged : 1000
system : 65536
max-msg-messages (count)
privileged : 8192
system : 4294967295
max-msg-qbytes (bytes)
privileged : 65536
system : 18446744073709551615
max-port-events (count)
privileged : 65536
system : 2147483647
max-sem-nsems (count)
privileged : 512
system : 32767
max-sem-ops (count)
privileged : 512
system : 2147483647
max-sigqueue-size (count)
basic : 128
privileged : 512
system : 8192
max-stack-size (bytes)
basic : 8388608
privileged : 1098437885952
system : 1098437885952
task
max-cpu-time (seconds)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-processes (count)
system : 2147483647
project
cpu-cap (count)
system : 4294967295
cpu-shares (count)
privileged : 1
system : 65535
max-contracts (count)
privileged : 10000
system : 2147483647
max-crypto-memory (bytes)
privileged : 2143089664
system : 18446744073709551615
max-locked-memory (bytes)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-mrp-ids (count)
privileged : 128
system : 16777216
max-msg-ids (count)
privileged : 128
system : 16777216
max-port-ids (count)
privileged : 8192
system : 65536
max-processes (count)
system : 2147483647
max-sem-ids (count)
privileged : 128
system : 16777216
max-shm-ids (count)
privileged : 128
system : 16777216
max-shm-memory (bytes)
privileged : 2143089664
system : 18446744073709551615
max-tasks (count)
system : 2147483647
zone
cpu-cap (count)
system : 4294967295
cpu-shares (count)
privileged : 1
system : 65535
max-locked-memory (bytes)
system : 18446744073709551615
max-lofi (count)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-mrp-ids (count)
system : 16777216
max-msg-ids (count)
system : 16777216
max-processes (count)
system : 2147483647
max-sem-ids (count)
system : 16777216
max-shm-ids (count)
system : 16777216
max-shm-memory (bytes)
system : 18446744073709551615
max-swap (bytes)
system : 18446744073709551615
It lists all the controls that are active to its running process.
Following the listing there's a sample output.
#include <rctl.h>
#include <alloca.h>
#include <cstdlib>
#include <cerrno>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <iostream>
#include <iomanip>
//
// Convenience "special" vector.
//
template< typename T >
struct vector : public std::vector< T >
{
};
//
// Convenience operator for just the "special" vector.
// For simplicity, not dealing with formatting or state issues.
//
template< typename T >
std::istream & operator >> ( std::istream & is, vector<T> & v )
{
typename vector<T>::value_type element;
if ( is >> element )
v.push_back( element );
return is;
}
//
// The main data structure for organization.
// Key: resource containment.
// Data: list of controls.
//
std::map< const std::string, vector< std::string > > resource;
//
// The resource walking routine.
//
int active( const char * name, void * )
{
std::istringstream iss( name );
std::string containment;
if ( std::getline( iss, containment, '.' ) )
iss >> resource[ containment ];
return 0;
}
const size_t size = ::rctlblk_size( );
typedef ::rctlblk_t * p_blk;
// May suffer from stream formatting issues...
void print_limit( const p_blk rl )
{
//
// Type
//
std::cout
<< "\t\t"
<< std::setw( 11 ) << std::left;
switch ( ::rctlblk_get_privilege( rl ) )
{
case RCPRIV_BASIC:
std::cout << "basic";
break;
case RCPRIV_PRIVILEGED:
std::cout << "privileged";
break;
case RCPRIV_SYSTEM:
std::cout << "system";
break;
}
//
// Value
//
std::cout
<< ":"
<< std::setw( 21 ) << std::right
<< ::rctlblk_get_value( rl );
std::cout
<< std::endl;
std::cout
<< std::setw( 0 ) << std::left;
}
// May suffer from stream formatting issues...
void print_control( std::string containment,
vector< std::string > & control_list )
{
p_blk rl = static_cast < p_blk >
(
// Never leaks memory
::alloca( size )
);
containment += ".";
std::sort( control_list.begin( ), control_list.end( ) );
for ( auto & control : control_list )
{
std::cout
<< "\t";
std::cout
<< std::setw( 32 ) << std::left
<< control;
const std::string name = containment + control;
p_blk p = 0; // Tracking pointer
int rv = ::getrctl( name.c_str(), p, rl, RCTL_FIRST );
const int gflags = ::rctlblk_get_global_flags( rl );
std::cout
<< std::setw( 9 ) << std::right
<<
(
gflags & RCTL_GLOBAL_BYTES ? "(bytes)" :
gflags & RCTL_GLOBAL_SECONDS ? "(seconds)" :
gflags & RCTL_GLOBAL_COUNT ? "(count)" :
"(?)"
)
<< std::endl;
std::cout
<< std::setw( 0 ) << std::left;
while ( rv == 0 )
{
print_limit( rl );
p = rl; // Smart(?) move...
rv = ::getrctl( name.c_str(), p, rl, RCTL_NEXT );
}
if ( errno != ENOENT )
std::cout
<< "\t\tError getting limits!"
<< std::endl;
std::cout
<< std::endl;
}
}
// May suffer from stream formatting issues...
void print( )
{
std::cout
<< std::endl
<< "Printing active resource controls..."
<< std::endl
<< std::endl;
// I want to list containments as ordered below
auto known = { "process", "task", "project", "zone" };
for ( auto & containment : known )
{
std::cout
<< containment
<< std::endl
<< std::endl;
print_control( containment, resource[ containment ] );
}
//
// In case new (currently unknown) containments appear
// in the future, just list them at the bottom.
//
for ( auto & r : resource )
{
auto c = r.first; // A containment
if ( std::none_of( known.begin( ), known.end( ),
[ &c ]( const char * s ) { return s == c; } ) )
{
std::cout
<< c // An unknown containment
<< std::endl
<< std::endl;
print_control( r.first, r.second );
}
}
}
// May suffer from stream formatting issues...
int main( )
{
std::cout
<< std::endl
<< "Gathering active resource controls..."
<< std::endl
<< std::endl;
std::cout
<< "\tRC walk starting..."
<< std::endl;
if ( ::rctl_walk( active, 0 ) == 0 )
std::cout
<< "\tRC walk completed successfuly!"
<< std::endl;
print( );
return EXIT_SUCCESS;
}
A possible output is:
$ ./rc-03
Gathering active resource controls...
RC walk starting...
RC walk completed successfuly!
Printing active resource controls...
process
max-address-space (bytes)
privileged : 18446744073709551615
system : 18446744073709551615
max-core-size (bytes)
privileged : 9223372036854775807
system : 9223372036854775807
max-cpu-time (seconds)
privileged : 18446744073709551615
system : 18446744073709551615
max-data-size (bytes)
privileged : 18446744073709551615
system : 18446744073709551615
max-deferred-posts (count)
basic : 32
privileged : 100
system : 8192
max-file-descriptor (count)
basic : 1024
privileged : 65536
system : 2147483647
max-file-size (bytes)
privileged : 9223372036854775807
system : 9223372036854775807
max-itimers (count)
privileged : 1000
system : 65536
max-msg-messages (count)
privileged : 8192
system : 4294967295
max-msg-qbytes (bytes)
privileged : 65536
system : 18446744073709551615
max-port-events (count)
privileged : 65536
system : 2147483647
max-sem-nsems (count)
privileged : 512
system : 32767
max-sem-ops (count)
privileged : 512
system : 2147483647
max-sigqueue-size (count)
basic : 128
privileged : 512
system : 8192
max-stack-size (bytes)
basic : 8388608
privileged : 1098437885952
system : 1098437885952
task
max-cpu-time (seconds)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-processes (count)
system : 2147483647
project
cpu-cap (count)
system : 4294967295
cpu-shares (count)
privileged : 1
system : 65535
max-contracts (count)
privileged : 10000
system : 2147483647
max-crypto-memory (bytes)
privileged : 2143089664
system : 18446744073709551615
max-locked-memory (bytes)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-mrp-ids (count)
privileged : 128
system : 16777216
max-msg-ids (count)
privileged : 128
system : 16777216
max-port-ids (count)
privileged : 8192
system : 65536
max-processes (count)
system : 2147483647
max-sem-ids (count)
privileged : 128
system : 16777216
max-shm-ids (count)
privileged : 128
system : 16777216
max-shm-memory (bytes)
privileged : 2143089664
system : 18446744073709551615
max-tasks (count)
system : 2147483647
zone
cpu-cap (count)
system : 4294967295
cpu-shares (count)
privileged : 1
system : 65535
max-locked-memory (bytes)
system : 18446744073709551615
max-lofi (count)
system : 18446744073709551615
max-lwps (count)
system : 2147483647
max-mrp-ids (count)
system : 16777216
max-msg-ids (count)
system : 16777216
max-processes (count)
system : 2147483647
max-sem-ids (count)
system : 16777216
max-shm-ids (count)
system : 16777216
max-shm-memory (bytes)
system : 18446744073709551615
max-swap (bytes)
system : 18446744073709551615
Thursday, April 27, 2017
Resource control - rc-02
This program (rc-02) uses the Solaris interface to resource control.
The main() function was listed first just to let the logic more clear.
Note how its approach is more complex than the traditional one:
#include <rctl.h>
#include <strings.h>
#include <alloca.h>
#include <unistd.h>
#include <cerrno>
#include <cstdlib>
#include <iostream>
const ::pid_t ppid = ::getppid( );
const size_t size = ::rctlblk_size();
static const char name[] = "process.max-file-descriptor";
typedef ::rctlblk_t * p_blk;
// May suffer from stream formatting issues...
int main( )
{
std::cout
<< std::endl
<< "Resource limit: " << name
<< std::endl;
p_blk p = 0; // Tracking pointer
p_blk rl = static_cast < p_blk >
(
// Never leaks memory
::alloca( size )
);
int rv = ::getrctl( name, p, rl, RCTL_FIRST );
while ( rv == 0 )
{
print( rl );
p = rl; // Smart(?) move...
rv = ::getrctl( name, p, rl, RCTL_NEXT );
}
if ( errno != ENOENT )
{
...
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
And now the auxiliary printing function:
// May suffer from stream formatting issues...
void print( const p_blk rl )
{
std::cout << std::endl;
//
// Type
//
std::cout << "\tType: ";
switch ( ::rctlblk_get_privilege( rl ) )
{
case RCPRIV_BASIC:
std::cout << "Basic";
break;
case RCPRIV_PRIVILEGED:
std::cout << "Privileged";
break;
case RCPRIV_SYSTEM:
std::cout << "System";
break;
}
//
// PID & PPID
//
const ::id_t pid = ::rctlblk_get_recipient_pid( rl );
std::cout << " (PID " << pid;
if ( pid > -1 )
std::cout << "; PPID " << ppid;
std::cout << ")" << std::endl;
//
// Flags
//
const int gflags = ::rctlblk_get_global_flags( rl );
std::cout << "\tGlobal action: "
<<
(
gflags == RCTL_GLOBAL_NOACTION ? "no action" :
gflags & RCTL_GLOBAL_DENY_ALWAYS ? "deny" :
gflags & RCTL_GLOBAL_DENY_NEVER ? "allow" :
"other"
)
<< "; ";
std::cout << "Syslog: "
<<
(
gflags & RCTL_GLOBAL_SYSLOG ? "yes" : "no"
)
<< std::endl;
std::cout << "\tLowerable: "
<<
(
gflags & RCTL_GLOBAL_LOWERABLE ? "yes" : "no"
)
<< "; ";
std::cout << "Infinite: "
<<
(
gflags & RCTL_GLOBAL_INFINITE ? "yes" : "no"
)
<< std::endl;
const int lflags = ::rctlblk_get_local_flags( rl );
std::cout << "\tLocally maximal: "
<<
(
lflags & RCTL_LOCAL_MAXIMAL ? "yes" : "no"
)
<< "; ";
std::cout << "Local project: "
<<
(
lflags & RCTL_LOCAL_PROJDB ? "yes" : "no"
)
<< std::endl;
std::cout << "\tLimit type: "
<<
(
gflags & RCTL_GLOBAL_BYTES ? "bytes" :
gflags & RCTL_GLOBAL_SECONDS ? "seconds" :
gflags & RCTL_GLOBAL_COUNT ? "count" :
"?"
)
<< std::endl;
//
// Values
//
std::cout << "\tCurrent: "
<< ::rctlblk_get_value( rl )
<< std::endl;
std::cout << "\tEnforced: "
<< ::rctlblk_get_enforced_value( rl )
<< std::endl;
}
This program works in Solaris 11.3.
I used the GCC 4.8.2 and NetBeans 8.1 with no issues at all.
The main() function was listed first just to let the logic more clear.
Note how its approach is more complex than the traditional one:
#include <rctl.h>
#include <strings.h>
#include <alloca.h>
#include <unistd.h>
#include <cerrno>
#include <cstdlib>
#include <iostream>
const ::pid_t ppid = ::getppid( );
const size_t size = ::rctlblk_size();
static const char name[] = "process.max-file-descriptor";
typedef ::rctlblk_t * p_blk;
// May suffer from stream formatting issues...
int main( )
{
std::cout
<< std::endl
<< "Resource limit: " << name
<< std::endl;
p_blk p = 0; // Tracking pointer
p_blk rl = static_cast < p_blk >
(
// Never leaks memory
::alloca( size )
);
int rv = ::getrctl( name, p, rl, RCTL_FIRST );
while ( rv == 0 )
{
print( rl );
p = rl; // Smart(?) move...
rv = ::getrctl( name, p, rl, RCTL_NEXT );
}
if ( errno != ENOENT )
{
...
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
And now the auxiliary printing function:
// May suffer from stream formatting issues...
void print( const p_blk rl )
{
std::cout << std::endl;
//
// Type
//
std::cout << "\tType: ";
switch ( ::rctlblk_get_privilege( rl ) )
{
case RCPRIV_BASIC:
std::cout << "Basic";
break;
case RCPRIV_PRIVILEGED:
std::cout << "Privileged";
break;
case RCPRIV_SYSTEM:
std::cout << "System";
break;
}
//
// PID & PPID
//
const ::id_t pid = ::rctlblk_get_recipient_pid( rl );
std::cout << " (PID " << pid;
if ( pid > -1 )
std::cout << "; PPID " << ppid;
std::cout << ")" << std::endl;
//
// Flags
//
const int gflags = ::rctlblk_get_global_flags( rl );
std::cout << "\tGlobal action: "
<<
(
gflags == RCTL_GLOBAL_NOACTION ? "no action" :
gflags & RCTL_GLOBAL_DENY_ALWAYS ? "deny" :
gflags & RCTL_GLOBAL_DENY_NEVER ? "allow" :
"other"
)
<< "; ";
std::cout << "Syslog: "
<<
(
gflags & RCTL_GLOBAL_SYSLOG ? "yes" : "no"
)
<< std::endl;
std::cout << "\tLowerable: "
<<
(
gflags & RCTL_GLOBAL_LOWERABLE ? "yes" : "no"
)
<< "; ";
std::cout << "Infinite: "
<<
(
gflags & RCTL_GLOBAL_INFINITE ? "yes" : "no"
)
<< std::endl;
const int lflags = ::rctlblk_get_local_flags( rl );
std::cout << "\tLocally maximal: "
<<
(
lflags & RCTL_LOCAL_MAXIMAL ? "yes" : "no"
)
<< "; ";
std::cout << "Local project: "
<<
(
lflags & RCTL_LOCAL_PROJDB ? "yes" : "no"
)
<< std::endl;
std::cout << "\tLimit type: "
<<
(
gflags & RCTL_GLOBAL_BYTES ? "bytes" :
gflags & RCTL_GLOBAL_SECONDS ? "seconds" :
gflags & RCTL_GLOBAL_COUNT ? "count" :
"?"
)
<< std::endl;
//
// Values
//
std::cout << "\tCurrent: "
<< ::rctlblk_get_value( rl )
<< std::endl;
std::cout << "\tEnforced: "
<< ::rctlblk_get_enforced_value( rl )
<< std::endl;
}
This program works in Solaris 11.3.
I used the GCC 4.8.2 and NetBeans 8.1 with no issues at all.
Resource control - rc-01
This program (rc-01) uses the UNIX portable interface to resource control.
This is the traditional (legacy) standard as well.
Note how simple it is!
But the recommended Solaris approach is far more complex...
#include <sys/resource.h>
#include <cstdlib>
#include <iostream>
// May suffer from stream formatting issues...
int main( )
{
::rlimit rl;
if ( ::getrlimit( RLIMIT_NOFILE, &rl ) != 0 )
{
...
return EXIT_FAILURE;
}
std::cout << "Process' inherited FD limits:" << std::endl;
std::cout << "Current: " << rl.rlim_cur << "." << std::endl;
std::cout << "Maximum: " << rl.rlim_max << "." << std::endl;
return EXIT_SUCCESS;
}
This program works in Solaris 11.3.
I used the GCC 4.8.2 and NetBeans 8.1 with no issues at all.
This is the traditional (legacy) standard as well.
Note how simple it is!
But the recommended Solaris approach is far more complex...
#include <sys/resource.h>
#include <cstdlib>
#include <iostream>
// May suffer from stream formatting issues...
int main( )
{
::rlimit rl;
if ( ::getrlimit( RLIMIT_NOFILE, &rl ) != 0 )
{
...
return EXIT_FAILURE;
}
std::cout << "Process' inherited FD limits:" << std::endl;
std::cout << "Current: " << rl.rlim_cur << "." << std::endl;
std::cout << "Maximum: " << rl.rlim_max << "." << std::endl;
return EXIT_SUCCESS;
}
This program works in Solaris 11.3.
I used the GCC 4.8.2 and NetBeans 8.1 with no issues at all.
Monday, April 24, 2017
Resource control - Intro
Resource control historically appeared for limiting the system's
resources that processes and their children could consume, but nowadays
in Solaris this concept has been elaborated to other collections of
processes: tasks, projects and zones as well.
The best practice is to carefully assess (as using extended accounting) the resource consumption of the workloads on the system before applying any fine-grained resource control to prevent over-consumptions. And, of course, above all, the system must meet or exceed the combined resource requirements of all the workloads it's supposed to host.
This topic is vast because there are many resources (resource-controls(5)) ranging from the most "elementary" to the most complex ones, there 3 control levels (basic, privileged and system), there are 4 containment levels (process, task, project and zone), 2 types of actions and flags (local and global) as well more than one available interface managing part (ulimit(1) and getrlimit(2)) or all of this stuff (rctladm(1M), prctl(1), setrctl(2), the projects database and zone configuration).
All the manpages provide extensive information I won't discuss, at least for now. In addition there are some other lenghty references such as the chapter 5 of Resource Management and Oracle® Solaris Zones Developer's Guide which is a kind of revamp of the original chapter 5 of the (partially) archived Solaris Containers: Resource Management and Solaris Zones Developer's Guide.
The best practice is to carefully assess (as using extended accounting) the resource consumption of the workloads on the system before applying any fine-grained resource control to prevent over-consumptions. And, of course, above all, the system must meet or exceed the combined resource requirements of all the workloads it's supposed to host.
This topic is vast because there are many resources (resource-controls(5)) ranging from the most "elementary" to the most complex ones, there 3 control levels (basic, privileged and system), there are 4 containment levels (process, task, project and zone), 2 types of actions and flags (local and global) as well more than one available interface managing part (ulimit(1) and getrlimit(2)) or all of this stuff (rctladm(1M), prctl(1), setrctl(2), the projects database and zone configuration).
All the manpages provide extensive information I won't discuss, at least for now. In addition there are some other lenghty references such as the chapter 5 of Resource Management and Oracle® Solaris Zones Developer's Guide which is a kind of revamp of the original chapter 5 of the (partially) archived Solaris Containers: Resource Management and Solaris Zones Developer's Guide.
Subscribe to:
Posts (Atom)

