Newsgroup: it.comp.os.linux.development
Titolo: statvfs() problemino

Salve, dunque, ho questa SC mediante la quale posso verificare il
filestem del sistema, tuttavia devo confessarvi che mi sta creando
qualche grattacapo.
Il risultato delle chiamate e' naturalmente in byte, però confrontando
i valori con il classico df, non ottengo mai e dico mai un risultato
che possa lontanamente avvicinarsi al reale sfruttamento del filesystem.
Qualche anima pia che mi aiuti a risolvere per favore, io vorrei
semplicemente emulare il comportamento di df, fornendo al client la
possibilita' di verificare il risultato in KB, MB e GB.
Le pagine di man non sono poi così esaustive, ho solo appurato che
questa SC è consigliata, dal 2.6 in poi, al posto della vecchia
statfs() ma niente altro di particolarmente interessante, inoltre, con
mia grande sorpresa lo Stevens non la accenna minimanente.
========= 8< ===============
struct statvfs hdd;
unsigned long block_size, blocks, blocks_free, 
              disk_size, disk_used, disk_free;
        if (statvfs( "/", &hdd) < 0)
                exit(EXIT_FAILURE);
        else {
                block_size = hdd.f_bsize;
                blocks = hdd.f_blocks;
                blocks_free = hdd.f_bfree;
                disk_size = (blocks * block_size);
                disk_free = (blocks_free * block_size);
                disk_used = (disk_size - disk_free);
========= 8< ===============
Ecco disk_size, disk_free e disk_used sono in byte, ma non appena tento
di convertirli in KB (risultato diviso per 1024) o per MB (1024 * 1024)
etc... sballa di brutto, come posso risolvere?
Non mi piace affatto fornire al client il risultato in byte, ho bisogno
do un human readable.


Dovresti specificare meglio cos'è che non va, a me va benissimo con 
tutti i miei filesystem.
A occhio mi vengono in mente due cose:
1) overflow - io sono su x86_64
2) spazio libero - se i conti non tornano, è perchè una certa % 
(variabile, ma di solito attorno al 5%) è assegnata a root, e non viene 
computata: per intenderci, hai una partizione di 100 GB, 80 usati -> ti 
riporta 15 liberi.
Qui sotto il codice che non mi dà problemi, poi vedrò al massimo di 
provarlo a 32 bit.
 
========= 8<  ===============
#include <sys/statvfs.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
	struct statvfs hdd;
	unsigned long block_size, blocks, blocks_free,
		      disk_size, disk_used, disk_free;
 
	if (statvfs(argc>1?argv[1]:"/", &hdd) < 0)
		exit(EXIT_FAILURE);
	else {
		block_size = hdd.f_bsize;
		blocks = hdd.f_blocks;
		blocks_free = hdd.f_bfree;
 
		disk_size = (blocks * block_size);
		disk_free = (blocks_free * block_size);
		disk_used = (disk_size - disk_free);
#define p(var) printf("%s = %lu\n", #var, var)
		p(block_size);
		p(blocks);
		p(blocks_free);
		p(disk_size);
		p(disk_free);
		p(disk_used);
	}
	return 0;
}
========= 8<  ===============

                 disk_used = (disk_size - disk_free);
come hai definito disk_size ? e blocks?
Probabilmente hai semplicemente un overflow nella prima delle citate 
istruzioni. Prova a scrivere sul terminale il valore delle varie 
variabili...

 [...]
Ho visto il codice grazie.

 variabili...
sono entrambi "unsigned long", e se provassi con "unsigned long long"?
avrebbe un senso?
Odio lasciare il risultato in byte!

 ========= 8<  ===============
Oppure e' troppo rozzo? Ho dato una sbirciatina al codice di df, e
anche lì si fa la medesima operazione!
Mah, vabeh, grazie comunque a tutti


quanto vale nella tua architettura  sizeof(unsigned long) ? se č 4 
byte, hai trovato il problema.
 


Straquoto, anche perchè GNU/df usa uintmax_t (cioè l'unsigned più grosso 
in assoluto).
E btw, se posti un esempio di output ottenuto vs output atteso...

 E btw, se posti un esempio di output ottenuto vs output atteso...
 
=========== 8< ===========
        struct statvfs hdd;
        double disk_size, disk_free, disk_used;
 
 
        if (statvfs("/", &hdd) != -1) {
                disk_size = (double)(hdd.f_bsize * hdd.f_blocks)/MB;
                disk_free = (double)(hdd.f_bsize * hdd.f_bfree)/MB;
                disk_used = (double)(disk_size - disk_free);
 
                printf("Disk size: %.5g MB\n", disk_size);
                printf("Disk free: %.5g MB\n", disk_free);
                printf("Disk used: %.5g MB\n", disk_used);
        }
=========== 8< ===========
Risolto
 
$ ./a.out
Disk size: 461.75 MB
Disk free: 165.18 MB
Disk used: 296.57 MB
 
df naturalmente arrotonda, ma i byte sono identici, ed e' questo cio'
che conta: 462, 165, 297.
 
Volevo questa precisione, ora posso crearmi con tutta calma una
funzioncina per la conversione e vado liscio liscio. 
 
Così posso gestirlo come mi pare, naturalmente non fate caso al codice,
e' solo il test finale per la verifica dei valori.
 
Grazie per il prezioso aiuto.
 
P.S. sizeof(unsigned long) = 4