← All 129 books file permissions, one command per page
One command per page

file permissions, one command per page

Twenty-eight lessons on file permissions, one command or concept per page: the ls -l mode string and its three rwx triplets; stat's %A against %a; octal digits as 4, 2 and 1 and symbolic ugoa with +, - and =; chown's one-operand colon forms and chgrp beside it; the ownership gate that answers who may chmod, and the two denials, Permission denied and Operation not permitted; umask math where 666 less 022 makes 644; the execute bit that means search on a directory; setuid on passwd, setgid on files, the fourth octal digit and the sticky t on /tmp; getfacl, setfacl -m, the mask ceiling and -x against -b; install -m, chattr's immutable i and lsattr's flag string; and one final stat -c readout that audits it all.


Steve Hodgkiss 7 lessons

One command, one mode string, one real bit. That's a page.

file permissions, one command per page

Twenty-eight lessons on file permissions, one command or concept per page: the ls -l mode string and its three rwx triplets; stat's %A against %a; octal digits as 4, 2 and 1 and symbolic ugoa with +, - and =; chown's one-operand colon forms and chgrp beside it; the ownership gate that answers who may chmod, and the two denials, Permission denied and Operation not permitted; umask math where 666 less 022 makes 644; the execute bit that means search on a directory; setuid on passwd, setgid on files, the fourth octal digit and the sticky t on /tmp; getfacl, setfacl -m, the mask ceiling and -x against -b; install -m, chattr's immutable i and lsattr's flag string; and one final stat -c readout that audits it all.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

Every fact in this book is as the official source states it, fetched and read during this build: the Linux man-pages man7.org pages for chmod(1), chown(1), chgrp(1), ls(1), stat(1) and install(1) from GNU coreutils; chmod(2), umask(2) and inode(7) from the man-pages project; acl(5), getfacl(1) and setfacl(1) from the acl project; chattr(1) and lsattr(1) from e2fsprogs; and the POSIX umask utility from The Open Group (IEEE Std 1003.1-2017). No facts are sourced from Reddit, Stack Overflow or vendor blogs. Every command and output pair on every page was run on this machine (coreutils 9.4, acl 2.3.2, e2fsprogs 1.47.0, bash 5.2.21, kernel 6.8.0-147-generic) and confirmed before printing. The setuid, setgid and sticky demonstrations were run on scratch files in a scratch directory, never on system files. An independent guide, not affiliated with or endorsed by the GNU coreutils, man-pages, acl or e2fsprogs projects, The Open Group, or the Linux kernel developers.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · ls -l and stat
Read the mode string4
Part 2 · chmod
chmod 644 or 7555
Part 3 · chown and chgrp
chown user:group6
Part 4 · umask and the x bit
umask does the math7
Part 5 · special bits
The fourth digit8
Part 6 · ACLs
getfacl9
Part 7 · Beyond the mode
chattr +i10

Per Linux man-pages ls(1) (GNU coreutils): -l, the long listing format, lists one file per line with its mode, link count, owner, group, size and name; per stat(1), %A prints the permission bits and file type in human readable form, the same string ls -l leads with. This machine's ls -l report.txt printed -rw-r--r-- 1 root root 0 Oct 26 22:23 report.txt, and ls -ld project printed drwxr-xr-x 2 root root 4096 Oct 26 22:23 project.

permissions companion · No. 01
ls -l

Read the mode string

Ten characters, four facts

one line, ten characters, four facts$ ls -l report.txt-rw-r--r-- 1 root root0 Oct 26 22:23 report.txtls -ld projectdrwxr-xr-x 2 root root 4096ten leading characters:one type char, then threerwx triplets: owner, group,other; then link count,owner, group, size, mtimed says directory before the same nine permission bits

The first ten characters are the mode string: one type character, then three triplets for owner, group and other. Here -rw-r--r--.

After it: 1 hard link, owner root, group root, size 0, mtime, name. Our project directory reads drwxr-xr-x for the same reason: d for directory.

Read the string left to right and it answers who may read, write or run this file. The next two pages take the triplets apart.

RUN IT THIS WEEK

Run ls -l on any file you own and say each of the ten leading characters out loud.

Per Linux man-pages chmod(1): chmod changes the file mode bits of each given file according to mode, which can be either a symbolic representation of changes to make, or an octal number representing the bit pattern for the new mode bits; an octal mode sets the whole pattern at once. This machine ran chmod 755 report.txt and stat -c '%A %a' printed -rwxr-xr-x 755; a later scratch run of chmod 400 probe.txt was followed by stat -c '%A %a' printing -r-------- 400.

permissions companion · No. 02
chmod

chmod 644 or 755

Three digits set it all

octal sets all nine bits at once$ chmod 755 report.txt$ stat -c '%A %a' report.txt-rwxr-xr-x 755chmod 400 probe.txt-r-------- 400an octal mode writes thewhole pattern: bits you donot mention are cleared,not kept. 400 keeps onebit: owner readchmod(1): an octal number for the bit pattern of the new mode bits

chmod 755 report.txt set the whole mode at once: owner rwx, group and other r-x. Our stat printed -rwxr-xr-x 755.

Octal is total: chmod 400 left the probe file -r-------- 400, owner read only. Unmentioned bits are cleared, not kept.

That totality is the difference from symbolic modes, which change named bits and leave the rest alone.

RUN IT THIS WEEK

Set a scratch file to 755, then to 400, and stat it after each: watch what disappears.

Per Linux man-pages chown(1) (GNU coreutils): if only an owner is given, that user is made the owner of each given file and the files' group is not changed; if the owner is followed by a colon and a group name, with no spaces between them, the group ownership is changed as well; if the colon and group are given but the owner is omitted, only the group is changed, and chown performs the same function as chgrp. This machine's chgrp daemon note.txt then stat -c '%U:%G %n' printed root:daemon note.txt, and chown :root printed root:root note.txt.

permissions companion · No. 03
chown

chown user:group

One colon, both sides

one operand, three shapes$ chgrp daemon note.txtroot:daemon note.txtchown :root note.txtroot:root note.txtstat -c '%U:%G %n' after eachuser: owner moves, groupstays; user:group: both move:group: group only, andper chown(1) that form isthe same function as chgrpno spaces around the colon, says chown(1)

One operand, three shapes: user changes the owner only; user:group changes both; :group changes the group only.

Our capture: root:daemon after a group change, then root:root after chown :root gave it back. No spaces around the colon, per chown(1).

The colon-with-no-owner form is exactly chgrp, says chown(1) itself. The next page takes that shorter spelling.

RUN IT THIS WEEK

Change a scratch file to user:group form and back with the colon-only form, stat -c '%U:%G' between.

Per Linux man-pages umask(2): in the usual case where the mode argument to open(2) is 0666 when creating a new file, the permissions on the resulting file will be S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH, because 0666 & ~022 = 0644, i.e. rw-r--r--. This machine ran bash -c 'umask 077; touch fresh.txt; stat -c %a fresh.txt' and it printed 600; with umask 027, touch printed 640 and mkdir printed 750.

permissions companion · No. 04
umask

umask does the math

666 less the mask, 777 too

subtract the mask at creation$ bash -c 'umask 027; touch m'mask file dir022 644 755027 640 750077 600 700captured: 640, 750, 600 on this boxfiles ask 666, directoriesask 777; the mask comes off0666 & ~022 = 0644the canonical line fromumask(2), and 777 and 022 is 755no mask can add an execute bit to a new file; 666 never asks

Files are requested as 666, directories as 777; the mask is subtracted. 666 and 022 leave 644; 777 and 022 leave 755.

Our runs: umask 077 gave a 600 file; umask 027 gave a 640 file and a 750 directory. umask(2) writes the canonical line: 0666 & ~022 = 0644.

No execute bit is ever requested for files, so no mask can add one. Directories always ask for x.

RUN IT THIS WEEK

With umask 027, predict a new file and a new directory, then touch and mkdir to check.

Per Linux man-pages chmod(1): a numeric mode is from one to four octal digits, and the first digit selects the set user ID (4) and set group ID (2) and restricted deletion or sticky (1) attributes; omitted digits are assumed to be leading zeros. This machine's chmod 4755 script.sh printed -rwsr-xr-x 4755 and chmod 2755 printed -rwxr-sr-x 2755; the mode 755 alone, 0755, leaves all three attributes off.

permissions companion · No. 05
special bits

The fourth digit

4 setuid, 2 setgid, 1 sticky

the digit you usually omit$ chmod 4755 script.shlead selects captures4 set user ID -rwsr-xr-x2 set group ID -rwxr-sr-x1 sticky drwxrwxrwtmodes 4755, 2755, 1777chmod(1): the first digitselects set user ID (4),set group ID (2), sticky (1)plain 755 is 0755: omitteddigits are leading zerosread 4755 right to left: 755 the permissions, 4 the crown

The digit you usually omit: 4 setuid, 2 setgid, 1 sticky, and they add. chmod 4755 gave -rwsr-xr-x; chmod 2755 gave -rwxr-sr-x.

Per chmod(1), omitted digits are leading zeros: plain 755 is 0755, all three special bits off.

5755 would set setuid and sticky at once. Read a mode like 4755 right to left: 755 the permissions, 4 the crown.

RUN IT THIS WEEK

Compute what 2750 sets, then run it on a scratch file and verify every letter with stat -c %A.

Per Linux man-pages getfacl(1) (acl project): for each file, getfacl displays the file name, owner, the group, and the Access Control List; lines user::, group:: and other:: correspond to the user, group and other fields of the file mode permission bits and are called the base ACL entries; a # flags: line indicates the setuid, setgid and sticky bits and is included if any of those bits is set. This machine's getfacl note.txt printed the # file, # owner and # group header, then user::rw-, user:daemon:rw-, group::rw-, mask::rw-, other::r--.

permissions companion · No. 06
ACLs

getfacl

The whole access list

the whole list, entry by entry$ getfacl note.txt# file: note.txt# owner: root # group: rootuser::rw- user:daemon:rw-group::rw- mask::rw-other::r--header comments, then entriesuser, group and other arethe base ACL entries: themode bits in long formuser:daemon:rw- is theextension the mode cannot saywhere ls -l says 664, getfacl says the same thing plus names

getfacl prints the whole list, not just nine bits: header lines, then one entry per line.

Our note.txt: the base entries user::rw-, group::rw-, other::r-- plus the extension, user:daemon:rw-, and a mask. The named user is an ACL entry, not a mode bit.

Per getfacl(1) the base entries are the mode bits themselves. Where ls -l says 664, getfacl says the same thing in long form.

RUN IT THIS WEEK

Run getfacl on a file you own and on /tmp and compare the entry counts.

Per Linux man-pages chattr(1) (e2fsprogs): a file with the 'i' attribute cannot be modified: it cannot be deleted or renamed, no link can be created to this file, most of the file's metadata can not be modified, and the file can not be opened in write mode; only the superuser or a process possessing the CAP_LINUX_IMMUTABLE capability can set or clear this attribute; per chmod(2), EPERM is returned when the file is marked immutable or append-only. This machine's chattr +i app.sh was followed by lsattr app.sh printing ----i---------e------- app.sh, and chattr -i restored --------------e-------.

permissions companion · No. 07
attributes

chattr +i

Immutable, beyond chmod

immutable sits outside the mode$ chattr +i app.shlsattr app.sh----i---------e-------chattr -i app.sh--------------e-------chattr(1) on the i flag:cannot be modified, deleted,renamed, linked or openedfor writing; only root orCAP_LINUX_IMMUTABLE mayset or clear itchmod(2) reports EPERM: the file is marked immutable, a different layer

Attributes sit outside the mode: the i flag freezes the file past chmod, past rm, past rename.

Per chattr(1), an i file cannot be modified, deleted, renamed, hard linked, or opened for writing; only root or CAP_LINUX_IMMUTABLE may set or clear it. Our lsattr read ----i---------e-------.

chmod(2) reports it as EPERM: the file is marked immutable. Not a permission problem; a different layer.

RUN IT THIS WEEK

Set +i on a scratch file, try to delete it, then clear it with chattr -i before you clean up.

Index

Index


chattr +i10
chmod 644 or 7555
chown user:group6
getfacl9
Read the mode string4
The fourth digit8
umask does the math7