Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

When I try to print the device file output shows binary data in hexadecimal format. But upon doing a ls -l /dev/sda I get:

brw-rw----  1 root disk      8,   0 Jan 29 12:29 /dev/sda

I don't understand what is the actual size of the file? What do these numbers mean?

share|improve this question
The 8, 0 has actually nothing to do with file size, but represents the device's major and minor number. Read this article to learn more: – Byte Commander Jan 30 at 22:57
To get the physical size of a block device (disk or partition), use lsblk. If you need the exact size in bytes (instead of e.g. "4.8G"), use lsblk -b. – Byte Commander Jan 30 at 23:00
Made a major edit to my answer. Please review ! – Serg Jan 31 at 6:22
up vote 5 down vote accepted

TL;DR : that's how the developers have implemented the ls.c. Depending on the filetype, the output string for long option -l will be build up differently. GNU documentation fails to mention the format difference(see side note about OpenBSD man page).

Device files and ls source code

/dev/sda is a block device (explained later in the section). It's different from regular file. ls.c builds up the long output string according to what filetype it is working on. As is shown below, for block devices nothing about size is appended to the output string !

ls.c has the following lines of code:

   3757 static void
   3758 print_long_format (const struct fileinfo *f)
   3759 {

( partially omited )

   3868   if (f->stat_ok
   3869       && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
   3870     {
   3871       char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
   3872       char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
   3873       int blanks_width = (file_size_width
   3874                           - (major_device_number_width + 2
   3875                              + minor_device_number_width));
   3876       sprintf (p, "%*s, %*s ",
   3877                major_device_number_width + MAX (0, blanks_width),
   3878                umaxtostr (major (f->stat.st_rdev), majorbuf),
   3879                minor_device_number_width,
   3880                umaxtostr (minor (f->stat.st_rdev), minorbuf));
   3881       p += file_size_width + 1;
   3882     }
   3883   else
   3884     {
   3885       char hbuf[LONGEST_HUMAN_READABLE + 1];
   3886       char const *size =
   3887         (! f->stat_ok
   3888          ? "?"
   3889          : human_readable (unsigned_file_size (f->stat.st_size),
   3890                            hbuf, file_human_output_opts, 1,
   3891                            file_output_block_size));
   3892       int pad;
   3893       for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--)
   3894         *p++ = ' ';
   3895       while ((*p++ = *size++))
   3896         continue;
   3897       p[-1] = ' ';
   3898     }

Notice that if filetype is S_ISCHR (character device, continuous stream of data) or S_ISBLK (block device, random access) the major and minor device numbers are printed to character array p (which is essentially a string). That is the only data that is appended to the output string p . However, when we get to else part , ls understands that we're working with files other than block or character devices. For those files it assigns data stored in size array to the next segments of that p size array ( that's while ((*p++ = *size++)) part).

The core idea is that ls knows what filetype it's looking at , and builds up output accordingly

What are device files anyway?

Essentially they are references. They are way for applications to deal with actual physical devices and their drivers. For example , /dev/sda and /dev/sr0 (which is CD/DVD drive). Some of the devices are just abstraction. For example, /dev/zero, /dev/null, and /dev/random aren't physical devices. They are ways of interfacing with kernel processes.

Since they are references, it makes sense that they wouldn't have filesize. It's possible to know the size of those files that they take up in the /dev directory, but they don't correspond to the actual devices they represent !

Thus it is understandable why ls.c developers implemented the code that way. The file size of the references is 99.99% of the times not needed for any reason whatsoever.

But block devices, by which we typically mean hard drives and USB drives, are physical devices, with real physical size, so how do we find out that ?

Finding out the size of actual block devices

The bellow methods illustrate how one could find out size of a hard/ssd/USB drive referenced by a block device in `/dev/

  • lsblk or lsblk /dev/sda
  • sudo blockdev --getsize64 /dev/sda
  • sudo fdisk -l /dev/sda or sudo fdisk -l for all devs
  • sudo parted /dev/sda print or sudo parted -l for all devs
  • awk '{print $1*512}' /sys/class/block/sda/size
  • awk '{$3=$3*1024;print}' /proc/partitions or awk '$4 == "sda1" {$3=$3*1024;print}' /proc/partitions for specific partitions.

Side notes

  • /proc/devices contains list of all major numbers corresponding to the block devices
  • du, stat and find commands can show you the size of those references, but not necessary for daily life (if at all)
  • There is difference between representation of block devices; some files implement representation blocks of 512 (such as under /sys filesystem), while others - 1024. This is a convention in the Unix/Linux world, since that's how actual physical blocks on hard drives are allocated.
  • Unlike GNU ls documentation, OpenBSD man page explicitly states: "If the file is a character special or block special file, the major and minor device numbers for the file are displayed in the size field." (emphasis added by me)


share|improve this answer

I can't find any documentation for why ls shows them instead of a plain 0 like du or stat, but, as Byte Commander says, they are the major and minor device numbers of that special file. From the source:

if (f->stat_ok
  && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
  char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
  char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
  int blanks_width = (file_size_width
                      - (major_device_number_width + 2
                         + minor_device_number_width));
  sprintf (p, "%*s, %*s ",
           major_device_number_width + MAX (0, blanks_width),
           umaxtostr (major (f->stat.st_rdev), majorbuf),
           umaxtostr (minor (f->stat.st_rdev), minorbuf));
  p += file_size_width + 1;

This code, part of the print_long_format() function, used when the output format is long (which it is with -l), uses the device numbers in place of size for character and block device.

To get the actual size of the device, several methods are listed in this Unix & Linux post.

share|improve this answer

It seems you missed the concept of 'everything-is-a-file'.

In the world of UNIX everything (data, devices, sockets, ..) is mapped to a file. Those files have types - in the case of your home directory you will (mostly) find so called regular files (text, programs,...).

In contrast to these regular files the /dev-directory holds - implied by the name - device files. Therefore you will find files of type character, block and pipe representing devices, eg. /dev/mem is a file that represents your systems memory, /dev/ttyACM0 can be a serial modem. The link between these (device-)files and the responsible drivers is created using the major and minor numbers as shown by ls (and as explained above).

The size of a device is a device specific attribute and must be queried using device specific tools (as shown in the post above) cause there is no unique way to deal with that attribute (a SSD may have a fixed size - but a serial port can deliver an endless stream of data so there is no fixed size, /dev/null has endless storage :)).

You can read on here:

share|improve this answer
Very good , much improved answer :) – Serg Jan 31 at 6:23
Thank you for guiding me. – hecke Jan 31 at 10:33

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.