26

On linux, there is a /dev/root device node. This will be the same block device as another device node, like /dev/sdaX. How can I resolve /dev/root to the 'real' device node in this situation, so that I can show a user a sensible device name?

For example, I might encounter this situation when parsing /proc/mounts.

I'm looking for solutions that would work from a shell/python script but not C.

kdt
  • 443
  • have you checked here ? http://linux-diag.sourceforge.net/Sysfsutils.html It recommends way to query the kernel about attached devices of all kinds, not sure, if its what you are looking for ! –  Jul 28 '11 at 23:02

6 Answers6

20

Parse the root= parameter from /proc/cmdline.

  • 1
    So much safer than dereferencing a symbolic link. +1 :) – Tim Post Jul 29 '11 at 02:38
  • 1
    This works on the three distros (fc14, rhel5, ubuntu 11.04) that I've looked at, with the slight caveat that there is an extra step needed to deal with root=UUID= type arguments. – kdt Jul 29 '11 at 10:16
  • I'm interested in why this is safer than the readlink solution, could someone elaborate? – opello Jun 26 '13 at 13:53
  • readlink does not always work, I'm working on this problem right now and found a user whose system shows no results from: readlink /dev/root - which tripped a glitch in the program I'm working on, which is why I came to this thread. The correct test is to first do: readlink /dev/root, then if null, find it in /proc/cmdline, but parsing /proc/cmdline is not as easy as a better solution, so I'll keep looking. – Lizardx Mar 18 '18 at 20:31
  • @kdt how do I deal with root=UUID arguments? – Choylton B. Higginbottom Feb 21 '22 at 21:41
  • A lot can happen to / between the kernel booting from root=foo to the system is up. I wouldn't trust parsing /proc/cmdline at all. It's better to check the major:minor of / and checking for a match in /sys/block/*/dev as described below. This is what I ended up doing in Finit. – troglobit May 01 '22 at 18:28
15

This should probably be updated, because a lot of the information given here is misleading, and may actually never have been comprehensively correct.

https://bootlin.com/blog/find-root-device/

For the / mount point, you are just told that it corresponds to /dev/root, which is not the real device you are looking for.

Of course, you can look at the kernel command line and see on which initial root filesystem Linux was instructed to boot (root parameter):

$ cat /proc/cmdline mem=512M console=ttyS2,115200n8 root=/dev/mmcblk0p2 rw rootwait

However, this doesn’t mean that what you see is the current root device. Many Linux systems boot on intermediate root filesystems (like initramdisks and initramfs), which are just used to access the final one.

One thing this points out was that the thing in /proc/cmdline is not necessarily the actual final device root actually live on.

That's from the busybox people, who I assume know what they are talking about when it comes to boot situations.

https://www.linuxquestions.org/questions/slackware-14/slackware-current-dev-root-688189/page2.html

The second useful resource I found is a very old Slackware thread about the question of /dev/root, from the age of this thread, we can see that all the variants were always present, but I believe 'most' distros were using the symbolic link method, but that was a simple kernel compile switch, it could make one, or not make one if I understood the posters correctly, that is, switch it one way, and readlink /dev/root reports the real device name, switch it the other, and it doesn't.

Since the main topic of that thread was how to get rid of /dev/root, they had to get into what it actually is, what makes it, etc, which means, they had to understand it to get rid of it.

gnashly explained it well:

/dev/root is a generic device which can be used in the fstab. One can also use 'rootfs'. Doing this offers some advantage in that it allows yout to be less specific. What I mean is, if the root partition is on an external drive, it may not always show up as the same device and successfully mounting it as / would require changing the fstab to match the correct device. By using /dev/root it will always match whatever device is specified in the kernel boot paramters from lilo or grub.

/dev/root has always been present as a virtual mount point, even if you never saw it. So has rootfs (compare this to the special virtual devices like proc and tmpfs which have no preceeding /dev)

/dev/root is a virtual device like 'proc' or /dev/tcp'. There is no device node in /dev for these things -it's already in the kernel as a virtual device.

This explains why a symbolic link does not necessarily exist. I'm surprised I never hit this issue before now, given that I maintain some programs that need to know this information, but better late than never.

I believe some of the solutions offered here will 'often' work, and are probably what I will do, but they are not the actual true solution to the problem, which as the busybox author noted, is significantly more complicated to implement in a very robust manner.

[UPDATE:} After getting some user test data, I'm going with the mount method, which seemed to be ok for some cases at least. The /proc/cmdline was not useful because there are too many variants. In the first example, you see the old method. This is less and less common because it's strongly discouraged to use it (the original /dev/sdx[0-9] type syntax) because those paths can change dynamically (swap disk order, insert new disk, etc, and suddenly /dev/sda1 becomes /dev/sdb1).

root=/dev/sda1
root=UUID=5a25cf4a-9772-40cd-b527-62848d4bdfda
root=LABEL=random string
root=PARTUUID=a2079bfb-02

VS the very clean and easy to parse:

mount
/dev/sda1 on / type ext4 (rw,noatime,data=ordered)

In the case of cmdline, you'll see, the only variant that is the right 'answer' in theory is the first, deprecated one, since you should not refer root to a moving target like /dev/sdxy

The next two require doing the further action of getting the symbolic link from that string in either /dev/disk/by-uuid or /dev/disk/by-label

The last one requires I believe using parted -l to find what that parted id is pointing to.

That's only the variants I know of and have seen, there could well be others, like GPTID, for example.

So the solution I'm using is this:

first, see if /dev/root is a symbolic link. If it is, verify it's not to /dev/disk/by-uuid or by-label, if it is, you have to do a second step of processing to get the last real path. Depends on the tool you use.

If you got nothing, then go to mount, and see how that is. As a last fallback case, one I'm not using because the arguments given against it not even necessarily being the actual partition or device in question are good enough for me to reject that solution for my program. mount is not a fully robust solution, and I'm sure given enough samples, it would be easy to find cases where it's not right at all, but I believe these two cases cover 'most' users, which is all I needed.

The nicest, cleanest, and most reliable solution would have been for the kernel to just always make the symbolic link, which would not have hurt anything or anyone, and call it good, but that's not how it worked out in the real world. .

I don't consider any of these as 'good or robust' solutions, but the mount option appears to satisfy the 'good enough', and if the truly robust solution is required, use the stuff that busybox recommended.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Lizardx
  • 3,058
  • 17
  • 18
14

On the systems I've looked at, /dev/root is a symlink to the real device, so readlink /dev/root (or readlink -f /dev/root if you want the full path), will do it.

cjm
  • 27,160
  • Or just ls -l /dev/root - shorter to type :) – rozcietrzewiacz Jul 29 '11 at 06:32
  • @jankes, but then you have to parse the output of ls (he asked for something to use in a script). – cjm Jul 29 '11 at 07:17
  • Ah, sorry - overlooked that. – rozcietrzewiacz Jul 29 '11 at 07:46
  • Nope -- on my RHEL5 machine it's definitely not a symlink, although on an FC14 or ubuntu 11.04 machine it is. – kdt Jul 29 '11 at 10:15
  • 2
    Does not work on archlinux. –  Jul 30 '13 at 18:31
  • 1
    @g33kz0r, my Arch Linux box doesn't have a /dev/root, which makes the question meaningless. – cjm Jul 30 '13 at 19:52
  • @cjm then perhaps your Arch Linux box isn't an Arch Linux ARM box... –  Jul 31 '13 at 00:42
  • 4
    Just to clarify, some systems with /dev/root will NOT show output for either ls -l or readlink because it's not a link, not in the normal sense we think of links anyway. I'm hitting this issue right now. So I'd update this answer to be correct for the systems he's looked at, but incorrect for an entire class of systems, like current ubuntu I believe, that he had not seen. I also had not seen this new variant for what it's worth until recently. – Lizardx Mar 18 '18 at 20:33
7

Well /dev/root is just a symbolic link to the real device, so you can use readlink(2) to find out where it points from a program, or readlink(1) to do the same thing from a shell script.

TomH
  • 3,002
6

Maybe I'm missing something, but what about:

mount|grep ' / '|cut -d' ' -f 1
2

If what you are looking for is a the device which the / filesystem is mounted on, then the easiest answer is probably to use: findmnt / (or findmnt -n -o SOURCE / for machine-readable output).

findmnt is part of util-linux, which should be present on all mainstream Linux distrubutions.

Tim Small
  • 121