#include "pmap.h"

#include <cstdio>

#include <util/system/maxlen.h>
#include <util/system/shellcommand.h>

TVector<NUtil::TMappedRegionInfo> NUtil::GetMappedRegions(int pid) {
    char fname[PATH_MAX];
    FILE *f;

    sprintf(fname, "/proc/%ld/maps", (long)pid);
    f = fopen(fname, "r");

    if (!f)
        return TVector<NUtil::TMappedRegionInfo>();

    TVector<NUtil::TMappedRegionInfo> results;
    while (!feof(f)) {
        char buf[PATH_MAX + 100], perm[5], dev[6], mapname[PATH_MAX], deletedFlag[PATH_MAX];
        unsigned long begin, end, inode, foo;

        if (fgets(buf, sizeof(buf), f) == nullptr)
            break;
        mapname[0] = '\0';
        deletedFlag[0] = '\0';
        sscanf(buf, "%lx-%lx %4s %lx %5s %ld %s %s", &begin, &end, perm,
            &foo, dev, &inode, mapname, deletedFlag);

        NUtil::TMappedRegionInfo info;
        info.Size = end - begin;
        info.Ptr = (void*)begin;
        if (perm[3] == 'p') {
            if (perm[1] == 'w')
                info.Writable = true;
        } else if (perm[3] == 's') {
            info.Shared = true;
        }

        info.File = mapname;
        if (*deletedFlag)
            info.IsDeleted = true;

        results.push_back(info);
    }
    fclose(f);
    return results;
}

TVector<TString> NUtil::GetDescriptorsInUsage(int pid) {
    TShellCommandOptions options;
    options.SetClearSignalMask(true);
    options.SetCloseAllFdsOnExec(true);
    TShellCommand cmd("lsof -p " + ToString(pid));
    cmd.Run();
    cmd.Wait();
    TString info;
    switch (cmd.GetStatus()) {
    case TShellCommand::SHELL_FINISHED:
        info = cmd.GetOutput();
        break;
    default:
        ythrow yexception() << "Can't run lsof for pid " << pid << ":" << cmd.GetError();
    }
    return SplitString(info, "\n");
}
