C for more storage

I need a simple way to get additional storage data (for example, total size, used and free space) in (daemon) c code for linux;

This is what I tried

  • statvfs - don't know how to get disk information instead of files
  • using the system ("df -h --total | grep total> disk.stat") in the c code, and then read the file.

but the aforementioned involves writing and reading files, which is inefficient because this c-code is a daemon that will continuously process the system data as input to generate a graph.

if there is no other way, tell me a simple and fast ipc mechanism with an example for exchanging data between these bash and c-code.

/*
* @breif returns total percentage of secondary storage used
*
*   - uses bash command to get storage data and store in a file
*   - and use c code retrive the percent of usage from file and return it
*/
int calculate_storage_size( )
{
  if ( system("df -h --total | grep total > disk.stat") >= 0 )
  {
    char *temp_char_ptr = (char *)NULL;
    int storage_size_percent = -1;  
    FILE *fp ;
    fp = fopen ("disk.stat" , "r");
    if (fp != (FILE *)NULL)
    {
      temp_char_ptr = (char*) calloc ( 6 , 1 );
      fscanf( fp,"%s %s %s %s %d", temp_char_ptr, temp_char_ptr, temp_char_ptr, temp_char_ptr, &storage_size_percent);
    }
    free (temp_char_ptr);
    fclose(fp);
    return storage_size_percent;
  }
  return -1;
}

Thanks and welcome in advance

+4
4

, , , , , .

: info.c:

#define  _POSIX_C_SOURCE 200809L
#define  _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/statvfs.h>
#include <mntent.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

static void free_array(char **array)
{
    if (array) {
        size_t i;    
        for (i = 0; array[i] != NULL; i++) {
            free(array[i]);
            array[i] = NULL;
        }
        free(array);
    }
}

static char **normal_mounts(void)
{
    char         **list = NULL, **temp;
    size_t         size = 0;
    size_t         used = 0;
    char           buffer[4096];
    struct mntent  entry;
    FILE          *mounts;

    mounts = fopen("/proc/mounts", "r");
    if (!mounts)
        return NULL;

    while (getmntent_r(mounts, &entry, buffer, sizeof buffer) == &entry)
        if (strcmp(entry.mnt_fsname, "tmpfs") &&
            strcmp(entry.mnt_fsname, "swap")  &&
            strcmp(entry.mnt_dir, "/proc")    && strncmp(entry.mnt_dir, "/proc/", 6) &&
            strcmp(entry.mnt_dir, "/boot")    && strncmp(entry.mnt_dir, "/boot/", 6) &&
            strcmp(entry.mnt_dir, "/sys")     && strncmp(entry.mnt_dir, "/sys/", 5) &&
            strcmp(entry.mnt_dir, "/run")     && strncmp(entry.mnt_dir, "/run/", 5) &&
            strcmp(entry.mnt_dir, "/dev")     && strncmp(entry.mnt_dir, "/dev/", 5) &&
            strcmp(entry.mnt_dir, "/mnt")     && strncmp(entry.mnt_dir, "/mnt/", 5) &&
            strcmp(entry.mnt_dir, "/media")   && strncmp(entry.mnt_dir, "/media/", 7) &&
            strcmp(entry.mnt_dir, "/var/run") && strncmp(entry.mnt_dir, "/var/run/", 9)) {

            if (used >= size) {
                size = (used | 15) + 17;
                temp = realloc(list, size * sizeof list[0]);
                if (!temp) {
                    endmntent(mounts);
                    free_array(list);
                    errno = ENOMEM;
                    return NULL;
                }
                list = temp;
            }

            if (!(list[used++] = strdup(entry.mnt_dir))) {
                endmntent(mounts);
                free_array(list);
                errno = ENOMEM;
                return NULL;
            }
        }

    if (ferror(mounts) || !feof(mounts)) {
        endmntent(mounts);
        free_array(list);
        errno = EIO;
        return NULL;
    } else
        endmntent(mounts);

    if (!used) {
        free_array(list);
        errno = 0;
        return NULL;
    }

    if (size != used + 1) {
        size = used + 1;
        temp = realloc(list, size * sizeof list[0]);
        if (!temp) {
            free_array(list);
            errno = ENOMEM;
            return NULL;
        }
        list = temp;
    }

    list[used] = NULL;
    errno = 0;
    return list;
}

static int statistics(const char **mountpoint, uint64_t *bytes_total, uint64_t *bytes_free)
{
    struct statvfs  info;
    uint64_t        btotal = 0;
    uint64_t        bfree = 0;
    size_t          i;

    if (!mountpoint)
        return errno = EINVAL;

    for (i = 0; mountpoint[i] != NULL; i++)
        if (statvfs(mountpoint[i], &info) != -1) {
            btotal += (uint64_t)info.f_frsize * (uint64_t)info.f_blocks;
            bfree  += (uint64_t)info.f_bsize * (uint64_t)info.f_bavail;
        } else
            return errno;

    if (bytes_total)
        *bytes_total = btotal;
    if (bytes_free)
        *bytes_free = bfree;

    return 0;
}

int main(int argc, char *argv[])
{
    uint64_t total = 0;
    uint64_t nfree = 0;

    if (argc > 1) {
        if (statistics((const char **)argv + 1, &total, &nfree)) {
            fprintf(stderr, "%s.\n", strerror(errno));
            return EXIT_FAILURE;
        }
    } else {
        char **mounts = normal_mounts();
        size_t i;
        if (!mounts) {
            if (errno)
                fprintf(stderr, "Error determining file systems: %s.\n", strerror(errno));
            else
                fprintf(stderr, "No normal file systems found.\n");
            return EXIT_FAILURE;
        }
        fprintf(stderr, "Considering mount points");
        for (i = 0; mounts[i] != NULL; i++)
            fprintf(stderr, " %s", mounts[i]);
        fprintf(stderr, "\n");

        if (statistics((const char **)mounts, &total, &nfree)) {
            fprintf(stderr, "%s.\n", strerror(errno));
            return EXIT_FAILURE;
        }
        free_array(mounts);
    }

    printf("%20" PRIu64 " bytes total\n", total);
    printf("%20" PRIu64 " bytes free\n",  nfree); 
    return EXIT_SUCCESS;
}

statistics() NULL- 64- . 0 errno . .

, . (POSIX argv[argc] == NULL, .)

normal_mounts() /proc/mounts "" . getmntent() () , . tmpfs (ramdisks) swap , , /proc, /boot, /sys, /run, /dev, /mnt, /media, /var/run. , .

( ) statistics() . . : ( , /tmp /var/tmp tmpfs mounts), /home.

HUP USR1 USR2, , - . , DBUS /, , , , .

, ,

gcc -Wall -O2 info.c -o info

./info

-

Considering mount points / /home
        119989497856 bytes total
         26786156544 bytes free

, - . - , , -:

./info /home /tmp

, , : stat(path1, &info1) , stat(path2, &info2) - . (info1.st_dev == info2.st_dev), . ( , , , , , .)

, , df. C/POSIX ( , , ),

handle = popen("LANG=C LC_ALL=C df -Pl", "r");

, len = getline(&line, &size, handle).

+3

popen() system()/fopen(): .

+3

There is no ANSI C portable mechanism besides the system and file kludge, and even this is a bit of an illusion, as it depends on the presence of df. However, the Posix popen () function does almost the same thing, but gives you the output as FILE *.

+1
source
#include <stdio.h>
#include <stdlib.h>
#include <sys/statvfs.h>
int main( )
{
  struct statvfs stat;
  statvfs("/media/hp",&stat);

  printf("\n\navail size --%ld GB\n\n", stat.f_bsize * stat.f_bavail / 1000000000 );
  printf("\n\nblocks size --%ld GB\n\n", stat.f_frsize * stat.f_blocks / 1000000000 );

}

I finally made statvfs itself, it works great.

0
source

Source: https://habr.com/ru/post/1656551/


All Articles