Monday, May 8, 2017

VirtualBox VM additions

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)

   

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



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.

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.
 

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.