//===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
#include <stdio.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Error.h"
#include "lldb/Target/Process.h"

#include "lldb/Host/Host.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"

using namespace lldb;
using namespace lldb_private;

bool
Host::GetOSVersion(uint32_t &major, 
                   uint32_t &minor, 
                   uint32_t &update)
{
    struct utsname un;
    int status;

    if (uname(&un))
        return false;

    status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update);
     return status == 3;
}

Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
{
    Error error;
    assert(!"Not implemented yet!!!");
    return error;
}

lldb::DataBufferSP
Host::GetAuxvData(lldb_private::Process *process)
{
    static const size_t path_size = 128;
    static char path[path_size];
    lldb::DataBufferSP buf_sp;

    int fd;

    // Ideally, we would simply create a FileSpec and call ReadFileContents.
    // However, files in procfs have zero size (since they are, in general,
    // dynamically generated by the kernel) which is incompatible with the
    // current ReadFileContents implementation.  Therefore we simply stream the
    // data into a DataBuffer ourselves.
    if (snprintf(path, path_size, "/proc/%" PRIu64 "/auxv", process->GetID()) < 0)
        return buf_sp;

    if ((fd = open(path, O_RDONLY, 0)) < 0)
        return buf_sp;

    size_t bytes_read = 0;
    std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
    for (;;) 
    {
        size_t avail = buf_ap->GetByteSize() - bytes_read;
        ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail);

        if (status < 0) 
            break;

        bytes_read += status;

        if (status == 0) 
        {
            buf_ap->SetByteSize(bytes_read);
            buf_sp.reset(buf_ap.release());
            break;
        }

        if (avail - status == 0)
            buf_ap->SetByteSize(2 * buf_ap->GetByteSize());
    }

    return buf_sp;
}
