What is /proc in Linux (for beginners)

What is /proc

There is a directory named /proc on Linux. The files in this directory are virtual, for the Linux kernel to provide internal information; there is no file entity anywhere, like files on an SSD.

Example of files in /proc

An example is as follows. The ls command is executed with -F option, directories and symbolic links are respectively shown with / and @ at the tail.
$ ls -F /proc/
1/      73669/     crypto          irq/         modules       sys/
3674/   73681/     devices         kallsyms     mounts@       sysrq-trigger
3675/   73687/     diskstats       kcore        mtrr          sysvipc/
38/     91/        dma             keys         net@          thread-self@
4771/   92/        driver/         key-users    pagetypeinfo  timer_list
4777/   acpi/      dynamic_debug/  kmsg         partitions    tty/
4778/   asound/    execdomains     kpagecgroup  pressure/     uptime
61/     buddyinfo  fb              kpagecount   schedstat     version
72/     bus/       filesystems     kpageflags   self@         vmallocinfo
73/     cgroups    fs/             loadavg      slabinfo      vmstat
73632/  cmdline    interrupts      locks        softirqs      zoneinfo
73638/  consoles   iomem           meminfo      stat
73639/  cpuinfo    ioports         misc         swaps
As you can see at first glance, there are directories with only numbers (e.g. 1/, 3674/, etc.) and other files and directories (e.g. acpi/, buddyinfo, etc.). Numeric directories contain information on processes with process numbers of that value in the form of files under that directory. Other files and directories (files included in) contain information about the entire system.

Directories for process

Now, as an example, let's run the sleep command and start the process. The process is started with process ID 73717.
$ sleep 3600 &
[1] 73717
Let's look at the /proc information about this process.
$ ls -F /proc/73717/
arch_status         fd/                net/           setgroups
attr/               fdinfo/            ns/            smaps
autogroup           gid_map            numa_maps      smaps_rollup
auxv                io                 oom_adj        stack
cgroup              ksm_merging_pages  oom_score      stat
clear_refs          ksm_stat           oom_score_adj  statm
cmdline             limits             pagemap        status
comm                loginuid           patch_state    syscall
coredump_filter     map_files/         personality    task/
cpu_resctrl_groups  maps               projid_map     timens_offsets
cpuset              mem                root@          timers
cwd@                mountinfo          sched          timerslack_ns
environ             mounts             schedstat      uid_map
exe@                mountstats         sessionid      wchan
There are many different files and directories, but I will list here two that I often use.

exe

Here is a link to the executable of the process. You can see that the executable of the process is /usr/bin/sleep.
 $ ls -l /proc/73717/exe
lrwxrwxrwx 1 foo foo 0 Mar 19 11:06 /proc/73717/exe -> /usr/bin/sleep

fd

It contains a symbolic link to the file that the process is opening. The file name of the symbolic link is the descriptor number. In this case, we see that three files for standard I/O are open.
$ ls -l /proc/73717/fd
total 0
lrwx------ 1 foo foo 64 Mar 19 11:15 0 -> /dev/pts/5
lrwx------ 1 foo foo 64 Mar 19 11:15 1 -> /dev/pts/5
lrwx------ 1 foo foo 64 Mar 19 11:15 2 -> /dev/pts/5

Entire system information

Three system-wide files are also presented.

partitions

Partitions detected by the Linux kernel are included. In the following, the NVMe storage partition is shown. When a USB storage device is inserted, sda, sda1, sda2, etc. will be added to the list. This is useful to check if the Linux kernel recognizes the connected storage device.
$ cat /proc/partitions 
major minor  #blocks  name

 259        0 1953514584 nvme0n1
 259        1     498688 nvme0n1p1
 259        2   19530752 nvme0n1p2
 259        3   19530752 nvme0n1p3
 259        4   19530752 nvme0n1p4
 259        5   19530752 nvme0n1p5
 259        6 1874891776 nvme0n1p6

uptime

The time since Linux was started is stored.
$ uptime
 11:22:23 up  9:19,  2 users,  load average: 0.00, 0.00, 0.00

self

When a process refers to this file, it is a link to the directory for that process. In other words, different links point to different destinations depending on the process reading them.

In the following example, The link 73729 is the directory for the ls command itself which is reading /proc.

$ ls -l /proc/self
lrwxrwxrwx 1 root root 0 Mar 19 02:02 /proc/self -> 73729

More information

There are many files in /proc as shown in the examples in this article. See below for a detailed description of them.

How to build a Linux kernel

This article shows you how to build a Linux kernel, which is useful for using features supported only in the latest kernels from the Linux community or for creating your own Linux OS. The commands listed here have been verified to run on Debian 11, but are basically the same for other Linux operating systems (except for how to install packages).

Preparation to build

Install the following packages.
sudo apt install gcc make flex bison bc libncurses-dev libelf-dev libssl-dev

Get a kernel source code

Linux kernel source code can be downloaded from the following site.

The latest stable version on the day this post was written was6.2.7. The following shows an example of downloading it to a working directory on a build machine.
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.2.7.tar.xz

Build

Extract the source code

tar xf linux-6.2.7.tar.xz

Configuration

ここではデフォルト設定を行います。
cd linux-6.2.7
make defconfig

When more configuration is required

make menuconfig
After entering the above, the following TUI-based configuration screen will appear. This can be used to add/remove the required CONFIGs.

Compile

make -j32

The above -j32 is an option to compile in 32 parallel. It should be changed accordingly to the actual number of CPUs.

If the following message appears, the build was successful. The following bzImage is the same as the named like vmlinuz-6.1.0-5-amd64 in many Linux OS.

Kernel: arch/x86/boot/bzImage is ready  (#1)

Launch test

Here we will use a Debian 11 drive image as a rootfs and boot with QEMU.

Download of a rootfs drive image

Download the rootfs image as follows.
wget https://cloud.debian.org/images/cloud/bullseye/20230124-1270/debian-11-nocloud-amd64-20230124-1270.qcow2

Launch

Run QEMU as follows. --nographic option is given so that a serial device is created in the virtual machine. The kernel option console=ttyS0 makes the serial device become a console. These make the terminal running QEMU the input/output terminal to the serial device as it is.

Note that when configured with defconfig, the virtio storage functionality is built into the kernel. The kernel can mount rootfs directly without initrd.

sudo qemu-system-x86_64 \
-cpu host \
--enable-kvm \
-m 1024 \
-nographic \
-drive id=drive0,format=qcow2,file=debian-11-nocloud-amd64-20230124-1270.qcow2,if=virtio \
-kernel arch/x86_64/boot/bzImage \
-append "root=/dev/vda1 console=ttyS0"
If the following login prompt appears, you have succeeded.
(abbr.)
Debian GNU/Linux 11 debian ttyS0

debian login:
This image allows to log in without password by use root as a user name.
Linux debian 6.2.7 #1 SMP PREEMPT_DYNAMIC Sun Mar 19 02:39:21 UTC 2023 x86_64
(abbr.)
root@debian:~#

How to force terminate QEMU when a launch fails

While QEMU is running, enter Ctrl-a followed by c to go to the QEMU monitor screen. Enter q here.
(Enter Ctrl-a, c)
QEMU 7.2.0 monitor - type 'help' for more information
(qemu) q

How to get the Web contents though a remote site with SOCKS proxy by ssh

Abstract

As shown in the figure below, when My Site cannot connect to Web Server X directly, but can connect via a remote SSH server (remote_server) that can be connected via SSH, this post explains how to get WebServer X pages in My Site's Web browser.

As a remote_server, AWS and Azure can be available. In that case, the region of the request source can be set to that of the data center.

Create a SOCKS proxy

Run the following command with a SSH client on My Site. This creates a SOCKS proxy and has HTTP requests being sent from remote_server. The port number 8080 can be changed.
ssh -D 8080 remote_server

Configuration of Web browser

Configure a SOCK proxy in your Web browser. When the SSH client is executed in localhost (the same machine), set the address like below.

Chrome

google-chrome --proxy-server="socks://localhost:8080"

Firefox

Proxy setting dialog will be shown as you follow Menu -> Settings -> Network Settings -> Settings...
Set the IP adddress and port in the dialog.

How to create a MySQL database on a memory (tmps)

Chgage datadir in /etc/mysql/my.conf to the directory on a tmpfs.
-datadir                = /var/lib/mysql
+datadir                = /dev/shm/mysql
Run the following command to create a DB on a new directory.
# mysql_install_db
Then, launch mysqld.
/etc/init.d/mysqld start

Note

The file created by mysql_install_db will be removed after reboot, so it may be a good idea to write the above setting in /etc/init.d/mysqld to be executed at the beginning. In some cases, such as Ubuntu, access may be restricted by apparmor. In that case, add the following description to /etc/apparmor.d/usr.sbin.mysqld.
  /dev/shm/mysql/** rwk,

An example to unbind/bind a USB device on Linux

# cd /sys/bus/usb/drivers/usb
# echo -n '2-1.6' > unbind; echo -n '2-1.6' > bind
The above 2-1.6 is a bus number. It changes by environment. You can find the device corresponding to the bus number as below.
# cat 2-1.6/manufacturer
RATOC Systems,Inc.
# cat 2-1.6/product
RAL-2496UT1 USB-Transport

A way to address the problem when 'X11 forwarding request failed on channel 0' is shown and X11 forwarding isn't working in ssh

Let's investigate the root case. You can show details by adding '-v' option to ssh. When No auth program is shown as below, you should install xauth by apt or yum.
...
debug1: Remote: No xauth program; cannot forward with spoofing.
X11 forwarding request failed on channel 0

Run Python script in GDB

Recent GDB (at least afeter version 7) can run Python script. To run it, we use source command as same as the GDB macro.

Let's try it. We prepare the following Python script.
$ cat hello.py
#!/usr/bin/env python
import sys
sys.stdout.write('Hello, my first script.\n')
Launch GDB and run the script
(gdb) source hello.py
Hello, my first script.

Use of GDB functions from a Python script

The following is the example to use GDB functions from a Python script. gdb.execute() can run operations used in the GDB command line.

The following example uses target.cc as a debug target.
[target.cc]
#include <cstdio>
#include <cstdlib>
#include <time.h>

int getval(int div)
{
        return time(NULL) / div;
}

int main(void)
{
        printf("val: %d\n", getval(5));
        return EXIT_SUCCESS;
}
show-bt.py will perform the following 4 operations.
  • Set a break point at the head of getval() function
  • Run the program
  • Show the bracktrace at the break point
  • Show rax register at the break point
[show-bt.py] 
gdb.execute('b getval')
gdb.execute('run')
gdb.execute('bt')
gdb.execute('p/x $rax')
The following is an example to run a script in the command line. The command line argument '-q' disables to show startup messages of GDB such as copyright. '-x' specifies the script to be executed.
$ gdb -q -x show-bt.py  target
Reading symbols from /home/foo/target...done.
Breakpoint 1 at 0x400627: file target.cc, line 7.

Breakpoint 1, getval (div=5) at target.cc:7
7               return time(NULL) / div;
#0  getval (div=5) at target.cc:7
#1  0x0000000000400656 in main () at target.cc:12
#2  0x00007ffff72d2ead in __libc_start_main (main=, argc=, ubp_av=, init=, fini=, rtld_fini=, stack_end=0x7fffffffe128) at libc-start.c:228
#3  0x0000000000400539 in _start ()
$1 = 0x7ffff763aee8

Get output of a command as a Python string

The above example only executes normal GDB commands. Let's get the output as a Python string. It can be achived by passing True to to_string parameter of get.execute() function. Python is also good at string processing, so you can easily extract and display specific strings in a formatted format.

The following exmaple shows the frame number and the last word from the stacktrace.
$ cat show-bt-and-format.py 
gdb.execute('b getval')
gdb.execute('run')
bt = gdb.execute('bt', to_string=True)
for line in bt.split('\n'):
  words = line.split(' ')
  print '%s %s' % (words[0], words[-1])
$ gdb -q -x show-bt-and-format.py  target
Reading symbols from /home/foo/target...done.
Breakpoint 1 at 0x400627: file target.cc, line 7.

Breakpoint 1, getval (div=5) at target.cc:7
7               return time(NULL) / div;
#0 target.cc:7
#1 target.cc:12
#2 libc-start.c:228
#3 ()