Read from /dev/disk* while device is mounted

Discussion in 'Mac Programming' started by chris-morrison, May 20, 2010.

  1. chris-morrison macrumors newbie

    Joined:
    May 19, 2010
    #1
    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
     
  2. Detrius macrumors 68000

    Joined:
    Sep 10, 2008
    Location:
    Asheville, NC
    #2
    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.
     
  3. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #3
    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.
     
  4. chris-morrison thread starter macrumors newbie

    Joined:
    May 19, 2010
    #4
    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.
     
  5. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #5
    You should be able to open and read it with, open and read in fcntl.h and stdlib.h.
     
  6. chris-morrison thread starter macrumors newbie

    Joined:
    May 19, 2010
    #6
    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.
     
  7. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #7
    I just tried it here, no problem. Perhaps you forgot to sudo before running it?
     
  8. chris-morrison thread starter macrumors newbie

    Joined:
    May 19, 2010
    #8
    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?
     
  9. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #9
    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.
     
  10. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
  11. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #11
    Might there be another process that has exclusive access to the device preventing you from opening it?
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    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`
     
  13. chris-morrison thread starter macrumors newbie

    Joined:
    May 19, 2010
    #13
    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.
     

Share This Page