w 命令与 who 命令的对比与实现原理

w 命令与 who 命令

w 命令与 who 命令可以用来查看当前系统中登录的用户信息,这是通过读取 /var/run/utmp 文件中的信息来实现的。

这里需要注意的是并非所有的程序都使用 /var/run/utmp 文件来保存登录信息,因此系统中实际在线的用户数目可能要比 w 命令与 who 命令的输出多

w 命令与 who 命令输出信息对比

w 命令输出:

10:02:55 up  1:30,  2 users,  load average: 2.25, 2.13, 2.10
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
longyu   :0       :0               08:33   ?xdm?  10:30   0.00s /usr/lib/gdm3/gdm-x-session --run-script /usr/bin/gnome-session
longyu   pts/3    d                09:41    0.00s  0.21s  0.00s w

who 命令输出:

longyu   pts/3    d                09:41   12:34   0.00s  0.00s /bin/bash --login
[longyu@debian-10:10:02:55] who $ who
longyu   :0           2020-07-11 08:33 (:0)
longyu   pts/3        2020-07-11 09:41 (d)

相同的项目:

  1. user name
  2. login tty
  3. login time

w 命令多出来的项目:

第一行中系统运行时间与当前用户数及运行负载
第二行中的如下字段:

  1. IDLE
  2. JCPU
  3. PCPU
  4. WHAT

man w 命令获取到的 manual 信息

执行 man w查看到的一些信息:

DESCRIPTION
       w displays information about the users currently on the machine, and their processes.  The header shows, in this order, the current time, how long the system has
       been running, how many users are currently logged on, and the system load averages for the past 1, 5, and 15 minutes.

       The following entries are displayed for each user: login name, the tty name, the remote host, login time, idle time, JCPU, PCPU, and the command  line  of  their
       current process.

       The  JCPU  time  is  the time used by all processes attached to the tty.  It does not include past background jobs, but does include currently running background
       jobs.

       The PCPU time is the time used by the current process, named in the "what" field.

FILES
       /var/run/utmp
              information about who is currently logged on

       /proc  process information

上面的 manual 中描述了 w 命令输出项目的含义及程序使用到的文件。

w 命令第一行字段中有系统运行时间,当前登录用户数目,系统负载。这与 uptime 命令输的的信息是相同的,那下面我们就来研究下 uptime 命令的输出是如何实现的吧!

uptime 命令的输出及其实现

uptime 命令输出示例如下:

[longyu@debian-10:10:35:33] 1 $ uptime
 10:35:40 up  2:02,  2 users,  load average: 2.34, 2.32, 2.30

通过执行 strace uptime 2>&1 | grep ‘open’ 可以查看到 uptime 执行过程中使用的文件。

[longyu@debian-10:10:35:25] 1 $ strace uptime 2>&1 | grep 'open'
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libprocps.so.7", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libsystemd.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblzma.so.5", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblz4.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcrypt.so.20", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgpg-error.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/auxv", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/sys/kernel/osrelease", O_RDONLY) = 3
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/auxv", O_RDONLY) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/uptime", O_RDONLY) = 3
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/proc/loadavg", O_RDONLY) = 4

上面的输出中,前几项访问了动态库与 /proc 目录下的一些文件。这里我们重点看 /proc/uptime/proc/loadavg/var/run/utmp 文件。

执行 man proc 获取帮助信息,找到如下描述:

/proc/uptime
              This file contains two numbers: the uptime of the system (seconds), and the amount of time spent in idle process (seconds).
/proc/loadavg
              The first three fields in this file are load average figures giving the number of jobs in the run queue (state R) or waiting for disk I/O (state D)  aver‐
              aged  over  1,  5, and 15 minutes.  They are the same as the load average numbers given by uptime(1) and other programs.  The fourth field consists of two
              numbers separated by a slash (/).  The first of these is the number of currently runnable kernel scheduling entities (processes, threads).  The value  af‐
              ter the slash is the number of kernel scheduling entities that currently exist on the system.  The fifth field is the PID of the process that was most re‐
              cently created on the system.

/proc/uptime 中保存了系统启动的时间(单位为 s),有了这个时间与当前时间进行计算就能够得到系统启动时间与已经运行的时长。

在线用户数目可以通过读取 /var/run/utmp 文件,遍历所有记录并判断 utmp 结构体中的 ut_type 的值是否为 USER_PROCESS 来统计在线用户数目。

loadavg 更简单,直接从 /proc/loadavg 中读取到信息后打印即可。

写到这里,我们已经清楚了 uptime 命令的大致实现原理,w 命令的第一行输出实现原理也与 uptime 相同。

w 命令的 IDLE、JCPU、PCPU、WHAT 输出的实现

w 命令与 who 命令都通过读取 /var/run/utmp 文件来获取当前的用户登录信息。w 命令比 who 命令多出来的项目也是使用从 utmp 文件中读取到的信息来实现的。

utmp 结构体定义如下:

/* The structure describing an entry in the user accounting database.  */
struct utmp
{
  short int ut_type;		/* Type of login.  */
  pid_t ut_pid;			/* Process ID of login process.  */
  char ut_line[UT_LINESIZE]
    __attribute_nonstring__;	/* Devicename.  */
  char ut_id[4];		/* Inittab ID.  */
  char ut_user[UT_NAMESIZE]
    __attribute_nonstring__;	/* Username.  */
  char ut_host[UT_HOSTSIZE]
    __attribute_nonstring__;	/* Hostname for remote login.  */
  struct exit_status ut_exit;	/* Exit status of a process marked
				   as DEAD_PROCESS.  */
/* The ut_session and ut_tv fields must be the same size when compiled
   32- and 64-bit.  This allows data files and shared memory to be
   shared between 32- and 64-bit applications.  */
#if __WORDSIZE_TIME64_COMPAT32
  int32_t ut_session;		/* Session ID, used for windowing.  */
  struct
  {
    int32_t tv_sec;		/* Seconds.  */
    int32_t tv_usec;		/* Microseconds.  */
  } ut_tv;			/* Time entry was made.  */
#else
  long int ut_session;		/* Session ID, used for windowing.  */
  struct timeval ut_tv;		/* Time entry was made.  */
#endif

  int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
  char __glibc_reserved[20];		/* Reserved for future use.  */
};

这里的 ut_pid 中保存了登录进程的 pid 号,获取到这个 pid 号后通过访问 /proc/pid/ 目录下的文件,w 命令就能够获取到其它输出项的信息了。

为了确认这个信息,我对 who 命令进行修改,打印出 ut_pid 信息。

[longyu@debian-10:10:15:09] who $ ./who
longyu   :0       Jul 11 08:33 (:0) 2473 
longyu   pts/3    Jul 11 09:41 (d) 5048 

使用 2473 这个 pid 查看 /proc 目录下的信息,有如下输出:

[longyu@debian-10:10:25:42] 1 $ cat /proc/2473/cmdline 
/usr/lib/gdm3/gdm-x-session--run-script/usr/bin/gnome-session
[longyu@debian-10:10:26:09] 1 $ cat /proc/2473/stat
2473 (gdm-x-session) S 2435 2473 2473 1026 2473 4194560 669 0 1 0 0 0 0 0 20 0 3 0 3827 183635968 1559 18446744073709551615 94108019777536 94108019837133 140721565482256 0 0 0 0 4096 81920 0 0 0 17 5 0 0 0 0 0 94108019859920 94108019863816 94108048117760 140721565486336 140721565486400 140721565486400 140721565487068 0

可以看到 cmdline 的输出与 w 命令的输出一致,stat 文件的输出就用来计算 IDLE、JCPU、PCPU 等字段(可能还需要依赖其它的文件内容),这里也就不再进一步探讨了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值