0

I am trying to build my own C program that basically works just like fdisk vdisk 'p' command. I just want to be able to read in the first 512 bytes of the disk, lseek to the start of the partitions at (0x1BE) and then read the partition type, name, size, ect. I am unsure how to actually read these values. I have used the read() linux function to read in 512 bytes but when I try displaying/viewing them in any way, nothing is shown. What am I doing wrong?

int main(int argc, char *argv[]) {
    int bytes_read;
    char mbr[512];
    int file;
    if(argc == 1) {
        // Print some help info
        printf ("Here is some help info: \n\n");
    } else if(argc < 3) {
        printf("File: %s\n\n", argv[1]);
        file = open(argv[1], O_RDONLY);
        lseek(bytes_read, 0, 0);
        //First get the MBR
        bytes_read = read(file, mbr, 512);
        printf("MBR=%s\n\nbytes_read=%d\n\n", mbr, bytes_read);
    } else {
        printf ("Incorrect usage: fdisk <disk>\n\n");
    }
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Matt Hintzke
  • 7,744
  • 16
  • 55
  • 113

2 Answers2

3

Don't try to use printf with binary data. If your binary data starts with a NUL (ASCII 0), then printf will assume you've got an empty string. You can use write() to write out arbitrary data (it takes a buffer and length), e.g:

#include <unistd.h>

write(STDOUT_FILENO, mbr, 512)

...but even this won't necessarily display anything useful, because your terminal may try to interpret control characters in the output. You're best bet would then be to pipe the output to something like xxd or od, both of which will produce a hexdump of their input data.

For example, the first 512 bytes of my local drive are all NUL. Using write() in your code (and removing that lseek) results in 512 NUL bytes on output. Try passing something other than disk to your code, e.g.:

myexe /etc/passwd

The structure of a standard DOS MBR is documented here, suggesting that you might start with data structures like this:

struct _partition {
        uint8_t         status;
        uint8_t         chs_start[3];
        uint8_t         part_type;
        uint8_t         chs_end[3];
        uint32_t        lba_start;
        uint32_t        sectors;
};

And populate it something like this:

        fd = open(target, O_RDONLY);
        lseek(fd, 446, SEEK_SET);
        for (i=0; i<4; i++) {
                struct _partition p;

                bytes_read = read(fd, &p, sizeof(struct _partition));

                // assume this prints information to stdout or something.
                print_part(i, &p);
        }
larsks
  • 277,717
  • 41
  • 399
  • 399
  • I can hex-dump, but that still doesn't help me read actual values of partition properties. Do I have to parse the raw binary data? – Matt Hintzke Jan 16 '13 at 01:32
  • 1
    ...of course! What were you expecting? The partition map is a binary structure; you'll need to read up on exactly what the structure looks like, create the necessary C data structures, populate them as necessary, and write function to produce human-readable output. – larsks Jan 16 '13 at 01:33
  • thanks for all the help. I understand how all this works, only thing is figuring out a way to print it in plain text rather than binary. Is there some kind of special way to do this? – Matt Hintzke Jan 16 '13 at 04:29
  • Well, with a data structure like I've suggested, you would do something like `printf("Type: %d\n", part->part_type)`, assuming that `part` was a `struct _partition *`. – larsks Jan 16 '13 at 04:31
0

Get rid of the lseek. Your compiler should be throwing a warning right now, as you're passing it an argument (bytes_read) which has not been initialized.

Once that's done, you'll need to do something to display the contents; right now, you've got nothing that uses the data you read.