
//This file didn't work, because the bug of 120s delay at boot happened before this program,
//right at systemctl start. I'm keeping it because it has some good subroutines. JMC.

#include <stdio.h>
#include <fcntl.h>

#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

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

//#include <unistd.h>
#include <utmp.h>
#include <string.h>
#include <memory.h>


//If the system is just starting and multi user target is not yet reached,
//it won't work.
//So I use the uptime to detect whether the system just started,
//and a command line option to ignore that detection.


long get_uptime_seconds() {
    struct sysinfo s_info;
    if (sysinfo(&s_info) != 0) {
        perror("sysinfo error");
        return -1; //Handle error appropriately
    }
    return s_info.uptime; //Seconds since boot
}


//Returns 1 on success, 0 otherwise.
//The caller must free the output string.
int system_with_output(char** output, char* command) {
    FILE *fp;
    int MAX_BUFFER_SIZE = 8192;
    char buffer[MAX_BUFFER_SIZE];
    char* result = NULL; // Buffer to store the full output
    int resultSize = 1;
    int resultStrlen = 0;
    //debug: const char *command = "ls -l"; // Replace with your desired command
    char* resultTmp;

    /* Open the command for reading */
    fp = popen(command, "r");
    if (fp == NULL) {
        printf("Failed to run command\n");
        return 0;
    }

    result = (char*)malloc(1);
    result[0] = '\0';

    /* Read the output line by line and append to the result string */
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        if (strlen(buffer) > (resultSize - strlen(result))) {
            resultSize = strlen(buffer) + resultSize;
            resultTmp = malloc(resultSize);
            resultTmp[0] = '\0';
            strcat(resultTmp, result);
            strcat(resultTmp, buffer);
            free(result);
            result = resultTmp;
        } else {
            strcat(result, buffer);
        }
    }

    /* Close the pipe */
    pclose(fp);

    /* Print the captured output */
    printf("Captured Output:\n%s", result);

    *output = result;

    return 1;
}

//Remove newlines inplace, returns the same pointer:
char* remove_newlines(char* str) {
    for (int i=0; i < strlen(str); ++i) {
        if (str[i] == '\n') {
            //str[i] = ' ';
            str[i] = 'T';  //debug!
        }
    }
    return str;
}


int get_runlevel() {

    struct utmp* ut;
    struct utmp filter;
    char* strlog = NULL;
    char* system_output = NULL;

    memset(&filter, 0, sizeof(struct utmp));  //debug!

    strlog = (char*) malloc(10240); //debug

    system("logger -t SEPARADOR -p user.warn  textText");  //debug

    if (system_with_output(&system_output, "ps f")) {
        sprintf(strlog, "logger -t SEPARADOR -p user.warn  '%s'", remove_newlines(system_output));  //debug
        system(strlog);
    }

    setutent(); // Set the utmp entry to the beginning
    filter.ut_type = RUN_LVL; // Specify the type of entry to look for

    free(system_output);
    system_output = NULL;
    if (system_with_output(&system_output, "systemctl get-default")) {
        sprintf(strlog, "logger -t SEPARADOR -p user.warn  '%s'", remove_newlines(system_output));  //debug
        system(strlog);
    }

    long uptime_seconds = get_uptime_seconds();
    free(system_output);
    sprintf(strlog, "logger -t SEPARADOR -p user.warn  '%d'", (int)uptime_seconds);  //debug
    system(strlog);

    //execl("/bin/sh", "sh", "-c", command, (char *) NULL);


    //int filterId = 0;
    //int notFound = 1;
    //while (notFound) {
    //    filterId += 1;
    //    filter.ut_type = filterId; // Specify the type of entry to look for
    //    ut = getutid(&filter); // Get the first entry that matches the filter

    //    if (!ut) {
    //        perror("getutid");
    //        fprintf(stderr, "Can't find RUN_LVL entry in utmp\n");
    //        //debug: endutent(); // Close the utmp file
    //        //debug: return -1;
    //        continue;
    //    }

    //    //The current runlevel character is often found in the ut_line field
    //    if (ut->ut_type == RUN_LVL && !strncmp(ut->ut_line, "run-level", 9)) {
    //        sprintf(strlog, "logger -t SEPARADOR -p user.warn  %s", (char*)ut->ut_line);  //debug
    //        system(strlog);
    //        fprintf(stdout, "Current Runlevel: %c \n", ut->ut_line[10]);
    //        notFound = 0; //debug
    //    } else {
    //        sprintf(strlog, "logger -t SEPARADOR -p user.warn  %s", (char*)ut->ut_line);  //debug
    //        system(strlog);
    //        fprintf(stdout, "Found RUN_LVL entry, but could not parse the exact level from ut_line.\n");
    //    }
    //}

    endutent(); // Close the utmp file

    return 0; //debug
}


int main() {
    get_runlevel(); //debug

    long uptime_seconds = get_uptime_seconds();
    if (uptime_seconds != -1) {
        int days = uptime_seconds / 86400;
        int hours = (uptime_seconds % 86400) / 3600;
        int minutes = (uptime_seconds % 3600) / 60;
        int seconds = uptime_seconds % 60;
        printf("System Uptime: %d days, %d hours, %d minutes, %d seconds\n", days, hours, minutes, seconds);
        printf("Uptime secs: %d \n", (int)uptime_seconds);
    }
    return 0;
}

int disable_C_states_greater_than_C1_and_keep(int latency) {
    int fd = 0;
    printf("setting latency to %d us\n", latency);
    fd = open("/dev/cpu_dma_latency", O_WRONLY);
    if (fd < 0) {
        perror("open /dev/cpu_dma_latency");
        return 1;
    }
    if (write(fd, &latency, sizeof(latency)) != sizeof(latency)) {
        perror("write to /dev/cpu_dma_latency");
        return 1;
    }
    while (1) pause();
}

//int main(int argc, char **argv) {
//    int32_t l;
//    int fd;
//    if (argc != 2) {
//        fprintf(stderr, "Usage: %s <latency in us> [--skip-multi-user-check]\n", argv[0]);
//        fprintf(stderr, "The check is so that it doesn't hang the system boot for 2 minutes when spawned by AC from udev");
//        fprintf(stderr, "To start at boot we can use KDE Autostart or similar");
//        fprintf(stderr, "Example:   lenovo_fix_coil_whine 250");
//        return 2;
//    }
//    l = atoi(argv[1]);
//    //debug arg
//    disable_C_states_greater_than_C1_and_keep(l); //debug
////    printf("setting latency to %d us\n", l);
////    fd = open("/dev/cpu_dma_latency", O_WRONLY);
////    if (fd < 0) {
////        perror("open /dev/cpu_dma_latency");
////        return 1;
////    }
////    if (write(fd, &l, sizeof(l)) != sizeof(l)) {
////        perror("write to /dev/cpu_dma_latency");
////        return 1;
////    }
////    while (1) pause();
//}


