// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
// SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>

#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>

#include <string.h>

#include <sys/sysinfo.h>
#include <sys/utsname.h>

// https://github.com/torvalds/linux/commit/92890123749bafc317bbfacbe0a62ce08d78efb7

int main()
{
    // We use the ephemeral directory as this tool is meant to run during every bootup so long as unit conditions are met.
    // This has the advantage that we don't manually have to take care of cleaning up once the kernel version is great enough.
    const std::filesystem::path dir("/run/sysctl.d/");
    const auto path = "/run/sysctl.d/40-neon-inotify.conf";
    const auto min_watches = 8192UL;
    const auto max_watches = 1048576UL;
    // inotify weight as per kernel 5.11, in bytes (on x86-64).
    const auto watch_weight = 1279UL;

    struct sysinfo info {
    };
    if (sysinfo(&info) != 0) {
        const auto err = errno;
        std::cerr << "Failed to get sysinfo: " << strerror(err) << "\n";
        return -1;
    }

    // Our calculation is a bit different from the kernel because they divide pages whereas we divide bytes, we could
    // >>PAGE_SHIFT, divide, and then <<PAGE_SHIFT back but honestly it makes nary a difference.
    const auto watches = std::clamp((((info.totalram - info.totalhigh) / 100)) / watch_weight, min_watches, max_watches);
    std::filesystem::create_directory(dir);
    std::ofstream output;
    output.open(path, std::ios::out | std::ios::trunc);
    if (!output.is_open()) {
        std::cerr << "Failed to open for writing: " << path << "\n";
        return -2;
    }
    output << "# This file gets auto-generated by neon-configure-inotify. Changes will be overwritten!\n";
    output << "fs.inotify.max_user_watches=" << watches << "\n";

    return 0;
}
