umask and default permissions
◈ 13 cardsComputing the permissions a new file or directory receives under a given umask, showing the work in binary rather than guessing at a subtraction.
A mask of bits to withhold
Nothing you create asks you for a mode. touch, mkdir, cc -o, a redirection like cat > notes.txt — each one hands the kernel a requested mode and the kernel takes bits away before creating the object. The thing that decides which bits get taken away is your umask, a per-process value inherited by every command you run.
umask [-S] [mask]
With no argument it prints the current mask in octal, four digits, e.g. 0022. The rightmost three digits are owner, group and other; the leftmost is the special-bit field (SUID, SGID, sticky), which is almost always 0. With an argument it sets the mask.
The critical thing to fix in your head before any arithmetic: the numeric mask names the bits you are withholding, not the bits you are granting. umask 022 does not mean give everybody write; it means never hand out group-write or other-write.
The formula
Stated as Boolean algebra, which is how the exam wants it shown:
A = B AND C'
- A — the permissions the new object actually gets.
- B — the base: the default permissions for that kind of object.
- C — the umask.
- C' — the one’s complement of C, every bit flipped.
ANDing with the complement clears exactly the bits the mask names and leaves everything else alone.
The base B is where the real lesson is
B is not always 777:
- 777 for a directory, and for an executable produced by a compiler or linker.
- 666 for an ordinary text or data file.
That is the answer to why does a new text file never come out executable. It is not the mask — a mask of 000 still produces rw-rw-rw- for a text file. The execute bits were never in B to begin with. cat > notes.txt asks for 666, and 666 has no execute bit anywhere in it. Say that in an exam and you have the whole of §5.5.4 in one sentence.
Worked example — the same mask, two bases
Mask 022 on a directory (mkdir courses):
C = 022 = 000 010 010
C' = 111 101 101
B = 777 = 111 111 111
A = 111 101 101 = 755 = rwxr-xr-x
Mask 022 on a text file (cat > notes.txt):
C' = 111 101 101
B = 666 = 110 110 110
A = 110 100 100 = 644 = rw-r--r--
Same mask, same complement, different base — and that alone is the difference between 755 and 644. Now tighten the mask:
Mask 077 on a text file:
C = 077 = 000 111 111
C' = 111 000 000
B = 666 = 110 110 110
A = 110 000 000 = 600 = rw-------
Verify, do not trust
The habit that makes this stick is prediction followed by measurement. Set a mask, create one of each kind of object, and list all three at once:
$ umask 022
$ mkdir courses
$ cat > notes.txt
hello
^D
$ ls -ld courses notes.txt
drwxr-xr-x 2 ada dev 4096 Sep 1 12:31 courses
-rw-r--r-- 1 ada dev 6 Sep 1 12:31 notes.txt
755 and 644, exactly as predicted. Repeat under umask 077 and you get 700 and 600. Two commands, six predictions checked.
Going backwards
The assignments also ask the inverse — what mask yields this result? Since A = B AND C', the mask you need is exactly the bits that B has and A must not: C = B AND NOT A. To get rwxr-x--- (750) on a new directory, B is 777, so C = 777 AND NOT 750 = 027. Set umask 027 and the next mkdir produces drwxr-x---. The same 027 applied to a text file gives 666 AND NOT 027 = 640.