<commit_before>#include "command.hh"
#include "attr-path.hh"
#include "common-eval-args.hh"
#include "derivations.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"
#include "primops/flake.hh"

#include <regex>

namespace nix {

SourceExprCommand::SourceExprCommand()
{
    mkFlag()
        .shortName('f')
        .longName("file")
        .label("file")
        .description("evaluate a set of attributes from FILE (deprecated)")
        .dest(&file);

    mkFlag()
        .longName("impure")
        .description("allow access to mutable paths and repositories")
        .handler([&](std::vector<std::string> ss) {
            evalSettings.pureEval = false;
        });
}

ref<EvalState> SourceExprCommand::getEvalState()
{
    if (!evalState)
        evalState = std::make_shared<EvalState>(searchPath, getStore());
    return ref<EvalState>(evalState);
}

Buildable Installable::toBuildable()
{
    auto buildables = toBuildables();
    if (buildables.size() != 1)
        throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
    return std::move(buildables[0]);
}

struct InstallableStorePath : Installable
{
    Path storePath;

    InstallableStorePath(const Path & storePath) : storePath(storePath) { }

    std::string what() override { return storePath; }

    Buildables toBuildables() override
    {
        return {{isDerivation(storePath) ? storePath : "", {{"out", storePath}}}};
    }
};

struct InstallableValue : Installable
{
    SourceExprCommand & cmd;

    InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }

    Buildables toBuildables() override
    {
        auto state = cmd.getEvalState();

        auto v = toValue(*state);

        Bindings & autoArgs = *cmd.getAutoArgs(*state);

        DrvInfos drvs;
        getDerivations(*state, *v, "", autoArgs, drvs, false);

        Buildables res;

        PathSet drvPaths;

        for (auto & drv : drvs) {
            Buildable b{drv.queryDrvPath()};
            drvPaths.insert(b.drvPath);

            auto outputName = drv.queryOutputName();
            if (outputName == "")
                throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);

            b.outputs.emplace(outputName, drv.queryOutPath());

            res.push_back(std::move(b));
        }

        // Hack to recognize .all: if all drvs have the same drvPath,
        // merge the buildables.
        if (drvPaths.size() == 1) {
            Buildable b{*drvPaths.begin()};
            for (auto & b2 : res)
                b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
            return {b};
        } else
            return res;
    }
};

struct InstallableExpr : InstallableValue
{
    std::string text;

    InstallableExpr(SourceExprCommand & cmd, const std::string & text)
         : InstallableValue(cmd), text(text) { }

    std::string what() override { return text; }

    Value * toValue(EvalState & state) override
    {
        auto v = state.allocValue();
        state.eval(state.parseExprFromString(text, absPath(".")), *v);
        return v;
    }
};

struct InstallableAttrPath : InstallableValue
{
    Value * v;
    std::string attrPath;

    InstallableAttrPath(SourceExprCommand & cmd, Value * v, const std::string & attrPath)
        : InstallableValue(cmd), v(v), attrPath(attrPath)
    { }

    std::string what() override { return attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto vRes = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), *v);
        state.forceValue(*vRes);
        return vRes;
    }
};

struct InstallableFlake : InstallableValue
{
    FlakeRef flakeRef;
    std::string attrPath;

    InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, const std::string & attrPath)
        : InstallableValue(cmd), flakeRef(flakeRef), attrPath(attrPath)
    { }

    std::string what() override { return flakeRef.to_string() + ":" + attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto vTemp = state.allocValue();
        auto vFlake = *makeFlakeValue(state, flakeRef, true, *vTemp);

        auto vProvides = (*vFlake.attrs->get(state.symbols.create("provides")))->value;

        state.forceValue(*vProvides);

        auto emptyArgs = state.allocBindings(0);

        if (auto aPackages = *vProvides->attrs->get(state.symbols.create("packages"))) {
            try {
                auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *aPackages->value);
                state.forceValue(*v);
                return v;
            } catch (AttrPathNotFound & e) {
            }
        }

        auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vProvides);
        state.forceValue(*v);
        return v;
    }
};

// FIXME: extend
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));

std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
    ref<Store> store, std::vector<std::string> ss)
{
    std::vector<std::shared_ptr<Installable>> result;

    if (file) {
        // FIXME: backward compatibility hack
        evalSettings.pureEval = false;

        auto state = getEvalState();
        auto vFile = state->allocValue();
        state->evalFile(lookupFileArg(*state, *file), *vFile);

        if (ss.empty())
            ss = {""};

        for (auto & s : ss)
            result.push_back(std::make_shared<InstallableAttrPath>(*this, vFile, s));

    } else {

        for (auto & s : ss) {

            size_t colon;

            if (s.compare(0, 1, "(") == 0)
                result.push_back(std::make_shared<InstallableExpr>(*this, s));

            else if (hasPrefix(s, "nixpkgs.")) {
                bool static warned;
                warnOnce(warned, "the syntax 'nixpkgs.<attr>' is deprecated; use 'nixpkgs:<attr>' instead");
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"), std::string(s, 8)));
            }

            else if ((colon = s.rfind(':')) != std::string::npos) {
                auto flakeRef = std::string(s, 0, colon);
                auto attrPath = std::string(s, colon + 1);
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef(flakeRef, true), attrPath));
            }

            else if (s.find('/') != std::string::npos || s == ".") {
                Path storePath;
                try {
                    storePath = store->toStorePath(store->followLinksToStore(s));
                } catch (Error) { }
                if (storePath != "")
                    result.push_back(std::make_shared<InstallableStorePath>(storePath));
                else
                    result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef(s, true), "defaultPackage"));
            }

            else
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"), s));
        }
    }

    return result;
}

std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
    ref<Store> store, const std::string & installable)
{
    auto installables = parseInstallables(store, {installable});
    assert(installables.size() == 1);
    return installables.front();
}

Buildables build(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    if (mode != Build)
        settings.readOnlyMode = true;

    Buildables buildables;

    PathSet pathsToBuild;

    for (auto & i : installables) {
        for (auto & b : i->toBuildables()) {
            if (b.drvPath != "") {
                StringSet outputNames;
                for (auto & output : b.outputs)
                    outputNames.insert(output.first);
                pathsToBuild.insert(
                    b.drvPath + "!" + concatStringsSep(",", outputNames));
            } else
                for (auto & output : b.outputs)
                    pathsToBuild.insert(output.second);
            buildables.push_back(std::move(b));
        }
    }

    if (mode == DryRun)
        printMissing(store, pathsToBuild, lvlError);
    else if (mode == Build)
        store->buildPaths(pathsToBuild);

    return buildables;
}

PathSet toStorePaths(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    PathSet outPaths;

    for (auto & b : build(store, mode, installables))
        for (auto & output : b.outputs)
            outPaths.insert(output.second);

    return outPaths;
}

Path toStorePath(ref<Store> store, RealiseMode mode,
    std::shared_ptr<Installable> installable)
{
    auto paths = toStorePaths(store, mode, {installable});

    if (paths.size() != 1)
            throw Error("argument '%s' should evaluate to one store path", installable->what());

    return *paths.begin();
}

PathSet toDerivations(ref<Store> store,
    std::vector<std::shared_ptr<Installable>> installables, bool useDeriver)
{
    PathSet drvPaths;

    for (auto & i : installables)
        for (auto & b : i->toBuildables()) {
            if (b.drvPath.empty()) {
                if (!useDeriver)
                    throw Error("argument '%s' did not evaluate to a derivation", i->what());
                for (auto & output : b.outputs) {
                    auto derivers = store->queryValidDerivers(output.second);
                    if (derivers.empty())
                        throw Error("'%s' does not have a known deriver", i->what());
                    // FIXME: use all derivers?
                    drvPaths.insert(*derivers.begin());
                }
            } else
                drvPaths.insert(b.drvPath);
        }

    return drvPaths;
}

void InstallablesCommand::prepare()
{
    installables = parseInstallables(getStore(), _installables);
}

void InstallableCommand::prepare()
{
    installable = parseInstallable(getStore(), _installable);
}

}
<commit_msg>Whitespace<commit_after>#include "command.hh"
#include "attr-path.hh"
#include "common-eval-args.hh"
#include "derivations.hh"
#include "eval-inline.hh"
#include "eval.hh"
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"
#include "primops/flake.hh"

#include <regex>

namespace nix {

SourceExprCommand::SourceExprCommand()
{
    mkFlag()
        .shortName('f')
        .longName("file")
        .label("file")
        .description("evaluate a set of attributes from FILE (deprecated)")
        .dest(&file);

    mkFlag()
        .longName("impure")
        .description("allow access to mutable paths and repositories")
        .handler([&](std::vector<std::string> ss) {
            evalSettings.pureEval = false;
        });
}

ref<EvalState> SourceExprCommand::getEvalState()
{
    if (!evalState)
        evalState = std::make_shared<EvalState>(searchPath, getStore());
    return ref<EvalState>(evalState);
}

Buildable Installable::toBuildable()
{
    auto buildables = toBuildables();
    if (buildables.size() != 1)
        throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size());
    return std::move(buildables[0]);
}

struct InstallableStorePath : Installable
{
    Path storePath;

    InstallableStorePath(const Path & storePath) : storePath(storePath) { }

    std::string what() override { return storePath; }

    Buildables toBuildables() override
    {
        return {{isDerivation(storePath) ? storePath : "", {{"out", storePath}}}};
    }
};

struct InstallableValue : Installable
{
    SourceExprCommand & cmd;

    InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }

    Buildables toBuildables() override
    {
        auto state = cmd.getEvalState();

        auto v = toValue(*state);

        Bindings & autoArgs = *cmd.getAutoArgs(*state);

        DrvInfos drvs;
        getDerivations(*state, *v, "", autoArgs, drvs, false);

        Buildables res;

        PathSet drvPaths;

        for (auto & drv : drvs) {
            Buildable b{drv.queryDrvPath()};
            drvPaths.insert(b.drvPath);

            auto outputName = drv.queryOutputName();
            if (outputName == "")
                throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);

            b.outputs.emplace(outputName, drv.queryOutPath());

            res.push_back(std::move(b));
        }

        // Hack to recognize .all: if all drvs have the same drvPath,
        // merge the buildables.
        if (drvPaths.size() == 1) {
            Buildable b{*drvPaths.begin()};
            for (auto & b2 : res)
                b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
            return {b};
        } else
            return res;
    }
};

struct InstallableExpr : InstallableValue
{
    std::string text;

    InstallableExpr(SourceExprCommand & cmd, const std::string & text)
         : InstallableValue(cmd), text(text) { }

    std::string what() override { return text; }

    Value * toValue(EvalState & state) override
    {
        auto v = state.allocValue();
        state.eval(state.parseExprFromString(text, absPath(".")), *v);
        return v;
    }
};

struct InstallableAttrPath : InstallableValue
{
    Value * v;
    std::string attrPath;

    InstallableAttrPath(SourceExprCommand & cmd, Value * v, const std::string & attrPath)
        : InstallableValue(cmd), v(v), attrPath(attrPath)
    { }

    std::string what() override { return attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto vRes = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), *v);
        state.forceValue(*vRes);
        return vRes;
    }
};

struct InstallableFlake : InstallableValue
{
    FlakeRef flakeRef;
    std::string attrPath;

    InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, const std::string & attrPath)
        : InstallableValue(cmd), flakeRef(flakeRef), attrPath(attrPath)
    { }

    std::string what() override { return flakeRef.to_string() + ":" + attrPath; }

    Value * toValue(EvalState & state) override
    {
        auto vTemp = state.allocValue();
        auto vFlake = *makeFlakeValue(state, flakeRef, true, *vTemp);

        auto vProvides = (*vFlake.attrs->get(state.symbols.create("provides")))->value;

        state.forceValue(*vProvides);

        auto emptyArgs = state.allocBindings(0);

        if (auto aPackages = *vProvides->attrs->get(state.symbols.create("packages"))) {
            try {
                auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *aPackages->value);
                state.forceValue(*v);
                return v;
            } catch (AttrPathNotFound & e) {
            }
        }

        auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vProvides);
        state.forceValue(*v);
        return v;
    }
};

// FIXME: extend
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));

std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
    ref<Store> store, std::vector<std::string> ss)
{
    std::vector<std::shared_ptr<Installable>> result;

    if (file) {
        // FIXME: backward compatibility hack
        evalSettings.pureEval = false;

        auto state = getEvalState();
        auto vFile = state->allocValue();
        state->evalFile(lookupFileArg(*state, *file), *vFile);

        if (ss.empty())
            ss = {""};

        for (auto & s : ss)
            result.push_back(std::make_shared<InstallableAttrPath>(*this, vFile, s));

    } else {

        for (auto & s : ss) {

            size_t colon;

            if (s.compare(0, 1, "(") == 0)
                result.push_back(std::make_shared<InstallableExpr>(*this, s));

            else if (hasPrefix(s, "nixpkgs.")) {
                bool static warned;
                warnOnce(warned, "the syntax 'nixpkgs.<attr>' is deprecated; use 'nixpkgs:<attr>' instead");
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"), std::string(s, 8)));
            }

            else if ((colon = s.rfind(':')) != std::string::npos) {
                auto flakeRef = std::string(s, 0, colon);
                auto attrPath = std::string(s, colon + 1);
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef(flakeRef, true), attrPath));
            }

            else if (s.find('/') != std::string::npos || s == ".") {
                Path storePath;
                try {
                    storePath = store->toStorePath(store->followLinksToStore(s));
                } catch (Error) { }
                if (storePath != "")
                    result.push_back(std::make_shared<InstallableStorePath>(storePath));
                else
                    result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef(s, true), "defaultPackage"));
            }

            else
                result.push_back(std::make_shared<InstallableFlake>(*this, FlakeRef("nixpkgs"), s));
        }
    }

    return result;
}

std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
    ref<Store> store, const std::string & installable)
{
    auto installables = parseInstallables(store, {installable});
    assert(installables.size() == 1);
    return installables.front();
}

Buildables build(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    if (mode != Build)
        settings.readOnlyMode = true;

    Buildables buildables;

    PathSet pathsToBuild;

    for (auto & i : installables) {
        for (auto & b : i->toBuildables()) {
            if (b.drvPath != "") {
                StringSet outputNames;
                for (auto & output : b.outputs)
                    outputNames.insert(output.first);
                pathsToBuild.insert(
                    b.drvPath + "!" + concatStringsSep(",", outputNames));
            } else
                for (auto & output : b.outputs)
                    pathsToBuild.insert(output.second);
            buildables.push_back(std::move(b));
        }
    }

    if (mode == DryRun)
        printMissing(store, pathsToBuild, lvlError);
    else if (mode == Build)
        store->buildPaths(pathsToBuild);

    return buildables;
}

PathSet toStorePaths(ref<Store> store, RealiseMode mode,
    std::vector<std::shared_ptr<Installable>> installables)
{
    PathSet outPaths;

    for (auto & b : build(store, mode, installables))
        for (auto & output : b.outputs)
            outPaths.insert(output.second);

    return outPaths;
}

Path toStorePath(ref<Store> store, RealiseMode mode,
    std::shared_ptr<Installable> installable)
{
    auto paths = toStorePaths(store, mode, {installable});

    if (paths.size() != 1)
        throw Error("argument '%s' should evaluate to one store path", installable->what());

    return *paths.begin();
}

PathSet toDerivations(ref<Store> store,
    std::vector<std::shared_ptr<Installable>> installables, bool useDeriver)
{
    PathSet drvPaths;

    for (auto & i : installables)
        for (auto & b : i->toBuildables()) {
            if (b.drvPath.empty()) {
                if (!useDeriver)
                    throw Error("argument '%s' did not evaluate to a derivation", i->what());
                for (auto & output : b.outputs) {
                    auto derivers = store->queryValidDerivers(output.second);
                    if (derivers.empty())
                        throw Error("'%s' does not have a known deriver", i->what());
                    // FIXME: use all derivers?
                    drvPaths.insert(*derivers.begin());
                }
            } else
                drvPaths.insert(b.drvPath);
        }

    return drvPaths;
}

void InstallablesCommand::prepare()
{
    installables = parseInstallables(getStore(), _installables);
}

void InstallableCommand::prepare()
{
    installable = parseInstallable(getStore(), _installable);
}

}
<|endoftext|>


<commit_before>#include "nodeevents.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/mark.h"

namespace YAML
{
	void NodeEvents::AliasManager::RegisterReference(const detail::node& node)
	{
		m_anchorByIdentity.insert(std::make_pair(node.ref(), _CreateNewAnchor()));
	}

	anchor_t NodeEvents::AliasManager::LookupAnchor(const detail::node& node) const
	{
		AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(node.ref());
		if(it == m_anchorByIdentity.end())
			return 0;
		return it->second;
	}

	NodeEvents::NodeEvents(const Node& node): m_pMemory(node.m_pMemory), m_root(*node.m_pNode)
	{
		Setup(m_root);
	}

	void NodeEvents::Setup(const detail::node& node)
	{
		int& refCount = m_refCount[node.ref()];
		refCount++;
		if(refCount > 1)
			return;

		if(node.type() == NodeType::Sequence) {
			for(detail::const_node_iterator it=node.begin();it!=node.end();++it)
				Setup(**it);
		} else if(node.type() == NodeType::Map) {
			for(detail::const_node_iterator it=node.begin();it!=node.end();++it) {
				Setup(*it->first);
				Setup(*it->second);
			}
		}
	}

	void NodeEvents::Emit(EventHandler& handler)
	{
		AliasManager am;

		handler.OnDocumentStart(Mark());
		Emit(m_root, handler, am);
		handler.OnDocumentEnd();
	}

	void NodeEvents::Emit(const detail::node& node, EventHandler& handler, AliasManager& am) const
	{
		anchor_t anchor = NullAnchor;
		if(IsAliased(node)) {
			anchor = am.LookupAnchor(node);
			if(anchor) {
				handler.OnAlias(Mark(), anchor);
				return;
			}

			am.RegisterReference(node);
			anchor = am.LookupAnchor(node);
		}

		switch(node.type()) {
			case NodeType::Undefined:
				break;
			case NodeType::Null:
				handler.OnNull(Mark(), anchor);
				break;
			case NodeType::Scalar:
				handler.OnScalar(Mark(), "", anchor, node.scalar());
				break;
			case NodeType::Sequence:
				handler.OnSequenceStart(Mark(), "", anchor);
				for(detail::const_node_iterator it=node.begin();it!=node.end();++it)
					Emit(**it, handler, am);
				handler.OnSequenceEnd();
				break;
			case NodeType::Map:
				handler.OnMapStart(Mark(), "", anchor);
				for(detail::const_node_iterator it=node.begin();it!=node.end();++it) {
					Emit(*it->first, handler, am);
					Emit(*it->second, handler, am);
				}
				handler.OnMapEnd();
				break;
		}
	}

	bool NodeEvents::IsAliased(const detail::node& node) const
	{
		RefCount::const_iterator it = m_refCount.find(node.ref());
		return it != m_refCount.end() && it->second > 1;
	}
}
<commit_msg>Added tags to Node emitter output<commit_after>#include "nodeevents.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/mark.h"

namespace YAML
{
	void NodeEvents::AliasManager::RegisterReference(const detail::node& node)
	{
		m_anchorByIdentity.insert(std::make_pair(node.ref(), _CreateNewAnchor()));
	}

	anchor_t NodeEvents::AliasManager::LookupAnchor(const detail::node& node) const
	{
		AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(node.ref());
		if(it == m_anchorByIdentity.end())
			return 0;
		return it->second;
	}

	NodeEvents::NodeEvents(const Node& node): m_pMemory(node.m_pMemory), m_root(*node.m_pNode)
	{
		Setup(m_root);
	}

	void NodeEvents::Setup(const detail::node& node)
	{
		int& refCount = m_refCount[node.ref()];
		refCount++;
		if(refCount > 1)
			return;

		if(node.type() == NodeType::Sequence) {
			for(detail::const_node_iterator it=node.begin();it!=node.end();++it)
				Setup(**it);
		} else if(node.type() == NodeType::Map) {
			for(detail::const_node_iterator it=node.begin();it!=node.end();++it) {
				Setup(*it->first);
				Setup(*it->second);
			}
		}
	}

	void NodeEvents::Emit(EventHandler& handler)
	{
		AliasManager am;

		handler.OnDocumentStart(Mark());
		Emit(m_root, handler, am);
		handler.OnDocumentEnd();
	}

	void NodeEvents::Emit(const detail::node& node, EventHandler& handler, AliasManager& am) const
	{
		anchor_t anchor = NullAnchor;
		if(IsAliased(node)) {
			anchor = am.LookupAnchor(node);
			if(anchor) {
				handler.OnAlias(Mark(), anchor);
				return;
			}

			am.RegisterReference(node);
			anchor = am.LookupAnchor(node);
		}

		switch(node.type()) {
			case NodeType::Undefined:
				break;
			case NodeType::Null:
				handler.OnNull(Mark(), anchor);
				break;
			case NodeType::Scalar:
				handler.OnScalar(Mark(), node.tag(), anchor, node.scalar());
				break;
			case NodeType::Sequence:
				handler.OnSequenceStart(Mark(), node.tag(), anchor);
				for(detail::const_node_iterator it=node.begin();it!=node.end();++it)
					Emit(**it, handler, am);
				handler.OnSequenceEnd();
				break;
			case NodeType::Map:
				handler.OnMapStart(Mark(), node.tag(), anchor);
				for(detail::const_node_iterator it=node.begin();it!=node.end();++it) {
					Emit(*it->first, handler, am);
					Emit(*it->second, handler, am);
				}
				handler.OnMapEnd();
				break;
		}
	}

	bool NodeEvents::IsAliased(const detail::node& node) const
	{
		RefCount::const_iterator it = m_refCount.find(node.ref());
		return it != m_refCount.end() && it->second > 1;
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <iostream>

#include <errno.h>
#include <fcntl.h>
#ifdef __linux__
# include <unistd.h>
# include <linux/unistd.h>
# include <sys/types.h>
#endif
#ifdef __APPLE__
// See man 3 environ (PROGRAMMING)
# include <crt_externs.h> // for _NSGetEnviron
# include <pthread.h>
#endif

#include <sys/wait.h>
#ifndef __ANDROID__
#  include <spawn.h>
#endif
#include <stdarg.h>

#include <sstream>
#include <string>

#include <boost/filesystem.hpp>
#include <locale>

#include <qi/os.hpp>
#include <qi/path.hpp>
#include "filesystem.hpp"

#include <signal.h>

namespace qi
{
  namespace os
  {

#ifdef __linux__
    /**
     * Set cloexec flag to close all FD on exec process
     * @param pID pid of the process.
     * @return 0
     */
    static int setCloexecFlag(pid_t pID)
    {
      std::string pid;
      std::stringstream ss;
      ss << pID;
      pid = ss.str();

      // get path of the current pid
      boost::filesystem::path path("/proc", qi::unicodeFacet());
      path = path / pid / "fd";

      try
      {
        // foreach fd set FD_CLOEXEC flag
        for (boost::filesystem::directory_iterator itr(path);
             itr != boost::filesystem::directory_iterator();
             ++itr)
        {
          // do not close stdin, stdout, stderr
          if (itr->path().filename() != "0"
              && itr->path().filename() != "1"
              && itr->path().filename() != "2")
          {
            // get file descriptor
            int fd;
            std::istringstream iss(itr->path().filename().string(qi::unicodeFacet()));
            iss >> fd;

            // get flags
            int oldflags = fcntl(fd, F_GETFD, 0);

            // If reading the flags failed, return error indication now.
            if (oldflags < 0)
              return oldflags;

            // Set just the flag we want to set.
            oldflags |= FD_CLOEXEC;

            // Store modified flag word in the descriptor.
            return fcntl(fd, F_SETFD, oldflags);
          }
        }
      }
      catch (...)
      {
        return 0;
      }

      return 0;
    }
#endif

    int spawnvp(char *const argv[])
    {
#ifdef __linux__
      // Set all parent FD to close them when exec
      setCloexecFlag(getpid());
#endif

      pid_t pID = -1;
      int err;
      posix_spawnattr_t* pSpawnattr = NULL;

#ifdef __linux__
      posix_spawnattr_t spawnattr;
      spawnattr.__flags = POSIX_SPAWN_USEVFORK;
      pSpawnattr = &spawnattr;
#endif

      // Err != 0 means vfork failed.
      // If exec() fails, then err = 0 and we have to get the status of the child
      // process to know what happened.
      // Note: child process environment will be the same as parent process.
      // TODO: maybe we should have a way of setting child process env?
#ifdef __linux__
      char** child_env = environ;
#else
      char*** environ_ptr = _NSGetEnviron();
      char** child_env = *environ_ptr;
#endif
      /* Upon successful completion, posix_spawn() and posix_spawnp() shall return the process ID of the child process to the parent process,
       * in the variable pointed to by a non-NULL pid argument, and shall return zero as the function return value.
       * Otherwise, no child process shall be created, the value stored into the variable pointed to by a non-NULL pid is unspecified,
       * and an error number shall be returned as the function return value to indicate the error */
      /*
       * WARNING : Today, 17/07/2012, posix_spawnp always returns 0 on linux
       */
      errno = 0;
      err = posix_spawnp(&pID,
                         argv[0],
                         NULL,
                         pSpawnattr,
                         (char* const*)argv,
                         child_env);

      if (err == EINVAL || err == ENOENT)
      {
        return -1;
      }
      if (err != 0)
      {
        return -1;
      }
      if (errno)
      {
        return -1;
      }

      return pID;
    }

    int spawnlp(const char* argv, ...)
    {
      const char* cmd[64];

      va_list ap;
      const char* arg;

      int i = 0;
      va_start(ap, argv);
      for (arg = argv; arg != NULL; arg = va_arg(ap, const char*), ++i)
        cmd[i] = arg;

      va_end(ap);
      cmd[i] = NULL;

      pid_t pID = -1;
      int err;

#ifdef __linux__
      // Set all parent FD to close them when exec
      setCloexecFlag(getpid());
#endif

      posix_spawnattr_t* pSpawnattr = NULL;

#ifdef __linux__
      posix_spawnattr_t spawnattr;
      spawnattr.__flags = POSIX_SPAWN_USEVFORK;
      pSpawnattr = &spawnattr;
#endif

      // Err != 0 means vfork failed.
      // If exec() fails, then err = 0 and we have to get the status of the child
      // process to know what happened.
      // Note: child process environment will be the same as parent process.
      // TODO: maybe we should have a way of setting child process env?
#ifdef __linux__
      char** child_env = environ;
#else
      char*** environ_ptr = _NSGetEnviron();
      char** child_env = *environ_ptr;
#endif
      /* Upon successful completion, posix_spawn() and posix_spawnp() shall return the process ID of the child process to the parent process,
       * in the variable pointed to by a non-NULL pid argument, and shall return zero as the function return value.
       * Otherwise, no child process shall be created, the value stored into the variable pointed to by a non-NULL pid is unspecified,
       * and an error number shall be returned as the function return value to indicate the error */
      /*
       * WARNING : Today, 17/07/2012, posix_spawnp always returns 0 on linux
       */
      errno = 0;
      err = posix_spawnp(&pID,
                         cmd[0],
                         NULL,
                         pSpawnattr,
                         (char* const*)cmd,
                         child_env);

      if (err == EINVAL || err == ENOENT)
      {
        return -1;
      }
      if (err != 0)
      {
        return -1;
      }
      if (errno)
      {
        return -1;
      }

      return pID;
    }

    int system(const char *command)
    {
#ifdef __linux__
      // Set all parent FD to close them when exec
      setCloexecFlag(getpid());
#endif

      int status = 0;
      pid_t pID = vfork();

      if (pID < 0)
      {
        return -1;
      }
      if (pID == 0)
      {
        // In the child process.

        // WARNING: critical code!
        // The entire process is stuck here until we call exec() or _exit.
        // Never access variables from the parent process, call another funciton, etc.
        // Just call exec right away.
        execlp("/bin/sh", "/bin/sh", "-c", command, NULL);

        // In case exec fails, we kill the child process.
        _exit(errno);
      }
      else
      {
        // Parent process.
        qi::os::waitpid(pID, &status);
        return status;
      }

      return -1;
    }

    int getpid()
    {
      return ::getpid();
    }

    int gettid()
    {
      int ret = 0;
#ifdef __linux__
      ret = syscall(__NR_gettid);
#endif
#ifdef __APPLE__
      ret = pthread_mach_thread_np(pthread_self());
#endif
      return ret;
    }

    int waitpid(int pid, int* status)
    {
      int result = 0;
      int st = 0;
      errno = 0;

      ::waitpid(pid, &st, 0);

      if (WIFSIGNALED(st))
      {
        result -= WTERMSIG(st);
        if (status)
          *status = 0;
      }
      else
      {
        result = errno;
        if (status)
          *status = WEXITSTATUS(st);
      }

#ifdef __APPLE__
      if (errno == ECHILD)
      {
        result = 0;
        if (status)
          *status = 127;
        return result;
      }
#endif

      return result;
    }

    int kill(int pid, int sig)
    {
        return ::kill(pid, sig);
    }
  }
}
<commit_msg>Simplify spawnvp<commit_after>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <iostream>

#include <errno.h>
#include <fcntl.h>
#ifdef __linux__
# include <unistd.h>
# include <linux/unistd.h>
# include <sys/types.h>
#endif
#ifdef __APPLE__
// See man 3 environ (PROGRAMMING)
# include <crt_externs.h> // for _NSGetEnviron
# include <pthread.h>
#endif

#include <sys/wait.h>
#ifndef __ANDROID__
#  include <spawn.h>
#endif
#include <stdarg.h>

#include <sstream>
#include <string>

#include <boost/filesystem.hpp>
#include <locale>

#include <qi/os.hpp>
#include <qi/path.hpp>
#include "filesystem.hpp"

#include <signal.h>

namespace qi
{
  namespace os
  {

#ifdef __linux__
    /**
     * Set cloexec flag to close all FD on exec process
     * @param pID pid of the process.
     * @return 0
     */
    static int setCloexecFlag(pid_t pID)
    {
      std::string pid;
      std::stringstream ss;
      ss << pID;
      pid = ss.str();

      // get path of the current pid
      boost::filesystem::path path("/proc", qi::unicodeFacet());
      path = path / pid / "fd";

      try
      {
        // foreach fd set FD_CLOEXEC flag
        for (boost::filesystem::directory_iterator itr(path);
             itr != boost::filesystem::directory_iterator();
             ++itr)
        {
          // do not close stdin, stdout, stderr
          if (itr->path().filename() != "0"
              && itr->path().filename() != "1"
              && itr->path().filename() != "2")
          {
            // get file descriptor
            int fd;
            std::istringstream iss(itr->path().filename().string(qi::unicodeFacet()));
            iss >> fd;

            // get flags
            int oldflags = fcntl(fd, F_GETFD, 0);

            // If reading the flags failed, return error indication now.
            if (oldflags < 0)
              return oldflags;

            // Set just the flag we want to set.
            oldflags |= FD_CLOEXEC;

            // Store modified flag word in the descriptor.
            return fcntl(fd, F_SETFD, oldflags);
          }
        }
      }
      catch (...)
      {
        return 0;
      }

      return 0;
    }
#endif

    int spawnvp(char *const argv[])
    {
#ifdef __linux__
      // Set all parent FD to close them when exec
      setCloexecFlag(getpid());
#endif

      pid_t pID = -1;
      int err;
      posix_spawnattr_t* pSpawnattr = NULL;

#ifdef __linux__
      posix_spawnattr_t spawnattr;
      spawnattr.__flags = POSIX_SPAWN_USEVFORK;
      pSpawnattr = &spawnattr;
#endif

      // Err != 0 means vfork failed.
      // If exec() fails, then err = 0 and we have to get the status of the child
      // process to know what happened.
      // Note: child process environment will be the same as parent process.
      // TODO: maybe we should have a way of setting child process env?
#ifdef __linux__
      char** child_env = environ;
#else
      char*** environ_ptr = _NSGetEnviron();
      char** child_env = *environ_ptr;
#endif
      /* Upon successful completion, posix_spawn() and posix_spawnp() shall return the process ID of the child process to the parent process,
       * in the variable pointed to by a non-NULL pid argument, and shall return zero as the function return value.
       * Otherwise, no child process shall be created, the value stored into the variable pointed to by a non-NULL pid is unspecified,
       * and an error number shall be returned as the function return value to indicate the error */
      /*
       * WARNING : Today, 17/07/2012, posix_spawnp always returns 0 on linux
       */
      errno = 0;
      err = posix_spawnp(&pID,
                         argv[0],
                         NULL,
                         pSpawnattr,
                         (char* const*)argv,
                         child_env);

      if (err != 0 | errno)
      {
        return -1;
      }

      return pID;
    }

    int spawnlp(const char* argv, ...)
    {
      const char* cmd[64];

      va_list ap;
      const char* arg;

      int i = 0;
      va_start(ap, argv);
      for (arg = argv; arg != NULL; arg = va_arg(ap, const char*), ++i)
        cmd[i] = arg;

      va_end(ap);
      cmd[i] = NULL;

      return spawnvp(cmd);
    }

    int system(const char *command)
    {
#ifdef __linux__
      // Set all parent FD to close them when exec
      setCloexecFlag(getpid());
#endif

      int status = 0;
      pid_t pID = vfork();

      if (pID < 0)
      {
        return -1;
      }
      if (pID == 0)
      {
        // In the child process.

        // WARNING: critical code!
        // The entire process is stuck here until we call exec() or _exit.
        // Never access variables from the parent process, call another funciton, etc.
        // Just call exec right away.
        execlp("/bin/sh", "/bin/sh", "-c", command, NULL);

        // In case exec fails, we kill the child process.
        _exit(errno);
      }
      else
      {
        // Parent process.
        qi::os::waitpid(pID, &status);
        return status;
      }

      return -1;
    }

    int getpid()
    {
      return ::getpid();
    }

    int gettid()
    {
      int ret = 0;
#ifdef __linux__
      ret = syscall(__NR_gettid);
#endif
#ifdef __APPLE__
      ret = pthread_mach_thread_np(pthread_self());
#endif
      return ret;
    }

    int waitpid(int pid, int* status)
    {
      int result = 0;
      int st = 0;
      errno = 0;

      ::waitpid(pid, &st, 0);

      if (WIFSIGNALED(st))
      {
        result -= WTERMSIG(st);
        if (status)
          *status = 0;
      }
      else
      {
        result = errno;
        if (status)
          *status = WEXITSTATUS(st);
      }

#ifdef __APPLE__
      if (errno == ECHILD)
      {
        result = 0;
        if (status)
          *status = 127;
        return result;
      }
#endif

      return result;
    }

    int kill(int pid, int sig)
    {
        return ::kill(pid, sig);
    }
  }
}
<|endoftext|>


<commit_before>//
//  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

const char *binstr(int v, int n)
{
	static char buffer[16];
	char *p = buffer;

	for (int i = n-1; i >= 0; i--)
		*(p++) = ((v >> i) & 1) ? '1' : '0';
	*(p++) = 0;

	return buffer;
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options]\n", cmd);
	printf("\n");
	printf("    -i <input_freq_mhz>\n");
	printf("        PLL Input Frequency (default: 12 MHz)\n");
	printf("\n");
	printf("    -o <output_freq_mhz>\n");
	printf("        PLL Output Frequency (default: 60 MHz)\n");
	printf("\n");
	printf("    -S\n");
	printf("        Disable SIMPLE feedback path mode\n");
	printf("\n");
	printf("    -f <filename>\n");
	printf("        Save PLL configuration as Verilog to file\n");
	printf("\n");
	printf("    -m\n");
	printf("        Save PLL configuration as Verilog module (use with -f)\n");
	printf("\n");
	printf("    -q\n");
	printf("        Do not print PLL configuration to stdout\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	double f_pllin = 12;
	double f_pllout = 60;
	bool simple_feedback = true;
	char* filename = NULL;
	bool save_as_module = false;
	bool quiet = false;

	int opt;
	while ((opt = getopt(argc, argv, "i:o:Smf:q")) != -1)
	{
		switch (opt)
		{
		case 'i':
			f_pllin = atof(optarg);
			break;
		case 'o':
			f_pllout = atof(optarg);
			break;
		case 'S':
			simple_feedback = false;
			break;
		case 'm':
			save_as_module = true;
			break;
		case 'f':
			filename = optarg;
			break;
		case 'q':
			quiet = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (optind != argc)
		help(argv[0]);

	// error: shall save as module, but no filename was given
	if (save_as_module && filename == NULL)
		help(argv[0]);

	bool found_something = false;
	double best_fout = 0;
	int best_divr = 0;
	int best_divf = 0;
	int best_divq = 0;

	if (f_pllin < 10 || f_pllin > 133) {
		fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
		exit(1);
	}

	if (f_pllout < 16 || f_pllout > 275) {
		fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
		exit(1);
	}

	for (int divr = 0; divr <= 15; divr++)
	{
		double f_pfd = f_pllin / (divr + 1);
		if (f_pfd < 10 || f_pfd > 133) continue;

		for (int divf = 0; divf <= 63; divf++)
		{
			if (simple_feedback)
			{
				double f_vco = f_pfd * (divf + 1);
				if (f_vco < 533 || f_vco > 1066) continue;

				for (int divq = 1; divq <= 6; divq++)
				{
					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
			else
			{
				for (int divq = 1; divq <= 6; divq++)
				{
					double f_vco = f_pfd * (divf + 1) * exp2(divq);
					if (f_vco < 533 || f_vco > 1066) continue;

					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
		}
	}

	double f_pfd = f_pllin / (best_divr + 1);;
	double f_vco = f_pfd * (best_divf + 1);

	int filter_range =
			f_pfd < 17 ? 1 :
			f_pfd < 26 ? 2 :
			f_pfd < 44 ? 3 :
			f_pfd < 66 ? 4 :
			f_pfd < 101 ? 5 : 6;

	if (!simple_feedback)
		f_vco *= exp2(best_divq);

	if (!found_something) {
		fprintf(stderr, "Error: No valid configuration found!\n");
		exit(1);
	}

	if (!quiet)
	{
		printf("\n");

		printf("F_PLLIN:  %8.3f MHz (given)\n", f_pllin);
		printf("F_PLLOUT: %8.3f MHz (requested)\n", f_pllout);
		printf("F_PLLOUT: %8.3f MHz (achieved)\n", best_fout);

		printf("\n");

		printf("FEEDBACK: %s\n", simple_feedback ? "SIMPLE" : "NON_SIMPLE");
		printf("F_PFD: %8.3f MHz\n", f_pfd);
		printf("F_VCO: %8.3f MHz\n", f_vco);

		printf("\n");

		printf("DIVR: %2d (4'b%s)\n", best_divr, binstr(best_divr, 4));
		printf("DIVF: %2d (7'b%s)\n", best_divf, binstr(best_divf, 7));
		printf("DIVQ: %2d (3'b%s)\n", best_divq, binstr(best_divq, 3));

		printf("\n");

		printf("FILTER_RANGE: %d (3'b%s)\n", filter_range, binstr(filter_range, 3));

		printf("\n");
	}

	// save PLL configuration as file
	if (filename != NULL)
	{
		// open file for writing
		FILE *f;
		f = fopen(filename, "w");

		if (save_as_module)
		{
			// save PLL configuration as Verilog module

			// header
			fprintf(f, "/**\n * PLL configuration\n *\n"
						" * This Verilog module was generated automatically\n"
						" * using the icepll tool from the IceStorm project.\n"
						" * Use at your own risk.\n"
						" *\n"
						" * Given input frequency:      %8.3f MHz\n"
						" * Requested output frequency: %8.3f MHz\n"
						" * Achieved output frequency:  %8.3f MHz\n"
						" */\n\n",
						f_pllin, f_pllout, best_fout);

			// generate Verilog module
			fprintf(f,  "module pll(\n"
						"\tinput  clock_in,\n"
						"\toutput clock_out,\n"
						"\toutput locked\n"
						"\t);\n\n"
					);

			// save iCE40 PLL tile configuration
			fprintf(f, "SB_PLL40_CORE #(\n");
			fprintf(f, "\t\t.FEEDBACK_PATH(\"%s\"),\n", (simple_feedback ? "SIMPLE" : "NON_SIMPLE"));
			fprintf(f, "\t\t.DIVR(4'b%s),\t\t"      "// DIVR = %2d\n", binstr(best_divr, 4), best_divr);
			fprintf(f, "\t\t.DIVF(7'b%s),\t"        "// DIVF = %2d\n", binstr(best_divf, 7), best_divf);
			fprintf(f, "\t\t.DIVQ(3'b%s),\t\t"      "// DIVQ = %2d\n", binstr(best_divq, 3), best_divq);
			fprintf(f, "\t\t.FILTER_RANGE(3'b%s)\t" "// FILTER_RANGE = %d\n", binstr(filter_range, 3), filter_range);
			fprintf(f, "\t) uut (\n"
						"\t\t.LOCK(locked),\n"
						"\t\t.RESETB(1'b1),\n"
						"\t\t.BYPASS(1'b0),\n"
						"\t\t.REFERENCECLK(clock_in),\n"
						"\t\t.PLLOUTCORE(clock_out),\n"
						"\t\t);\n\n"
					);

			fprintf(f, "endmodule\n");
		}
		else
		{
			// only save PLL configuration values

			// header
			fprintf(f, "/**\n * PLL configuration\n *\n"
						" * This Verilog header file was generated automatically\n"
						" * using the icepll tool from the IceStorm project.\n"
						" * It is intended for use with FPGA primitives SB_PLL40_CORE,\n"
						" * SB_PLL40_PAD, SB_PLL40_2_PAD, SB_PLL40_2F_CORE or SB_PLL40_2F_PAD.\n"
						" * Use at your own risk.\n"
						" *\n"
						" * Given input frequency:      %8.3f MHz\n"
						" * Requested output frequency: %8.3f MHz\n"
						" * Achieved output frequency:  %8.3f MHz\n"
						" */\n\n",
						f_pllin, f_pllout, best_fout);

			// PLL configuration
			fprintf(f, ".FEEDBACK_PATH(\"%s\"),\n", (simple_feedback ? "SIMPLE" : "NON_SIMPLE"));
			fprintf(f, ".DIVR(4'b%s),\t\t"      "// DIVR = %2d\n", binstr(best_divr, 4), best_divr);
			fprintf(f, ".DIVF(7'b%s),\t"        "// DIVF = %2d\n", binstr(best_divf, 7), best_divf);
			fprintf(f, ".DIVQ(3'b%s),\t\t"      "// DIVQ = %2d\n", binstr(best_divq, 3), best_divq);
			fprintf(f, ".FILTER_RANGE(3'b%s)\t" "// FILTER_RANGE = %d\n", binstr(filter_range, 3), filter_range);
		}

		fclose(f);

		printf("PLL configuration written to: %s\n", filename);
	}

	return 0;
}
<commit_msg>Remove trailing comma in icepll module output.<commit_after>//
//  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

const char *binstr(int v, int n)
{
	static char buffer[16];
	char *p = buffer;

	for (int i = n-1; i >= 0; i--)
		*(p++) = ((v >> i) & 1) ? '1' : '0';
	*(p++) = 0;

	return buffer;
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options]\n", cmd);
	printf("\n");
	printf("    -i <input_freq_mhz>\n");
	printf("        PLL Input Frequency (default: 12 MHz)\n");
	printf("\n");
	printf("    -o <output_freq_mhz>\n");
	printf("        PLL Output Frequency (default: 60 MHz)\n");
	printf("\n");
	printf("    -S\n");
	printf("        Disable SIMPLE feedback path mode\n");
	printf("\n");
	printf("    -f <filename>\n");
	printf("        Save PLL configuration as Verilog to file\n");
	printf("\n");
	printf("    -m\n");
	printf("        Save PLL configuration as Verilog module (use with -f)\n");
	printf("\n");
	printf("    -q\n");
	printf("        Do not print PLL configuration to stdout\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	double f_pllin = 12;
	double f_pllout = 60;
	bool simple_feedback = true;
	char* filename = NULL;
	bool save_as_module = false;
	bool quiet = false;

	int opt;
	while ((opt = getopt(argc, argv, "i:o:Smf:q")) != -1)
	{
		switch (opt)
		{
		case 'i':
			f_pllin = atof(optarg);
			break;
		case 'o':
			f_pllout = atof(optarg);
			break;
		case 'S':
			simple_feedback = false;
			break;
		case 'm':
			save_as_module = true;
			break;
		case 'f':
			filename = optarg;
			break;
		case 'q':
			quiet = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (optind != argc)
		help(argv[0]);

	// error: shall save as module, but no filename was given
	if (save_as_module && filename == NULL)
		help(argv[0]);

	bool found_something = false;
	double best_fout = 0;
	int best_divr = 0;
	int best_divf = 0;
	int best_divq = 0;

	if (f_pllin < 10 || f_pllin > 133) {
		fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
		exit(1);
	}

	if (f_pllout < 16 || f_pllout > 275) {
		fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
		exit(1);
	}

	for (int divr = 0; divr <= 15; divr++)
	{
		double f_pfd = f_pllin / (divr + 1);
		if (f_pfd < 10 || f_pfd > 133) continue;

		for (int divf = 0; divf <= 63; divf++)
		{
			if (simple_feedback)
			{
				double f_vco = f_pfd * (divf + 1);
				if (f_vco < 533 || f_vco > 1066) continue;

				for (int divq = 1; divq <= 6; divq++)
				{
					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
			else
			{
				for (int divq = 1; divq <= 6; divq++)
				{
					double f_vco = f_pfd * (divf + 1) * exp2(divq);
					if (f_vco < 533 || f_vco > 1066) continue;

					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
		}
	}

	double f_pfd = f_pllin / (best_divr + 1);;
	double f_vco = f_pfd * (best_divf + 1);

	int filter_range =
			f_pfd < 17 ? 1 :
			f_pfd < 26 ? 2 :
			f_pfd < 44 ? 3 :
			f_pfd < 66 ? 4 :
			f_pfd < 101 ? 5 : 6;

	if (!simple_feedback)
		f_vco *= exp2(best_divq);

	if (!found_something) {
		fprintf(stderr, "Error: No valid configuration found!\n");
		exit(1);
	}

	if (!quiet)
	{
		printf("\n");

		printf("F_PLLIN:  %8.3f MHz (given)\n", f_pllin);
		printf("F_PLLOUT: %8.3f MHz (requested)\n", f_pllout);
		printf("F_PLLOUT: %8.3f MHz (achieved)\n", best_fout);

		printf("\n");

		printf("FEEDBACK: %s\n", simple_feedback ? "SIMPLE" : "NON_SIMPLE");
		printf("F_PFD: %8.3f MHz\n", f_pfd);
		printf("F_VCO: %8.3f MHz\n", f_vco);

		printf("\n");

		printf("DIVR: %2d (4'b%s)\n", best_divr, binstr(best_divr, 4));
		printf("DIVF: %2d (7'b%s)\n", best_divf, binstr(best_divf, 7));
		printf("DIVQ: %2d (3'b%s)\n", best_divq, binstr(best_divq, 3));

		printf("\n");

		printf("FILTER_RANGE: %d (3'b%s)\n", filter_range, binstr(filter_range, 3));

		printf("\n");
	}

	// save PLL configuration as file
	if (filename != NULL)
	{
		// open file for writing
		FILE *f;
		f = fopen(filename, "w");

		if (save_as_module)
		{
			// save PLL configuration as Verilog module

			// header
			fprintf(f, "/**\n * PLL configuration\n *\n"
						" * This Verilog module was generated automatically\n"
						" * using the icepll tool from the IceStorm project.\n"
						" * Use at your own risk.\n"
						" *\n"
						" * Given input frequency:      %8.3f MHz\n"
						" * Requested output frequency: %8.3f MHz\n"
						" * Achieved output frequency:  %8.3f MHz\n"
						" */\n\n",
						f_pllin, f_pllout, best_fout);

			// generate Verilog module
			fprintf(f,  "module pll(\n"
						"\tinput  clock_in,\n"
						"\toutput clock_out,\n"
						"\toutput locked\n"
						"\t);\n\n"
					);

			// save iCE40 PLL tile configuration
			fprintf(f, "SB_PLL40_CORE #(\n");
			fprintf(f, "\t\t.FEEDBACK_PATH(\"%s\"),\n", (simple_feedback ? "SIMPLE" : "NON_SIMPLE"));
			fprintf(f, "\t\t.DIVR(4'b%s),\t\t"      "// DIVR = %2d\n", binstr(best_divr, 4), best_divr);
			fprintf(f, "\t\t.DIVF(7'b%s),\t"        "// DIVF = %2d\n", binstr(best_divf, 7), best_divf);
			fprintf(f, "\t\t.DIVQ(3'b%s),\t\t"      "// DIVQ = %2d\n", binstr(best_divq, 3), best_divq);
			fprintf(f, "\t\t.FILTER_RANGE(3'b%s)\t" "// FILTER_RANGE = %d\n", binstr(filter_range, 3), filter_range);
			fprintf(f, "\t) uut (\n"
						"\t\t.LOCK(locked),\n"
						"\t\t.RESETB(1'b1),\n"
						"\t\t.BYPASS(1'b0),\n"
						"\t\t.REFERENCECLK(clock_in),\n"
						"\t\t.PLLOUTCORE(clock_out)\n"
						"\t\t);\n\n"
					);

			fprintf(f, "endmodule\n");
		}
		else
		{
			// only save PLL configuration values

			// header
			fprintf(f, "/**\n * PLL configuration\n *\n"
						" * This Verilog header file was generated automatically\n"
						" * using the icepll tool from the IceStorm project.\n"
						" * It is intended for use with FPGA primitives SB_PLL40_CORE,\n"
						" * SB_PLL40_PAD, SB_PLL40_2_PAD, SB_PLL40_2F_CORE or SB_PLL40_2F_PAD.\n"
						" * Use at your own risk.\n"
						" *\n"
						" * Given input frequency:      %8.3f MHz\n"
						" * Requested output frequency: %8.3f MHz\n"
						" * Achieved output frequency:  %8.3f MHz\n"
						" */\n\n",
						f_pllin, f_pllout, best_fout);

			// PLL configuration
			fprintf(f, ".FEEDBACK_PATH(\"%s\"),\n", (simple_feedback ? "SIMPLE" : "NON_SIMPLE"));
			fprintf(f, ".DIVR(4'b%s),\t\t"      "// DIVR = %2d\n", binstr(best_divr, 4), best_divr);
			fprintf(f, ".DIVF(7'b%s),\t"        "// DIVF = %2d\n", binstr(best_divf, 7), best_divf);
			fprintf(f, ".DIVQ(3'b%s),\t\t"      "// DIVQ = %2d\n", binstr(best_divq, 3), best_divq);
			fprintf(f, ".FILTER_RANGE(3'b%s)\t" "// FILTER_RANGE = %d\n", binstr(filter_range, 3), filter_range);
		}

		fclose(f);

		printf("PLL configuration written to: %s\n", filename);
	}

	return 0;
}
<|endoftext|>


<commit_before>/**
 * Request.h
 *
 *      Author: Sara Vallero
 *      Author: Valentina Zaccolo
 */
#include "FassDb.h"
#include "FassLog.h"

#include <fstream>
#include <sstream>
#include <stdexcept>
#include <unistd.h>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

using boost::asio::ip::tcp;
using namespace std;

bool InfluxDb::init_db(){

    ostringstream oss;
    oss << "Initializing database \"" << _dbname << "\" at http://" << _endpoint << ":" << _port;
    FassLog::log("INFLUXDB", Log::INFO, oss);

    string response;
    bool rc;

    // ping endpoint
    rc = InfluxDb::ping_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Could not ping DB!");
        return false;
    }
    // create a new database, the action has no effect if the database already exists
    rc = InfluxDb::create_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Error creating database!");
    }

    return true;
}

bool InfluxDb::query_db(string method, string q, string &retval){

    // for the time being we let it hardcoded
    const string protocol("HTTP/1.0");
    //FassLog::log("SARA", Log::INFO, "Starting query");

    try{
       // Taken form an example in the boost documentation
       boost::asio::io_service io_service;

       // Get a list of endpoints corresponding to the server name
       tcp::resolver resolver(io_service);
       tcp::resolver::query query(_endpoint, boost::lexical_cast<string>(_port));
       tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

       // Try each endpoint until we successfully establish a connection
       tcp::socket socket(io_service);
       boost::asio::connect(socket, endpoint_iterator);

       // Form the request. We specify the "Connection: close" header so that the
       // server will close the socket after transmitting the response. This will
       // allow us to treat all data up until the EOF as the content
       boost::asio::streambuf request;
       std::ostream request_stream(&request);
       //request_stream << "GET " << "/ping" << " HTTP/1.0\r\n";
       //request_stream << method << " " << "/ping" << " HTTP/1.0\r\n";
       //string search = "show%20databases";
       //request_stream << method << " " << "/query?pretty=true&db=" << _dbname << "&q=" << search << " " << protocol << "\r\n";
       request_stream << method << " " << q << " " << protocol << "\r\n";
       request_stream << "Host: " << _endpoint << "\r\n";
       request_stream << "Accept: */*\r\n";
       request_stream << "Content-Type: application/x-www-form-urlencoded\r\n";
       request_stream << "Connection: close\r\n\r\n";

       // Send the request
       boost::asio::write(socket, request);

       // Read the response status line. The response streambuf will automatically
       // grow to accommodate the entire line. The growth may be limited by passing
       // a maximum size to the streambuf constructor
       boost::asio::streambuf response;
       boost::asio::read_until(socket, response, "\r\n");

       // Check that response is OK
       std::istream response_stream(&response);
       std::string http_version;
       response_stream >> http_version;
       unsigned int status_code;
       response_stream >> status_code;
       std::string status_message;
       std::getline(response_stream, status_message);
       if (!response_stream || http_version.substr(0, 5) != "HTTP/"){
                retval="Invalid response.";
       		FassLog::log("DB-QUERY", Log::ERROR, retval);
                return false;
       }
       if (status_code != 200 && status_code != 204){ // ping success results in 204
	       ostringstream oss_sc;
	       oss_sc << "Response returned with status code " << status_code;
               //retval=oss_sc.str();
               retval=status_message;
       	       FassLog::log("DB_QUERY", Log::ERROR, retval);
               return false;
       }
       if (status_code == 204 ){ // ping success results in 204
       	       FassLog::log("DB-QUERY", Log::DDEBUG, "Success pinging InfluxDb!");
               return true;
       }

       // Read the response headers, which are terminated by a blank line
       boost::asio::read_until(socket, response, "\r\n\r\n");

       // Process the response headers
       ostringstream oss_h;
       std::string header;
       while (std::getline(response_stream, header) && header != "\r")
               oss_h  << header << "\n";
       oss_h << "\n";

       // Write whatever content we already have to output
       if (response.size() > 0)  oss_h << &response;
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_h);

       // Read until EOF, writing data to output as we go
       boost::system::error_code error;
       ostringstream oss_r;
       while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error))
               oss_r << &response;
       if (error != boost::asio::error::eof)
               throw boost::system::system_error(error);
       retval=oss_r.str();
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_r);
    } catch (std::exception& e){
       ostringstream oss_e;
       oss_e << e.what();
       FassLog::log("DB-QUERY", Log::ERROR, oss_e);
       retval=oss_e.str();
       return false;
    }

    return true;

}

bool InfluxDb::ping_db(){

    string response;
    bool retval=InfluxDb::query_db("GET", "/ping", response);
    return retval;
}

bool InfluxDb::create_db(){

    string response;
    ostringstream query;
    query << "/query?pretty=true&q=create%20database%20" << _dbname;
    bool retval=InfluxDb::query_db("POST", query.str(), response);
    return retval;
}

bool InfluxDb::write_initial_shares(const float share, const string user, const string group, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing initial shares.");

    return true;

}

bool InfluxDb::write_queue(const int priority, const string user, const string group, const int vmid,  const float cpus, const float memory, const long int starttime, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing queue.");

    return true;
}

bool InfluxDb::write_usage(const float cpu_usage, const float memory_usage, const string user, const string group, const long int since, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing usage records.");

    return true;
}
<commit_msg>Update InfluxDb.cc<commit_after>/**
 * Copyright © 2017 INFN Torino - INDIGO-DataCloud
 *
 * 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 "FassDb.h"
#include "FassLog.h"

#include <fstream>
#include <sstream>
#include <stdexcept>
#include <unistd.h>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

using boost::asio::ip::tcp;
using namespace std;

bool InfluxDb::init_db(){

    ostringstream oss;
    oss << "Initializing database \"" << _dbname << "\" at http://" << _endpoint << ":" << _port;
    FassLog::log("INFLUXDB", Log::INFO, oss);

    string response;
    bool rc;

    // ping endpoint
    rc = InfluxDb::ping_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Could not ping DB!");
        return false;
    }
    // create a new database, the action has no effect if the database already exists
    rc = InfluxDb::create_db();
    if ( !rc ) {
    	FassLog::log("INFLUXDB", Log::ERROR, "Error creating database!");
    }

    return true;
}

bool InfluxDb::query_db(string method, string q, string &retval){

    // for the time being we let it hardcoded
    const string protocol("HTTP/1.0");
    //FassLog::log("SARA", Log::INFO, "Starting query");

    try{
       // Taken form an example in the boost documentation
       boost::asio::io_service io_service;

       // Get a list of endpoints corresponding to the server name
       tcp::resolver resolver(io_service);
       tcp::resolver::query query(_endpoint, boost::lexical_cast<string>(_port));
       tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

       // Try each endpoint until we successfully establish a connection
       tcp::socket socket(io_service);
       boost::asio::connect(socket, endpoint_iterator);

       // Form the request. We specify the "Connection: close" header so that the
       // server will close the socket after transmitting the response. This will
       // allow us to treat all data up until the EOF as the content
       boost::asio::streambuf request;
       std::ostream request_stream(&request);
       //request_stream << "GET " << "/ping" << " HTTP/1.0\r\n";
       //request_stream << method << " " << "/ping" << " HTTP/1.0\r\n";
       //string search = "show%20databases";
       //request_stream << method << " " << "/query?pretty=true&db=" << _dbname << "&q=" << search << " " << protocol << "\r\n";
       request_stream << method << " " << q << " " << protocol << "\r\n";
       request_stream << "Host: " << _endpoint << "\r\n";
       request_stream << "Accept: */*\r\n";
       request_stream << "Content-Type: application/x-www-form-urlencoded\r\n";
       request_stream << "Connection: close\r\n\r\n";

       // Send the request
       boost::asio::write(socket, request);

       // Read the response status line. The response streambuf will automatically
       // grow to accommodate the entire line. The growth may be limited by passing
       // a maximum size to the streambuf constructor
       boost::asio::streambuf response;
       boost::asio::read_until(socket, response, "\r\n");

       // Check that response is OK
       std::istream response_stream(&response);
       std::string http_version;
       response_stream >> http_version;
       unsigned int status_code;
       response_stream >> status_code;
       std::string status_message;
       std::getline(response_stream, status_message);
       if (!response_stream || http_version.substr(0, 5) != "HTTP/"){
                retval="Invalid response.";
       		FassLog::log("DB-QUERY", Log::ERROR, retval);
                return false;
       }
       if (status_code != 200 && status_code != 204){ // ping success results in 204
	       ostringstream oss_sc;
	       oss_sc << "Response returned with status code " << status_code;
               //retval=oss_sc.str();
               retval=status_message;
       	       FassLog::log("DB_QUERY", Log::ERROR, retval);
               return false;
       }
       if (status_code == 204 ){ // ping success results in 204
       	       FassLog::log("DB-QUERY", Log::DDEBUG, "Success pinging InfluxDb!");
               return true;
       }

       // Read the response headers, which are terminated by a blank line
       boost::asio::read_until(socket, response, "\r\n\r\n");

       // Process the response headers
       ostringstream oss_h;
       std::string header;
       while (std::getline(response_stream, header) && header != "\r")
               oss_h  << header << "\n";
       oss_h << "\n";

       // Write whatever content we already have to output
       if (response.size() > 0)  oss_h << &response;
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_h);

       // Read until EOF, writing data to output as we go
       boost::system::error_code error;
       ostringstream oss_r;
       while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error))
               oss_r << &response;
       if (error != boost::asio::error::eof)
               throw boost::system::system_error(error);
       retval=oss_r.str();
       FassLog::log("DB-QUERY", Log::DDEBUG, oss_r);
    } catch (std::exception& e){
       ostringstream oss_e;
       oss_e << e.what();
       FassLog::log("DB-QUERY", Log::ERROR, oss_e);
       retval=oss_e.str();
       return false;
    }

    return true;

}

bool InfluxDb::ping_db(){

    string response;
    bool retval=InfluxDb::query_db("GET", "/ping", response);
    return retval;
}

bool InfluxDb::create_db(){

    string response;
    ostringstream query;
    query << "/query?pretty=true&q=create%20database%20" << _dbname;
    bool retval=InfluxDb::query_db("POST", query.str(), response);
    return retval;
}

bool InfluxDb::write_initial_shares(const float share, const string user, const string group, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing initial shares.");

    return true;

}

bool InfluxDb::write_queue(const int priority, const string user, const string group, const int vmid,  const float cpus, const float memory, const long int starttime, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing queue.");

    return true;
}

bool InfluxDb::write_usage(const float cpu_usage, const float memory_usage, const string user, const string group, const long int since, const long int timestamp){

    FassLog::log("INFLUXDB", Log::INFO, "Writing usage records.");

    return true;
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// Syslog plugin (UDP)

#include <os>
#include <plugins/syslogd.hpp>
#include <service>
#include <net/inet4>
#include <errno.h>		// errno
#include <unistd.h>		// getpid

#include <syslog.h> 								// POSIX symbolic constants
#include <util/syslogd.hpp>					// Header with weak method declarations
#include <util/syslog_facility.hpp>	// Header with weak method declarations

// ------------------------- Syslog_facility -----------------------------

void Syslog_facility::syslog(const std::string& log_message) {
	if (logopt_ & LOG_CONS /*and priority_ == LOG_ERR*/)
		std::cout << log_message.c_str() << '\n';

  if (logopt_ & LOG_PERROR)
    std::cerr << log_message.c_str() << '\n';

  send_udp_data(log_message);
}

Syslog_facility::~Syslog_facility() {
  if (sock_)
    sock_->udp().close(sock_->local_port());
}

void Syslog_facility::open_socket() {
  if (sock_ == nullptr)
    sock_ = &net::Inet4::stack<>().udp().bind();
}

void Syslog_facility::close_socket() {
	if (sock_) {
    sock_->udp().close(sock_->local_port());
    sock_ = nullptr;	// Necessary?
	}
}

void Syslog_facility::send_udp_data(const std::string& data) {
  open_socket();
  sock_->sendto( net::Inet4::stack().gateway(), UDP_PORT, data.c_str(), data.size() );
}

// ----------------------------- Syslog ---------------------------------

void Syslog::syslog(const int priority, const char* buf) {

	/*
  	All syslog-calls comes through here in the end, so
  	here we want to format the log-message with header and body
  */

	// % is kept if calling this with %m and no arguments

	/* If the priority is not valid, call syslog again with LOG_ERR as priority
		 and an unknown priority-message
		 Could also document by setting logopt to LOG_PID | LOG_CONS | LOG_PERROR, but
		 then only for this specific message */
  if (not valid_priority(priority)) {
  	syslog(LOG_ERR, "Syslog: Unknown priority %d. Message: %s", priority, buf);
    return;
  }

 	fac_->set_priority(priority);

 	/* Building the log message based on RFC5424 */

 	/* Header: PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID */

 	// First: Priority- and facility-value (PRIVAL) and Syslog-version
 	std::string message = "<" + std::to_string(fac_->calculate_pri()) + ">1 ";

 	// Second: Timestamp
 	char timebuf[TIMELEN];
 	time_t now;
 	time(&now);
 	strftime(timebuf, TIMELEN, "%FT%T.000Z", localtime(&now));

 	// Third: Hostname ( Preferably: 1. FQDN (RFC1034) 2. Static IP address 3. Hostname 4. Dynamic IP address 5. NILVALUE (-) )
 	message += std::string{timebuf} + " " + net::Inet4::stack().ip_addr().str() + " ";

 	// Fourth: App-name, PROCID (LOG_PID) and MSGID
 	message += Service::binary_name() + " " + std::to_string(getpid()) + " UDPOUT ";

 	/* Structured data: SD-element (SD-ID PARAM-NAME=PARAM-VALUE) */
 	message += "- ";	// NILVALUE

 	/* Message */

 	// Add ident before message (buf) if is set (through openlog)
 	if (fac_->ident_is_set())
 		message += std::string{fac_->ident()} + " ";

 	/*
 		%m:
		(The message body is generated from the message (argument) and following arguments
		in the same manner as if these were arguments to printf(), except that the additional
		conversion specification %m shall be recognized;)
		it shall convert no arguments, shall cause the output of the error message string
		associated with the value of errno on entry to syslog(), and may be mixed with argument
		specifications of the "%n$" form. If a complete conversion specification with the m conversion
		specifier character is not just %m, the behavior is undefined. A trailing <newline> may be
		added if needed.
	*/
  // Handle %m (replace it with strerror(errno)) and add the message (buf)
  std::regex m_regex{"\\%m"};
  message += std::regex_replace(buf, m_regex, strerror(errno));

 	/* Last: Send the log string */
 	fac_->syslog(message);
}

void Syslog::openlog(const char* ident, int logopt, int facility) {
	fac_->set_ident(ident);

  if (valid_logopt(logopt) or logopt == 0)  // Should be possible to clear the logopt
    fac_->set_logopt(logopt);
  else
  	fac_->set_logopt(0);	// Because of call to openlog from closelog

  if (valid_facility(facility))
    fac_->set_facility(facility);

  if (logopt & LOG_NDELAY) {
    // Connect to syslog daemon immediately
    fac_->open_socket();
  }
  /*else if (logopt & LOG_ODELAY) {
    // Delay open until syslog() is called = do nothing (the converse of LOG_NDELAY)
  }*/

  /*if (logopt & LOG_NOWAIT) {
    // Do not wait for child processes - deprecated
  }*/
}

void Syslog::closelog() {
  // Back to default values:
  // ident_ = nullptr;
  // logopt = 0;
  // facility = LOG_USER;
  openlog(nullptr, 0, LOG_USER);
  fac_->close_socket();
}<commit_msg>Syslog plugin attribute constructor added<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// Syslog plugin (UDP)

#include <os>
#include <plugins/syslogd.hpp>
#include <service>
#include <net/inet4>
#include <errno.h>		// errno
#include <unistd.h>		// getpid

#include <syslog.h> 								// POSIX symbolic constants
#include <util/syslogd.hpp>					// Header with weak method declarations
#include <util/syslog_facility.hpp>	// Header with weak method declarations
#include <info>                     // INFO

// ------------------------- Syslog_facility -----------------------------

void Syslog_facility::syslog(const std::string& log_message) {
	if (logopt_ & LOG_CONS /*and priority_ == LOG_ERR*/)
		std::cout << log_message.c_str() << '\n';

  if (logopt_ & LOG_PERROR)
    std::cerr << log_message.c_str() << '\n';

  send_udp_data(log_message);
}

Syslog_facility::~Syslog_facility() {
  if (sock_)
    sock_->udp().close(sock_->local_port());
}

void Syslog_facility::open_socket() {
  if (sock_ == nullptr)
    sock_ = &net::Inet4::stack<>().udp().bind();
}

void Syslog_facility::close_socket() {
	if (sock_) {
    sock_->udp().close(sock_->local_port());
    sock_ = nullptr;	// Necessary?
	}
}

void Syslog_facility::send_udp_data(const std::string& data) {
  open_socket();
  sock_->sendto( net::Inet4::stack().gateway(), UDP_PORT, data.c_str(), data.size() );
}

// ----------------------------- Syslog ---------------------------------

void Syslog::syslog(const int priority, const char* buf) {

	/*
  	All syslog-calls comes through here in the end, so
  	here we want to format the log-message with header and body
  */

	// % is kept if calling this with %m and no arguments

	/* If the priority is not valid, call syslog again with LOG_ERR as priority
		 and an unknown priority-message
		 Could also document by setting logopt to LOG_PID | LOG_CONS | LOG_PERROR, but
		 then only for this specific message */
  if (not valid_priority(priority)) {
  	syslog(LOG_ERR, "Syslog: Unknown priority %d. Message: %s", priority, buf);
    return;
  }

 	fac_->set_priority(priority);

 	/* Building the log message based on RFC5424 */

 	/* Header: PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID */

 	// First: Priority- and facility-value (PRIVAL) and Syslog-version
 	std::string message = "<" + std::to_string(fac_->calculate_pri()) + ">1 ";

 	// Second: Timestamp
 	char timebuf[TIMELEN];
 	time_t now;
 	time(&now);
 	strftime(timebuf, TIMELEN, "%FT%T.000Z", localtime(&now));

 	// Third: Hostname ( Preferably: 1. FQDN (RFC1034) 2. Static IP address 3. Hostname 4. Dynamic IP address 5. NILVALUE (-) )
 	message += std::string{timebuf} + " " + net::Inet4::stack().ip_addr().str() + " ";

 	// Fourth: App-name, PROCID (LOG_PID) and MSGID
 	message += Service::binary_name() + " " + std::to_string(getpid()) + " UDPOUT ";

 	/* Structured data: SD-element (SD-ID PARAM-NAME=PARAM-VALUE) */
 	message += "- ";	// NILVALUE

 	/* Message */

 	// Add ident before message (buf) if is set (through openlog)
 	if (fac_->ident_is_set())
 		message += std::string{fac_->ident()} + " ";

 	/*
 		%m:
		(The message body is generated from the message (argument) and following arguments
		in the same manner as if these were arguments to printf(), except that the additional
		conversion specification %m shall be recognized;)
		it shall convert no arguments, shall cause the output of the error message string
		associated with the value of errno on entry to syslog(), and may be mixed with argument
		specifications of the "%n$" form. If a complete conversion specification with the m conversion
		specifier character is not just %m, the behavior is undefined. A trailing <newline> may be
		added if needed.
	*/
  // Handle %m (replace it with strerror(errno)) and add the message (buf)
  std::regex m_regex{"\\%m"};
  message += std::regex_replace(buf, m_regex, strerror(errno));

 	/* Last: Send the log string */
 	fac_->syslog(message);
}

void Syslog::openlog(const char* ident, int logopt, int facility) {
	fac_->set_ident(ident);

  if (valid_logopt(logopt) or logopt == 0)  // Should be possible to clear the logopt
    fac_->set_logopt(logopt);
  else
  	fac_->set_logopt(0);	// Because of call to openlog from closelog

  if (valid_facility(facility))
    fac_->set_facility(facility);

  if (logopt & LOG_NDELAY) {
    // Connect to syslog daemon immediately
    fac_->open_socket();
  }
  /*else if (logopt & LOG_ODELAY) {
    // Delay open until syslog() is called = do nothing (the converse of LOG_NDELAY)
  }*/

  /*if (logopt & LOG_NOWAIT) {
    // Do not wait for child processes - deprecated
  }*/
}

void Syslog::closelog() {
  // Back to default values:
  // ident_ = nullptr;
  // logopt = 0;
  // facility = LOG_USER;
  openlog(nullptr, 0, LOG_USER);
  fac_->close_socket();
}

__attribute__((constructor))
void register_plugin_syslogd() {
  INFO("Syslog", "Sending buffered data to syslog plugin");

  /*
    @todo
    Get dmesg (kernel logs) and send to syslog
    INFO needs to be rewritten to use kprint and kprint needs to be rewritten to buffer the data
  */

}<|endoftext|>