1

I'm trying to create a simple script in c which is able to identify bad sectors of (a device) for educational purpose. In my example, I use an HD with read-only mode. The idea behind is simple, but maybe too simple and I would know if this is correct and eventually get known about any other way to reach my goal.

Let's take a look to my code:

#include<stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char ** argcv){
        size_t size_block = 512;
        int fd = open("/dev/disk2",O_RDONLY);
        ssize_t bytes_read = 1;
        char *buff = malloc(size_block * sizeof(char));

        if (buff == NULL){
           exit(EXIT_FAILURE);
        }

        while (bytes_read > 0){
                bytes_read = read(fd,buff,size_block);
                int position = lseek(fd, 0, SEEK_CUR);
                if (bytes_read == -1){
                        perror("main");
                }
                //printf("%s",buff); //prints the content of what I read
                if (bytes_read < size_block){
                        printf("the block at %p address is probably damaged",&position);
                }
        }
        free(buff);
        close(fd);
        return 0;
}

So I try to read sectors of my HD with read syscalls by seeking the file pointer of 512 bytes every time. And that's the first question: since the preferred, I/O block size is 2048 byte (info retrieved with stat of sys/stat.h), is it correct seek every time of 512 bytes instead of 2048? Also, to check if a sector is bad I use to compare (bytes_read < size_block)because I assume that if I cannot read the totality of bytes of a sector, it could be damaged. But if I reach the end "of the file" and it isn't a multiple of 512 with this method I will get that the sector is damaged anyway also if it isn't. Is what I wrote really working? Otherwise, how can I do this check?

Virgula
  • 318
  • 4
  • 12
  • 1
    Always check whether malloc does not return NULL – Hawk Aug 24 '20 at 11:22
  • There is no point in malloc/free each loop. Just malloc once, before the loop. `lseek` returns `off_t`, not an `int`, and `read` returns `ssize_t`, not an `int`. And [do not cast result of malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) and the `(int)size_block` cast is strange also - remove it. And I do not think I follow the `read+lseek` operation - `read` seeks the cursor by itself, so by calling `lseek` you are moving at `2*size_block` at a time. – KamilCuk Aug 24 '20 at 11:22
  • Setting `bytes_read` to 1 just so that the while loop runs the first time... is counter-intuitive. Just use a `do {} while` loop instead of `while{}` – Hawk Aug 24 '20 at 11:37
  • @Hawk I forgot, thank you. – Virgula Aug 24 '20 at 11:42
  • @KamilCuk Are you sure about that read pointer behaviour? Any reference? – Virgula Aug 24 '20 at 11:43
  • [posix read](https://pubs.opengroup.org/onlinepubs/009695399/functions/read.html) `The file offset shall be incremented by the number of bytes actually read.` – KamilCuk Aug 24 '20 at 11:47
  • @KamilCuk OK so I have only to print fd address. Thank you. – Virgula Aug 24 '20 at 11:55

1 Answers1

0

On Linux, at least, I'm fairly sure that a block device will always appear to have a readable size that is be a multiple of 512 bytes, regardless of the underlying device capacity. The kernel pads out the last block if there isn't enough physical data to fill 512 bytes. When a filesystem is created on a device, the filesystem tools round down the allocated size to account for this.

What that means is that a read() of size 512 will always return 512 or an error, even if it's the last read and it doesn't fill a whole 512 byte buffer.

However, I think it's unlikely that a bad sector will cause what appears to be a short read. I think it's more likely that the read() will simply fail and return -1, or just appear to succeed and return some nonsense. I suspect that you need to write and read to check for bad sectors.

Kevin Boone
  • 4,092
  • 1
  • 11
  • 15
  • "I suspect that you need to write and read to check for bad sectors" But writing on the sectors may replace my real data and software like badblocks don't do this. [link](https://linux.101hacks.com/unix/badblocks/) (read at the end when the article says: By default badblocks command will perform read-only test.). Also take a look about this program: [github](https://github.com/trapexit/bbf) The first feature says: "read-only scanning of bad blocks". So I think it's possible to do. – Virgula Aug 24 '20 at 14:40
  • If you know of a utility that can do what you want, why not contact the author? However, I suspect that read-only testing will only show bad blocks if they have already been marked as bad by the drive firmware or filesystem. Such marking usually happens happens during exhaustive testing, but I think it might also happen if an application has the bad fortune to write an unwritable block. I don't think a simple read can _reliably_ find bad blocks that are not known to the system, but I've been wrong before. – Kevin Boone Aug 24 '20 at 14:52
  • It occurs to be that a read might fail if the drive firmware signals an error in, say, the block checksum. That would indicate that the data on the disk is unreliable, but it doesn't necessarily mean that the sector can't be used again. I really think you need to write to determine that. Conceivably the problem here is the lack of a precise definition of "bad". For all that, I still don't think you need to worry about getting a short read that _isn't_ the result of a defect, which I think is what you were originally asking. – Kevin Boone Aug 24 '20 at 15:06
  • Ok, my first idea was that for bad "sectors" we mean sectors that cannot be used neither for writing nor reading independently of the definition of bad. At this point I got that it's pretty difficult to determinate precisely if a sector is really a bad sector or not, so I will be satisfied anyway to determinate what sectors we are unable to read independently from the writing status. – Virgula Aug 24 '20 at 15:26
  • 1
    A read will fail if a block gets bad check bits and the drive firmware can't recover the data. Once the block is marked bad, writing it will use a spare sector so the disk will appear repaired. Writes are not verified so don't usually fail. – stark Aug 25 '20 at 11:40