what is Linux file system – linux development course

Linux File System Hierarchy
A Complete Guide for Embedded Linux Students — Every Directory Explained with Real Commands
20+
Directories Covered
50+
Hands-on Commands
FHS
Standard Explained

Why Should You Learn the Linux File System?

Hello students welcome to free linux development course by embedded pathashala, in this free linux development course you will studey what is Linux file system, whey we need linux file system, how linux file system is organized so When you work on embedded Linux systems — whether it’s a Raspberry Pi, a custom SoC board, or a Yocto-built image — the very first thing you will encounter is the Linux root filesystem. Every binary you run, every configuration you edit, every kernel module you load, every log you read — all of it is rooted in a well-defined directory structure called the Filesystem Hierarchy Standard (FHS).

Understanding why each directory exists, what lives inside it, and how permissions work is not optional knowledge — it is the foundation of embedded Linux engineering. This post walks you through every major directory with real Ubuntu commands so you can verify everything on your own machine.

Prerequisites: Basic familiarity with the Linux terminal. All examples tested on Ubuntu 22.04 / 24.04 with kernel 6.8.

Topics Covered in This Post

FHS Standard /bin /sbin /usr /proc Virtual FS /dev Device Files /sys Sysfs /lib Shared Libs /etc Config Files File Permissions User Group Others Symlinks Explained /proc/cpuinfo chmod chown

The Big Picture — What Does Linux See?

Linux runs as three layers: Hardware at the bottom, Kernel in the middle (the bridge), and User-space programs on top. The filesystem hierarchy is how user-space programs and the kernel organize their files, configuration, and data.

Linux System Layers
USER SPACE  |  bash  ·  python  ·  gcc  ·  grep  ·  GNOME  ·  your-app
↕   System Call Interface   ↕
KERNEL SPACE  |  Process Control  ·  Memory Mgmt  ·  File Subsystem  ·  Device Drivers
↕   Hardware Abstraction Layer   ↕
HARDWARE  |  CPU  ·  RAM  ·  Disk  ·  Network  ·  Keyboard  ·  Display

The kernel has two “rings” of operation (in x86 terms: Ring 0 = kernel mode, Ring 3 = user mode). When user programs need hardware access, they cross this boundary via system calls. The filesystem is what makes all resources available in a uniform, hierarchical way — even hardware devices appear as files in Linux!

linux file system hirearcy, free linux development course
linux file system hirearcy, free linux development course

The Root Filesystem — Everything Starts at /

In Linux, there is only one root — the / (forward slash). Unlike Windows which has C:\, D:\, etc., Linux mounts everything under a single root. Every partition, every USB drive, every network share — all appear as subdirectories somewhere under /.

Linux Root Filesystem Hierarchy (FHS)
/ (root)
├── /bin → /usr/bin (essential user binaries)
├── /sbin → /usr/sbin (system binaries)
├── /lib → /usr/lib (shared libraries)
├── /lib32 → /usr/lib32
├── /lib64 → /usr/lib64
├── /usr
├── /usr/bin
├── /usr/sbin
├── /usr/lib
├── /usr/include
├── /usr/share
├── /usr/src
└── /usr/local
├── /usr/local/bin
├── /usr/local/lib
└── /usr/local/share
├── /etc (configuration)
├── /home
└── /home/raviteja
├── /root (root user home)
├── /boot
├── /dev
├── /proc
├── /sys
├── /tmp
├── /var
├── /var/log
├── /var/mail
├── /var/spool
└── /var/cache
├── /run
├── /media
├── /mnt
├── /opt
├── /srv
├── /snap
└── /lost+found

Let’s verify this on a real Ubuntu system:

raviteja@raviteja-Inspiron-15-3511:/$ ls -l /
total 2097232
lrwxrwxrwx   1 root root          7 Nov  2 18:18 bin -> usr/bin
drwxr-xr-x   4 root root       4096 Apr 26 11:36 boot
drwxrwxr-x   2 root root       4096 Nov  2 18:21 cdrom
drwxr-xr-x  21 root root       5040 Apr 26 11:34 dev
drwxr-xr-x 135 root root      12288 Apr 26 11:35 etc
drwxr-xr-x   3 root root       4096 Nov  2 18:21 home
lrwxrwxrwx   1 root root          7 Nov  2 18:18 lib -> usr/lib
lrwxrwxrwx   1 root root          9 Nov  2 18:18 lib32 -> usr/lib32
lrwxrwxrwx   1 root root          9 Nov  2 18:18 lib64 -> usr/lib64
lrwxrwxrwx   1 root root         10 Nov  2 18:18 libx32 -> usr/libx32
drwx------   2 root root      16384 Nov  2 18:18 lost+found
drwxr-xr-x   3 root root       4096 Apr 11 20:36 media
drwxr-xr-x   2 root root       4096 Sep 11  2024 mnt
drwxr-xr-x   5 root root       4096 Feb 26 23:19 opt
dr-xr-xr-x 339 root root          0 Apr 26 11:34 proc
drwx------   7 root root       4096 Apr  5 22:23 root
drwxr-xr-x  36 root root        960 Apr 26 11:36 run
lrwxrwxrwx   1 root root          8 Nov  2 18:18 sbin -> usr/sbin
drwxr-xr-x  21 root root       4096 Dec 16 23:39 snap
drwxr-xr-x   2 root root       4096 Sep 11  2024 srv
-rw-------   1 root root 2147483648 Nov  2 18:18 swapfile
dr-xr-xr-x  13 root root          0 Apr 26 11:34 sys
drwxrwxrwt  20 root root       4096 Apr 26 12:30 tmp
drwxr-xr-x  17 root root       4096 Apr 25 15:24 usr
drwxr-xr-x  14 root root       4096 Sep 11  2024 var

Key Observation: Notice bin -> usr/bin, lib -> usr/lib, sbin -> usr/sbin. These are symbolic links! Modern Ubuntu (since 20.04) merged the old root-level /bin into /usr/bin. The symlinks exist for backward compatibility. We will explain why this happened.

Understanding ls -l Output — Permissions, Owner, Group

Before we dive into each directory, you must understand how to read file permissions in Linux. This is fundamental — embedded engineers deal with this every day when deploying files onto a target board.

Anatomy of ls -l Output

$ ls -l /bin/bash

-rwxr-xr-x 1 root root 1396520 Mar 2 2023 /bin/bash
│────────── Permissions
│── Hard Links
│── Owner (User)
│── Group
│── File Size
│── Date
│── Filename

Breaking down permissions:

-rwxr-xr-x
File type
├── User (owner): rwx (read, write, execute)
├── Group: r-x (read, execute)
└── Others: r-x (read, execute)

File type meanings:

= regular file
d = directory
l = symbolic link
c = character device
b = block device
p = named pipe (FIFO)
s = socket

Permission Values (Octal)
Symbol Octal Meaning
—————————————-
0 No permissions
–x 1 Execute only
-w- 2 Write only
-wx 3 Write + Execute
r– 4 Read only
r-x 5 Read + Execute
rw- 6 Read + Write
rwx 7 Read + Write + ExecuteExample: chmod 755 myfile
7 = rwx → Owner: read, write, execute
5 = r-x → Group: read, execute
5 = r-x → Others: read, executeExample: chmod 644 config.txt
6 = rw- → Owner: read, write
4 = r– → Group: read only
4 = r– → Others: read only

Let’s try these commands on your Ubuntu machine:

# View permissions of files in /bin
ls -l /bin/bash /bin/ls /bin/cat

# Output:
-rwxr-xr-x 1 root root 1396520 Mar  2  2023 /bin/bash
-rwxr-xr-x 1 root root  147176 Feb  9  2024 /bin/cat
-rwxr-xr-x 1 root root  142144 Feb  9  2024 /bin/ls

# Who owns a file?
stat /bin/bash

# Output:
  File: /bin/bash
  Size: 1396520   Blocks: 2728       IO Block: 4096   regular file
Device: 259,2     Inode: 10880       Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2026-04-25 08:10:12
Modify: 2023-03-02 12:27:18
Change: 2026-04-25 08:10:10

# Check your groups
groups
# Output: raviteja adm dialout cdrom sudo dip plugdev lpadmin lxd sambashare

# View /etc/passwd — user database
cat /etc/passwd | head -5
# Output:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync

# View /etc/group — group database
cat /etc/group | grep raviteja
# Output:
adm:x:4:syslog,raviteja
cdrom:x:24:raviteja
sudo:x:27:raviteja
dip:x:30:raviteja

Anatomy of /etc/passwd Entry
root : x : 0 : 0 : root : /root : /bin/bash
│──────── Username
│──────── Password placeholder (x → stored in /etc/shadow)
│──────── User ID (UID)
│──────── Group ID (GID)
│──────── GECOS (full name / comment)
│──────── Home directory
│──────── Login shellField Meaning:Username → login name
x → password stored in /etc/shadow
UID → user identifier
GID → primary group
GECOS → user info (name/comment)
Home → user home directory
Shell → default login shell
# Change file owner (requires sudo)
sudo chown raviteja:raviteja myfile.txt

# Change permissions
chmod 755 myscript.sh      # Owner: rwx, Group: r-x, Others: r-x
chmod 644 config.txt       # Owner: rw-, Group: r--, Others: r--
chmod +x myscript.sh       # Add execute permission for all
chmod o-r secret.txt       # Remove read from others

# View numeric permissions
stat -c "%a %n" /bin/bash
# Output: 755 /bin/bash

# Special permissions: SUID, SGID, Sticky bit
ls -l /usr/bin/passwd
# Output: -rwsr-xr-x 1 root root 59976 Feb  6  2024 /usr/bin/passwd
# Note: 's' in owner execute position = SUID bit
# SUID: runs with the file owner's privileges (root here)
# This is why 'passwd' can modify /etc/shadow even as a normal user

ls -ld /tmp
# Output: drwxrwxrwt 20 root root 4096 Apr 26 12:30 /tmp
# Note: 't' in others execute position = Sticky bit
# Sticky bit: Only file owner can delete their own files in this dir

1. /bin — Essential User Binaries

/bin → symlink to /usr/bin (modern Ubuntu)

The /bin directory contains the essential command-line tools that every user needs — even during single-user mode or system recovery when /usr might not yet be mounted. Think of this as the “survival kit” of Linux: if you only have /bin, you can still do basic work.

Why does it exist as a symlink to /usr/bin in Ubuntu 20.04+? Historically, /bin and /usr/bin were on separate partitions. As systems evolved, this separation became unnecessary and caused headaches. The UsrMerge project merged everything into /usr/bin and made /bin a symlink for backward compatibility.

Old vs Modern Layout

Old Layout (pre-Ubuntu 20.04)
————————————/bin/bash
/bin/ls
/bin/cat
/sbin/fdisk
/usr/bin/python3
/usr/sbin/useradd

Modern Layout (Ubuntu 20.04+)
————————————/bin → /usr/bin
/sbin → /usr/sbin
/lib → /usr/libAll binaries in:
/usr/bin
/usr/sbin

Benefits:
✔ Simpler structure (no split /usr)
✔ Easier system maintenance

Backward Compatibility:
/bin/bash still works (via symlink)

# Verify /bin is a symlink
ls -la /bin
# Output: lrwxrwxrwx 1 root root 7 Nov  2 18:18 /bin -> usr/bin

# Both these paths work identically:
/bin/bash --version
/usr/bin/bash --version

# List what's in /bin (same as /usr/bin)
ls /bin | head -20
# Output: (hundreds of executables)
# [         addr2line  ar         as         bash
# bunzip2   bzcat      bzip2      c89        c99
# cat       cc         chcon      chgrp      chmod ...

# Count total binaries
ls /bin | wc -l
# Output: 1914  (on a typical Ubuntu 22.04 install)

# Find a specific binary
which ls
# Output: /usr/bin/ls

which bash
# Output: /usr/bin/bash

# View file type of a binary
file /bin/bash
# Output: /bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
#          dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
#          BuildID[sha1]=..., for GNU/Linux 3.2.0, stripped

Key binaries in /bin (some important ones):

Important /bin Commands

Shell
bash, sh, dash → Shell interpretersFile Operations
ls, cp, mv, rmFile Viewing
cat, head, tail

Text Processing
grep, awk, sed

Permissions
chmod, chownFilesystem
mount, umountProcesses
ps, kill

Networking
ping, ip

Archive
tar, gzip, bzip2

Search
find, which

Utilities
echo, printf, date, sleep

User
su → Switch user

2. /sbin — System Binaries (Root Only)

/sbin → symlink to /usr/sbin

The /sbin directory contains system administration binaries — tools needed to boot, repair, and maintain the system. Unlike /bin, most commands in /sbin require root (superuser) privileges. A regular user can see them but cannot run them without sudo.

/bin vs /sbin — Key Difference

/bin
——————————–Access:
All users can run

Purpose:
Basic daily tools

Examples:
ls, cat, grep, cp, mv
bash, ping, tar

Usage:
Available in rescue mode

Files:
~1914 files (typical)

/sbin
——————————–Access:
Root / sudo required

Purpose:
System management tools

Examples:
fdisk, fsck, mkfs, iptables
useradd, route, ifconfig

Usage:
Used for boot & repair

Files:
~400 files (typical)

# /sbin is a symlink too
ls -la /sbin
# Output: lrwxrwxrwx 1 root root 8 Nov  2 18:18 /sbin -> usr/sbin

# List important sbin commands
ls /sbin | head -30
# Output:
# agetty         badblocks      blockdev       chroot
# debugfs        depmod         dhclient       dumpe2fs
# e2fsck         fdisk          fsck           getty
# grub-install   halt           ifconfig       init
# insmod         iptables       ldconfig       lsmod
# mkfs           modprobe       mount.ext4     parted
# reboot         rmmod          route          shutdown
# swapon         swapoff        tune2fs        useradd

# Try running fdisk as normal user:
fdisk -l
# Output: fdisk: cannot open /dev/sda: Permission denied

# Run with sudo:
sudo fdisk -l
# Output:
# Disk /dev/sda: 476.94 GiB, 512110190592 bytes, 1000215216 sectors
# Disk model: WDC WDS500G2B0A-
# Units: sectors of 1 * 512 = 512 bytes
# ...

# Check kernel modules (embedded Linux essential!)
lsmod | head -10
# Output:
# Module                  Size  Used by
# snd_hda_intel          57344  0
# snd_hda_codec         196608  1 snd_hda_intel
# bluetooth             802816  0
# rfkill                 32768  4 bluetooth

# Load a kernel module
sudo modprobe bluetooth

# Remove a kernel module
sudo modprobe -r bluetooth

# Check module info
modinfo bluetooth | head -10
# Output:
# filename: /lib/modules/6.8.0-58-generic/kernel/net/bluetooth/bluetooth.ko
# alias:          net-pf-31
# license:        GPL
# description:    Bluetooth Core ver 2.22

3. /usr — Unix System Resources

/usr — The Largest Directory on Most Systems

/usr is the second most important directory after /. Its name originally meant “user” but now stands for Unix System Resources. It contains the majority of user-space applications, libraries, documentation, and header files. On a typical Ubuntu desktop, /usr may contain 10–30 GB of data.

/usr Directory Tree
/usr/
├── bin/ (python3, gcc, vim, git)
├── sbin/ (useradd, nginx)
├── lib/ (libraries for binaries)
├── x86_64-linux-gnu/ (.so files)
├── python3/ (Python standard library)
└── modules/ (kernel modules)
├── lib32/ (32-bit libraries)
├── lib64/ (64-bit libraries)
├── include/ (header files)
├── stdio.h
├── stdlib.h
├── linux/ (kernel headers)
└── bluetooth/ (Bluetooth headers)
├── share/ (architecture-independent data)
├── man/ (manual pages)
├── doc/ (documentation)
├── locale/ (language data)
└── fonts/ (fonts)
├── local/ (custom installed software)
├── bin/ (your binaries)
├── lib/
└── share/
└── src/ (source code)
# How big is /usr?
du -sh /usr
# Output: 11G    /usr   (typical for Ubuntu 22.04)

# List /usr structure
ls -lh /usr
# Output:
# drwxr-xr-x  2 root root  60K Apr 25 15:24 bin
# drwxr-xr-x  2 root root 4.0K Sep 11  2024 games
# drwxr-xr-x 80 root root  28K Apr 25 15:24 include
# drwxr-xr-x 95 root root  20K Apr 25 15:24 lib
# drwxr-xr-x  2 root root 4.0K Nov  2 18:18 lib32
# drwxr-xr-x  2 root root 4.0K Nov  2 18:18 lib64
# drwxr-xr-x 14 root root 4.0K Nov  2 18:18 libexec
# drwxr-xr-x  2 root root 4.0K Nov  2 18:18 libx32
# drwxr-xr-x 12 root root 4.0K Nov  2 18:18 local
# drwxr-xr-x  3 root root  24K Apr 25 15:24 sbin
# drwxr-xr-x 219 root root  12K Apr 25 15:24 share
# drwxr-xr-x  8 root root 4.0K Nov  2 18:18 src

# Find where python3 lives
which python3
# Output: /usr/bin/python3

ls -la /usr/bin/python3
# Output: lrwxrwxrwx 1 root root 10 ... /usr/bin/python3 -> python3.11

# Check C header files (important for embedded devs)
ls /usr/include/ | head -20
# Output:
# aio.h         alloca.h      argp.h        arpa
# asm            asm-generic   assert.h      bluetooth
# c++            complex.h     crypt.h       ctype.h

# Bluetooth headers for embedded dev:
ls /usr/include/bluetooth/
# Output:
# bluetooth.h  hci.h  hci_lib.h  l2cap.h  rfcomm.h
# sdp.h  sdp_lib.h  sco.h

# /usr/local — for your own compiled programs (not managed by apt)
ls /usr/local/bin/
# Usually empty or has your custom tools

# Example: after compiling your own program
# ./configure --prefix=/usr/local
# make && sudo make install
# It goes to /usr/local/bin/, /usr/local/lib/ etc.

4. /lib — Shared Libraries (The .so Files)

/lib → symlink to /usr/lib

Shared libraries (.so files — “Shared Objects”) are the Linux equivalent of Windows DLLs. When you run ls or bash, they don’t contain all the code they need — they dynamically load library code at runtime. /lib (now merged into /usr/lib) stores these shared libraries.

Static vs Shared Libraries

Static Library (.a)
——————————–Code copied into each binary
Each binary is self-contained
Larger binary size
No dependency issues
Good for embedded systems

Example:
libc.a (static C library)

Shared Library (.so)
——————————–Code shared among binaries
Loaded at runtime
Smaller binary size
Needs correct .so version
Default on Linux systems

Example:
libc.so (used by most programs)

# /lib is a symlink
ls -la /lib
# Output: lrwxrwxrwx 1 root root 7 Nov  2 18:18 /lib -> usr/lib

# What's inside /usr/lib?
ls /usr/lib | head -20
# Output:
# bfd-plugins     bluetooth        cmake
# debug           dpkg             gcc
# grub            hdparm           kernel
# locale          mime             modules
# os-release      pam.d            python3
# systemd         terminfo         udev
# x86_64-linux-gnu

# Architecture-specific libraries (most .so files are here)
ls /usr/lib/x86_64-linux-gnu/ | head -20
# Output:
# libc.so.6            ← The C standard library (used by almost everything)
# libm.so.6            ← Math library
# libpthread.so.0      ← POSIX threads library
# libssl.so.3          ← OpenSSL
# libcrypt.so.2        ← Cryptography
# libbluetooth.so.3    ← Bluetooth (important for embedded!)
# libz.so.1            ← Zlib compression

# See what libraries a binary depends on (very useful for embedded!)
ldd /bin/bash
# Output:
#     linux-vdso.so.1 (0x00007ffd26bfb000)
#     libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f89bc4d0000)
#     libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f89bc2a8000)
#     /lib64/ld-linux-x86-64.so.2 (0x00007f89bc79e000)

ldd /usr/bin/python3.11
# Output: (many .so dependencies listed)

# Check library version (important for compatibility)
ls -la /usr/lib/x86_64-linux-gnu/libc*
# Output:
# -rw-r--r-- 1 root root  5.0M libc.a
# lrwxrwxrwx 1 root root     6 ... libc.so -> libc.so.6
# -rwxr-xr-x 1 root root  2.2M ... libc.so.6

# ldconfig — update shared library cache (run after installing .so files)
sudo ldconfig

# View library cache
ldconfig -p | grep bluetooth
# Output: libbluetooth.so.3 (libc6,x86-64) => /lib/x86_64-linux-gnu/libbluetooth.so.3

# Kernel modules (special kind of library for the kernel)
ls /lib/modules/
# Output: 6.8.0-58-generic   (your current kernel version)

ls /lib/modules/$(uname -r)/kernel/
# Output:
# arch/    block/    crypto/    drivers/    fs/
# kernel/  lib/      mm/        net/        sound/

# Find Bluetooth kernel modules
ls /lib/modules/$(uname -r)/kernel/net/bluetooth/
# Output:
# bluetooth.ko.zst    ← Core Bluetooth module
# hidp/               ← HID over Bluetooth
# rfcomm/             ← Serial port emulation
# bnep/               ← Network encapsulation

5. /proc — The Virtual Process Filesystem ⭐

/proc — This Directory Does NOT Exist on Disk!

/proc is the most fascinating directory in Linux. It is a virtual filesystem (also called a pseudo-filesystem) — it does not exist on your hard drive at all. It lives entirely in RAM and is created fresh each time the kernel boots. The kernel populates it in real-time to expose process information and kernel internals as regular files you can read with cat.

This is the Linux philosophy: “Everything is a file.” Even running processes, CPU info, memory stats, network connections — all readable as files under /proc.

/proc Structure
/proc/
├── [PID]/ (one directory per process)
├── cmdline (startup command)
├── status (state, memory, UID, GID)
├── maps (memory map, loaded libraries)
├── fd/ (open file descriptors)
├── exe (symlink to executable)
├── cwd (current working directory)
└── net/ (process network namespace)
├── cpuinfo (CPU details)
├── meminfo (memory usage)
├── version (kernel version)
├── uptime (system uptime)
├── loadavg (CPU load averages)
├── net/ (network stats)
├── tcp
├── udp
├── dev
└── arp
├── sys/ (kernel parameters)
├── kernel/
├── net/
└── vm/
├── mounts (mounted filesystems)
├── filesystems (supported FS types)
├── interrupts (hardware interrupts)
├── ioports (I/O ports)
├── devices (device numbers)
└── self (current process link)
# /proc is virtual — 0 bytes on disk but infinite info!
df -h /proc
# Output:
# Filesystem     Size  Used Avail Use% Mounted on
# proc              0     0     0    -  /proc

# ---- CPU Information ----
cat /proc/cpuinfo | head -30
# Output:
# processor   : 0
# vendor_id   : GenuineIntel
# cpu family  : 6
# model       : 140
# model name  : 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
# stepping    : 1
# microcode   : 0xaa
# cpu MHz     : 800.024
# cache size  : 8192 KB
# physical id : 0
# siblings    : 8
# core id     : 0
# cpu cores   : 4
# flags       : fpu vme de pse tsc msr pae mce cx8 apic ...

# How many CPU cores?
nproc
# Output: 8

grep "cpu cores" /proc/cpuinfo | uniq
# Output: cpu cores   : 4

# ---- Memory Information ----
cat /proc/meminfo | head -20
# Output:
# MemTotal:       16071972 kB   ← 16 GB RAM
# MemFree:         1234567 kB
# MemAvailable:    8901234 kB
# Buffers:          234567 kB
# Cached:          4567890 kB
# SwapTotal:       2097152 kB   ← 2 GB swap
# SwapFree:        2097152 kB

free -h
# Output:
#               total   used    free   shared  buff/cache  available
# Mem:           15Gi   6.7Gi  1.1Gi   543Mi     7.2Gi    8.5Gi
# Swap:         2.0Gi    0B    2.0Gi

# ---- Kernel Version ----
cat /proc/version
# Output:
# Linux version 6.8.0-58-generic (buildd@lcy02-amd64-017)
# (gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0, GNU ld (GNU Binutils for Ubuntu) 2.42)
# #60-Ubuntu SMP PREEMPT_DYNAMIC Thu Mar 27 17:23:22 UTC 2025

uname -a
# Output:
# Linux raviteja-Inspiron-15-3511 6.8.0-58-generic #60-Ubuntu SMP ...

# ---- System Uptime ----
cat /proc/uptime
# Output: 3721.43 12345.67
# First number = seconds since boot, Second = idle CPU seconds

uptime
# Output: 12:30:22 up 1:02, 2 users, load average: 0.52, 0.48, 0.45

# ---- Process Information ----
# Each running process has a directory named by its PID
ls /proc | grep -E '^[0-9]+$' | head -10
# Output: 1  2  3  9  10  11  12  15  ... (one per process)

# What is process 1?
cat /proc/1/cmdline | tr '\0' ' '
# Output: /sbin/init splash  (systemd — the init process)

ls -la /proc/1/exe
# Output: lrwxrwxrwx 1 root root 0 ... /proc/1/exe -> /usr/lib/systemd/systemd

# Find your bash process
echo $$         # Your current shell PID
# Output: 12345

cat /proc/$$/cmdline | tr '\0' ' '
# Output: bash

cat /proc/$$/status | head -20
# Output:
# Name:   bash
# Umask:  0022
# State:  S (sleeping)
# Tgid:   12345
# Pid:    12345
# PPid:   12344        ← Parent PID
# Uid:    1000  1000  1000  1000   ← real, effective, saved, filesystem UID
# Gid:    1000  1000  1000  1000

# Open files of a process (file descriptors)
ls -la /proc/$$/fd
# Output:
# lrwxrwxrwx 1 raviteja raviteja 64 ... 0 -> /dev/pts/1   (stdin)
# lrwxrwxrwx 1 raviteja raviteja 64 ... 1 -> /dev/pts/1   (stdout)
# lrwxrwxrwx 1 raviteja raviteja 64 ... 2 -> /dev/pts/1   (stderr)

# Memory map of your bash process
cat /proc/$$/maps | head -10
# Output: (shows all memory regions: code, heap, stack, libraries)

# ---- Network Information ----
cat /proc/net/tcp | head -5
# Output: (TCP connections in hex format)

# More readable:
ss -tn     # TCP connections
ss -un     # UDP sockets

# ---- Kernel Parameters (sysctl) ----
# /proc/sys/ contains tunable kernel parameters
cat /proc/sys/kernel/hostname
# Output: raviteja-Inspiron-15-3511

cat /proc/sys/vm/swappiness
# Output: 60   (how aggressively kernel uses swap — 0-100)

# Change a parameter temporarily (lost on reboot):
echo 10 | sudo tee /proc/sys/vm/swappiness

# Make it permanent — add to /etc/sysctl.conf:
# vm.swappiness=10
# Then run: sudo sysctl -p

# ---- Load Average ----
cat /proc/loadavg
# Output: 0.52 0.48 0.45 2/1423 12345
# 0.52 = 1 min avg, 0.48 = 5 min avg, 0.45 = 15 min avg
# 2/1423 = 2 running / 1423 total threads
# 12345 = last PID assigned

# ---- Interrupt Statistics (Embedded debugging!) ----
cat /proc/interrupts | head -15
# Output:
#             CPU0   CPU1   CPU2   CPU3
#   0:         16      0      0      0   IO-APIC   2-edge      timer
#   1:          0      0   3412      0   IO-APIC   1-edge      i8042 (keyboard)
#  16:          0      0      0      0   IO-APIC  16-level      ...
# Bluetooth: shows interrupt count per CPU — useful for embedded tuning!

Embedded Tip: On embedded boards, /proc/cpuinfo shows the ARM processor, features (neon, vfp, etc.), and hardware model. Always check this first when bringup a new board. /proc/interrupts helps you debug which IRQ your peripheral is using.

6. /dev — Device Files

/dev — “Everything is a File” in Action

In Linux, hardware devices are represented as files in /dev. Your hard disk, USB drive, terminal, random number generator, Bluetooth adapter, serial port — all appear as files here. This is managed by udev (the device manager daemon) which dynamically creates and removes entries as hardware is plugged/unplugged.

Device File Types

Block Devices (b) — read/write in blocks (buffered)

├── /dev/sda → First SATA/SSD disk
├── /dev/sda1 → First partition
├── /dev/nvme0n1 → NVMe SSD
├── /dev/nvme0n1p1 → NVMe partition
├── /dev/mmcblk0 → eMMC / SD card
└── /dev/mmcblk0p1 → eMMC partition

Character Devices (c) — byte-by-byte (unbuffered)

├── /dev/tty → Current terminal
├── /dev/ttyS0 → Serial port
├── /dev/ttyUSB0 → USB serial
├── /dev/input/event0 → Input devices
├── /dev/video0 → Camera
├── /dev/snd/ → Sound devices
├── /dev/i2c-0 → I2C bus
├── /dev/spidev0.0 → SPI bus
└── /dev/gpiochip0 → GPIO controller

Special Devices

├── /dev/null → Discards all data
├── /dev/zero → Infinite zero bytes
├── /dev/random → Secure random
├── /dev/urandom → Fast random
├── /dev/mem → Physical memory (root)
├── /dev/kmem → Kernel memory
└── /dev/pts/ → Pseudo-terminals

# List block devices
lsblk
# Output:
# NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
# sda           8:0    0  476.9G  0 disk
# ├─sda1        8:1    0    512M  0 part /boot/efi
# ├─sda2        8:2    0      1G  0 part /boot
# └─sda3        8:3    0  475.4G  0 part /
# sr0          11:0    1  1024M  0 rom

# List all devices with details
ls -la /dev | head -20
# Output:
# crw--w---- 1 root   tty    4,   0 Apr 26 ...  tty0     (c = char device)
# brw-rw---- 1 root   disk   8,   0 Apr 26 ...  sda      (b = block device)
# crw-rw-rw- 1 root   root   1,   3 Apr 26 ...  null
# crw-rw-rw- 1 root   root   1,   5 Apr 26 ...  zero
# crw-rw-rw- 1 root   root   1,   9 Apr 26 ...  urandom

# MAJ:MIN — Major:Minor numbers
# Major = which driver handles this device
# Minor = which device instance

# Practical use of /dev/null — discard output
ls -la /nonexistent 2>/dev/null       # Discard error
ls -la /nonexistent > /dev/null 2>&1  # Discard all output

# Practical use of /dev/zero — create empty file
dd if=/dev/zero of=empty_1MB.bin bs=1024 count=1024
# Output: Creates a 1MB file filled with zeros (useful for filesystem images!)

# Practical use of /dev/urandom — generate random data
dd if=/dev/urandom of=random_data.bin bs=1 count=32
hexdump -C random_data.bin
# Used for encryption keys, test data

# Read from serial port (UART — common in embedded!)
# sudo screen /dev/ttyS0 115200    ← Connect to UART at 115200 baud
# stty -F /dev/ttyS0 115200        ← Set baud rate

# Your current terminal
echo $TTY
ls -la /dev/pts/
# Output: (one entry per open terminal session)

# What is your Bluetooth device?
ls /dev | grep -i bluetooth
# Output: Bluetooth device files (if present)

# Check device file type (b=block, c=char)
ls -la /dev/sda
# Output: brw-rw---- 1 root disk 8, 0 Apr 26 11:34 /dev/sda
# Note: 'b' at start = block device
# Note: 8, 0 = major 8, minor 0

ls -la /dev/tty
# Output: crw-rw-rw- 1 root tty 5, 0 Apr 26 11:34 /dev/tty
# Note: 'c' at start = character device

7. /sys — The sysfs Virtual Filesystem

/sys — Kernel’s Window to Hardware

/sys is another virtual filesystem (like /proc) but more structured. While /proc is process-centric, /sys is hardware/driver-centric. It exposes the kernel’s device model — what devices are connected, what drivers are loaded, and lets you control hardware settings directly. Embedded engineers spend a lot of time in /sys.

/sys Directory Structure
/sys/
├── bus/ (i2c, spi, pci, usb, platform, bluetooth)
├── class/ (net, block, input, leds, tty)
├── devices/ (kernel device tree)
├── firmware/ (ACPI, EFI tables)
├── fs/ (ext4, cgroup, etc.)
├── kernel/ (kernel internals)
└── debug/ (debug information)
├── module/ (loaded kernel modules + parameters)
└── power/ (power management)
# /sys is also virtual — 0 bytes on disk
df -h /sys
# Output: sysfs 0 0 0 - /sys

# List all network interfaces (embedded boards have eth0, wlan0, etc.)
ls /sys/class/net/
# Output: enp2s0  lo  wlp0s20f3

# Get network interface speed
cat /sys/class/net/enp2s0/speed
# Output: 1000  (1000 Mbps = Gigabit)

cat /sys/class/net/lo/operstate
# Output: unknown

cat /sys/class/net/wlp0s20f3/operstate
# Output: up

# Control LED brightness (embedded boards often have LEDs!)
# ls /sys/class/leds/
# echo 0 > /sys/class/leds/led0/brightness   # Turn off LED
# echo 1 > /sys/class/leds/led0/brightness   # Turn on LED

# Check block device info
ls /sys/class/block/
# Output: loop0 loop1 ... sda sda1 sda2 sda3

cat /sys/class/block/sda/size
# Output: 1000215216  (sectors, multiply by 512 for bytes)

# I2C buses (embedded!)
ls /sys/bus/i2c/devices/
# Output: i2c-0  i2c-1  i2c-2  (I2C buses on your system)

# USB devices
ls /sys/bus/usb/devices/ | head -10
# Output: (one entry per USB device/port)

# Loaded kernel modules and their parameters
ls /sys/module/ | head -10
# Output:
# 8250  acpi_cpufreq  aesni_intel  ahci  ata_piix  ...

# Bluetooth module parameters
ls /sys/module/bluetooth/parameters/
# Output: disable_esco  enable_ecred  enable_hs

cat /sys/module/bluetooth/parameters/disable_esco
# Output: N  (ESCO is enabled)

# CPU frequency scaling (important for embedded power management!)
ls /sys/devices/system/cpu/cpu0/cpufreq/
# Output:
# cpuinfo_cur_freq    cpuinfo_max_freq    cpuinfo_min_freq
# scaling_governor    scaling_available_governors

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# Output: powersave   (or performance, schedutil)

cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
# Output: 4200000  (4.2 GHz max)

8. /etc — System-Wide Configuration

/etc — “Edit to Configure” (not “etcetera”!)

/etc contains all system-wide configuration files. Every installed program that needs configuration stores its config here. No binaries live here — only text files (mostly) that control system behavior. As an embedded developer, you will frequently edit files in /etc to configure networking, Bluetooth, users, and services.

Important /etc Files
/etc/
├── passwd (user accounts)
├── shadow (encrypted passwords)
├── group (group definitions)
├── sudoers (sudo permissions)
├── hostname
├── hosts (static DNS)
├── resolv.conf (DNS config)
├── fstab (mount at boot)
├── mtab (mounted FS)
├── os-release (OS info)
├── issue (login banner)
├── timezone
├── locale.conf
├── bash.bashrc (global bash config)
├── profile (shell profile)
├── environment (env variables)
├── network/ (network config)
├── netplan/ (Ubuntu YAML config)
├── NetworkManager/
├── bluetooth/
└── main.conf (BlueZ config)
├── systemd/
├── system/ (services)
└── network/ (networkd)
├── udev/
└── rules.d/ (device rules)
├── apt/
└── sources.list (repositories)
├── ssl/ (certificates)
├── ssh/
└── sshd_config
├── cron.d/ (scheduled tasks)
└── init.d/ (legacy scripts)
# System identification
cat /etc/os-release
# Output:
# PRETTY_NAME="Ubuntu 22.04.4 LTS"
# NAME="Ubuntu"
# VERSION_ID="22.04"
# VERSION="22.04.4 LTS (Jammy Jellyfish)"
# ID=ubuntu
# ID_LIKE=debian

# Hostname
cat /etc/hostname
# Output: raviteja-Inspiron-15-3511

# Hosts file (local DNS)
cat /etc/hosts
# Output:
# 127.0.0.1   localhost
# 127.0.1.1   raviteja-Inspiron-15-3511
# ::1         localhost ip6-localhost

# Filesystem table (what mounts at boot)
cat /etc/fstab
# Output:
# UUID=xxxx  /          ext4   errors=remount-ro 0       1
# UUID=yyyy  /boot/efi  vfat   umask=0077        0       1
# /swapfile  none       swap   sw                0       0

# Bluetooth configuration (embedded Bluetooth dev essential!)
cat /etc/bluetooth/main.conf | head -30
# Output:
# [Policy]
# AutoEnable=true
#
# [General]
# Name = raviteja-Inspiron-15-3511
# Class = 0x000000
# DiscoverableTimeout = 0

# udev rules — how device files are created (embedded essential!)
ls /etc/udev/rules.d/
# Output: 70-snap.snapd.rules  70-uaccess.rules  etc.

# Example custom udev rule for a USB serial device:
# SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001",
# SYMLINK+="my_ftdi_device", MODE="0666"

# Network config (Ubuntu 20.04+)
cat /etc/netplan/01-netcfg.yaml
# Output:
# network:
#   version: 2
#   renderer: networkd
#   ethernets:
#     eth0:
#       dhcp4: true

# sudoers — who has root access
sudo cat /etc/sudoers | grep -v "#" | grep -v "^$"
# Output:
# root    ALL=(ALL:ALL) ALL
# %admin  ALL=(ALL) ALL
# %sudo   ALL=(ALL:ALL) ALL

# Edit safely with visudo (validates syntax before saving)
# sudo visudo

9. /home and /root — User Directories

/home/[username] and /root

/home contains a personal directory for each regular user. /root is the home directory for the root (superuser) account. Note that root does NOT live under /home — root gets its own special directory at /root. This separation matters for security: even if /home is on a full partition, root can still log in.

# Your home directory
echo $HOME
# Output: /home/raviteja

ls -la ~/
# Output: (your personal files, hidden config files)
# drwxr-x--- 23 raviteja raviteja  4096 Apr 26 ...  .
# drwxr-xr-x  3 root     root      4096 Nov  2 ...  ..
# drwxr-xr-x  5 raviteja raviteja  4096 Apr  5 ...  .config
# drwxr-xr-x  4 raviteja raviteja  4096 Apr  5 ...  .local
# -rw-r--r--  1 raviteja raviteja   220 Nov  2 ...  .bash_logout
# -rw-r--r--  1 raviteja raviteja  3526 Nov  2 ...  .bashrc
# -rw-r--r--  1 raviteja raviteja   807 Nov  2 ...  .profile

# Root's home (drwx------ = only root can access!)
ls -la /root
# Output: ls: cannot open directory '/root': Permission denied

sudo ls -la /root
# Output:
# drwx------  7 root root 4096 Apr  5 22:23 .
# drwxr-xr-x 20 root root 4096 Apr 26 11:34 ..
# -rw-------  1 root root 3526 Jan  6  2022 .bashrc

# Check who is logged in
who
# Output: raviteja pts/0  2026-04-26 11:30 (192.168.1.10)

w
# Output: (detailed session info)

# Check your UID and GID
id
# Output: uid=1000(raviteja) gid=1000(raviteja) groups=1000(raviteja),4(adm),
#          24(cdrom),27(sudo),30(dip),46(plugdev),...

# Add a new user (creates /home/newuser automatically)
sudo useradd -m -s /bin/bash newuser
sudo passwd newuser

# Switch to another user
su - newuser

# Delete a user (keep home dir with -r to remove it)
sudo userdel newuser
sudo userdel -r newuser    # Also removes /home/newuser

10. /boot — Boot Files

/boot — What the System Needs to Start

/boot contains everything needed to boot the Linux system before the root filesystem is fully mounted. This includes the bootloader (GRUB), the kernel image, and the initial RAM disk (initrd/initramfs). On embedded systems, this content may be on a separate boot partition (FAT32 on SD cards, NAND flash, etc.)

ls -lh /boot
# Output:
# -rw-r--r-- 1 root root  265K Apr 16 ... config-6.8.0-58-generic  ← Kernel config
# drwxr-xr-x 5 root root  4.0K Apr 16 ... grub/                    ← Bootloader
# -rw-r--r-- 1 root root   79M Apr 16 ... initrd.img-6.8.0-58-generic ← Initial RAM disk
# -rw-r--r-- 1 root root  183M Apr 16 ... System.map-6.8.0-58-generic ← Kernel symbol table
# -rw-r--r-- 1 root root   13M Apr 16 ... vmlinuz-6.8.0-58-generic    ← Compressed kernel

file /boot/vmlinuz-6.8.0-58-generic
# Output: Linux kernel x86 boot executable bzImage, version 6.8.0-58-generic ...

# initrd = Initial RAM Disk
# It's a small filesystem loaded into RAM before the real root FS mounts
# Contains essential drivers needed to mount root (e.g., storage drivers)

# What's inside initrd?
# mkdir /tmp/initrd_extract
# cd /tmp/initrd_extract
# zcat /boot/initrd.img-$(uname -r) | cpio -idmv 2>/dev/null | head -20
# (shows a mini Linux filesystem!)

# GRUB bootloader config
cat /boot/grub/grub.cfg | head -30
# (contains menu entries for each kernel version)

11. /tmp — Temporary Files

/tmp — Cleared on Every Reboot

/tmp is world-writable (any user can write here) but has the sticky bit set, meaning you can only delete your own files, not others’. It is cleared on system reboot. On modern Ubuntu, /tmp is often mounted as tmpfs (in RAM), making it very fast for temporary work.

ls -ld /tmp
# Output: drwxrwxrwt 20 root root 4096 Apr 26 12:30 /tmp
# Note: rwxrwxrwt
#   rwx = owner (root) can read/write/execute
#   rwx = group can read/write/execute
#   rwt = others can read/write, 't' = sticky bit (can't delete others' files!)

# Is /tmp in RAM? (tmpfs)
df -h /tmp
# Output:
# Filesystem      Size  Used Avail Use% Mounted on
# tmpfs           7.7G  2.1M  7.7G   1% /tmp
# Yes! /tmp is in RAM — very fast, gone on reboot

# Create a temp file safely
TMPFILE=$(mktemp)
echo "Test data" > $TMPFILE
cat $TMPFILE
rm $TMPFILE

# Create a temp directory
TMPDIR=$(mktemp -d)
ls $TMPDIR    # empty temp dir
rm -rf $TMPDIR

12. /var — Variable Data (Logs, Mail, Cache)

/var — Data That Grows and Changes

/var contains data that is expected to change continuously — log files, mail spools, print queues, package databases. Unlike /tmp, data in /var persists across reboots. In production servers and embedded devices, monitoring /var/log is essential for debugging.

/var Structure
/var/
├── log/ (VERY IMPORTANT — system logs)
├── syslog (general messages)
├── kern.log (kernel logs)
├── auth.log (login, sudo)
├── dmesg (boot logs)
├── apt/ (package history)
└── bluetooth/ (Bluetooth logs)
├── cache/ (app cache)
├── apt/ (.deb cache)
└── man/ (man pages)
├── lib/ (persistent state)
├── dpkg/ (package DB)
└── bluetooth/ (pairing database)
├── spool/ (queued jobs)
├── cron/ (scheduled jobs)
└── mail/ (mailboxes)
├── run → /run (runtime data)
└── tmp/ (temp files)
# View system logs (essential for debugging embedded!)
sudo tail -f /var/log/syslog
# Output: (real-time log stream — Ctrl+C to stop)
# Apr 26 12:30:15 hostname kernel: [  431.123] usb 1-1: new high-speed USB
# Apr 26 12:30:16 hostname bluetoothd[789]: Bluetooth daemon 5.64

# View kernel messages
dmesg | tail -20
# or
sudo cat /var/log/kern.log | tail -20

# View Bluetooth logs (embedded dev!)
sudo journalctl -u bluetooth -f
# Output: (real-time bluetoothd log)

# Bluetooth device pairing database!
sudo ls /var/lib/bluetooth/
# Output: (your Bluetooth adapter MAC address)
# AA:BB:CC:DD:EE:FF/
sudo ls /var/lib/bluetooth/AA:BB:CC:DD:EE:FF/
# Output: (paired device MAC addresses)

# APT package database
ls /var/lib/dpkg/
# Output: alternatives  arch  available  info  lock  status  triggers  updates

# Disk usage of /var (important — can fill up on busy servers!)
du -sh /var/*
# Output:
# 4.0K  /var/backups
# 128M  /var/cache
# 4.0K  /var/crash
# 64M   /var/lib
# 4.0K  /var/lock
# 128M  /var/log
# ...

# Authentication log — see who logged in
sudo tail -20 /var/log/auth.log
# Output:
# Apr 26 12:00:01 hostname sudo: raviteja : TTY=pts/0 ; COMMAND=/bin/bash
# Apr 26 12:05:23 hostname sshd[1234]: Accepted publickey for raviteja

13. /mnt and /media — Mount Points

/mnt — Manual Mounts | /media — Auto Mounts

/mnt is for manually mounting filesystems (you do it yourself with the mount command). /media is where the system automatically mounts removable media like USB drives and CD-ROMs when you plug them in. For embedded development, you’ll frequently use /mnt to mount SD card images or NFS exports.

# Mount a USB drive manually
sudo mount /dev/sdb1 /mnt

# Mount an SD card partition (embedded dev common workflow!)
sudo mount /dev/mmcblk0p1 /mnt/boot_part
sudo mount /dev/mmcblk0p2 /mnt/rootfs

# Mount an NFS share (from build server to embedded board)
sudo mount -t nfs 192.168.1.100:/exports/rootfs /mnt/nfs

# Mount a filesystem image
sudo mount -o loop rootfs.ext4 /mnt
ls /mnt     # Browse the embedded rootfs!
sudo umount /mnt

# Auto-mounted USB drives appear here
ls /media/raviteja/
# Output: USB_DRIVE_NAME/  (appears when USB is plugged in)

# View all currently mounted filesystems
mount | column -t
# Or better:
findmnt
# Output: (nice tree of all mount points)

14. /opt — Optional / Third-Party Software

/opt — Self-Contained Third-Party Apps

/opt is for optional add-on software packages that don’t follow the FHS convention of splitting themselves across /usr/bin, /usr/lib, etc. Applications like Zoom, Google Chrome (older versions), and proprietary embedded toolchains often install here in a self-contained directory.

# Check what's in /opt
ls /opt
# Output: zoom  google  android-studio  (whatever you've installed)

# Zoom is a typical /opt application
ls /opt/zoom/
# Output:
# ZoomLauncher  libQt5WebEngine.so  Qt/  cef/  ...

# The /bin symlink for zoom
ls -la /bin/zoom
# Output: lrwxrwxrwx 1 root root 22 ... /bin/zoom -> /opt/zoom/ZoomLauncher

# ARM toolchains for embedded dev often go here!
# sudo tar -xf gcc-arm-none-eabi.tar.xz -C /opt/
# ls /opt/gcc-arm-none-eabi/bin/
# Output: arm-none-eabi-gcc  arm-none-eabi-gdb  arm-none-eabi-ld  ...

15. /run — Runtime Data

/run — Fresh Every Boot (tmpfs)

/run is a tmpfs (in RAM) directory created at early boot. It stores runtime state like PID files, lock files, and Unix sockets needed by running daemons. It replaced the old pattern of scattering such files across /var/run, /var/lock, etc.

ls /run | head -20
# Output:
# NetworkManager/   acpid.pid         avahi-daemon/
# bluetooth/        crond.pid         dbus/
# lock/             mount/            samba/
# snapd.pid         sshd.pid          systemd/
# udev/             user/             utmp

# Bluetooth socket lives here!
ls /run/bluetooth/
# Output: bluetooth.service  

ls /run/dbus/
# Output: system_bus_socket  ← The D-Bus system socket (bluetoothd uses this!)

# PID files — contains the PID of running daemon
cat /run/sshd.pid
# Output: 1234  (SSH daemon's process ID)

# Verify:
ps aux | grep sshd | head -2

Understanding Symbolic Links in Linux

Hard Links vs Symbolic Links (Symlinks)
Hard Link vs Symbolic Link

Hard Link
——————————–fileA
fileB
└──▶ [same inode]

Both names point to same inode
Same data, multiple filenames
Deleting one → data still exists
Cannot cross filesystems
Cannot link directories

ls output:
-rw-r–r– (no special flag)

Symbolic Link (Symlink)
——————————–fileA.txt

link.txt“/fileA.txt”

Stores path to original file
Acts like a shortcut
Deleting original breaks link
Can cross filesystems
Can link directories

ls output:
lrwxrwxrwx (l = symlink)

Real-world Example:

/bin → /usr/bin (directory symlink)
/bin/bash → /usr/bin/bash

# Create a symbolic link
ln -s /usr/bin/python3 /usr/local/bin/python   # python → python3

# Create a hard link
ln original.txt hardlink.txt

# Verify symlink
ls -la /bin
# Output: lrwxrwxrwx 1 root root 7 ... /bin -> usr/bin
# 'l' at start = symbolic link
# '-> usr/bin' = points to usr/bin (relative path!)

# Follow a symlink chain
readlink -f /bin/python3
# Output: /usr/bin/python3.11   (resolves full chain)

readlink /bin
# Output: usr/bin   (just the immediate target)

# Broken symlink example
ln -s /nonexistent/file broken_link
ls -la broken_link
# Output: lrwxrwxrwx 1 raviteja ... broken_link -> /nonexistent/file
# (it exists but points to nothing — "dangling symlink")
cat broken_link
# Output: cat: broken_link: No such file or directory

# Find all symlinks in /
find / -maxdepth 1 -type l
# Output:
# /bin  /lib  /lib32  /lib64  /libx32  /sbin

# The Python version chain:
ls -la /usr/bin/python3
# Output: lrwxrwxrwx ... /usr/bin/python3 -> python3.11
ls -la /usr/bin/python3.11
# Output: -rwxr-xr-x ... (actual binary)

Complete Guide: Users, Groups, Permissions

Linux Permission System — Everything You Need
Permission System Overview

Every file/directory has:

Owner (one user)
Group (one group)
Permissions (access rules)

Permission Categories:

u = user (owner)
g = group
o = others
a = all (u + g + o)

Permission Bits:

r (4) → read
files: read content
dirs: list contents

w (2) → write
files: modify content
dirs: create/delete files

x (1) → execute
files: run program
dirs: enter (cd)

Special Bits:

SUID (4000)s in user execute
Runs as file owner

SGID (2000)s in group execute
Runs as group / inherit group

Sticky Bit (1000)t in others execute
Only owner can delete (e.g., /tmp)

# ---- VIEWING PERMISSIONS ----
ls -l /bin/bash
# -rwxr-xr-x 1 root root 1396520 Mar 2 2023 /bin/bash

ls -l /etc/shadow
# -rw-r----- 1 root shadow 1234 Apr 26 ... /etc/shadow
# Owner (root) can read/write
# Group (shadow) can read
# Others: NO access

ls -ld /tmp
# drwxrwxrwt 20 root root 4096 Apr 26 ... /tmp
# d = directory, t = sticky bit

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 59976 Feb 6 2024 /usr/bin/passwd
# s in owner execute = SUID
# Runs as root even when launched by normal user!

# ---- CHANGING PERMISSIONS ----
# Symbolic method:
chmod u+x script.sh         # Add execute for owner
chmod g-w group_file.txt    # Remove write from group
chmod o=r other_file.txt    # Set others to read-only
chmod a+r public.txt        # Add read for all (u+g+o)
chmod u=rwx,g=rx,o= prog    # Set all at once

# Numeric (octal) method:
chmod 755 script.sh          # rwxr-xr-x
chmod 644 config.txt         # rw-r--r--
chmod 600 private_key        # rw------- (only owner!)
chmod 700 private_dir/       # rwx------ (only owner can enter!)
chmod 1777 /shared/tmp       # Sticky bit on world-writable dir
chmod 4755 /usr/bin/myapp    # SUID: runs as owner

# Recursive (apply to all files in dir):
chmod -R 755 /my/project/

# ---- CHANGING OWNERSHIP ----
# Change owner:
sudo chown raviteja file.txt

# Change owner and group:
sudo chown raviteja:developers file.txt

# Change just the group:
sudo chgrp developers file.txt

# Recursive ownership change:
sudo chown -R raviteja:raviteja /home/raviteja/

# ---- USER AND GROUP MANAGEMENT ----
# Add a new user:
sudo useradd -m -s /bin/bash -c "Full Name" username
sudo passwd username

# Add user to a group:
sudo usermod -aG sudo username      # Add to sudo group
sudo usermod -aG bluetooth username # Add to bluetooth group (for BT dev!)
sudo usermod -aG dialout username   # Add to dialout group (for serial ports!)

# Create a group:
sudo groupadd mygroup

# View user's groups:
groups raviteja
id raviteja

# ---- ACCESS CONTROL LISTS (ACL) — Fine-grained permissions ----
# When basic u/g/o isn't enough:
sudo apt install acl

# Give user 'alice' read access to bob's file:
setfacl -m u:alice:r-- /home/bob/report.txt

# View ACL:
getfacl /home/bob/report.txt
# Output:
# user::rw-
# user:alice:r--
# group::r--
# other::---

# ---- UMASK — Default permission mask ----
umask
# Output: 0022
# Files created get permissions: 666 - 022 = 644 (rw-r--r--)
# Dirs created get permissions: 777 - 022 = 755 (rwxr-xr-x)

# Change umask (more restrictive, private files):
umask 077   # New files: 600, new dirs: 700

# ---- PRACTICAL EXAMPLES ----
# Lock down a config file (only root can read/write):
sudo chmod 600 /etc/ssl/private/my.key
sudo chown root:root /etc/ssl/private/my.key

# Make a shared directory where group members can write:
sudo mkdir /shared
sudo chgrp developers /shared
sudo chmod 2775 /shared  # SGID + rwxrwxr-x
# SGID ensures new files inherit 'developers' group

# Script must be executable:
chmod +x deploy.sh
./deploy.sh   # Now runs!

Quick Reference — All Directories at a Glance

Linux Filesystem Hierarchy — Quick Reference
Directory Type Purpose Who Uses
————————————————————————————–
/ Real Root of everything Everyone
/bin Symlink Essential user commands All users
/sbin Symlink System admin commands Root/sudo
/usr/bin Real All user programs All users
/usr/sbin Real System programs Root/sudo
/usr/lib Real Shared libraries (.so) Programs
/usr/local Real Local software installs Admin
/usr/include Real C/C++ headers Developers
/etc Real Configuration files Admin
/home Real User home directories Users
/root Real Root user home Root only
/boot Real Kernel + bootloader Boot process
/dev Virtual Device files Kernel + users
/proc Virtual Process/kernel info Tools + admin
/sys Virtual Hardware/driver info Kernel + admin
/tmp tmpfs Temporary files Everyone
/var/log Real Log files Admin
/var/lib Real App state Daemons
/run tmpfs Runtime data Daemons
/mnt Real Manual mount Admin
/media Real Auto-mount devices Desktop
/opt Real Third-party software Vendors
/srv Real Service data Servers
/lost+found Real Recovered files FS tools

Filesystem Hierarchy in Embedded Linux

How This All Applies to Embedded Linux Development

In embedded Linux (Yocto, Buildroot, custom rootfs), the same directory structure applies but with important differences: the rootfs is often much smaller (tens of MBs instead of GBs), and some directories may be on read-only flash, while others (like /var, /tmp) are on writable RAM or overlay filesystems.

Typical Embedded Linux Rootfs Layout

Embedded Board (Raspberry Pi / BeagleBone / SoC)

/dev/mmcblk0 (SD Card / eMMC)
├── /dev/mmcblk0p1 (FAT32 → /boot)
├── kernel8.img / Image (ARM kernel)
├── bcm2711-rpi-4-b.dtb (Device Tree)
├── initrd.img (init RAM disk)
└── config.txt (boot config)
└── /dev/mmcblk0p2 (ext4 → rootfs)
├── bin/ (busybox symlinks)
├── sbin/ (system tools)
├── lib/ (ARM libraries)
├── etc/ (board configs)
├── dev/ (device files)
├── proc/ (mount: proc)
├── sys/ (mount: sysfs)
└── tmp/ (tmpfs in RAM)

Key Embedded Difference:

/bin/ls → /bin/busybox

Example:
lrwxrwxrwx /bin/ls → busybox

BusyBox implements 300+ commands in ONE binary (space saving)

# On an embedded board: check if using BusyBox
ls -la /bin/sh
# lrwxrwxrwx 1 root root 7 ... /bin/sh -> busybox

# BusyBox reports all its applets:
busybox --list

# Device Tree — how embedded kernel knows what hardware exists
ls /proc/device-tree/
# Output: (hardware description from DTB)
cat /proc/device-tree/model
# Output: Raspberry Pi 4 Model B Rev 1.4

# Check processor architecture (embedded vs desktop):
uname -m
# Desktop: x86_64
# Embedded ARM 32-bit: armv7l
# Embedded ARM 64-bit: aarch64

# Cross-compiling for ARM (on Ubuntu x86 dev machine):
sudo apt install gcc-aarch64-linux-gnu
aarch64-linux-gnu-gcc hello.c -o hello_arm

# Check the binary is for ARM:
file hello_arm
# Output: hello_arm: ELF 64-bit LSB executable, ARM aarch64

# Copy to embedded board over SSH:
scp hello_arm root@192.168.1.100:/tmp/

# Mount embedded rootfs on dev machine for inspection:
sudo mount -o loop,offset=$((512*526336)) rpi4.img /mnt
ls /mnt   # Browse the RPi rootfs!

Hands-On Lab — Explore Your System

Step-by-Step Exploration Commands
# STEP 1: Install tree to visualize the filesystem
sudo apt install tree

# STEP 2: See the top-level structure
tree / -L 1
# Output:
# /
# ├── bin -> usr/bin
# ├── boot
# ├── dev
# ├── etc
# ├── home
# ├── lib -> usr/lib
# ...

# STEP 3: Explore /proc
tree /proc -L 1 | head -30

# STEP 4: Count how many processes are running
ls /proc | grep -E '^[0-9]+$' | wc -l

# STEP 5: How many binaries on your system?
ls /usr/bin | wc -l
ls /usr/sbin | wc -l

# STEP 6: Find all SUID programs (potential security audit!)
find / -perm /4000 -type f 2>/dev/null
# Output: /usr/bin/passwd  /usr/bin/sudo  /usr/bin/mount  ...

# STEP 7: Find all world-writable directories
find / -maxdepth 4 -type d -perm -o+w 2>/dev/null
# Output: /tmp  /var/tmp  /run/shm  ...

# STEP 8: Check disk usage per directory
du -sh /* 2>/dev/null | sort -rh | head -10
# Output:
# 11G   /usr
# 2.0G  /swapfile
# 487M  /var
# 220M  /boot
# 128M  /opt
# ...

# STEP 9: Find config files changed recently
find /etc -newer /etc/os-release -type f 2>/dev/null | head -10

# STEP 10: Show all mounted filesystems including virtual ones
cat /proc/mounts
# or
findmnt --real
findmnt --pseudo

What’s Next?

Now that you understand the Linux filesystem hierarchy, you’re ready to go deeper into Linux system programming and embedded Linux development.

All content on EmbeddedPathashala is free forever. If this post helped you, share it with your colleagues!

Leave a Reply

Your email address will not be published. Required fields are marked *