Build and Verify a SquashFS Image with mksquashfs
mksquashfs turns a directory into a compressed, read-only SquashFS image, and this guide gets you from an empty folder to a verified archive. Along the way you will inspect what actually went in, exclude files cleanly, and append to an existing image without wrecking it. The examples use the locally installed squashfs-tools 4.6.1 package, version 1:4.6.1-1build1.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, enough free space for the source scan and output image, and the mksquashfs and unsquashfs commands. Creating an image in a directory you own does not need sudo. Reading protected source files may need elevated access, but copying permissions into an image is not a reason to run every command as root.
Warning
Mksquashfs writes the destination named on its command line. Choose a new output path first. An existing SquashFS image is normally appended to, not replaced, unless you pass -noappend. Do not test against the only copy of an archive.
1. Confirm the installed tool
Check the executable and package before relying on examples. These are ordinary read-only commands:
$ command -v mksquashfs
/usr/bin/mksquashfs
$ dpkg-query -W -f='${Package} ${Version}\n' squashfs-tools
squashfs-tools 1:4.6.1-1build1
$ mksquashfs -version
mksquashfs version 4.6.1 (2023/03/25)
The local manual describes a default 128 KiB data block and gzip compression. It also lists zstd, xz, lz4, lzo and lzma as available compressor choices for this build. Defaults and supported compressors can vary between package releases, so keep this version check near scripts that depend on them.
Checkpoint
If command -v finds a different binary, stop and read that installation's manual before copying the commands below.
2. Create a small source tree
Use a disposable directory while learning. The following changes only the current user's temporary files:
$ work=$(mktemp -d)
$ mkdir -p "$work/source/docs"
$ printf 'release notes\n' > "$work/source/README.txt"
$ printf 'private draft\n' > "$work/source/docs/draft.txt"
$ printf 'built output\n' > "$work/source/output.log"
$ printf '%s\n' "$work"
/tmp/tmp.example
Replace /tmp/tmp.example in later commands with the path printed by your shell. The command syntax is positional: one or more source paths come first, followed by the destination filesystem. A directory source contributes its contents to the image root by default.
3. Build the image with an explicit destination
Create the image with the default compressor and block size:
$ mksquashfs "$work/source" "$work/archive.sqfs" -no-progress
Creating filesystem on /tmp/tmp.example/archive.sqfs, block size 131072.
...
Filesystem size ... bytes (.. Kbytes / .. Mbytes)
Filesystem size ... bytes (..% of uncompressed filesystem size)
Number of inodes ...
Number of files ...
Number of fragments ...
Number of duplicate files ...
Number of ids ...
Number of xattr ids ...
The sizes and counts depend on the source tree, so the ellipses above indicate variable output rather than literal text to paste. -no-progress keeps a progress display out of logs; it does not change the image. Without it, the tool may display a progress bar while scanning.
By default, 4.6.1 creates reproducible filesystems and stores extended attributes. Reproducible does not mean that unrelated source metadata becomes identical: file contents, modes, ownership, timestamps and xattrs still matter. For a build where timestamps must be controlled, set SOURCE_DATE_EPOCH or pass the relevant time options deliberately.
4. Inspect what was written
Use unsquashfs to list the image instead of trusting the creation summary:
$ unsquashfs -ll "$work/archive.sqfs"
drwxr-xr-x ... squashfs-root
-rw-r--r-- ... squashfs-root/README.txt
drwxr-xr-x ... squashfs-root/docs
-rw-r--r-- ... squashfs-root/docs/draft.txt
-rw-r--r-- ... squashfs-root/output.log
Owner, group, timestamps and exact spacing are host-specific. The useful check is that each expected path appears, and that no unexpected path was included. For a narrower check, ask the listing command for a particular path and inspect its exit status:
$ unsquashfs -ll "$work/archive.sqfs" | grep -F 'README.txt'
-rw-r--r-- ... squashfs-root/README.txt
$ test "$(unsquashfs -ll "$work/archive.sqfs" | grep -Fc 'README.txt')" -eq 1
$ echo 'image listing verified'
image listing verified
This does not mount anything and needs no elevated privilege. If you need to read a file, extract into a new directory with unsquashfs -d; do not extract over a live system directory by accident.
5. Exclude paths without shell expansion
Use -e followed by paths to exclude. The basic form does not enable wildcard matching:
$ mksquashfs "$work/source" "$work/public.sqfs" -no-progress -e docs/draft.txt output.log
$ unsquashfs -ll "$work/public.sqfs" | grep -E 'README.txt|draft.txt|output.log'
-rw-r--r-- ... squashfs-root/README.txt
For wildcard exclusions, add -wildcards and quote the pattern so the shell passes it to mksquashfs unchanged:
$ mksquashfs "$work/source" "$work/public.sqfs" -noappend -no-progress -wildcards -e '*.log'
$ unsquashfs -ll "$work/public.sqfs" | grep -F 'output.log' || echo 'output.log excluded'
output.log excluded
The second command uses -noappend because public.sqfs may already exist from the previous example. This option replaces the old image by creating a new filesystem at that path, so use it only when that overwrite is intentional. A failed build can leave an incomplete destination; keep the source tree and rebuild to a new filename if you need a cautious recovery path.
6. Choose compression and block size deliberately
For a general-purpose image, the defaults are a reasonable starting point. If compatibility with a reader matters, choose a compressor that the reader supports and record the choice:
$ mksquashfs "$work/source" "$work/zstd.sqfs" -no-progress -comp zstd -b 1M
$ unsquashfs -s "$work/zstd.sqfs"
Found a valid SQUASHFS 4:0 superblock on ...
Compression zstd
Block size 1048576
A larger block can improve compression for some data but changes memory and access characteristics. -comp zstd and -b 1M are image-format decisions, not cosmetic switches. If the target kernel or extraction utility is older, verify support before distributing the image. The installed manual is the authority for this host's accepted values.
7. Append only when the merge is intentional
When the destination already contains a SquashFS filesystem, mksquashfs appends new source items by default. This is useful for adding a directory, but it is easy to mistake for replacement:
$ mkdir -p "$work/additional"
$ printf 'later file\n' > "$work/additional/later.txt"
$ mksquashfs "$work/additional" "$work/archive.sqfs" -no-progress
$ unsquashfs -ll "$work/archive.sqfs" | grep -F 'later.txt'
-rw-r--r-- ... squashfs-root/later.txt
The new source is merged into the existing root. If you want it under a named directory, use -root-becomes NAME when appending, and verify the resulting path with unsquashfs -ll. Before appending to a valuable image, copy it or create a checksum so you have a recovery point:
$ cp --reflink=auto -- "$work/archive.sqfs" "$work/archive.sqfs.before-append"
$ sha256sum "$work/archive.sqfs.before-append"
...
The copy is the undo mechanism for an append. Do not delete it until the merged image has been inspected and any downstream reader has accepted it. During an abnormal interruption, mksquashfs may write a recovery file. Follow the exact recovery command printed by that run, and do not delete the recovery file while you may still need it.
Done means
- Checked the version. You confirmed the installed command is mksquashfs 4.6.1 from squashfs-tools.
- Built at a deliberate destination. You created the image without using elevated privileges unnecessarily.
- Inspected the result. You checked it with unsquashfs and confirmed the expected paths.
- Excluded paths safely. You quoted wildcard exclusions and used
-noappendonly for an intentional rebuild. - Recorded non-default choices. Any compression or block-size decision away from the default is written down.
- Protected the original before appending. You made a copy and know where the printed recovery instructions are if a build is interrupted.