Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

chris-morrison

macrumors newbie
Original poster
May 19, 2010
12
0
Hi all,

I am writing a shared library that needs to obtain the volume label of the device/drive on which the file it is working with resides. It does this by opening the raw device (/dev/disk*) and reading out the superblock structure of the mounted disk or device.

I have used statfs() to obtain the device but when I try to open it with open() is fails with EBUSY even when I specify the O_RDONLY flag. My code works perfectly under Linux.

Is there some way round this or should I be doing this another way under Mac OS/Darwin?

Regards,

Chris
 
There's got to be a better way than that, or even this:

The Unix command "df" will list out the currently mounted volumes as well as their device labels. "df <file>" will tell you what mounted volume includes that file.
 
I believe opening the boot device requires root permission.

Doesn't f_mntonname give you a good enough value for the volume name?

Edit: this "superblock" - from a quick google it seems like it's specific to EXT2. Is that right? If so that'll fail to work completely on HFS+. If you can link to the CoreServices framework then there is a more standard way of doing this, but I would imagine there is a POSIX alternative.
 
Thank you for your replies.

Yes, the term superblock refers to the Ext filing system, I was using the word generally to refer to the metadata that is usually stored at the beginning of the disk in which the volume label is usually stored.

Using the mount point of the disk (/Volumes/XXXX) as returned in f_mntonname is not reliable. The type of disks that my library would be most interested in the volume label of would be formatted with the FAT/MSDOS filing system. Without going into too much detail FAT stores the volume label in two places on the disk. If the same value is not stored in both places, or if the volume label contains characters that are illegal in a pathname then Mac OS will mount the disk on a folder entitled /Volumes/NO NAME.

As I am writing a library in C a Unix command would not help.

I would like to find a POSIX like solution if possible as I really don't want to link loads of frameworks into my library just for this one little function.

I was also under the impression that we cannot use Carbon anymore.

I wonder if IOKit could provide a solution to this.
 
You should be able to open and read it with, open and read in fcntl.h and stdlib.h.
 
That's the whole point I can't.

When I call open() with the name of the device file (/dev/disk5) it fails with EBUSY (Resource busy) even though I have requested read-only access, re: my initial post.

This is the show stopper.
 
That's the whole point I can't.

When I call open() with the name of the device file (/dev/disk5) it fails with EBUSY (Resource busy) even though I have requested read-only access, re: my initial post.

This is the show stopper.

I just tried it here, no problem. Perhaps you forgot to sudo before running it?
 
Running with superuser privileges made no difference. I would have expected EACCESS to have been returned if it was a permissions problem.

Can you post exactly what you did?
 
Running with superuser privileges made no difference. I would have expected EACCESS to have been returned if it was a permissions problem.

Can you post exactly what you did?

Sure no problem, I used disk0 which is hfs+, it might make a difference I don't know.

Code:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

#define OUT_ON_NULL(fp, msg) if(!fp) { fprintf( stderr, "%s\n", msg ); goto out; }
#define OUT_ON_ERR(fp, msg) if(fp == -1) { fprintf( stderr, "%s\n", msg ); goto out; }

#define SIZ 10000

int main()
{
        unsigned char buf[SIZ] = {0};

        int fp;
        fp = open("/dev/disk0", O_RDONLY);
        OUT_ON_NULL( fp, "Could not open file");

        int err = read(fp, buf, SIZ);
        OUT_ON_ERR( err, "Could not read from /dev/disk0");

        int fpOut;
        fpOut = open("./dump", O_CREAT | O_WRONLY);
        OUT_ON_NULL( fpOut, "Could not create out file");

        err = write(fpOut, buf, SIZ);
        OUT_ON_ERR( err, "Could not write to file");

out:
        if(fp)
                close(fp);
        if(fpOut)
                close(fpOut);

        return 0;
}

Edit: this will not work if you don't use sudo BTW.
 
Might there be another process that has exclusive access to the device preventing you from opening it?
 
Try using /dev/rdiskN instead of /dev/diskN.

Also, /dev/diskN is going to be the partition map. If you want the volume header, you'll need to use /dev/diskNsM. Or the rdisk equivalent.

EDIT:
You can confirm what you read with your own code by using the 'diskutil' command. It has a large set of actions it can apply to disks, partitions, etc.
http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man8/diskutil.8.html

The man page also describes some of the arcana of disk mgmt.

Example command:
Code:
diskutil list disk0
It uses private frameworks to do its disk-munging:
Code:
otool -L `which diskutil`
 
I seem to have solved it.

I was passing f_mntfromname to open() which is "/dev/disk5s1", by stripping the s1 from the end of the string it now works OK. Although the code will have to quietly fail if the device has multiple partitions that should not be a major issue.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.