lpfs/pid/fd.rs
1//! /proc/[pid]/fd/
2//!
3//! <pre>
4//! > This is a subdirectory containing one entry for each file
5//! > which the process has open, named by its file descriptor, and
6//! > which is a symbolic link to the actual file. Thus, 0 is stan‐
7//! > dard input, 1 standard output, 2 standard error, and so on.
8//! >
9//! > For file descriptors for pipes and sockets, the entries will
10//! > be symbolic links whose content is the file type with the
11//! > inode. A readlink(2) call on this file returns a string in
12//! > the format:
13//! >
14//! > type:[inode]
15//! >
16//! > For example, socket:[2248868] will be a socket and its inode
17//! > is 2248868. For sockets, that inode can be used to find more
18//! > information in one of the files under /proc/net/.
19//! >
20//! > For file descriptors that have no corresponding inode (e.g.,
21//! > file descriptors produced by bpf(2), epoll_create(2),
22//! > eventfd(2), inotify_init(2), perf_event_open(2), signalfd(2),
23//! > timerfd_create(2), and userfaultfd(2)), the entry will be a
24//! > symbolic link with contents of the form
25//! >
26//! > anon_inode:<file-type>
27//! >
28//! > In many cases (but not all), the file-type is surrounded by
29//! > square brackets.
30//! >
31//! > For example, an epoll file descriptor will have a symbolic
32//! > link whose content is the string anon_inode:[eventpoll].
33//! >
34//! > In a multithreaded process, the contents of this directory are
35//! > not available if the main thread has already terminated (typi‐
36//! > cally by calling pthread_exit(3)).
37//! >
38//! > Programs that take a filename as a command-line argument, but
39//! > don't take input from standard input if no argument is sup‐
40//! > plied, and programs that write to a file named as a command-
41//! > line argument, but don't send their output to standard output
42//! > if no argument is supplied, can nevertheless be made to use
43//! > standard input or standard output by using /proc/[pid]/fd
44//! > files as command-line arguments. For example, assuming that
45//! > -i is the flag designating an input file and -o is the flag
46//! > designating an output file:
47//! >
48//! > $ foobar -i /proc/self/fd/0 -o /proc/self/fd/1 ...
49//! >
50//! > and you have a working filter.
51//! >
52//! > /proc/self/fd/N is approximately the same as /dev/fd/N in some
53//! > UNIX and UNIX-like systems. Most Linux MAKEDEV scripts sym‐
54//! > bolically link /dev/fd to /proc/self/fd, in fact.
55//! >
56//! > Most systems provide symbolic links /dev/stdin, /dev/stdout,
57//! > and /dev/stderr, which respectively link to the files 0, 1,
58//! > and 2 in /proc/self/fd. Thus the example command above could
59//! > be written as:
60//! >
61//! > $ foobar -i /dev/stdin -o /dev/stdout ...
62//! >
63//! > Permission to dereference or read (readlink(2)) the symbolic
64//! > links in this directory is governed by a ptrace access mode
65//! > PTRACE_MODE_READ_FSCREDS check; see ptrace(2).
66//! >
67//! > Note that for file descriptors referring to inodes (pipes and
68//! > sockets, see above), those inodes still have permission bits
69//! > and ownership information distinct from those of the
70//! > /proc/[pid]/fd entry, and that the owner may differ from the
71//! > user and group IDs of the process. An unprivileged process
72//! > may lack permissions to open them, as in this example:
73//! >
74//! > $ echo test | sudo -u nobody cat
75//! > test
76//! > $ echo test | sudo -u nobody cat /proc/self/fd/0
77//! > cat: /proc/self/fd/0: Permission denied
78//! >
79//! > File descriptor 0 refers to the pipe created by the shell and
80//! > owned by that shell's user, which is not nobody, so cat does
81//! > not have permission to create a new file descriptor to read
82//! > from that inode, even though it can still read from its exist‐
83//! > ing file descriptor 0.
84//! >
85//! > </pre>
86//! > -- http://man7.org/linux/man-pages/man5/proc.5.html
87//!
88
89//! > fd — A directory containing all of the file descriptors for a particular process. These are given in numbered links:
90//! > total 0
91//! > lrwx------ 1 root root 64 May 8 11:31 0 -> /dev/null
92//! > lrwx------ 1 root root 64 May 8 11:31 1 -> /dev/null
93//! > lrwx------ 1 root root 64 May 8 11:31 2 -> /dev/null
94//! > lrwx------ 1 root root 64 May 8 11:31 3 -> /dev/ptmx
95//! > lrwx------ 1 root root 64 May 8 11:31 4 -> socket:[7774817]
96//! > lrwx------ 1 root root 64 May 8 11:31 5 -> /dev/ptmx
97//! > lrwx------ 1 root root 64 May 8 11:31 6 -> socket:[7774829]
98//! > lrwx------ 1 root root 64 May 8 11:31 7 -> /dev/ptmx
99//! >
100//! > -- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/deployment_guide/s1-proc-directories#s2-proc-processdirs
101
102
103type Result<T> = std::result::Result<T, crate::ProcErr>;
104
105macro_rules! fd_impl {
106 ($path: expr) => {
107 let dir_entries = std::fs::read_dir($path)?;
108 let mut ret = vec![];
109
110 for task_dir in dir_entries {
111 let fd_str = task_dir?.file_name();
112 let fd = fd_str
113 .to_str()
114 .ok_or_else(||"contains non-unicode chatacter")?
115 .parse::<u32>()?;
116 ret.push(fd);
117 }
118
119 Ok(ret)
120 };
121}
122
123pub fn fd_of(pid: u32) -> Result<Vec<u32>> {
124 fd_impl!{format!("/proc/{}/fd", pid)}
125}
126
127pub fn fd_self() -> Result<Vec<u32>> {
128 fd_impl!{"/proc/self/fd"}
129}
130
131pub fn fd_of_task(pid: u32, tid: u32) -> Result<Vec<u32>> {
132 fd_impl!{format!("/proc/{}/task/{}/fd", pid, tid)}
133}
134
135pub fn fd_self_task(tid: u32) -> Result<Vec<u32>> {
136 fd_impl!{format!("/proc/self/task/{}/fd", tid)}
137}
138
139#[cfg(test)]
140mod test {
141 use super::*;
142
143 #[test]
144 fn test_fd() {
145 let ret = fd_self().unwrap();
146 assert!(ret.contains(&0));
147 assert!(ret.contains(&1));
148 assert!(ret.contains(&2));
149 }
150}