Skip to content

File Types

"Everything is a file" means that directories, devices, pipes and sockets all appear in the filesystem and are opened with the same system calls. The first character of ls -l output tells which of the seven types an entry is, and the type decides what reading or writing it does.

Track: Core · Interview weight: Med


Must-Know Facts

Fact Value Verify with
- Regular file ls -l
d Directory ls -ld /etc
l Symbolic link ls -l /bin
c Character device (byte stream: terminals, /dev/null) ls -l /dev/null
b Block device (disks, partitions) ls -l /dev/vda
p Named pipe (FIFO) mkfifo p; ls -l p
s Unix domain socket ls -l /run/systemd/journal/stdout
Device numbers Major (driver) and minor (instance) replace the size column ls -l /dev/vda
Type from content file reads magic bytes; extensions mean nothing to the kernel file <path>
Type as text stat -c %F stat -c %F /dev/null
Search by type find -type f,d,l,c,b,p,s find /dev -type b

The Seven Types

touch regular.txt
mkdir dir
ln -s regular.txt link
mkfifo pipe
python3 -c 'import socket; s=socket.socket(socket.AF_UNIX); s.bind("sock")'
ls -l

Output:

total 4
drwxrwxr-x 2 laborant laborant 4096 Sep 16 13:52 dir
lrwxrwxrwx 1 laborant laborant   11 Sep 16 13:52 link -> regular.txt
prw-rw-r-- 1 laborant laborant    0 Sep 16 13:52 pipe
-rw-rw-r-- 1 laborant laborant    0 Sep 16 13:52 regular.txt
srwxrwxr-x 1 laborant laborant    0 Sep 16 13:52 sock

Devices already exist in /dev:

ls -l /dev/null /dev/vda /dev/tty1

Output:

crw-rw-rw- 1 root root   1, 3 Sep 16 13:23 /dev/null
crw--w---- 1 root tty    4, 1 Sep 16 13:23 /dev/tty1
brw-rw---- 1 root disk 253, 0 Sep 16 13:23 /dev/vda

For devices, 1, 3 is the major and minor number: the kernel uses the major number to pick a driver (1 is the memory devices driver) and the minor number to pick the instance.

Type Holds data on disk Typical use
Regular Yes Text, binaries, images
Directory Names and inode numbers Organizing files
Symbolic link The target path Version switching, usrmerge
Character device No Terminals, /dev/null, /dev/urandom
Block device No Disks, partitions, LVM volumes
FIFO No (kernel buffer) Passing data between unrelated processes
Socket No Local service APIs: Docker, systemd journal, MySQL

Identifying Types

ls -F appends a marker, stat prints the type name, and file inspects content:

ls -F
stat -c '%n: %F' regular.txt dir link pipe sock /dev/null /dev/vda
file regular.txt dir link pipe sock /dev/null /dev/vda /usr/bin/ls /etc/os-release

Output:

dir/
link@
pipe|
regular.txt
sock=
regular.txt: regular empty file
dir: directory
link: symbolic link
pipe: fifo
sock: socket
/dev/null: character special file
/dev/vda: block special file
regular.txt:     empty
dir:             directory
link:            symbolic link to regular.txt
pipe:            fifo (named pipe)
sock:            socket
/dev/null:       character special (1/3)
/dev/vda:        block special (253/0)
/usr/bin/ls:     ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=daa5130f2a41f7fbc8662048f3294f3d439ca7ff, for GNU/Linux 3.2.0, stripped
/etc/os-release: symbolic link to ../usr/lib/os-release

file ignores extensions and trusts the first bytes:

printf '\x7fELF' > fake.bin; file fake.bin
echo "data" > report.pdf; file report.pdf

Output:

fake.bin: ELF
report.pdf: ASCII text

Check a download before running it

file ./tool tells a real binary from an HTML error page saved under a binary's name. After a failed curl without -f, running the "binary" produces shell errors such as syntax error near unexpected token, because the kernel refuses the file (ENOEXEC) and bash then runs it as a shell script.

find selects by type:

find /tmp/types /dev/vda /dev/null -maxdepth 1 \( -type p -o -type s -o -type l -o -type b -o -type c \) -printf '%y %p\n'

Output:

p /tmp/types/pipe
s /tmp/types/sock
l /tmp/types/link
b /dev/vda
c /dev/null

Pipes and Sockets in Practice

A named pipe blocks the writer until a reader opens it, then passes data through a kernel buffer:

( sleep 1; echo "message through the FIFO" > pipe ) &
cat pipe
wait

Output:

message through the FIFO

Unix sockets are how local services talk. logger and the C library's syslog() write to /dev/log, which systemd-journald owns:

ls -l /run/systemd/journal/stdout /dev/log

Output:

lrwxrwxrwx 1 root root 28 Sep 16 13:23 /dev/log -> /run/systemd/journal/dev-log
srw-rw-rw- 1 root root  0 Sep 16 13:23 /run/systemd/journal/stdout

Socket permissions are access control

Anyone who can write to /var/run/docker.sock controls the Docker daemon, which runs as root. The socket's group (docker) is effectively a root group.


Common Errors

tool-arm64 below is a copy of /usr/bin/true with the ELF machine field changed to aarch64.

file tool-arm64 | cut -c1-60
./tool-arm64; echo "rc=$?"
uname -m
/dev/vda; echo "rc=$?"

Output:

tool-arm64: ELF 64-bit LSB pie executable, ARM aarch64, vers
bash: line 1: ./tool-arm64: cannot execute binary file: Exec format error
rc=126
x86_64
bash: line 1: /dev/vda: Permission denied
rc=126

./tool-arm64: cannot execute binary file: Exec format error

Cause: the file is a binary for another architecture (aarch64 on an x86_64 host).

Fix: download the build that matches uname -m.

/dev/vda: Permission denied

Cause: a device node was run as a command; device files have no execute bit.

Fix: use the tool meant for the device (lsblk, sudo fdisk -l).


Interview Checkpoints

L1: What does everything is a file mean in Linux?

Say first: devices, pipes, sockets and kernel state appear as paths and are used with the same open, read and write calls as regular files.

Proof: ls -l /dev/null /run/systemd/journal/stdout; cat /proc/loadavg.

Follow-up: What is the exception? (Network interfaces have no device file.)

L1: What is the difference between a character device and a block device?

Say first: a character device is an unbuffered byte stream (terminals, /dev/null); a block device is addressed in fixed-size blocks with kernel caching (disks).

Proof: ls -l /dev/tty1 /dev/vda shows c and b.

Follow-up: What do the two numbers in place of the size mean?

L2: List every block device file and every socket under /run.

Say first: filter by type with find.

Proof: find /dev -type b; sudo find /run -type s

Follow-up: Which command shows the same disks as a tree? (lsblk.)

L2: Pass output from one process to another that starts later, without a temporary file.

Say first: a named pipe.

Proof: mkfifo /tmp/p; producer > /tmp/p & then consumer < /tmp/p.

Follow-up: What happens to the writer if no reader ever opens the FIFO?

L3: A downloaded binary fails with Exec format error.

Say first: check what the file really is and which architecture the host runs.

Proof: file ./tool reports ARM aarch64 or HTML document; uname -m reports x86_64.

Follow-up: How do you make the download fail on an HTTP error instead? (curl -fL.)

L3: A user added to the docker group still gets permission denied on docker.sock.

Say first: check the socket's mode and group, then the user's live group list.

Proof: ls -l /var/run/docker.sock shows group docker; id in the current session lacks it until a new login.

Follow-up: Why is membership of that group a security concern?


Captured on Rocky Linux 10.2 and Ubuntu 24.04.4 LTS (iximiuz Labs microVMs, kernel 6.1.167), 2026-09.