<commit_before>/*
   The MIT License

   Copyright (c) 2009 Institut of Mechanics and Fluid Dynamics,
   TU Bergakademie Freiberg.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    REKConverter.cpp
  \author  Andre Liebscher
           Institut of Mechanics and Fluid Dynamics
           TU Bergakademie Freiberg
  \date    March 2009
*/

#include <fstream>
#include <sstream>
#include <cstring>
#include "boost/cstdint.hpp"
#include "REKConverter.h"
#include "Controller/Controller.h"
#include "Basics/EndianConvert.h"

using namespace std;

REKConverter::REKConverter()
{
  m_vConverterDesc = "Fraunhofer EZRT Volume";
  m_vSupportedExt.push_back("REK");
}

bool
REKConverter::ConvertToRAW(const std::string& strSourceFilename,
                           const std::string&,
                           bool, UINT64& iHeaderSkip,
                           UINT64& iComponentSize,
                           UINT64& iComponentCount,
                           bool& bConvertEndianess, bool& bSigned,
                           bool& bIsFloat, UINT64VECTOR3& vVolumeSize,
                           FLOATVECTOR3& vVolumeAspect,
                           std::string& strTitle,
                           UVFTables::ElementSemanticTable& eType,
                           std::string& strIntermediateFile,
                           bool& bDeleteIntermediateFile)
{
  MESSAGE("Attempting to convert REK dataset %s", strSourceFilename.c_str());

  // Find out machine endianess
  bConvertEndianess = EndianConvert::IsBigEndian();

  // Read header an check for "magic" values of the REK file
  ifstream fileData(strSourceFilename.c_str(), ifstream::in | ifstream::binary);
  char buffer[2048];

  if(fileData.is_open()) {
    fileData.read( buffer, sizeof(buffer) );
    if(Parse<boost::uint16_t, 2>( &buffer[10], bConvertEndianess ) != 2 &&
       Parse<boost::uint16_t, 2>( &buffer[12], bConvertEndianess ) != 4) {
      WARNING("The file %s is not a REK file", strSourceFilename.c_str());
      fileData.close();
      return false;
    }
  } else {
    WARNING("Could not open REK file %s", strSourceFilename.c_str());
    return false;
  }
  fileData.close();

  // Standard values which are always true (I guess)
  strTitle = "Fraunhofer EZRT";
  eType = UVFTables::ES_UNDEFINED;
  vVolumeAspect = FLOATVECTOR3(1,1,1);
  bSigned = false;
  bIsFloat = false;
  iComponentCount = 1;
  strIntermediateFile = strSourceFilename;
  bDeleteIntermediateFile = false;

  // Read file format from header
  vVolumeSize[0] = Parse<boost::uint16_t, 2>(&buffer[0], bConvertEndianess);
  vVolumeSize[1] = Parse<boost::uint16_t, 2>(&buffer[2], bConvertEndianess);
  vVolumeSize[2] = Parse<boost::uint16_t, 2>(&buffer[6], bConvertEndianess);
  iComponentSize = Parse<boost::uint16_t, 2>(&buffer[4], bConvertEndianess);
  iHeaderSkip = Parse<boost::uint16_t, 2>(&buffer[8], bConvertEndianess);

  return true;
}

// unimplemented!
bool
REKConverter::ConvertToNative(const std::string&,
                              const std::string&,
                              UINT64, UINT64,
                              UINT64, bool,
                              bool,
                              UINT64VECTOR3,
                              FLOATVECTOR3,
                              bool,
                              bool)
{
  return false;
}
<commit_msg>Rename displayed dataset name.<commit_after>/*
   The MIT License

   Copyright (c) 2009 Institut of Mechanics and Fluid Dynamics,
   TU Bergakademie Freiberg.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    REKConverter.cpp
  \author  Andre Liebscher
           Institut of Mechanics and Fluid Dynamics
           TU Bergakademie Freiberg
  \date    March 2009
*/

#include <fstream>
#include <sstream>
#include <cstring>
#include "boost/cstdint.hpp"
#include "REKConverter.h"
#include "Controller/Controller.h"
#include "Basics/EndianConvert.h"

using namespace std;

REKConverter::REKConverter()
{
  m_vConverterDesc = "Fraunhofer Raw Volume";
  m_vSupportedExt.push_back("REK");
}

bool
REKConverter::ConvertToRAW(const std::string& strSourceFilename,
                           const std::string&,
                           bool, UINT64& iHeaderSkip,
                           UINT64& iComponentSize,
                           UINT64& iComponentCount,
                           bool& bConvertEndianess, bool& bSigned,
                           bool& bIsFloat, UINT64VECTOR3& vVolumeSize,
                           FLOATVECTOR3& vVolumeAspect,
                           std::string& strTitle,
                           UVFTables::ElementSemanticTable& eType,
                           std::string& strIntermediateFile,
                           bool& bDeleteIntermediateFile)
{
  MESSAGE("Attempting to convert REK dataset %s", strSourceFilename.c_str());

  // Find out machine endianess
  bConvertEndianess = EndianConvert::IsBigEndian();

  // Read header an check for "magic" values of the REK file
  ifstream fileData(strSourceFilename.c_str(), ifstream::in | ifstream::binary);
  char buffer[2048];

  if(fileData.is_open()) {
    fileData.read( buffer, sizeof(buffer) );
    if(Parse<boost::uint16_t, 2>( &buffer[10], bConvertEndianess ) != 2 &&
       Parse<boost::uint16_t, 2>( &buffer[12], bConvertEndianess ) != 4) {
      WARNING("The file %s is not a REK file", strSourceFilename.c_str());
      fileData.close();
      return false;
    }
  } else {
    WARNING("Could not open REK file %s", strSourceFilename.c_str());
    return false;
  }
  fileData.close();

  // Standard values which are always true (I guess)
  strTitle = "Fraunhofer EZRT";
  eType = UVFTables::ES_UNDEFINED;
  vVolumeAspect = FLOATVECTOR3(1,1,1);
  bSigned = false;
  bIsFloat = false;
  iComponentCount = 1;
  strIntermediateFile = strSourceFilename;
  bDeleteIntermediateFile = false;

  // Read file format from header
  vVolumeSize[0] = Parse<boost::uint16_t, 2>(&buffer[0], bConvertEndianess);
  vVolumeSize[1] = Parse<boost::uint16_t, 2>(&buffer[2], bConvertEndianess);
  vVolumeSize[2] = Parse<boost::uint16_t, 2>(&buffer[6], bConvertEndianess);
  iComponentSize = Parse<boost::uint16_t, 2>(&buffer[4], bConvertEndianess);
  iHeaderSkip = Parse<boost::uint16_t, 2>(&buffer[8], bConvertEndianess);

  return true;
}

// unimplemented!
bool
REKConverter::ConvertToNative(const std::string&,
                              const std::string&,
                              UINT64, UINT64,
                              UINT64, bool,
                              bool,
                              UINT64VECTOR3,
                              FLOATVECTOR3,
                              bool,
                              bool)
{
  return false;
}
<|endoftext|>


<commit_before>/*!
    \file console.cpp
    \brief Console management implementation
    \author Ivan Shynkarenka
    \date 29.07.2015
    \copyright MIT License
*/

#include "benchmark/console.h"

#include <cstdio>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppBenchmark {

std::ostream& operator<<(std::ostream& stream, Color color)
{
    Console::SetColor(color);
    return stream;
}

std::ostream& operator<<(std::ostream& stream, std::pair<Color, Color> colors)
{
    Console::SetColor(colors.first, colors.second);
    return stream;
}

void Console::SetColor(Color color, Color background)
{
#if defined(_WIN32) || defined(_WIN64)
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, (((WORD)color) & 0x0F) + ((((WORD)background) & 0x0F) << 4));
#elif defined(unix) || defined(__unix) || defined(__unix__)
    const char* colors[] =
    {
        "\033[22;30m",  // Black color
        "\033[22;34m",  // Blue color
        "\033[22;32m",  // Green color
        "\033[22;36m",  // Cyan color
        "\033[22;31m",  // Red color
        "\033[22;35m",  // Magenta color
        "\033[22;33m",  // Brown color
        "\033[22;37m",  // Grey color
        "\033[01;30m",  // Dark grey color
        "\033[01;34m",  // Light blue color
        "\033[01;32m",  // Light green color
        "\033[01;36m",  // Light cyan color
        "\033[01;31m",  // Light red color
        "\033[01;35m",  // Light magenta color
        "\033[01;33m",  // Yellow color
        "\033[01;37m"   // White color
    };
    const char* backgrounds[] =
    {
        "\033[22;40m",  // Black color
        "\033[22;44m",  // Blue color
        "\033[22;42m",  // Green color
        "\033[22;46m",  // Cyan color
        "\033[22;41m",  // Red color
        "\033[22;45m",  // Magenta color
        "\033[22;43m",  // Brown color
        "\033[22;47m",  // Grey color
        "\033[01;40m",  // Dark grey color
        "\033[01;44m",  // Light blue color
        "\033[01;42m",  // Light green color
        "\033[01;46m",  // Light cyan color
        "\033[01;41m",  // Light red color
        "\033[01;45m",  // Light magenta color
        "\033[01;43m",  // Yellow color
        "\033[01;47m"   // White color
    };
    std::fwrite(colors[color - Color::BLACK], 1, 8, stdout);
    std::fwrite(backgrounds[background - Color::BLACK], 1, 8, stdout);
#endif
}

} // namespace CppBenchmark
<commit_msg>Bugfixing<commit_after>/*!
    \file console.cpp
    \brief Console management implementation
    \author Ivan Shynkarenka
    \date 29.07.2015
    \copyright MIT License
*/

#include "benchmark/console.h"

#include <cstdio>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppBenchmark {

std::ostream& operator<<(std::ostream& stream, Color color)
{
    Console::SetColor(color);
    return stream;
}

std::ostream& operator<<(std::ostream& stream, std::pair<Color, Color> colors)
{
    Console::SetColor(colors.first, colors.second);
    return stream;
}

void Console::SetColor(Color color, Color background)
{
#if defined(_WIN32) || defined(_WIN64)
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, (((WORD)color) & 0x0F) + ((((WORD)background) & 0x0F) << 4));
#elif defined(unix) || defined(__unix) || defined(__unix__)
    const char* colors[] =
    {
        "\033[22;30m",  // Black color
        "\033[22;34m",  // Blue color
        "\033[22;32m",  // Green color
        "\033[22;36m",  // Cyan color
        "\033[22;31m",  // Red color
        "\033[22;35m",  // Magenta color
        "\033[22;33m",  // Brown color
        "\033[22;37m",  // Grey color
        "\033[01;30m",  // Dark grey color
        "\033[01;34m",  // Light blue color
        "\033[01;32m",  // Light green color
        "\033[01;36m",  // Light cyan color
        "\033[01;31m",  // Light red color
        "\033[01;35m",  // Light magenta color
        "\033[01;33m",  // Yellow color
        "\033[01;37m"   // White color
    };
    const char* backgrounds[] =
    {
        "\033[22;40m",  // Black color
        "\033[22;44m",  // Blue color
        "\033[22;42m",  // Green color
        "\033[22;46m",  // Cyan color
        "\033[22;41m",  // Red color
        "\033[22;45m",  // Magenta color
        "\033[22;43m",  // Brown color
        "\033[22;47m",  // Grey color
        "\033[01;40m",  // Dark grey color
        "\033[01;44m",  // Light blue color
        "\033[01;42m",  // Light green color
        "\033[01;46m",  // Light cyan color
        "\033[01;41m",  // Light red color
        "\033[01;45m",  // Light magenta color
        "\033[01;43m",  // Yellow color
        "\033[01;47m"   // White color
    };
    std::fwrite(colors[(int)color - (int)Color::BLACK], 1, 8, stdout);
    std::fwrite(backgrounds[(int)background - (int)Color::BLACK], 1, 8, stdout);
#endif
}

} // namespace CppBenchmark
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hwpf/hwp/sbe_centaur_init/sbe_centaur_init.C $        */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2014              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file sbe_centaur_init.C
 *
 *  Support file for IStep:
 *      sbe_centaur_init
 *
 *
 *
 *  HWP_IGNORE_VERSION_CHECK
 *
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include    <stdint.h>

#include <trace/interface.H>
#include <initservice/taskargs.H>
#include <errl/errlentry.H>
#include <initservice/isteps_trace.H>
#include <targeting/common/commontargeting.H>
#include <targeting/common/utilFilter.H>
#include <fapi.H>
#include <fapiPoreVeArg.H>
#include <fapiTarget.H>
#include <fapi.H>
#include <fapiPlatHwpInvoker.H>
#include <vfs/vfs.H>
#include "sbe_centaur_init.H"
#include <hwpisteperror.H>
#include <errl/errludtarget.H>
#include <sbe/sbeif.H>
#include "cen_xip_customize.H"

extern fapi::ReturnCode fapiPoreVe(const fapi::Target i_target,
           std::list<uint64_t> & io_sharedObjectArgs);

const uint64_t REPAIR_LOADER_RETRY_CTR_MASK = 0x000007FC00000000ull;

// Constants
// Memory Relocation Register for Centaur SBE image
const uint64_t CENTAUR_SBE_PNOR_MRR = 0;

// Max SBE image buffer size
const uint32_t MAX_SBE_IMG_SIZE = 48 * 1024;

namespace   SBE_CENTAUR_INIT
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;
using   namespace   fapi;
using   namespace   vsbe;

//
//  Wrapper function to call step 10
//
void*    call_sbe_centaur_init( void *io_pArgs )
{

    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
              "call_sbe_centaur_init entry");

    // Get target list to pass in procedure
    TARGETING::TargetHandleList l_membufTargetList;
    getAllChips(l_membufTargetList, TYPE_MEMBUF);

    size_t l_sbePnorSize = 0;
    void* l_sbePnorAddr = NULL;
    errlHndl_t  l_errl = NULL;

    IStepError  l_StepError;

    // Loop thru all Centaurs in list
    for (TargetHandleList::const_iterator
         l_membuf_iter = l_membufTargetList.begin();
         l_membuf_iter != l_membufTargetList.end();
         ++l_membuf_iter)
    {
        //find SBE image in PNOR
        TARGETING::Target* l_membuf_target = *l_membuf_iter;

        uint8_t cur_ec = (*l_membuf_iter)->getAttr<TARGETING::ATTR_EC>();

        TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK,
                   "call_sbe_centaur_init() - Find SBE image in PNOR");

        l_errl = SBE::findSBEInPnor(l_membuf_target,
                                 l_sbePnorAddr,
                                 l_sbePnorSize,
                                 NULL);
        if (l_errl)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK,
           "call_sbe_centaur_init() - Error getting image from PNOR. ec=0x%.2X",
                       cur_ec );

            TRACFBIN(ISTEPS_TRACE::g_trac_isteps_trace,
                     "call_sbe_centaur_init - l_sbePnorAddr",l_sbePnorAddr,400);

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_membuf_target).addToLog( l_errl );

            // Create IStep error log and cross reference error that occurred
            l_StepError.addErrorDetails( l_errl );

            // Commit Error
            errlCommit( l_errl, HWPF_COMP_ID );
            continue;
        }

        char l_header[10];
        memcpy (l_header, l_sbePnorAddr, 9);
        l_header[9] = '\0';

        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                     "call_sbe_centaur_init - Loading "
                     "centaur sbe from pnor, Addr 0x%llX, Size %d, Header %s",
                     l_sbePnorAddr, l_sbePnorSize, l_header);

        // Create a FAPI Target
        const fapi::Target l_fapiTarget( fapi::TARGET_TYPE_MEMBUF_CHIP,
                     (const_cast<TARGETING::Target*>(l_membuf_target)));

        // Expand buffer for new image size
        const uint32_t l_customizedMaxSize = MAX_SBE_IMG_SIZE;
        const uint32_t l_buf1Size = MAX_SBE_IMG_SIZE;
        const uint32_t l_buf2Size = MAX_SBE_IMG_SIZE;

        uint32_t l_customizedSize = l_customizedMaxSize;
        char * l_pCustomizedImage = (char *)malloc(l_customizedMaxSize);
        void * l_pBuf1 = malloc(l_buf1Size);
        void * l_pBuf2 = malloc(l_buf2Size);

        // Setup args
        std::list<uint64_t> myArgs;

        // Set FapiPoreVeOtherArg: run unlimited instructions
        FapiPoreVeOtherArg *l_otherArg =
                new FapiPoreVeOtherArg(vsbe::RUN_UNLIMITED, vsbe::PORE_SBE);
        // Entry point
        l_otherArg->iv_entryPoint = const_cast<char*>("pnor::_sbe_pnor_start");
        l_otherArg->iv_mrr = CENTAUR_SBE_PNOR_MRR;
        myArgs.push_back(reinterpret_cast<uint64_t>(l_otherArg));

        // Set FapiPoreVeMemArg for pnor option, base address = 0
        uint32_t base_addr = 0;
        char* l_dataPnor = const_cast<char*>(l_pCustomizedImage);
        FapiPoreVeMemArg* l_memArg = new FapiPoreVeMemArg(ARG_PNOR,
                                               base_addr, l_customizedSize,
                                               static_cast<void*>(l_dataPnor));
        myArgs.push_back(reinterpret_cast<uint64_t>(l_memArg));

        // Create state argument to dump out state for debugging purpose
        FapiPoreVeStateArg *l_stateArg = new FapiPoreVeStateArg(NULL);
        l_stateArg->iv_installState = false;
        l_stateArg->iv_extractState = true;
        myArgs.push_back(reinterpret_cast<uint64_t>(l_stateArg));

        //  Put out info on target
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "Running call_sbe_centaur_init on Centaur "
            " target HUID %.8X", TARGETING::get_huid(l_membuf_target));

        // XIP customize is going to look for a PLL ring with a "stub"
        // mem freq -- so set to a default, then clear it (so as not
        // to mess up MSS HWP later
        l_membuf_target->setAttr<TARGETING::ATTR_MSS_FREQ>(1600);

        FAPI_INVOKE_HWP( l_errl, cen_xip_customize,
                         l_fapiTarget, l_sbePnorAddr,
                         l_pCustomizedImage, l_customizedSize,
                         l_pBuf1, l_buf1Size,
                         l_pBuf2, l_buf2Size );

        l_membuf_target->setAttr<TARGETING::ATTR_MSS_FREQ>(0);

        if (l_errl)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR 0x%.8X call_sbe_centaur_init - Error returned from"
               " cen_xip_customize, l_rc 0x%llX", l_errl->reasonCode());
        }
        else
        {
            // Run the engine
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "call_sbe_centaur_init - Start VSBE engine...");

            FAPI_INVOKE_HWP(l_errl, fapiPoreVe, l_fapiTarget, myArgs);

            if (l_errl)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                   "ERROR 0x%.8X call_sbe_centaur_init - Error returned from"
                   " VSBE engine on this Centaur, l_rc 0x%llX",
                   l_errl->reasonCode());
                l_errl->collectTrace(FAPI_IMP_TRACE_NAME, 1024);
                l_errl->collectTrace("ISTEPS_TRACE", 512);
            }

            // Remove 0x0104000A reading, per Joe, the IPL procedures are no
            // longer writing information related to the repair loader into
            // this register

        }

        // Freeing memory
        delete l_otherArg;
        delete l_memArg;
        delete l_stateArg;
        free( l_pCustomizedImage );
        free( l_pBuf1 );
        free( l_pBuf2 );

        if (l_errl )
        {
            // capture the target data in the elog
            ErrlUserDetailsTarget(l_membuf_target).addToLog( l_errl );

            // Create IStep error log and cross reference error that occurred
            l_StepError.addErrorDetails( l_errl );

            // Commit Error
            errlCommit( l_errl, HWPF_COMP_ID );
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                 "call_sbe_centaur_init - VSBE engine runs successfully "
                 "on this Centaur");
        }

    }   // end for

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_sbe_centaur_init exit" );

    return l_StepError.getErrorHandle();
}

};   // end namespace

<commit_msg>Invalid trace on error path in sbe_centaur_init.C<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hwpf/hwp/sbe_centaur_init/sbe_centaur_init.C $        */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2014              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file sbe_centaur_init.C
 *
 *  Support file for IStep:
 *      sbe_centaur_init
 *
 *
 *
 *  HWP_IGNORE_VERSION_CHECK
 *
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include    <stdint.h>

#include <trace/interface.H>
#include <initservice/taskargs.H>
#include <errl/errlentry.H>
#include <initservice/isteps_trace.H>
#include <targeting/common/commontargeting.H>
#include <targeting/common/utilFilter.H>
#include <fapi.H>
#include <fapiPoreVeArg.H>
#include <fapiTarget.H>
#include <fapi.H>
#include <fapiPlatHwpInvoker.H>
#include <vfs/vfs.H>
#include "sbe_centaur_init.H"
#include <hwpisteperror.H>
#include <errl/errludtarget.H>
#include <sbe/sbeif.H>
#include "cen_xip_customize.H"

extern fapi::ReturnCode fapiPoreVe(const fapi::Target i_target,
           std::list<uint64_t> & io_sharedObjectArgs);

const uint64_t REPAIR_LOADER_RETRY_CTR_MASK = 0x000007FC00000000ull;

// Constants
// Memory Relocation Register for Centaur SBE image
const uint64_t CENTAUR_SBE_PNOR_MRR = 0;

// Max SBE image buffer size
const uint32_t MAX_SBE_IMG_SIZE = 48 * 1024;

namespace   SBE_CENTAUR_INIT
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;
using   namespace   fapi;
using   namespace   vsbe;

//
//  Wrapper function to call step 10
//
void*    call_sbe_centaur_init( void *io_pArgs )
{

    TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
              "call_sbe_centaur_init entry");

    // Get target list to pass in procedure
    TARGETING::TargetHandleList l_membufTargetList;
    getAllChips(l_membufTargetList, TYPE_MEMBUF);

    size_t l_sbePnorSize = 0;
    void* l_sbePnorAddr = NULL;
    errlHndl_t  l_errl = NULL;

    IStepError  l_StepError;

    // Loop thru all Centaurs in list
    for (TargetHandleList::const_iterator
         l_membuf_iter = l_membufTargetList.begin();
         l_membuf_iter != l_membufTargetList.end();
         ++l_membuf_iter)
    {
        //find SBE image in PNOR
        TARGETING::Target* l_membuf_target = *l_membuf_iter;

        uint8_t cur_ec = (*l_membuf_iter)->getAttr<TARGETING::ATTR_EC>();

        TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK,
                   "call_sbe_centaur_init() - Find SBE image in PNOR");

        l_errl = SBE::findSBEInPnor(l_membuf_target,
                                 l_sbePnorAddr,
                                 l_sbePnorSize,
                                 NULL);
        if (l_errl)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK,
           "call_sbe_centaur_init() - Error getting image from PNOR. "
           "Target 0x%.8X, EC=0x%.2X",
           TARGETING::get_huid(l_membuf_target), cur_ec );

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_membuf_target).addToLog( l_errl );

            // Create IStep error log and cross reference error that occurred
            l_StepError.addErrorDetails( l_errl );

            // Commit Error
            errlCommit( l_errl, HWPF_COMP_ID );
            continue;
        }

        char l_header[10];
        memcpy (l_header, l_sbePnorAddr, 9);
        l_header[9] = '\0';

        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                     "call_sbe_centaur_init - Loading "
                     "centaur sbe from pnor, Addr 0x%llX, Size %d, Header %s",
                     l_sbePnorAddr, l_sbePnorSize, l_header);

        // Create a FAPI Target
        const fapi::Target l_fapiTarget( fapi::TARGET_TYPE_MEMBUF_CHIP,
                     (const_cast<TARGETING::Target*>(l_membuf_target)));

        // Expand buffer for new image size
        const uint32_t l_customizedMaxSize = MAX_SBE_IMG_SIZE;
        const uint32_t l_buf1Size = MAX_SBE_IMG_SIZE;
        const uint32_t l_buf2Size = MAX_SBE_IMG_SIZE;

        uint32_t l_customizedSize = l_customizedMaxSize;
        char * l_pCustomizedImage = (char *)malloc(l_customizedMaxSize);
        void * l_pBuf1 = malloc(l_buf1Size);
        void * l_pBuf2 = malloc(l_buf2Size);

        // Setup args
        std::list<uint64_t> myArgs;

        // Set FapiPoreVeOtherArg: run unlimited instructions
        FapiPoreVeOtherArg *l_otherArg =
                new FapiPoreVeOtherArg(vsbe::RUN_UNLIMITED, vsbe::PORE_SBE);
        // Entry point
        l_otherArg->iv_entryPoint = const_cast<char*>("pnor::_sbe_pnor_start");
        l_otherArg->iv_mrr = CENTAUR_SBE_PNOR_MRR;
        myArgs.push_back(reinterpret_cast<uint64_t>(l_otherArg));

        // Set FapiPoreVeMemArg for pnor option, base address = 0
        uint32_t base_addr = 0;
        char* l_dataPnor = const_cast<char*>(l_pCustomizedImage);
        FapiPoreVeMemArg* l_memArg = new FapiPoreVeMemArg(ARG_PNOR,
                                               base_addr, l_customizedSize,
                                               static_cast<void*>(l_dataPnor));
        myArgs.push_back(reinterpret_cast<uint64_t>(l_memArg));

        // Create state argument to dump out state for debugging purpose
        FapiPoreVeStateArg *l_stateArg = new FapiPoreVeStateArg(NULL);
        l_stateArg->iv_installState = false;
        l_stateArg->iv_extractState = true;
        myArgs.push_back(reinterpret_cast<uint64_t>(l_stateArg));

        //  Put out info on target
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "Running call_sbe_centaur_init on Centaur "
            " target HUID %.8X", TARGETING::get_huid(l_membuf_target));

        // XIP customize is going to look for a PLL ring with a "stub"
        // mem freq -- so set to a default, then clear it (so as not
        // to mess up MSS HWP later
        l_membuf_target->setAttr<TARGETING::ATTR_MSS_FREQ>(1600);

        FAPI_INVOKE_HWP( l_errl, cen_xip_customize,
                         l_fapiTarget, l_sbePnorAddr,
                         l_pCustomizedImage, l_customizedSize,
                         l_pBuf1, l_buf1Size,
                         l_pBuf2, l_buf2Size );

        l_membuf_target->setAttr<TARGETING::ATTR_MSS_FREQ>(0);

        if (l_errl)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR 0x%.8X call_sbe_centaur_init - Error returned from"
               " cen_xip_customize, l_rc 0x%llX", l_errl->reasonCode());
        }
        else
        {
            // Run the engine
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "call_sbe_centaur_init - Start VSBE engine...");

            FAPI_INVOKE_HWP(l_errl, fapiPoreVe, l_fapiTarget, myArgs);

            if (l_errl)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                   "ERROR 0x%.8X call_sbe_centaur_init - Error returned from"
                   " VSBE engine on this Centaur, l_rc 0x%llX",
                   l_errl->reasonCode());
                l_errl->collectTrace(FAPI_IMP_TRACE_NAME, 1024);
                l_errl->collectTrace("ISTEPS_TRACE", 512);
            }

            // Remove 0x0104000A reading, per Joe, the IPL procedures are no
            // longer writing information related to the repair loader into
            // this register

        }

        // Freeing memory
        delete l_otherArg;
        delete l_memArg;
        delete l_stateArg;
        free( l_pCustomizedImage );
        free( l_pBuf1 );
        free( l_pBuf2 );

        if (l_errl )
        {
            // capture the target data in the elog
            ErrlUserDetailsTarget(l_membuf_target).addToLog( l_errl );

            // Create IStep error log and cross reference error that occurred
            l_StepError.addErrorDetails( l_errl );

            // Commit Error
            errlCommit( l_errl, HWPF_COMP_ID );
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                 "call_sbe_centaur_init - VSBE engine runs successfully "
                 "on this Centaur");
        }

    }   // end for

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_sbe_centaur_init exit" );

    return l_StepError.getErrorHandle();
}

};   // end namespace

<|endoftext|>


<commit_before>/*

   nsjail
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "nsjail.h"

#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>

#include <algorithm>
#include <cerrno>
#include <memory>
#include <vector>

#include "cmdline.h"
#include "logs.h"
#include "macros.h"
#include "net.h"
#include "sandbox.h"
#include "subproc.h"
#include "util.h"

namespace nsjail {

static __thread int sigFatal = 0;
static __thread bool showProc = false;

static void sigHandler(int sig) {
	if (sig == SIGALRM || sig == SIGCHLD || sig == SIGPIPE) {
		return;
	}
	if (sig == SIGUSR1 || sig == SIGQUIT) {
		showProc = true;
		return;
	}
	sigFatal = sig;
}

static bool setSigHandler(int sig) {
	LOG_D("Setting sighandler for signal %s (%d)", util::sigName(sig).c_str(), sig);

	sigset_t smask;
	sigemptyset(&smask);

	struct sigaction sa;
	sa.sa_handler = sigHandler;
	sa.sa_mask = smask;
	sa.sa_flags = 0;
	sa.sa_restorer = NULL;

	if (sig == SIGTTIN || sig == SIGTTOU) {
		sa.sa_handler = SIG_IGN;
	}
	if (sigaction(sig, &sa, NULL) == -1) {
		PLOG_E("sigaction(%d)", sig);
		return false;
	}
	return true;
}

static bool setSigHandlers(void) {
	for (const auto& i : nssigs) {
		if (!setSigHandler(i)) {
			return false;
		}
	}
	return true;
}

static bool setTimer(nsjconf_t* nsjconf) {
	if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
		return true;
	}

	struct itimerval it = {
	    .it_interval =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	    .it_value =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	};
	if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
		PLOG_E("setitimer(ITIMER_REAL)");
		return false;
	}
	return true;
}

static bool pipeTraffic(nsjconf_t* nsjconf, int listenfd) {
	std::vector<struct pollfd> fds;
	fds.reserve(nsjconf->pipes.size() * 3 + 1);
	for (const auto& p : nsjconf->pipes) {
		fds.push_back({
		    .fd = p.sock_fd,
		    .events = POLLIN | POLLOUT,
		    .revents = 0,
		});
		fds.push_back({
		    .fd = p.pipe_in,
		    .events = POLLOUT,
		    .revents = 0,
		});
		fds.push_back({
		    .fd = p.pipe_out,
		    .events = POLLIN,
		    .revents = 0,
		});
	}
	fds.push_back({
	    .fd = listenfd,
	    .events = POLLIN,
	    .revents = 0,
	});
	LOG_D("Waiting for fd activity");
	while (poll(fds.data(), fds.size(), -1) > 0) {
		if (sigFatal > 0 || showProc) {
			return false;
		}
		if (fds.back().revents != 0) {
			LOG_D("New connection ready");
			return true;
		}
		bool cleanup = false;
		for (size_t i = 0; i < fds.size() - 1; ++i) {
			if (fds[i].revents & POLLIN) {
				fds[i].events &= ~POLLIN;
			}
			if (fds[i].revents & POLLOUT) {
				fds[i].events &= ~POLLOUT;
			}
		}
		for (size_t i = 0; i < fds.size() - 3; i += 3) {
			const size_t pipe_no = i / 3;
			int in, out;
			const char* direction;
			bool closed = false;
			std::tuple<int, int, const char*> direction_map[] = {
			    {i, i + 1, "in"}, {i + 2, i, "out"}};
			for (const auto& entry : direction_map) {
				std::tie(in, out, direction) = entry;
				bool in_ready = (fds[in].events & POLLIN) == 0 ||
						(fds[in].revents & POLLIN) == POLLIN;
				bool out_ready = (fds[out].events & POLLOUT) == 0 ||
						 (fds[out].revents & POLLOUT) == POLLOUT;
				if (in_ready && out_ready) {
					LOG_D("#%zu piping data %s", pipe_no, direction);
					ssize_t rv = splice(fds[in].fd, nullptr, fds[out].fd,
					    nullptr, 4096, SPLICE_F_NONBLOCK);
					if (rv == -1 && errno != EAGAIN) {
						PLOG_E("splice fd pair #%zu {%d, %d}\n", pipe_no,
						    fds[in].fd, fds[out].fd);
					}
					if (rv == 0) {
						closed = true;
					}
					fds[in].events |= POLLIN;
					fds[out].events |= POLLOUT;
				}
				if ((fds[in].revents & (POLLERR | POLLHUP)) != 0 ||
				    (fds[out].revents & (POLLERR | POLLHUP)) != 0) {
					closed = true;
				}
			}
			if (closed) {
				LOG_D("#%zu connection closed", pipe_no);
				cleanup = true;
				close(nsjconf->pipes[pipe_no].sock_fd);
				close(nsjconf->pipes[pipe_no].pipe_in);
				close(nsjconf->pipes[pipe_no].pipe_out);
				nsjconf->pipes[pipe_no] = {};
			}
		}
		if (cleanup) {
			break;
		}
	}
	nsjconf->pipes.erase(std::remove(nsjconf->pipes.begin(), nsjconf->pipes.end(), pipemap_t{}),
	    nsjconf->pipes.end());
	return false;
}

static int listenMode(nsjconf_t* nsjconf) {
	int listenfd = net::getRecvSocket(nsjconf->bindhost.c_str(), nsjconf->port);
	if (listenfd == -1) {
		return EXIT_FAILURE;
	}
	for (;;) {
		if (sigFatal > 0) {
			subproc::killAndReapAll(nsjconf);
			logs::logStop(sigFatal);
			close(listenfd);
			return EXIT_SUCCESS;
		}
		if (showProc) {
			showProc = false;
			subproc::displayProc(nsjconf);
		}
		if (pipeTraffic(nsjconf, listenfd)) {
			int connfd = net::acceptConn(listenfd);
			if (connfd >= 0) {
				int in[2];
				int out[2];
				if (pipe(in) != 0 || pipe(out) != 0) {
					PLOG_E("pipe");
					continue;
				}
				nsjconf->pipes.push_back({
				    .sock_fd = connfd,
				    .pipe_in = in[1],
				    .pipe_out = out[0],
				});
				subproc::runChild(nsjconf, connfd, in[0], out[1], out[1]);
				close(in[0]);
				close(out[1]);
			}
		}
		subproc::reapProc(nsjconf);
	}
}

static int standaloneMode(nsjconf_t* nsjconf) {
	for (;;) {
		if (!subproc::runChild(
			nsjconf, /* netfd= */ -1, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
			LOG_E("Couldn't launch the child process");
			return 0xff;
		}
		for (;;) {
			int child_status = subproc::reapProc(nsjconf);
			if (subproc::countProc(nsjconf) == 0) {
				if (nsjconf->mode == MODE_STANDALONE_ONCE) {
					return child_status;
				}
				break;
			}
			if (showProc) {
				showProc = false;
				subproc::displayProc(nsjconf);
			}
			if (sigFatal > 0) {
				subproc::killAndReapAll(nsjconf);
				logs::logStop(sigFatal);
				return (128 + sigFatal);
			}
			pause();
		}
	}
	// not reached
}

std::unique_ptr<struct termios> getTC(int fd) {
	std::unique_ptr<struct termios> trm(new struct termios);

	if (ioctl(fd, TCGETS, trm.get()) == -1) {
		PLOG_D("ioctl(fd=%d, TCGETS) failed", fd);
		return nullptr;
	}
	LOG_D("Saved the current state of the TTY");
	return trm;
}

void setTC(int fd, const struct termios* trm) {
	if (!trm) {
		return;
	}
	if (ioctl(fd, TCSETS, trm) == -1) {
		PLOG_W("ioctl(fd=%d, TCSETS) failed", fd);
		return;
	}
	if (tcflush(fd, TCIFLUSH) == -1) {
		PLOG_W("tcflush(fd=%d, TCIFLUSH) failed", fd);
		return;
	}
}

}  // namespace nsjail

int main(int argc, char* argv[]) {
	std::unique_ptr<nsjconf_t> nsjconf = cmdline::parseArgs(argc, argv);
	std::unique_ptr<struct termios> trm = nsjail::getTC(STDIN_FILENO);

	if (!nsjconf) {
		LOG_F("Couldn't parse cmdline options");
	}
	if (nsjconf->daemonize && (daemon(0, 0) == -1)) {
		PLOG_F("daemon");
	}
	cmdline::logParams(nsjconf.get());
	if (!nsjail::setSigHandlers()) {
		LOG_F("nsjail::setSigHandlers() failed");
	}
	if (!nsjail::setTimer(nsjconf.get())) {
		LOG_F("nsjail::setTimer() failed");
	}
	if (!sandbox::preparePolicy(nsjconf.get())) {
		LOG_F("Couldn't prepare sandboxing policy");
	}

	int ret = 0;
	if (nsjconf->mode == MODE_LISTEN_TCP) {
		ret = nsjail::listenMode(nsjconf.get());
	} else {
		ret = nsjail::standaloneMode(nsjconf.get());
	}

	sandbox::closePolicy(nsjconf.get());
	/* Try to restore the underlying console's params in case some program has changed it */
	if (!nsjconf->daemonize) {
		nsjail::setTC(STDIN_FILENO, trm.get());
	}

	LOG_D("Returning with %d", ret);
	return ret;
}
<commit_msg>nsjail: don't change cwd during daemon()<commit_after>/*

   nsjail
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "nsjail.h"

#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>

#include <algorithm>
#include <cerrno>
#include <memory>
#include <vector>

#include "cmdline.h"
#include "logs.h"
#include "macros.h"
#include "net.h"
#include "sandbox.h"
#include "subproc.h"
#include "util.h"

namespace nsjail {

static __thread int sigFatal = 0;
static __thread bool showProc = false;

static void sigHandler(int sig) {
	if (sig == SIGALRM || sig == SIGCHLD || sig == SIGPIPE) {
		return;
	}
	if (sig == SIGUSR1 || sig == SIGQUIT) {
		showProc = true;
		return;
	}
	sigFatal = sig;
}

static bool setSigHandler(int sig) {
	LOG_D("Setting sighandler for signal %s (%d)", util::sigName(sig).c_str(), sig);

	sigset_t smask;
	sigemptyset(&smask);

	struct sigaction sa;
	sa.sa_handler = sigHandler;
	sa.sa_mask = smask;
	sa.sa_flags = 0;
	sa.sa_restorer = NULL;

	if (sig == SIGTTIN || sig == SIGTTOU) {
		sa.sa_handler = SIG_IGN;
	}
	if (sigaction(sig, &sa, NULL) == -1) {
		PLOG_E("sigaction(%d)", sig);
		return false;
	}
	return true;
}

static bool setSigHandlers(void) {
	for (const auto& i : nssigs) {
		if (!setSigHandler(i)) {
			return false;
		}
	}
	return true;
}

static bool setTimer(nsjconf_t* nsjconf) {
	if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
		return true;
	}

	struct itimerval it = {
	    .it_interval =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	    .it_value =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	};
	if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
		PLOG_E("setitimer(ITIMER_REAL)");
		return false;
	}
	return true;
}

static bool pipeTraffic(nsjconf_t* nsjconf, int listenfd) {
	std::vector<struct pollfd> fds;
	fds.reserve(nsjconf->pipes.size() * 3 + 1);
	for (const auto& p : nsjconf->pipes) {
		fds.push_back({
		    .fd = p.sock_fd,
		    .events = POLLIN | POLLOUT,
		    .revents = 0,
		});
		fds.push_back({
		    .fd = p.pipe_in,
		    .events = POLLOUT,
		    .revents = 0,
		});
		fds.push_back({
		    .fd = p.pipe_out,
		    .events = POLLIN,
		    .revents = 0,
		});
	}
	fds.push_back({
	    .fd = listenfd,
	    .events = POLLIN,
	    .revents = 0,
	});
	LOG_D("Waiting for fd activity");
	while (poll(fds.data(), fds.size(), -1) > 0) {
		if (sigFatal > 0 || showProc) {
			return false;
		}
		if (fds.back().revents != 0) {
			LOG_D("New connection ready");
			return true;
		}
		bool cleanup = false;
		for (size_t i = 0; i < fds.size() - 1; ++i) {
			if (fds[i].revents & POLLIN) {
				fds[i].events &= ~POLLIN;
			}
			if (fds[i].revents & POLLOUT) {
				fds[i].events &= ~POLLOUT;
			}
		}
		for (size_t i = 0; i < fds.size() - 3; i += 3) {
			const size_t pipe_no = i / 3;
			int in, out;
			const char* direction;
			bool closed = false;
			std::tuple<int, int, const char*> direction_map[] = {
			    {i, i + 1, "in"}, {i + 2, i, "out"}};
			for (const auto& entry : direction_map) {
				std::tie(in, out, direction) = entry;
				bool in_ready = (fds[in].events & POLLIN) == 0 ||
						(fds[in].revents & POLLIN) == POLLIN;
				bool out_ready = (fds[out].events & POLLOUT) == 0 ||
						 (fds[out].revents & POLLOUT) == POLLOUT;
				if (in_ready && out_ready) {
					LOG_D("#%zu piping data %s", pipe_no, direction);
					ssize_t rv = splice(fds[in].fd, nullptr, fds[out].fd,
					    nullptr, 4096, SPLICE_F_NONBLOCK);
					if (rv == -1 && errno != EAGAIN) {
						PLOG_E("splice fd pair #%zu {%d, %d}\n", pipe_no,
						    fds[in].fd, fds[out].fd);
					}
					if (rv == 0) {
						closed = true;
					}
					fds[in].events |= POLLIN;
					fds[out].events |= POLLOUT;
				}
				if ((fds[in].revents & (POLLERR | POLLHUP)) != 0 ||
				    (fds[out].revents & (POLLERR | POLLHUP)) != 0) {
					closed = true;
				}
			}
			if (closed) {
				LOG_D("#%zu connection closed", pipe_no);
				cleanup = true;
				close(nsjconf->pipes[pipe_no].sock_fd);
				close(nsjconf->pipes[pipe_no].pipe_in);
				close(nsjconf->pipes[pipe_no].pipe_out);
				nsjconf->pipes[pipe_no] = {};
			}
		}
		if (cleanup) {
			break;
		}
	}
	nsjconf->pipes.erase(std::remove(nsjconf->pipes.begin(), nsjconf->pipes.end(), pipemap_t{}),
	    nsjconf->pipes.end());
	return false;
}

static int listenMode(nsjconf_t* nsjconf) {
	int listenfd = net::getRecvSocket(nsjconf->bindhost.c_str(), nsjconf->port);
	if (listenfd == -1) {
		return EXIT_FAILURE;
	}
	for (;;) {
		if (sigFatal > 0) {
			subproc::killAndReapAll(nsjconf);
			logs::logStop(sigFatal);
			close(listenfd);
			return EXIT_SUCCESS;
		}
		if (showProc) {
			showProc = false;
			subproc::displayProc(nsjconf);
		}
		if (pipeTraffic(nsjconf, listenfd)) {
			int connfd = net::acceptConn(listenfd);
			if (connfd >= 0) {
				int in[2];
				int out[2];
				if (pipe(in) != 0 || pipe(out) != 0) {
					PLOG_E("pipe");
					continue;
				}
				nsjconf->pipes.push_back({
				    .sock_fd = connfd,
				    .pipe_in = in[1],
				    .pipe_out = out[0],
				});
				subproc::runChild(nsjconf, connfd, in[0], out[1], out[1]);
				close(in[0]);
				close(out[1]);
			}
		}
		subproc::reapProc(nsjconf);
	}
}

static int standaloneMode(nsjconf_t* nsjconf) {
	for (;;) {
		if (!subproc::runChild(
			nsjconf, /* netfd= */ -1, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
			LOG_E("Couldn't launch the child process");
			return 0xff;
		}
		for (;;) {
			int child_status = subproc::reapProc(nsjconf);
			if (subproc::countProc(nsjconf) == 0) {
				if (nsjconf->mode == MODE_STANDALONE_ONCE) {
					return child_status;
				}
				break;
			}
			if (showProc) {
				showProc = false;
				subproc::displayProc(nsjconf);
			}
			if (sigFatal > 0) {
				subproc::killAndReapAll(nsjconf);
				logs::logStop(sigFatal);
				return (128 + sigFatal);
			}
			pause();
		}
	}
	// not reached
}

std::unique_ptr<struct termios> getTC(int fd) {
	std::unique_ptr<struct termios> trm(new struct termios);

	if (ioctl(fd, TCGETS, trm.get()) == -1) {
		PLOG_D("ioctl(fd=%d, TCGETS) failed", fd);
		return nullptr;
	}
	LOG_D("Saved the current state of the TTY");
	return trm;
}

void setTC(int fd, const struct termios* trm) {
	if (!trm) {
		return;
	}
	if (ioctl(fd, TCSETS, trm) == -1) {
		PLOG_W("ioctl(fd=%d, TCSETS) failed", fd);
		return;
	}
	if (tcflush(fd, TCIFLUSH) == -1) {
		PLOG_W("tcflush(fd=%d, TCIFLUSH) failed", fd);
		return;
	}
}

}  // namespace nsjail

int main(int argc, char* argv[]) {
	std::unique_ptr<nsjconf_t> nsjconf = cmdline::parseArgs(argc, argv);
	std::unique_ptr<struct termios> trm = nsjail::getTC(STDIN_FILENO);

	if (!nsjconf) {
		LOG_F("Couldn't parse cmdline options");
	}
	if (nsjconf->daemonize && (daemon(/* nochdir= */ 1, /* noclose= */ 0) == -1)) {
		PLOG_F("daemon");
	}
	cmdline::logParams(nsjconf.get());
	if (!nsjail::setSigHandlers()) {
		LOG_F("nsjail::setSigHandlers() failed");
	}
	if (!nsjail::setTimer(nsjconf.get())) {
		LOG_F("nsjail::setTimer() failed");
	}
	if (!sandbox::preparePolicy(nsjconf.get())) {
		LOG_F("Couldn't prepare sandboxing policy");
	}

	int ret = 0;
	if (nsjconf->mode == MODE_LISTEN_TCP) {
		ret = nsjail::listenMode(nsjconf.get());
	} else {
		ret = nsjail::standaloneMode(nsjconf.get());
	}

	sandbox::closePolicy(nsjconf.get());
	/* Try to restore the underlying console's params in case some program has changed it */
	if (!nsjconf->daemonize) {
		nsjail::setTC(STDIN_FILENO, trm.get());
	}

	LOG_D("Returning with %d", ret);
	return ret;
}
<|endoftext|>


<commit_before>#include <kms++util/resourcemanager.h>
#include <algorithm>
#include <kms++util/strhelpers.h>

using namespace kms;
using namespace std;

template<class C, class T>
auto contains(const C& v, const T& x)
-> decltype(end(v), true)
{
	return end(v) != std::find(begin(v), end(v), x);
}

ResourceManager::ResourceManager(Card& card)
	: m_card(card)
{
}

void ResourceManager::reset()
{
	m_reserved_connectors.clear();
	m_reserved_crtcs.clear();
	m_reserved_planes.clear();
}

static Connector* find_connector(Card& card, const vector<Connector*> reserved)
{
	for (Connector* conn : card.get_connectors()) {
		if (!conn->connected())
			continue;

		if (contains(reserved, conn))
			continue;

		return conn;
	}

	return nullptr;
}

static Connector* resolve_connector(Card& card, const string& name, const vector<Connector*> reserved)
{
	auto connectors = card.get_connectors();

	if (name[0] == '@') {
		char* endptr;
		unsigned id = strtoul(name.c_str() + 1, &endptr, 10);
		if (*endptr == 0) {
			Connector* c = card.get_connector(id);

			if (!c || contains(reserved, c))
				return nullptr;

			return c;
		}
	} else {
		char* endptr;
		unsigned idx = strtoul(name.c_str(), &endptr, 10);
		if (*endptr == 0) {
			if (idx >= connectors.size())
				return nullptr;

			Connector* c = connectors[idx];

			if (contains(reserved, c))
				return nullptr;

			return c;
		}
	}

	for (Connector* conn : connectors) {
		if (to_lower(conn->fullname()).find(to_lower(name)) == string::npos)
			continue;

		if (contains(reserved, conn))
			continue;

		return conn;
	}

	return nullptr;
}

Connector* ResourceManager::reserve_connector(const string& name)
{
	Connector* conn;

	if (name.empty())
		conn = find_connector(m_card, m_reserved_connectors);
	else
		conn = resolve_connector(m_card, name, m_reserved_connectors);

	if (!conn)
		return nullptr;

	m_reserved_connectors.push_back(conn);
	return conn;
}

Connector* ResourceManager::reserve_connector(Connector* conn)
{
	if (!conn)
		return nullptr;

	if (contains(m_reserved_connectors, conn))
		return nullptr;

	m_reserved_connectors.push_back(conn);
	return conn;
}

Crtc* ResourceManager::reserve_crtc(Connector* conn)
{
	if (!conn)
		return nullptr;

	if (Crtc* crtc = conn->get_current_crtc()) {
		m_reserved_crtcs.push_back(crtc);
		return crtc;
	}

	for (Crtc* crtc : conn->get_possible_crtcs()) {
		if (contains(m_reserved_crtcs, crtc))
			continue;

		m_reserved_crtcs.push_back(crtc);
		return crtc;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_plane(Crtc* crtc, PlaneType type, PixelFormat format)
{
	if (!crtc)
		return nullptr;

	for (Plane* plane : crtc->get_possible_planes()) {
		if (plane->plane_type() == type)
			continue;

		if (format != PixelFormat::Undefined && !plane->supports_format(format))
			continue;

		if (contains(m_reserved_planes, plane))
			continue;

		m_reserved_planes.push_back(plane);
		return plane;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_generic_plane(Crtc* crtc, PixelFormat format)
{
	if (!crtc)
		return nullptr;

	for (Plane* plane : crtc->get_possible_planes()) {
		if (plane->plane_type() == PlaneType::Cursor)
			continue;

		if (format != PixelFormat::Undefined && !plane->supports_format(format))
			continue;

		if (contains(m_reserved_planes, plane))
			continue;

		m_reserved_planes.push_back(plane);
		return plane;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_primary_plane(Crtc* crtc, PixelFormat format)
{
	return reserve_plane(crtc, PlaneType::Primary, format);
}

Plane* ResourceManager::reserve_overlay_plane(Crtc* crtc, PixelFormat format)
{
	return reserve_plane(crtc, PlaneType::Overlay, format);
}
<commit_msg>resmgr: fix reserve_plane()<commit_after>#include <kms++util/resourcemanager.h>
#include <algorithm>
#include <kms++util/strhelpers.h>

using namespace kms;
using namespace std;

template<class C, class T>
auto contains(const C& v, const T& x)
-> decltype(end(v), true)
{
	return end(v) != std::find(begin(v), end(v), x);
}

ResourceManager::ResourceManager(Card& card)
	: m_card(card)
{
}

void ResourceManager::reset()
{
	m_reserved_connectors.clear();
	m_reserved_crtcs.clear();
	m_reserved_planes.clear();
}

static Connector* find_connector(Card& card, const vector<Connector*> reserved)
{
	for (Connector* conn : card.get_connectors()) {
		if (!conn->connected())
			continue;

		if (contains(reserved, conn))
			continue;

		return conn;
	}

	return nullptr;
}

static Connector* resolve_connector(Card& card, const string& name, const vector<Connector*> reserved)
{
	auto connectors = card.get_connectors();

	if (name[0] == '@') {
		char* endptr;
		unsigned id = strtoul(name.c_str() + 1, &endptr, 10);
		if (*endptr == 0) {
			Connector* c = card.get_connector(id);

			if (!c || contains(reserved, c))
				return nullptr;

			return c;
		}
	} else {
		char* endptr;
		unsigned idx = strtoul(name.c_str(), &endptr, 10);
		if (*endptr == 0) {
			if (idx >= connectors.size())
				return nullptr;

			Connector* c = connectors[idx];

			if (contains(reserved, c))
				return nullptr;

			return c;
		}
	}

	for (Connector* conn : connectors) {
		if (to_lower(conn->fullname()).find(to_lower(name)) == string::npos)
			continue;

		if (contains(reserved, conn))
			continue;

		return conn;
	}

	return nullptr;
}

Connector* ResourceManager::reserve_connector(const string& name)
{
	Connector* conn;

	if (name.empty())
		conn = find_connector(m_card, m_reserved_connectors);
	else
		conn = resolve_connector(m_card, name, m_reserved_connectors);

	if (!conn)
		return nullptr;

	m_reserved_connectors.push_back(conn);
	return conn;
}

Connector* ResourceManager::reserve_connector(Connector* conn)
{
	if (!conn)
		return nullptr;

	if (contains(m_reserved_connectors, conn))
		return nullptr;

	m_reserved_connectors.push_back(conn);
	return conn;
}

Crtc* ResourceManager::reserve_crtc(Connector* conn)
{
	if (!conn)
		return nullptr;

	if (Crtc* crtc = conn->get_current_crtc()) {
		m_reserved_crtcs.push_back(crtc);
		return crtc;
	}

	for (Crtc* crtc : conn->get_possible_crtcs()) {
		if (contains(m_reserved_crtcs, crtc))
			continue;

		m_reserved_crtcs.push_back(crtc);
		return crtc;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_plane(Crtc* crtc, PlaneType type, PixelFormat format)
{
	if (!crtc)
		return nullptr;

	for (Plane* plane : crtc->get_possible_planes()) {
		if (plane->plane_type() != type)
			continue;

		if (format != PixelFormat::Undefined && !plane->supports_format(format))
			continue;

		if (contains(m_reserved_planes, plane))
			continue;

		m_reserved_planes.push_back(plane);
		return plane;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_generic_plane(Crtc* crtc, PixelFormat format)
{
	if (!crtc)
		return nullptr;

	for (Plane* plane : crtc->get_possible_planes()) {
		if (plane->plane_type() == PlaneType::Cursor)
			continue;

		if (format != PixelFormat::Undefined && !plane->supports_format(format))
			continue;

		if (contains(m_reserved_planes, plane))
			continue;

		m_reserved_planes.push_back(plane);
		return plane;
	}

	return nullptr;
}

Plane* ResourceManager::reserve_primary_plane(Crtc* crtc, PixelFormat format)
{
	return reserve_plane(crtc, PlaneType::Primary, format);
}

Plane* ResourceManager::reserve_overlay_plane(Crtc* crtc, PixelFormat format)
{
	return reserve_plane(crtc, PlaneType::Overlay, format);
}
<|endoftext|>


<commit_before>/* lexer.cpp
 * this file provides lexical analysis for Tetra it implements the yylex
 * function used by the parser.  Tetra does not use flex principally because
 * doing whitespace-based blocking is difficult due to the limitations of flex
 * (not being able to capture and respond to EOF) */

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

#include "frontend.h"
#include "parser.genh"

using namespace std;

/* whether or not we have seen whitespace so far this line */
int start_of_line = 1;

/* the number of spaces used for one indentation level */
int spaces_per_indent = 0;

/* the current number of indent levels */
int indent_level = 0;

/* the number of DEDENTs to return before anything else */
int dedents_left = 0;

/* line number we are at - used for error messages */
int yylineno = 1;

/* reset the lexer state */
void reset_lexer() {
  start_of_line = 1;
  spaces_per_indent = 0;
  indent_level = 0;
  dedents_left = 0;
  yylineno = 1;
}

/* the symbol used to comunicate with bison */
extern YYSTYPE yylval;

/* the istream to use for doing all input */
istream* in;

/* look up a string and return its token code */
int lookupId(const string& id) {
  yylval.lineno = yylineno;
  if (id == "if") {
    return TOK_IF;
  }
  if (id == "elif") {
    return TOK_ELIF;
  }
  if (id == "else") {
    return TOK_ELSE;
  }
  if (id == "for") {
    return TOK_FOR;
  }
  if (id == "in") {
    return TOK_IN;
  }
  if (id == "parallel") {
    return TOK_PARALLEL;
  }
  if (id == "while") {
    return TOK_WHILE;
  }
  if (id == "continue") {
    return TOK_CONTINUE;
  }
  if (id == "break") {
    return TOK_BREAK;
  }
  if (id == "def") {
    return TOK_DEF;
  }
  if (id == "or") {
    return TOK_OR;
  }
  if (id == "and") {
    return TOK_AND;
  }
  if (id == "not") {
    return TOK_NOT;
  }
  if (id == "pass") {
    return TOK_PASS;
  }
  if (id == "return") {
    return TOK_RETURN;
  }
  if (id == "background") {
    return TOK_BACKGROUND;
  }
  if (id == "lock") {
    return TOK_LOCK;
  }
  if (id == "int") {
    return TOK_INT;
  }
  if (id == "real") {
    return TOK_REAL;
  }
  if (id == "bool") {
    return TOK_BOOL;
  }
  if (id == "constant") {
    return TOK_CONST;
  }
  if (id == "global") {
    return TOK_GLOBAL;
  }
  if (id == "string") {
    return TOK_STRING;
  }
  if (id == "init") {
    return TOK_INIT;
  }
  if (id == "none") {
    return TOK_NONE;
  }
  if (id == "lambda") {
    return TOK_LAMBDA;
  }
  if (id == "wait") {
    return TOK_WAIT;
  }
  if (id == "self") {
    return TOK_SELF;
  }
  if (id == "class") {
    return TOK_CLASS;
  }
  if (id == "open") {
    return TOK_OPEN;
  }
  if (id == "import") {
    return TOK_IMPORT;
  }
  if (id == "mutex") {
    return TOK_MUTEX;
  }
  if (id == "task") {
    return TOK_TASK;
  }
  if (id == "declare") {
    return TOK_DECLARE;
  }
  if (id == "true") {
    yylval.boolval = true;
    return TOK_BOOLVAL;
  } else if (id == "false") {
    yylval.boolval = false;
    return TOK_BOOLVAL;
  }

  /* save the identifier */
  strcpy(yylval.stringval, id.c_str());
  return TOK_IDENTIFIER;
}

/* lex an identifier (or reserved word) given a start */
int lexIdent(int start) {
  string id;
  id.push_back((char)start);

  while (isalnum(in->peek()) || in->peek() == '_') {
    id.push_back(in->get());
  }

  return lookupId(id);
}

/* lex a number
 * TODO handle more bases, scientific notation etc. */
int lexNumber(int start) {
  string number;
  number.push_back((char)start);

  /* have we seen a decimal point yet? */
  bool seendot = (start == '.');

  /* scan forward */
  while (true) {
    char next = in->peek();

    if (isdigit(next)) {
      number.push_back(next);
      in->get();
      continue;
    }

    if (next == '.' && seendot) {
      break;
    }

    if (next == '.') {
      /* hesitantly read the . */
      next = in->get();

      /* check if next is dot too */
      if (in->peek() == '.') {
        /* put the . back and bail */
        in->putback(next);
        break;
      } else {
        number.push_back(next);
        seendot = true;
        continue;
      }
    }

    /* it is not a number or dot, just break! */
    break;
  }

  /* if there's no decimal its an int */
  if (number.find('.') == string::npos) {
    yylval.intval = atoi(number.c_str());
    return TOK_INTVAL;
  } else {
    yylval.realval = atof(number.c_str());
    return TOK_REALVAL;
  }
}

/* lex a string constant */
int lexString() {
  string str;
  while (true) {
    char next = in->get();
    if (next == '\\') {
      /* get the thing after this */
      next = in->get();
      switch (next) {
        case 'n':
          str.push_back('\n');
          break;
        case 't':
          str.push_back('\t');
          break;
        case '"':
          str.push_back('"');
        case '\\':
          str.push_back('\\');
          break;
        default:
          str.push_back(next);
      }
    } else if (next == '"') {
      break;
    } else {
      str.push_back(next);
    }
  }

  /* save the string */
  strcpy(yylval.stringval, str.c_str());
  return TOK_STRINGVAL;
}

/* the lexer function - Tetra would have used flex, but it is not possible
 * (without
 * horrible hacks) to detect EOF and add DEDENT tokens - which makes it tough to
 * do
 * whitespace based blocking a la Python */
int yylex() {
  /* if there are dedents left to return, do it */
  if (dedents_left > 0) {
    dedents_left--;
    indent_level--;
    return TOK_DEDENT;
  }

  /* read in the next character in the stream */
  int next = in->get();

  /* check for EOF */
  if (in->eof()) {
    if (indent_level != 0) {
      dedents_left = indent_level;
      return yylex();
    } else {
      return 0;
    }
  }

  /* we do NOT allow tabs */
  if (next == '\t') {
    throw Error("Tab characters are not allowed in Tetra!", yylineno);
  }

  /* if it's a new line, set to beginning of line and return next */
  if (next == '\n') {
    start_of_line = 1;
    yylineno++;
    return TOK_NEWLINE;
  }

  /* if it's whitespace, NOT at the start of a line, ignore it */
  if (!start_of_line && next == ' ') {
    /* recurse to skip it */
    return yylex();
  }

  /* if it's whitespace and IS at the start of the line */
  if (start_of_line && next == ' ') {
    /* count the spaces */
    int spaces = 1;
    while (in->peek() == ' ') {
      in->get();
      spaces++;
    }
    start_of_line = 0;

    /* if this is the first one, treat it as the level */
    if (spaces_per_indent == 0) {
      spaces_per_indent = spaces;
    }

    /* level is spaces / spaces_per_indent */
    int level = spaces / spaces_per_indent;
    if ((spaces % spaces_per_indent) != 0) {
      throw Error("Indentation level inconsistent.", yylineno);
    }

    /* if the level is greater than the current one (by one) indent */
    if (level == (indent_level + 1)) {
      indent_level++;
      return TOK_INDENT;
    }

    /* If the level is EVEN greater than that, error */
    if (level > indent_level) {
      cerr << "Level = " << level << endl;
      cerr << "Indent level = " << indent_level << endl;
      throw Error("Too much indentation.", yylineno);
    }

    /* if the level is less than the current one */
    if (level < indent_level) {
      /* set dedents_left to the difference */
      dedents_left = indent_level - level;

      /* recurse */
      return yylex();
    }

    /* if it's the same, just move on */
    if (level == indent_level) {
      return yylex();
    }

    /* else it's the start of line, but NOT whitespace */
  } else if (start_of_line) {
    start_of_line = 0;
    /* if there is indentation, set the dedents to return to that - 1, and
     * return 1 */
    if (indent_level > 0) {
      /* put the thing we read back! */
      in->putback(next);
      dedents_left = indent_level - 1;
      indent_level--;
      return TOK_DEDENT;
    }
  }

  /* it's not start of line any more */
  start_of_line = 0;

  /* if it's a letter or underscore, we have an identifier (or reserved word) */
  if (isalpha(next)) {
    return lexIdent(next);
  }

  /* if it's three decimal points, it's an elipsis */
  if (next == '.' && in->peek() == '.') {
    in->get();

    if (in->get() != '.') {
      throw Error("Lexical error: '..' not correct", yylineno);
    }

    return TOK_ELLIPSIS;
  }

  /* if it's a number or decimal point, we have a number of some kind */
  if (isdigit(next) || (next == '.' && isdigit(in->peek()))) {
    return lexNumber(next);
  }

  /* check for the dot operator */
  if (next == '.') {
    return TOK_DOT;
  }

  /* handle comments */
  if (next == '#') {
    /* eat it all */
    while (in->peek() != '\n') {
      in->get();
    }
    /* get the new line */
    in->get();
    start_of_line = 1;
    yylineno++;

    /* skip it */
    return yylex();
  }

  /* handle string constants */
  if (next == '"') {
    return lexString();
  }

  /* character operators and punctuation */
  yylval.lineno = yylineno;
  switch (next) {
    /* single character ones */
    case '~':
      return TOK_BITNOT;
    case '(':
      return TOK_LEFTPARENS;
    case ')':
      return TOK_RIGHTPARENS;
    case ',':
      return TOK_COMMA;
    case ';':
      return TOK_SEMICOLON;
    case ':':
      return TOK_COLON;
    case '[':
      return TOK_LEFTBRACKET;
    case ']':
      return TOK_RIGHTBRACKET;
    case '{':
      return TOK_LEFTBRACE;
    case '}':
      return TOK_RIGHTBRACE;

    /* ones that have some single and double ones */
    case '=':
      if (in->peek() == '=') {
        in->get();
        return TOK_EQ;
      } else {
        return TOK_ASSIGN;
      }
    case '+':
      if (in->peek() == '=') {
        in->get();
        return TOK_PLUSEQ;
      } else {
        return TOK_PLUS;
      }
    case '-':
      if (in->peek() == '=') {
        in->get();
        return TOK_MINUSEQ;
      } else if (in->peek() == '>') {
        in->get();
        return TOK_RIGHTARROW;
      } else {
        return TOK_MINUS;
      }
    case '*':
      if (in->peek() == '=') {
        in->get();
        return TOK_TIMESEQ;
      } else if (in->peek() == '*') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_EXPEQ;
        } else {
          return TOK_EXP;
        }
      } else {
        return TOK_TIMES;
      }
    case '/':
      if (in->peek() == '=') {
        in->get();
        return TOK_DIVIDEEQ;
      } else {
        return TOK_DIVIDE;
      }
    case '%':
      if (in->peek() == '=') {
        in->get();
        return TOK_MODULUSEQ;
      } else {
        return TOK_MODULUS;
      }
    case '^':
      if (in->peek() == '=') {
        in->get();
        return TOK_XOREQ;
      } else {
        return TOK_BITXOR;
      }
    case '|':
      if (in->peek() == '=') {
        in->get();
        return TOK_OREQ;
      } else {
        return TOK_BITOR;
      }
    case '&':
      if (in->peek() == '=') {
        in->get();
        return TOK_ANDEQ;
      } else {
        return TOK_BITAND;
      }
    case '!':
      if (in->peek() != '=') {
        throw Error("Error, invalid lexeme '!'", yylineno);
      } else {
        in->get();
        return TOK_NEQ;
      }
    case '<':
      if (in->peek() == '=') {
        in->get();
        return TOK_LTE;
      } else if (in->peek() == '<') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_LSHIFTEQ;
        } else {
          return TOK_LSHIFT;
        }
      } else {
        return TOK_LT;
      }
    case '>':
      if (in->peek() == '=') {
        in->get();
        return TOK_GTE;
      } else if (in->peek() == '>') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_RSHIFTEQ;
        } else {
          return TOK_RSHIFT;
        }
      } else {
        return TOK_GT;
      }
  }

  /* if we get down here, there must be a lexer error :( */
  throw Error(string(next, 1) + " is not a valid lexeme.", yylineno);
  return 0;
}

<commit_msg>Add abiiltiy to escape a newline.<commit_after>/* lexer.cpp
 * this file provides lexical analysis for Tetra it implements the yylex
 * function used by the parser.  Tetra does not use flex principally because
 * doing whitespace-based blocking is difficult due to the limitations of flex
 * (not being able to capture and respond to EOF) */

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

#include "frontend.h"
#include "parser.genh"

using namespace std;

/* whether or not we have seen whitespace so far this line */
int start_of_line = 1;

/* the number of spaces used for one indentation level */
int spaces_per_indent = 0;

/* the current number of indent levels */
int indent_level = 0;

/* the number of DEDENTs to return before anything else */
int dedents_left = 0;

/* line number we are at - used for error messages */
int yylineno = 1;

/* reset the lexer state */
void reset_lexer() {
  start_of_line = 1;
  spaces_per_indent = 0;
  indent_level = 0;
  dedents_left = 0;
  yylineno = 1;
}

/* the symbol used to comunicate with bison */
extern YYSTYPE yylval;

/* the istream to use for doing all input */
istream* in;

/* look up a string and return its token code */
int lookupId(const string& id) {
  yylval.lineno = yylineno;
  if (id == "if") {
    return TOK_IF;
  }
  if (id == "elif") {
    return TOK_ELIF;
  }
  if (id == "else") {
    return TOK_ELSE;
  }
  if (id == "for") {
    return TOK_FOR;
  }
  if (id == "in") {
    return TOK_IN;
  }
  if (id == "parallel") {
    return TOK_PARALLEL;
  }
  if (id == "while") {
    return TOK_WHILE;
  }
  if (id == "continue") {
    return TOK_CONTINUE;
  }
  if (id == "break") {
    return TOK_BREAK;
  }
  if (id == "def") {
    return TOK_DEF;
  }
  if (id == "or") {
    return TOK_OR;
  }
  if (id == "and") {
    return TOK_AND;
  }
  if (id == "not") {
    return TOK_NOT;
  }
  if (id == "pass") {
    return TOK_PASS;
  }
  if (id == "return") {
    return TOK_RETURN;
  }
  if (id == "background") {
    return TOK_BACKGROUND;
  }
  if (id == "lock") {
    return TOK_LOCK;
  }
  if (id == "int") {
    return TOK_INT;
  }
  if (id == "real") {
    return TOK_REAL;
  }
  if (id == "bool") {
    return TOK_BOOL;
  }
  if (id == "constant") {
    return TOK_CONST;
  }
  if (id == "global") {
    return TOK_GLOBAL;
  }
  if (id == "string") {
    return TOK_STRING;
  }
  if (id == "init") {
    return TOK_INIT;
  }
  if (id == "none") {
    return TOK_NONE;
  }
  if (id == "lambda") {
    return TOK_LAMBDA;
  }
  if (id == "wait") {
    return TOK_WAIT;
  }
  if (id == "self") {
    return TOK_SELF;
  }
  if (id == "class") {
    return TOK_CLASS;
  }
  if (id == "open") {
    return TOK_OPEN;
  }
  if (id == "import") {
    return TOK_IMPORT;
  }
  if (id == "mutex") {
    return TOK_MUTEX;
  }
  if (id == "task") {
    return TOK_TASK;
  }
  if (id == "declare") {
    return TOK_DECLARE;
  }
  if (id == "true") {
    yylval.boolval = true;
    return TOK_BOOLVAL;
  } else if (id == "false") {
    yylval.boolval = false;
    return TOK_BOOLVAL;
  }

  /* save the identifier */
  strcpy(yylval.stringval, id.c_str());
  return TOK_IDENTIFIER;
}

/* lex an identifier (or reserved word) given a start */
int lexIdent(int start) {
  string id;
  id.push_back((char)start);

  while (isalnum(in->peek()) || in->peek() == '_') {
    id.push_back(in->get());
  }

  return lookupId(id);
}

/* lex a number
 * TODO handle more bases, scientific notation etc. */
int lexNumber(int start) {
  string number;
  number.push_back((char)start);

  /* have we seen a decimal point yet? */
  bool seendot = (start == '.');

  /* scan forward */
  while (true) {
    char next = in->peek();

    if (isdigit(next)) {
      number.push_back(next);
      in->get();
      continue;
    }

    if (next == '.' && seendot) {
      break;
    }

    if (next == '.') {
      /* hesitantly read the . */
      next = in->get();

      /* check if next is dot too */
      if (in->peek() == '.') {
        /* put the . back and bail */
        in->putback(next);
        break;
      } else {
        number.push_back(next);
        seendot = true;
        continue;
      }
    }

    /* it is not a number or dot, just break! */
    break;
  }

  /* if there's no decimal its an int */
  if (number.find('.') == string::npos) {
    yylval.intval = atoi(number.c_str());
    return TOK_INTVAL;
  } else {
    yylval.realval = atof(number.c_str());
    return TOK_REALVAL;
  }
}

/* lex a string constant */
int lexString() {
  string str;
  while (true) {
    char next = in->get();
    if (next == '\\') {
      /* get the thing after this */
      next = in->get();
      switch (next) {
        case 'n':
          str.push_back('\n');
          break;
        case 't':
          str.push_back('\t');
          break;
        case '"':
          str.push_back('"');
        case '\\':
          str.push_back('\\');
          break;
        default:
          str.push_back(next);
      }
    } else if (next == '"') {
      break;
    } else {
      str.push_back(next);
    }
  }

  /* save the string */
  strcpy(yylval.stringval, str.c_str());
  return TOK_STRINGVAL;
}

/* the lexer function - Tetra would have used flex, but it is not possible
 * (without
 * horrible hacks) to detect EOF and add DEDENT tokens - which makes it tough to
 * do
 * whitespace based blocking a la Python */
int yylex() {
  /* if there are dedents left to return, do it */
  if (dedents_left > 0) {
    dedents_left--;
    indent_level--;
    return TOK_DEDENT;
  }

  /* read in the next character in the stream */
  int next = in->get();

  /* check for EOF */
  if (in->eof()) {
    if (indent_level != 0) {
      dedents_left = indent_level;
      return yylex();
    } else {
      return 0;
    }
  }

  /* we do NOT allow tabs */
  if (next == '\t') {
    throw Error("Tab characters are not allowed in Tetra!", yylineno);
  }

  /* if it's a new line, set to beginning of line and return next */
  if (next == '\n') {
    start_of_line = 1;
    yylineno++;
    return TOK_NEWLINE;
  }

  /* if it's whitespace, NOT at the start of a line, ignore it */
  if (!start_of_line && next == ' ') {
    /* recurse to skip it */
    return yylex();
  }

  /* if it's whitespace and IS at the start of the line */
  if (start_of_line && next == ' ') {
    /* count the spaces */
    int spaces = 1;
    while (in->peek() == ' ') {
      in->get();
      spaces++;
    }
    start_of_line = 0;

    /* if this is the first one, treat it as the level */
    if (spaces_per_indent == 0) {
      spaces_per_indent = spaces;
    }

    /* level is spaces / spaces_per_indent */
    int level = spaces / spaces_per_indent;
    if ((spaces % spaces_per_indent) != 0) {
      throw Error("Indentation level inconsistent.", yylineno);
    }

    /* if the level is greater than the current one (by one) indent */
    if (level == (indent_level + 1)) {
      indent_level++;
      return TOK_INDENT;
    }

    /* If the level is EVEN greater than that, error */
    if (level > indent_level) {
      cerr << "Level = " << level << endl;
      cerr << "Indent level = " << indent_level << endl;
      throw Error("Too much indentation.", yylineno);
    }

    /* if the level is less than the current one */
    if (level < indent_level) {
      /* set dedents_left to the difference */
      dedents_left = indent_level - level;

      /* recurse */
      return yylex();
    }

    /* if it's the same, just move on */
    if (level == indent_level) {
      return yylex();
    }

    /* else it's the start of line, but NOT whitespace */
  } else if (start_of_line) {
    start_of_line = 0;
    /* if there is indentation, set the dedents to return to that - 1, and
     * return 1 */
    if (indent_level > 0) {
      /* put the thing we read back! */
      in->putback(next);
      dedents_left = indent_level - 1;
      indent_level--;
      return TOK_DEDENT;
    }
  }

  /* it's not start of line any more */
  start_of_line = 0;

  /* if it's a letter or underscore, we have an identifier (or reserved word) */
  if (isalpha(next)) {
    return lexIdent(next);
  }

  /* if it's three decimal points, it's an elipsis */
  if (next == '.' && in->peek() == '.') {
    in->get();

    if (in->get() != '.') {
      throw Error("Lexical error: '..' not correct", yylineno);
    }

    return TOK_ELLIPSIS;
  }

  /* if it's a number or decimal point, we have a number of some kind */
  if (isdigit(next) || (next == '.' && isdigit(in->peek()))) {
    return lexNumber(next);
  }

  /* check for the dot operator */
  if (next == '.') {
    return TOK_DOT;
  }

  /* handle comments */
  if (next == '#') {
    /* eat it all */
    while (in->peek() != '\n') {
      in->get();
    }
    /* get the new line */
    in->get();
    start_of_line = 1;
    yylineno++;

    /* skip it */
    return yylex();
  }

  /* handle string constants */
  if (next == '"') {
    return lexString();
  }

  /* character operators and punctuation */
  yylval.lineno = yylineno;
  switch (next) {
    /* single character ones */
    case '~':
      return TOK_BITNOT;
    case '(':
      return TOK_LEFTPARENS;
    case ')':
      return TOK_RIGHTPARENS;
    case ',':
      return TOK_COMMA;
    case ';':
      return TOK_SEMICOLON;
    case ':':
      return TOK_COLON;
    case '[':
      return TOK_LEFTBRACKET;
    case ']':
      return TOK_RIGHTBRACKET;
    case '{':
      return TOK_LEFTBRACE;
    case '}':
      return TOK_RIGHTBRACE;

    /* ones that have some single and double ones */
    case '=':
      if (in->peek() == '=') {
        in->get();
        return TOK_EQ;
      } else {
        return TOK_ASSIGN;
      }
    case '+':
      if (in->peek() == '=') {
        in->get();
        return TOK_PLUSEQ;
      } else {
        return TOK_PLUS;
      }
    case '-':
      if (in->peek() == '=') {
        in->get();
        return TOK_MINUSEQ;
      } else if (in->peek() == '>') {
        in->get();
        return TOK_RIGHTARROW;
      } else {
        return TOK_MINUS;
      }
    case '*':
      if (in->peek() == '=') {
        in->get();
        return TOK_TIMESEQ;
      } else if (in->peek() == '*') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_EXPEQ;
        } else {
          return TOK_EXP;
        }
      } else {
        return TOK_TIMES;
      }
    case '/':
      if (in->peek() == '=') {
        in->get();
        return TOK_DIVIDEEQ;
      } else {
        return TOK_DIVIDE;
      }
    case '%':
      if (in->peek() == '=') {
        in->get();
        return TOK_MODULUSEQ;
      } else {
        return TOK_MODULUS;
      }
    case '^':
      if (in->peek() == '=') {
        in->get();
        return TOK_XOREQ;
      } else {
        return TOK_BITXOR;
      }
    case '|':
      if (in->peek() == '=') {
        in->get();
        return TOK_OREQ;
      } else {
        return TOK_BITOR;
      }
    case '&':
      if (in->peek() == '=') {
        in->get();
        return TOK_ANDEQ;
      } else {
        return TOK_BITAND;
      }
    case '!':
      if (in->peek() != '=') {
        throw Error("Error, invalid lexeme '!'", yylineno);
      } else {
        in->get();
        return TOK_NEQ;
      }
    case '<':
      if (in->peek() == '=') {
        in->get();
        return TOK_LTE;
      } else if (in->peek() == '<') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_LSHIFTEQ;
        } else {
          return TOK_LSHIFT;
        }
      } else {
        return TOK_LT;
      }
    case '>':
      if (in->peek() == '=') {
        in->get();
        return TOK_GTE;
      } else if (in->peek() == '>') {
        in->get();
        if (in->peek() == '=') {
          in->get();
          return TOK_RSHIFTEQ;
        } else {
          return TOK_RSHIFT;
        }
      } else {
        return TOK_GT;
      }
    case '\\':
      if (in->peek() == '\n'){
        in->get();
        while(in->peek() == ' '){
          in->get();
        }

        /* recurse to skip it */
        return yylex();
      }
  }

  /* if we get down here, there must be a lexer error :( */
  throw Error(string(next, 1) + " is not a valid lexeme.", yylineno);
  return 0;
}

<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2017 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// UnitTest include.
#include <UnitTest/unit_test.hpp>

// cfgfile include.
#include <cfgfile/all.hpp>

TEST( QtParser, test_undefined_first_mandatory_tag )
{
	QDomDocument doc;

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_undefined_first_mandatory_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected end of file. "
			"Undefined mandatory tag \"cfg\". In file "
			"\"test_undefined_first_mandatory_tag\" on line -1." )
	}
}

TEST( QtParser, test_unexpected_tag )
{
	QDomDocument doc;
	QString error;
	int line = 0;
	int column = 0;

	doc.setContent( QLatin1String( "<wrong></wrong>" ),
		true, &error, &line, &column );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_unexpected_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected tag name. "
			"We expected \"cfg\", but we've got \"wrong\". In file "
			"\"test_unexpected_tag\" on line 1." )
	}
}

TEST( QtParser, test_unexpected_child_tag )
{
	QDomDocument doc;
	QString error;
	int line = 0;
	int column = 0;

	doc.setContent( QLatin1String( "<cfg><wrong></wrong></cfg>" ),
		true, &error, &line, &column );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_unexpected_child_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected tag name. "
			"We expected one child tag of tag \"cfg\", but we've got \"wrong\". "
			"In file \"test_unexpected_child_tag\" on line 1." )
	}
}

TEST( QtParser, test_cant_set_xml )
{
	QTextStream s( "abc" );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	try {
		cfgfile::read_cfgfile( tag, s, "test_cant_set_xml" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unable to parse XML "
			"from file: \"test_cant_set_xml\". \"unexpected end of file\" "
			"On line 1, column 7." )
	}
}

int main()
{
	RUN_ALL_TESTS()

	return 0;
}
<commit_msg>Testing.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2017 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

// UnitTest include.
#include <UnitTest/unit_test.hpp>

// cfgfile include.
#include <cfgfile/all.hpp>

TEST( QtParser, test_undefined_first_mandatory_tag )
{
	QDomDocument doc;

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_undefined_first_mandatory_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected end of file. "
			"Undefined mandatory tag \"cfg\". In file "
			"\"test_undefined_first_mandatory_tag\" on line -1." )
	}
}

TEST( QtParser, test_unexpected_tag )
{
	QDomDocument doc;
	QString error;
	int line = 0;
	int column = 0;

	doc.setContent( QLatin1String( "<wrong></wrong>" ),
		true, &error, &line, &column );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_unexpected_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected tag name. "
			"We expected \"cfg\", but we've got \"wrong\". In file "
			"\"test_unexpected_tag\" on line 1." )
	}
}

TEST( QtParser, test_unexpected_child_tag )
{
	QDomDocument doc;
	QString error;
	int line = 0;
	int column = 0;

	doc.setContent( QLatin1String( "<cfg><wrong></wrong></cfg>" ),
		true, &error, &line, &column );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_unexpected_child_tag" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected tag name. "
			"We expected one child tag of tag \"cfg\", but we've got \"wrong\". "
			"In file \"test_unexpected_child_tag\" on line 1." )
	}
}

TEST( QtParser, test_cant_set_xml )
{
	QTextStream s( "abc" );

	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	try {
		cfgfile::read_cfgfile( tag, s, "test_cant_set_xml" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unable to parse XML "
			"from file: \"test_cant_set_xml\". \"unexpected end of file\" "
			"On line 1, column 7." )
	}
}

TEST( QtParser, test_unexpected_xml )
{
	cfgfile::tag_no_value_t< cfgfile::qstring_trait_t > tag( "cfg", true );

	QDomDocument doc;

	QDomElement cfg = doc.createElement( "cfg" );

	doc.appendChild( cfg );

	QDomComment c = doc.createComment( "data" );

	cfg.appendChild( c );

	cfgfile::parser_t< cfgfile::qstring_trait_t > parser( tag, doc );

	try {
		parser.parse( "test_unexpected_xml" );

		CHECK_CONDITION( false )
	}
	catch( const cfgfile::exception_t< cfgfile::qstring_trait_t > & x )
	{
		CHECK_CONDITION( x.desc() == "Unexpected tag name. "
			"We expected one child tag of tag \"cfg\", but we've got \"#comment\". "
			"In file \"test_unexpected_xml\" on line -1." )
	}
}

int main()
{
	RUN_ALL_TESTS()

	return 0;
}
<|endoftext|>