Is there a way to programmatically get the same information that diskutil info / | grep "Free Space"
gives you? (For obvious reasons I'd rather have a better way to do this than just parsing the result of that command.)
Currently I'm using statfs
; however, it was brought to my attention that the space this reports is not always accurate, because OS X also places temporary files such as Time Machine snapshots on the drive. These files automatically get deleted if space is running out, and the OS does not report the usage of these files. In other words, statfs
often gives a lower number of free space than diskutil info
or looking at the disk information in Finder.
You can use popen(3)
:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *f;
char info[256];
f = popen("/usr/sbin/diskutil info /", "r");
if (f == NULL) {
perror("Failed to run diskutil");
exit(0);
}
while (fgets(info, sizeof(info), f) != NULL) {
printf("%s", info);
}
pclose(f);
return 0;
}
EDIT
Sorry, I didn't read the question carefully. You can also use the Disk Arbitration Framework. There's also some sample code that might be helpful (FSMegaInfo).
UPDATE
I took a look at the output from otool -L $(which diskutil)
and it seems that it's using a private framework called DiskManagement.framework
. After looking at the output from class-dump
I saw there's a volumeFreeSpaceForDisk:error:
method. So the sizes I got from diskutil -info /
and FSMegaInfo FSGetVolumeInfo /
and my tool were:
diskutil: 427031642112 Bytes
my tool: volumeFreeSpaceForDisk: 427031642112
FSMegaInfo: freeBytes = 427031642112 (397 GB)
I also observed that the sizes differ (with a few KB) every time I ran one of the tools and also that diskutil
is dividing by 1000 and FSMegaInfo
is dividing by 1024, so the size in GB will be always different (same reason as with df -h
and df -H
and diskutil
- base 10 and base 2).
Here's my sample tool:
#import <Foundation/Foundation.h>
#import "DiskManagement.h"
#import <DiskArbitration/DADisk.h>
int main(int argc, char *argv[])
{
int err;
const char * bsdName = "disk0s2";
DASessionRef session;
DADiskRef disk;
CFDictionaryRef descDict;
session = NULL;
disk = NULL;
descDict = NULL;
if (err == 0) {session = DASessionCreate(NULL); if (session == NULL) {err = EINVAL;}}
if (err == 0) {disk = DADiskCreateFromBSDName(NULL, session, bsdName); if (disk == NULL) {err = EINVAL;}}
if (err == 0) {descDict = DADiskCopyDescription(disk); if (descDict == NULL) {err = EINVAL;}}
DMManager *dmMan = [DMManager sharedManager];
NSLog(@"blockSizeForDisk: %@", [dmMan blockSizeForDisk:disk error:nil]);
NSLog(@"totalSizeForDisk: %@", [dmMan totalSizeForDisk:disk error:nil]);
NSLog(@"volumeTotalSizeForDisk: %@", [dmMan volumeTotalSizeForDisk:disk error:nil]);
NSLog(@"volumeFreeSpaceForDisk: %@", [dmMan volumeFreeSpaceForDisk:disk error:nil]);
return 0;
}
You can obtain the DiskManagement.h
by running class-dump /System/Library/PrivateFrameworks/DiskManagement.framework/Versions/Current/DiskManagement > DiskManagement.h
and you can link to that framework by including the private frameworks path using -F/System/Library/PrivateFrameworks/
and add -framework
.
Compile:
clang -g tool.m -F/System/Library/PrivateFrameworks/ -framework Foundation -framework DiskArbitration -framework DiskManagement -o tool
UPDATE2:
You can also take a look here and here. If the FSMegaInfo
sample is not working for you, then you can just stat
the /Volumes/.MobileBackups
and subtract it's size from what you get from statfs("/", &stats)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With