os.mknod
mkfifo creates a named pipe that two processes open like a file; mknod creates a node whose type comes from the stat.S_IF* bits in mode. mknod and mkfifo are Unix only (not WASI); major, minor and makedev are Unix only too - none of them exist on Windows, so the examples use stat, os.pipe and the Linux device-number formula instead.
Common call
os.mkfifo('jobs.fifo')
Returns
None
Replaces
mkfifo / mknod shell commands
Watch out
Opening a FIFO blocks until the other end is opened
os.mknod(pathpath — The node to create; it must not exist yet (FileExistsError).type: str | bytes | PathLike · required, modemode — Permission bits, reduced by the umask. For mknod OR in the node type: stat.S_IFREG, S_IFCHR, S_IFBLK or S_IFIFO.type: int · default: 0o600 (mknod) / 0o666 (mkfifo)=0o600, devicedevice — mknod with S_IFCHR / S_IFBLK: the device number, usually os.makedev(major, minor). Ignored otherwise.type: int · default: 0=0, *, dir_fddir_fd — Resolve a relative path against this open directory.type: int · default: None=None) / os.mkfifo(path, modemode — Permission bits, reduced by the umask. For mknod OR in the node type: stat.S_IFREG, S_IFCHR, S_IFBLK or S_IFIFO.type: int · default: 0o600 (mknod) / 0o666 (mkfifo)=0o666)
→ None | int
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | str | bytes | PathLike | yes | The node to create; it must not exist yet (FileExistsError). |
| mode | int | no (0o600 (mknod) / 0o666 (mkfifo)) | Permission bits, reduced by the umask. For mknod OR in the node type: stat.S_IFREG, S_IFCHR, S_IFBLK or S_IFIFO. |
| device | int | no (0) | mknod with S_IFCHR / S_IFBLK: the device number, usually os.makedev(major, minor). Ignored otherwise. |
| dir_fd | int | no (None) | Resolve a relative path against this open directory. |
Return value
None | int — mknod and mkfifo return None; major and minor return an int part, makedev the combined raw device number.
Common patterns
A named pipe between two processes (Unix)
The reader blocks in open() until a writer opens the FIFO, and vice versa.
import os os.mkfifo('jobs.fifo') # process A with open('jobs.fifo') as fifo: for line in fifo: handle(line) # process B with open('jobs.fifo', 'w') as fifo: fifo.write('build\n')
Which device holds this file? (Unix)
st_dev is the device of the filesystem; split it into major and minor.
import os st = os.stat(path) print(os.major(st.st_dev), os.minor(st.st_dev))
Create a character device (Unix, root only)
Same numbers as /dev/null (1, 3) on Linux.
import os import stat os.mknod('null', 0o666 | stat.S_IFCHR, os.makedev(1, 3))
Examples
1. What a FIFO looks like
import stat
stat.filemode(stat.S_IFIFO | 0o644)
Returns
'prw-r--r--'2. Device node types
import stat
(stat.filemode(stat.S_IFCHR | 0o666), stat.filemode(stat.S_IFBLK | 0o660))
Returns
('crw-rw-rw-', 'brw-rw----')3. Testing the node type
import stat
mode = stat.S_IFIFO | 0o600
(stat.S_ISFIFO(mode), stat.S_ISREG(mode))
Returns
(True, False)4. Linux (glibc) makedev by hand
def makedev(major, minor):
return ((major & 0xfff) << 8) | ((major & 0xfffff000) << 32) | (minor & 0xff) | ((minor & 0xffffff00) << 12)
(makedev(1, 3), makedev(8, 300))
Returns
(259, 1050668)5. And major / minor back
def major(dev):
return ((dev >> 8) & 0xfff) | ((dev >> 32) & 0xfffff000)
def minor(dev):
return (dev & 0xff) | ((dev >> 12) & 0xffffff00)
(major(1050668), minor(1050668))
Returns
(8, 300)6. Default mkfifo mode after umask 022
oct(0o666 & ~0o022)
Returns
'0o644'7. Portable alternative: os.pipe
import os
r, w = os.pipe()
try:
os.write(w, b'hi')
data = os.read(r, 2)
finally:
os.close(r)
os.close(w)
data
Returns
b'hi'Pitfalls
1. Leaving the node type out of mknod mode
mode=0o600 has no S_IF* bits, so mknod creates a regular file. Add the type to get a FIFO or device.
0o600
import stat stat.S_IFMT(0o600) == stat.S_IFIFO
False
S_IFIFO | 0o600
import stat stat.S_IFMT(stat.S_IFIFO | 0o600) == stat.S_IFIFO
True
2. Packing device numbers with a simple shift
(major << 8) | minor only works for minor < 256. Larger minors collide with the major bits; use os.makedev, which on Linux implements the full encoding shown here.
shift only
dev = (8 << 8) | 300 (dev >> 8, dev & 0xff)
(9, 44)
full encoding
dev = ((8 & 0xfff) << 8) | (300 & 0xff) | ((300 & 0xffffff00) << 12) (((dev >> 8) & 0xfff) | ((dev >> 32) & 0xfffff000), (dev & 0xff) | ((dev >> 12) & 0xffffff00))
(8, 300)
When to use
Use it
- Simple one-way IPC between unrelated processes on one Unix machine (mkfifo)
- Container, chroot or initramfs tooling that must create device nodes (mknod, as root)
- Reporting which disk a file lives on (major/minor of st_dev)
Reach for something else
- Parent/child communication → os.pipe or subprocess pipes
- Cross-platform or networked IPC → multiprocessing, sockets, queues
- Regular files → open(path, "x") instead of mknod
Notes
CPython impl
mknod(2) / mkfifo(3) (mknodat / mkfifoat with dir_fd) and the major / minor / makedev macros, in Modules/posixmodule.c
Availability
mknod, mkfifo: Unix, not WASI. major, minor, makedev: Unix (not present on Windows)
Encoding
The device-number formula on this page is the glibc one; it matched os.makedev / os.major / os.minor on 100000 random inputs on Linux. Other systems may encode differently - always call the os functions in real code
Linux checks
mkfifo with the default 0o666 and umask 022 gave 0o644; mknod(path) with no type gave a regular 0o600 file; creating a character device as a normal user raised PermissionError; /dev/null is device (1, 3)
FAQ
Named pipes on Windows are a different mechanism (\\.\pipe\ names), not filesystem nodes, so mkfifo, mknod, major, minor and makedev are Unix only. That is why this page has no live demo and its examples avoid calling them; use os.pipe or multiprocessing for portable pipes.