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.