$29
Implement a 'lsof'-like program
In this homework, you have to implement the 'lsof' tool by yourself. 'lsof' is a tool to list open files. It can be used to list all the files opened by processes running in the system. The output of your homework is required to follow the spec strictly. The TAs will use the 'diff' tool to compare your output directly against our prepared sample test data.
# Program Arguments
Your program should work without any arguments. In the meantime, your program has to handle the following arguments properly:
* `-c REGEX`: a regular expression (REGEX) filter for filtering command line. For example `-c sh` would match `bash`, `zsh`, and `share`.
* `-t TYPE`: a TYPE filter. Valid TYPE includes `REG`, `CHR`, `DIR`, `FIFO`, `SOCK`, and `unknown`. TYPEs other than the listed should be considered invalid. For invalid types, your program has to print out an error message `Invalid TYPE option`. in a single line and terminate your program.
* `-f REGEX`: a regular expression (REGEX) filter for filtering filenames.
A sample output from this homework is demonstrated as follows:
```shell=
$ ./hw1 | head -n 20
COMMAND PID USER FD TYPE NODE NAME
systemd 1 root cwd unknown /proc/1/cwd (Permission denied)
systemd 1 root rtd unknown /proc/1/root (Permission denied)
systemd 1 root txt unknown /proc/1/exe (Permission denied)
systemd 1 root NOFD /proc/1/fd (Permission denied)
kthreadd 2 root cwd unknown /proc/2/cwd (Permission denied)
kthreadd 2 root rtd unknown /proc/2/root (Permission denied)
kthreadd 2 root txt unknown /proc/2/exe (Permission denied)
kthreadd 2 root NOFD /proc/2/fd (Permission denied)
rcu_gp 3 root cwd unknown /proc/3/cwd (Permission denied)
rcu_gp 3 root rtd unknown /proc/3/root (Permission denied)
rcu_gp 3 root txt unknown /proc/3/exe (Permission denied)
rcu_gp 3 root NOFD /proc/3/fd (Permission denied)
rcu_par_gp 4 root cwd unknown /proc/4/cwd (Permission denied)
rcu_par_gp 4 root rtd unknown /proc/4/root (Permission denied)
rcu_par_gp 4 root txt unknown /proc/4/exe (Permission denied)
rcu_par_gp 4 root NOFD /proc/4/fd (Permission denied)
kworker/0:0H-events_highpri 6 root cwd unknown /proc/6/cwd (Permission denied)
kworker/0:0H-events_highpri 6 root rtd unknown /proc/6/root (Permission denied)
kworker/0:0H-events_highpri 6 root txt unknown /proc/6/exe (Permission denied)
...
```
The detailed spec of this homework is introduced as follows. Your program has to output the following fields (columns) for each file opened by a running process. Each line presents the information for a single file. The required fields include `COMMAND`, `PID`, `USERM`, `FD`, `TYPE`, `NODE`, and `NAME`. The meaning of each field (column) is explained below.
* `COMMAND`:
* The **executable filename** of a running process.
* DO NOT show arguments.
* `PID`:
* Process id of a running process.
* Only need to handle opened files in process level (check `/proc/[pid]`. No need to handle opened files at thread level (that would be in `/proc/[pid]/task/[tid]`).
* `USER`:
* The username who runs the process.
* Please show `username` instead of UID.
* `FD`: The file descriptor. The value shown in the `FD` field can be one of the following cases.
* `cwd`: The current working directory, which can be read from `/proc/[pid]/cwd`.
* `rtd`: root directory, which can be read from `/proc/[pid]/root`.
* `txt`: program file of this process, can be read from `/proc/[pid]/exe`.
* `mem`: memory mapping information, which can be read from `/proc/[pid]/maps`.
* If `/proc/<pid>/maps` is not accessible, you don't need to show any information about mapped files.
* A memory-mapped file may have multiple segments or be mapped multiple times. You only need to output the first one for duplicated files, i.e., files having the same i-node or filename.
* You don't need to handle memory segments that do not associate with a file. For example, [heap] or anonymously mapped memory segments. Those memory segments should have an i-node number of zero.
* `DEL`: indicate a memory-mapped file has been deleted. You should show this value if there is a (deleted) mark right after the filename in memory maps.
* `[0-9]+[rwu]`: file descriptor and opened mode.
* The numbers show the file descriptor number of the opened file.
* The mode "r" means the file is opened for reading.
* The mode "w" means the file is opened for writing.
* The mode "u" means the file is opened for reading and writing.
* `NOFD`: if `/proc/[pid]/fd` is not accessible. In this case, the values for `TYPE` and `NODE` fields can be left empty.
* `TYPE`: The type of the opened file. The value shown in `TYPE` can be one of the following cases.
* `DIR`: a directory. `cwd` and `rtd` are also classified as this type.
* `REG`: a regular file
* `CHR`: a character special file, for example
`crw-rw-rw- 1 root root 1, 3 Mar 17 17:31 /dev/null`
* `FIFO`: a pipe, for example
* A link to a pipe, e.g.,
`lr-x------ 1 root root 64 Mar 17 19:55 5 -> 'pipe:[138394]'`
* A file with `p` type (FIFO)
`prw------- 1 root root 0 Mar 17 19:54 /run/systemd/inhibit/11.ref`
* `SOCK`: a socket, for example
`lrwx------ 1 root root 64 Mar 17 19:55 1 -> 'socket:[136975]'`
* `unknown`: Any other unlisted types. Alternatively, if a file has been deleted or is not accessible (e.g., permission denied), this column can show `unknown`.
* `NODE`:
* The i-node number of the file
* It can be blank or empty if and only if `/proc/[pid]/fd` is not accessible.
* `NAME`:
* Show the opened filename if it is a typical file or directory.
* Show `pipe:[node number]` if it is a symbolic file to a pipe, e.g.,
`l-wx------ 1 ta ta 64 三 8 02:11 91 -> 'pipe:[2669735]'`
* Show `socket:[node number]` if it is a symbolic file to a socket, e.g.,
`lrwx------ 1 ta ta 64 三 8 02:11 51 -> 'socket:[2669792]'`
* Append `(Permission denied)` if the access to `/proc/pid/fd` or `/proc/pid/(cwd|root|exe)` is failed due to permission denied.
* If the filename you read from /proc file system contains a `(deleted)`, please remove it from the filename before you print it out.
# Additional Notes on REGEX
If you plan to test REGEX feature with the `lsof` package that comes with Linux distributions, you should run it with the option `-c /REGEX/`.
For students who programming with C++, consider working with `regex_search()` instead of `regex_match()`. Please work with `regcomp()` and `regexec()` for students who are programming with C to implement this feature.
More Outputs
Your program has to order the output lines by performing a numeric sort against process ID (PIDs). We will test your program with and without root permission. If an operation does not have sufficient permission to perform, you have to print out `Permission denied` message.
# Run the command without root permission
```shell=
$ ./hw1| head -n 20
COMMAND PID USER FD TYPE NODE NAME
systemd 1 root cwd unknown /proc/1/cwd (Permission denied)
systemd 1 root rtd unknown /proc/1/root (Permission denied)
systemd 1 root txt unknown /proc/1/exe (Permission denied)
systemd 1 root NOFD /proc/1/fd (Permission denied)
kthreadd 2 root cwd unknown /proc/2/cwd (Permission denied)
kthreadd 2 root rtd unknown /proc/2/root (Permission denied)
kthreadd 2 root txt unknown /proc/2/exe (Permission denied)
kthreadd 2 root NOFD /proc/2/fd (Permission denied)
kworker/0:0H 4 root cwd unknown /proc/4/cwd (Permission denied)
kworker/0:0H 4 root rtd unknown /proc/4/root (Permission denied)
kworker/0:0H 4 root txt unknown /proc/4/exe (Permission denied)
kworker/0:0H 4 root NOFD /proc/4/fd (Permission denied)
mm_percpu_wq 6 root cwd unknown /proc/6/cwd (Permission denied)
mm_percpu_wq 6 root rtd unknown /proc/6/root (Permission denied)
mm_percpu_wq 6 root txt unknown /proc/6/exe (Permission denied)
mm_percpu_wq 6 root NOFD /proc/6/fd (Permission denied)
ksoftirqd/0 7 root cwd unknown /proc/7/cwd (Permission denied)
ksoftirqd/0 7 root rtd unknown /proc/7/root (Permission denied)
ksoftirqd/0 7 root txt unknown /proc/7/exe (Permission denied)
```
# Run the command with root permission
```shell=
$ sudo ./hw1| head -n 20
COMMAND PID USER FD TYPE NODE NAME
systemd 1 root cwd DIR 2 /
systemd 1 root rtd DIR 2 /
systemd 1 root txt REG 23734219 /lib/systemd/systemd
systemd 1 root DEL REG 23724387 /lib/x86_64-linux-gnu/libm-2.27.so
systemd 1 root mem REG 23724289 /lib/x86_64-linux-gnu/libudev.so.1.6.9
systemd 1 root mem REG 23724380 /lib/x86_64-linux-gnu/libgpg-error.so.0.22.0
systemd 1 root mem REG 23724264 /lib/x86_64-linux-gnu/libjson-c.so.3.0.1
systemd 1 root mem REG 24775614 /usr/lib/x86_64-linux-gnu/libargon2.so.0
systemd 1 root mem REG 23724307 /lib/x86_64-linux-gnu/libdevmapper.so.1.02.1
systemd 1 root mem REG 23725490 /lib/x86_64-linux-gnu/libattr.so.1.1.0
systemd 1 root mem REG 23725195 /lib/x86_64-linux-gnu/libcap-ng.so.0.0.0
systemd 1 root mem REG 23724192 /lib/x86_64-linux-gnu/libuuid.so.1.3.0
systemd 1 root DEL REG 23724382 /lib/x86_64-linux-gnu/libdl-2.27.so
systemd 1 root mem REG 23724639 /lib/x86_64-linux-gnu/libpcre.so.3.13.3
systemd 1 root DEL REG 23724459 /lib/x86_64-linux-gnu/libpthread-2.27.so
systemd 1 root mem REG 24772961 /usr/lib/x86_64-linux-gnu/liblz4.so.1.7.1
systemd 1 root mem REG 23725142 /lib/x86_64-linux-gnu/liblzma.so.5.2.2
systemd 1 root mem REG 23724150 /lib/x86_64-linux-gnu/libidn.so.11.6.16
systemd 1 root mem REG 24772626 /usr/lib/x86_64-linux-gnu/libip4tc.so.0.1.0
```